You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2020/11/19 11:32:27 UTC
[incubator-echarts] 01/02: test: migrate test lib myTransform to ts.
This is an automated email from the ASF dual-hosted git repository.
sushuang pushed a commit to branch fix/aggregate
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git
commit be70a3979a48ed250f683e8b4d7a7d657526ee56
Author: 100pah <su...@gmail.com>
AuthorDate: Thu Nov 19 01:25:11 2020 +0800
test: migrate test lib myTransform to ts.
---
build/build.js | 6 +
build/config.js | 24 ++
build/release.js | 2 +-
src/data/helper/transform.ts | 2 +-
test/custom-shape-morphing2.html | 5 +-
test/custom-shape-morphing3.html | 8 +-
test/lib/config.js | 1 +
test/lib/myTransform/aggregate.js | 174 --------------
test/lib/myTransform/dist/myTransform.js | 219 +++++++++++++++++
test/lib/myTransform/dist/myTransform.js.map | 1 +
test/lib/myTransform/id.js | 88 -------
test/lib/myTransform/src/.eslintrc.yaml | 47 ++++
test/lib/myTransform/src/aggregate.ts | 342 +++++++++++++++++++++++++++
test/lib/myTransform/src/id.ts | 90 +++++++
test/lib/myTransform/src/index.ts | 3 +
tsconfig.json | 3 +-
16 files changed, 742 insertions(+), 273 deletions(-)
diff --git a/build/build.js b/build/build.js
index 24da784..42bb096 100755
--- a/build/build.js
+++ b/build/build.js
@@ -138,6 +138,12 @@ async function run() {
];
await build(cfgs, opt.min, opt.sourcemap);
}
+ else if (opt.type === 'myTransform') {
+ const cfgs = [
+ config.createMyTransform()
+ ];
+ await build(cfgs, opt.min, opt.sourcemap);
+ }
else {
const cfg = config.createECharts(opt);
await build([cfg], opt.min, opt.sourcemap);
diff --git a/build/config.js b/build/config.js
index 9cc6e82..53cec29 100644
--- a/build/config.js
+++ b/build/config.js
@@ -212,3 +212,27 @@ exports.createDataTool = function () {
}
};
};
+
+exports.createMyTransform = function () {
+ let input = nodePath.resolve(ecDir, `test/lib/myTransform/src/index.ts`);
+
+ return {
+ plugins: preparePlugins({
+ clean: true
+ }, {
+ include: [
+ nodePath.resolve(ecDir, 'test/lib/myTransform/src/**/*.ts')
+ ]
+ }),
+ input: input,
+ output: {
+ name: 'myTransform',
+ format: 'umd',
+ sourcemap: true,
+ file: nodePath.resolve(ecDir, `test/lib/myTransform/dist/myTransform.js`)
+ },
+ watch: {
+ include: [nodePath.resolve(ecDir, 'test/lib/myTransform/src/**')]
+ }
+ };
+};
diff --git a/build/release.js b/build/release.js
index 2a4e070..d9d6762 100644
--- a/build/release.js
+++ b/build/release.js
@@ -42,7 +42,7 @@ function release() {
}
}
- const argsList = ['', 'simple', 'common', 'extension'].map((type) => {
+ const argsList = ['', 'simple', 'common', 'extension', 'myTransform'].map((type) => {
return [
'--type',
type,
diff --git a/src/data/helper/transform.ts b/src/data/helper/transform.ts
index 287b55d..349e985 100644
--- a/src/data/helper/transform.ts
+++ b/src/data/helper/transform.ts
@@ -83,7 +83,7 @@ export interface ExternalDataTransformResultItem {
*/
dimensions?: DimensionDefinitionLoose[];
}
-interface ExternalDimensionDefinition extends Partial<DimensionDefinition> {
+export interface ExternalDimensionDefinition extends Partial<DimensionDefinition> {
// Mandatory
index: DimensionIndex;
}
diff --git a/test/custom-shape-morphing2.html b/test/custom-shape-morphing2.html
index ac12738..f55d367 100644
--- a/test/custom-shape-morphing2.html
+++ b/test/custom-shape-morphing2.html
@@ -27,7 +27,6 @@ under the License.
<script src='lib/jquery.min.js'></script>
<script src="../dist/echarts.js"></script>
<script src="lib/testHelper.js"></script>
- <script src="lib/myTransform/aggregate.js"></script>
<script src="lib/transitionPlayer.js"></script>
<link rel="stylesheet" href="lib/reset.css" />
</head>
@@ -76,9 +75,9 @@ under the License.
<script>
- require(['echarts', 'ecStat'], function (echarts, ecStat) {
+ require(['echarts', 'ecStat', 'myTransform'], function (echarts, ecStat, myTransform) {
- echarts.registerTransform(window.myTransform.aggregate);
+ echarts.registerTransform(myTransform.aggregate);
echarts.registerTransform(ecStat.transform.clustering);
diff --git a/test/custom-shape-morphing3.html b/test/custom-shape-morphing3.html
index 748b97a..1e762df 100644
--- a/test/custom-shape-morphing3.html
+++ b/test/custom-shape-morphing3.html
@@ -27,8 +27,6 @@ under the License.
<script src='lib/jquery.min.js'></script>
<script src="../dist/echarts.js"></script>
<script src="lib/testHelper.js"></script>
- <script src="lib/myTransform/aggregate.js"></script>
- <script src="lib/myTransform/id.js"></script>
<script src="lib/transitionPlayer.js"></script>
<link rel="stylesheet" href="lib/reset.css" />
</head>
@@ -42,11 +40,11 @@ under the License.
<script>
- require(['echarts', 'ecStat'], function (echarts, ecStat) {
+ require(['echarts', 'ecStat', 'myTransform'], function (echarts, ecStat, myTransform) {
$.get('data/life-expectancy-table.json', function (rawData) {
- echarts.registerTransform(window.myTransform.aggregate);
- echarts.registerTransform(window.myTransform.id);
+ echarts.registerTransform(myTransform.aggregate);
+ echarts.registerTransform(myTransform.id);
const COLORS = [
'#37A2DA', '#e06343', '#37a354', '#b55dba', '#b5bd48', '#8378EA', '#96BFFF'
diff --git a/test/lib/config.js b/test/lib/config.js
index 5966c4b..ad8e68b 100644
--- a/test/lib/config.js
+++ b/test/lib/config.js
@@ -64,6 +64,7 @@
'echarts': ecDistPath,
'zrender': 'node_modules/zrender/dist/zrender',
'ecStat': 'test/lib/ecStat.min',
+ 'myTransform': 'test/lib/myTransform/dist/myTransform',
// 'ecStat': 'http://localhost:8001/echarts/echarts-stat/dist/ecStat',
'geoJson': '../geoData/geoJson',
'theme': 'theme',
diff --git a/test/lib/myTransform/aggregate.js b/test/lib/myTransform/aggregate.js
deleted file mode 100644
index a5fd4eb..0000000
--- a/test/lib/myTransform/aggregate.js
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*/
-
-(function (exports) {
-
- /**
- * @usage
- *
- * ```js
- * dataset: [{
- * source: [
- * ['aa', 'bb', 'cc', 'tag'],
- * [12, 0.33, 5200, 'AA'],
- * [21, 0.65, 7100, 'AA'],
- * [51, 0.15, 1100, 'BB'],
- * [71, 0.75, 9100, 'BB'],
- * ...
- * ]
- * }, {
- * transform: {
- * type: 'my:aggregate',
- * config: {
- * resultDimensions: [
- * // by default, use the same name with `from`.
- * { from: 'aa', method: 'sum' },
- * { from: 'bb', method: 'count' },
- * { from: 'cc' }, // method by default: use the first value.
- * { from: 'tag' }
- * ],
- * groupBy: 'tag'
- * }
- * }
- * // Then the result data will be:
- * // [
- * // ['aa', 'bb', 'cc', 'tag'],
- * // [12, 0.33, 5200, 'AA'],
- * // [21, 0.65, 8100, 'BB'],
- * // ...
- * // ]
- * }]
- * ```
- */
- var transform = {
-
- type: 'myTransform:aggregate',
-
- /**
- * @param params
- * @param params.config.resultDimensions Mandatory.
- * {
- * // Optional. The name of the result dimensions.
- * // If not provided, inherit the name from `from`.
- * name: DimensionName;
- * // Mandatory. `from` is used to reference dimension from `source`.
- * from: DimensionIndex | DimensionName;
- * // Optional. Aggregate method. Currently only these method supported.
- * // If not provided, use `'first'`.
- * method: 'sum' | 'count' | 'first';
- * }[]
- * @param params.config.groupBy DimensionIndex | DimensionName Optional.
- */
- transform: function (params) {
- var upstream = params.upstream;
- var config = params.config;
- var resultDimensionsConfig = config.resultDimensions;
-
- var resultDimInfoList = [];
- var resultDimensions = [];
- for (var i = 0; i < resultDimensionsConfig.length; i++) {
- var resultDimInfoConfig = resultDimensionsConfig[i];
- var resultDimInfo = upstream.getDimensionInfo(resultDimInfoConfig.from);
- assert(resultDimInfo, 'Can not find dimension by `from`: ' + resultDimInfoConfig.from);
- resultDimInfo.method = resultDimInfoConfig.method;
- resultDimInfoList.push(resultDimInfo);
- if (resultDimInfoConfig.name != null) {
- resultDimInfo.name = resultDimInfoConfig.name;
- }
- resultDimensions.push(resultDimInfo.name);
- }
-
- var resultData = [];
-
- var groupBy = config.groupBy;
- var groupByDimInfo;
- if (groupBy != null) {
- var groupMap = {};
- groupByDimInfo = upstream.getDimensionInfo(groupBy);
- assert(groupByDimInfo, 'Can not find dimension by `groupBy`: ' + groupBy);
-
- for (var dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
- var groupByVal = upstream.retrieveValue(dataIndex, groupByDimInfo.index);
-
- if (!groupMap.hasOwnProperty(groupByVal)) {
- var newLine = createLine(upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal);
- resultData.push(newLine);
- groupMap[groupByVal] = newLine;
- }
- else {
- var targetLine = groupMap[groupByVal];
- aggregateLine(upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo);
- }
- }
- }
- else {
- var targetLine = createLine(upstream, 0, resultDimInfoList);
- resultData.push(targetLine);
- for (var dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
- aggregateLine(upstream, dataIndex, targetLine, resultDimInfoList);
- }
- }
-
- return {
- dimensions: resultDimensions,
- data: resultData
- };
- }
- };
-
- function createLine(upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal) {
- var newLine = [];
- for (var j = 0; j < resultDimInfoList.length; j++) {
- var resultDimInfo = resultDimInfoList[j];
- var method = resultDimInfo.method;
- newLine[j] = (groupByDimInfo && resultDimInfo.index === groupByDimInfo.index)
- ? groupByVal
- : (method === 'sum' || method === 'count')
- ? 0
- // By default, method: 'first'
- : upstream.retrieveValue(dataIndex, resultDimInfo.index);
- }
- return newLine;
- }
-
- function aggregateLine(upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo) {
- for (var j = 0; j < resultDimInfoList.length; j++) {
- var resultDimInfo = resultDimInfoList[j];
- var method = resultDimInfo.method;
- if (!groupByDimInfo || resultDimInfo.index !== groupByDimInfo.index) {
- if (method === 'sum') {
- targetLine[j] += upstream.retrieveValue(dataIndex, resultDimInfo.index);
- }
- else if (method === 'count') {
- targetLine[j] += 1;
- }
- }
- }
- }
-
- function assert(cond, msg) {
- if (!cond) {
- throw new Error(msg || 'transition player error');
- }
- }
-
- var myTransform = exports.myTransform = exports.myTransform || {};
- myTransform.aggregate = transform;
-
-})(this);
diff --git a/test/lib/myTransform/dist/myTransform.js b/test/lib/myTransform/dist/myTransform.js
new file mode 100644
index 0000000..9edeb7f
--- /dev/null
+++ b/test/lib/myTransform/dist/myTransform.js
@@ -0,0 +1,219 @@
+(function (global, factory) {
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.myTransform = {}));
+})(this, function (exports) {
+ 'use strict';
+
+ var transform = {
+ type: 'myTransform:id',
+ transform: function (params) {
+ var upstream = params.upstream;
+ var config = params.config;
+ var dimensionIndex = config.dimensionIndex;
+ var dimensionName = config.dimensionName;
+ var dimsDef = upstream.cloneAllDimensionInfo();
+ dimsDef[dimensionIndex] = dimensionName;
+ var data = upstream.cloneRawData();
+
+ for (var i = 0, len = data.length; i < len; i++) {
+ var line = data[i];
+ line[dimensionIndex] = i;
+ }
+
+ return {
+ dimensions: dimsDef,
+ data: data
+ };
+ }
+ };
+ var arrayProto = Array.prototype;
+ var nativeSlice = arrayProto.slice;
+
+ var ctorFunction = function () {}.constructor;
+
+ var protoFunction = ctorFunction ? ctorFunction.prototype : null;
+
+ function bindPolyfill(func, context) {
+ var args = [];
+
+ for (var _i = 2; _i < arguments.length; _i++) {
+ args[_i - 2] = arguments[_i];
+ }
+
+ return function () {
+ return func.apply(context, args.concat(nativeSlice.call(arguments)));
+ };
+ }
+
+ var bind = protoFunction && isFunction(protoFunction.bind) ? protoFunction.call.bind(protoFunction.bind) : bindPolyfill;
+
+ function isFunction(value) {
+ return typeof value === 'function';
+ }
+
+ function assert(condition, message) {
+ if (!condition) {
+ throw new Error(message);
+ }
+ }
+
+ function hasOwn(own, prop) {
+ return own.hasOwnProperty(prop);
+ }
+
+ var METHOD_INTERNAL = {
+ 'SUM': true,
+ 'COUNT': true,
+ 'FIRST': true,
+ 'AVERAGE': true,
+ 'Q1': true,
+ 'Q2': true,
+ 'Q3': true,
+ 'MIN': true,
+ 'MAX': true
+ };
+ var METHOD_ALIAS = {
+ MEDIAN: 'Q2'
+ };
+ var transform$1 = {
+ type: 'myTransform:aggregate',
+ transform: function (params) {
+ var upstream = params.upstream;
+ var config = params.config;
+ var dimWrap = prepareDimensions(config, upstream);
+ var resultDimInfoList = dimWrap.resultDimInfoList;
+ var resultDimensions = dimWrap.resultDimensions;
+ var groupByDimInfo = prepareGroupByDimInfo(config, upstream);
+ var finalResult = travel(groupByDimInfo, upstream, resultDimInfoList, createResultLine, aggregateResultLine);
+ return {
+ dimensions: resultDimensions,
+ data: finalResult.outList
+ };
+ }
+ };
+
+ function prepareDimensions(config, upstream) {
+ var resultDimensionsConfig = config.resultDimensions;
+ var resultDimInfoList = [];
+ var resultDimensions = [];
+
+ for (var i = 0; i < resultDimensionsConfig.length; i++) {
+ var resultDimInfoConfig = resultDimensionsConfig[i];
+ var resultDimInfo = upstream.getDimensionInfo(resultDimInfoConfig.from);
+ assert(resultDimInfo, 'Can not find dimension by `from`: ' + resultDimInfoConfig.from);
+ resultDimInfo.method = normalizeMethod(resultDimInfoConfig.method);
+ assert(resultDimInfo.method, 'method is required');
+ resultDimInfoList.push(resultDimInfo);
+
+ if (resultDimInfoConfig.name != null) {
+ resultDimInfo.name = resultDimInfoConfig.name;
+ }
+
+ resultDimensions.push(resultDimInfo.name);
+ }
+
+ return {
+ resultDimensions: resultDimensions,
+ resultDimInfoList: resultDimInfoList
+ };
+ }
+
+ function prepareGroupByDimInfo(config, upstream) {
+ var groupByConfig = config.groupBy;
+ var groupByDimInfo;
+
+ if (groupByConfig != null) {
+ groupByDimInfo = upstream.getDimensionInfo(groupByConfig);
+ assert(groupByDimInfo, 'Can not find dimension by `groupBy`: ' + groupByConfig);
+ }
+
+ return groupByDimInfo;
+ }
+
+ function travel(groupByDimInfo, upstream, resultDimInfoList, doCreate, doAggregate) {
+ var outList = [];
+ var groupMap;
+
+ if (groupByDimInfo) {
+ groupMap = {};
+
+ for (var dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
+ var groupByVal = upstream.retrieveValue(dataIndex, groupByDimInfo.index);
+
+ if (groupByVal == null) {
+ continue;
+ }
+
+ var groupByValStr = groupByVal + '';
+
+ if (!hasOwn(groupMap, groupByValStr)) {
+ var newLine = doCreate(upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal);
+ outList.push(newLine);
+ groupMap[groupByValStr] = newLine;
+ } else {
+ var targetLine = groupMap[groupByValStr];
+ doAggregate(upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo);
+ }
+ }
+ } else {
+ var targetLine = doCreate(upstream, 0, resultDimInfoList);
+ outList.push(targetLine);
+
+ for (var dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
+ doAggregate(upstream, dataIndex, targetLine, resultDimInfoList);
+ }
+ }
+
+ return {
+ groupMap: groupMap,
+ outList: outList
+ };
+ }
+
+ function normalizeMethod(method) {
+ if (method == null) {
+ return 'FIRST';
+ }
+
+ var methodInternal = method.toUpperCase();
+ methodInternal = hasOwn(METHOD_ALIAS, methodInternal) ? METHOD_ALIAS[methodInternal] : methodInternal;
+ assert(hasOwn(METHOD_INTERNAL, methodInternal), "Illegal method " + method + ".");
+ return methodInternal;
+ }
+
+ var createResultLine = function (upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal) {
+ var newLine = [];
+
+ for (var j = 0; j < resultDimInfoList.length; j++) {
+ var resultDimInfo = resultDimInfoList[j];
+ var method = resultDimInfo.method;
+ newLine[j] = groupByDimInfo && resultDimInfo.index === groupByDimInfo.index ? groupByVal : method === 'SUM' || method === 'COUNT' ? 0 : upstream.retrieveValue(dataIndex, resultDimInfo.index);
+ }
+
+ return newLine;
+ };
+
+ var aggregateResultLine = function (upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo) {
+ for (var j = 0; j < resultDimInfoList.length; j++) {
+ var resultDimInfo = resultDimInfoList[j];
+ var method = resultDimInfo.method;
+
+ if (groupByDimInfo && resultDimInfo.index === groupByDimInfo.index) {
+ continue;
+ }
+
+ if (method === 'SUM') {
+ targetLine[j] += upstream.retrieveValue(dataIndex, resultDimInfo.index);
+ } else if (method === 'COUNT') {
+ targetLine[j] += 1;
+ } else if (method === 'AVERAGE') {
+ targetLine[j] += upstream.retrieveValue(dataIndex, resultDimInfo.index) / 1;
+ }
+ }
+ };
+
+ exports.aggregate = transform$1;
+ exports.id = transform;
+ Object.defineProperty(exports, '__esModule', {
+ value: true
+ });
+});
\ No newline at end of file
diff --git a/test/lib/myTransform/dist/myTransform.js.map b/test/lib/myTransform/dist/myTransform.js.map
new file mode 100644
index 0000000..4b03361
--- /dev/null
+++ b/test/lib/myTransform/dist/myTransform.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"myTransform.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
\ No newline at end of file
diff --git a/test/lib/myTransform/id.js b/test/lib/myTransform/id.js
deleted file mode 100644
index 9e91370..0000000
--- a/test/lib/myTransform/id.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements. See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership. The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License. You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied. See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*/
-
-(function (exports) {
-
- /**
- * @usage
- *
- * ```js
- * dataset: [{
- * source: [
- * ['aa', 'bb', 'cc', 'tag'],
- * [12, 0.33, 5200, 'AA'],
- * [21, 0.65, 8100, 'AA'],
- * ...
- * ]
- * }, {
- * transform: {
- * type: 'my:id',
- * config: {
- * dimensionIndex: 4,
- * dimensionName: 'ID'
- * }
- * }
- * // Then the result data will be:
- * // [
- * // ['aa', 'bb', 'cc', 'tag', 'ID'],
- * // [12, 0.33, 5200, 'AA', 0],
- * // [21, 0.65, 8100, 'BB', 1],
- * // ...
- * // ]
- * }]
- * ```
- */
- var transform = {
-
- type: 'myTransform:id',
-
- /**
- * @param params.config.dimensionIndex DimensionIndex
- * Mandatory. Specify where to put the new id dimension.
- * @param params.config.dimensionName DimensionName
- * Optional. If not provided, left the dimension name not defined.
- */
- transform: function (params) {
- var upstream = params.upstream;
- var config = params.config;
- var dimensionIndex = config.dimensionIndex;
- var dimensionName = config.dimensionName;
-
- var dimsDef = upstream.cloneAllDimensionInfo();
- dimsDef[dimensionIndex] = dimensionName;
-
- var data = upstream.cloneRawData();
-
- for (var i = 0, len = data.length; i < len; i++) {
- var line = data[i];
- line[dimensionIndex] = i;
- }
-
- return {
- dimensions: dimsDef,
- data: upstream.data
- };
- }
- };
-
- var myTransform = exports.myTransform = exports.myTransform || {};
- myTransform.id = transform;
-
-})(this);
-
diff --git a/test/lib/myTransform/src/.eslintrc.yaml b/test/lib/myTransform/src/.eslintrc.yaml
new file mode 100644
index 0000000..6bda6d7
--- /dev/null
+++ b/test/lib/myTransform/src/.eslintrc.yaml
@@ -0,0 +1,47 @@
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Note:
+# If eslint does not work in VSCode, please check:
+# (1) Whether "@typescript-eslint/eslint-plugin" and "@typescript-eslint/parser"
+# are npm installed locally. Should better in the same version.
+# (2) Whether "VSCode ESlint extension" is installed.
+# (3) If the project folder is not the root folder of your working space, please
+# config the "VSCode ESlint extension" in "settings":
+# ```json
+# "eslint.workingDirectories": [{"mode": "auto"}]
+# ```
+# Note that it should be "workingDirectories" rather than "WorkingDirectories".
+
+parser: "@typescript-eslint/parser"
+parserOptions:
+ ecmaVersion: 6
+ sourceType: module
+ ecmaFeatures:
+ modules: true
+ project: "tsconfig.json"
+plugins: ["@typescript-eslint"]
+env:
+ browser: true
+ node: true
+ es6: false
+globals:
+ jQuery: false
+ Promise: false
+ __DEV__: false
+extends: '../../../../.eslintrc-common.yaml'
diff --git a/test/lib/myTransform/src/aggregate.ts b/test/lib/myTransform/src/aggregate.ts
new file mode 100644
index 0000000..68a4d04
--- /dev/null
+++ b/test/lib/myTransform/src/aggregate.ts
@@ -0,0 +1,342 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import {
+ DataTransformOption, ExternalDataTransform, ExternalSource, ExternalDimensionDefinition
+} from '../../../../src/data/helper/transform';
+import {
+ DimensionName, DimensionLoose, DimensionDefinitionLoose, OptionDataValue
+} from '../../../../src/util/types';
+import { hasOwn, assert } from 'zrender/src/core/util';
+
+
+/**
+ * @usage
+ *
+ * ```js
+ * dataset: [{
+ * source: [
+ * ['aa', 'bb', 'cc', 'tag'],
+ * [12, 0.33, 5200, 'AA'],
+ * [21, 0.65, 7100, 'AA'],
+ * [51, 0.15, 1100, 'BB'],
+ * [71, 0.75, 9100, 'BB'],
+ * ...
+ * ]
+ * }, {
+ * transform: {
+ * type: 'my:aggregate',
+ * config: {
+ * resultDimensions: [
+ * // by default, use the same name with `from`.
+ * { from: 'aa', method: 'sum' },
+ * { from: 'bb', method: 'count' },
+ * { from: 'cc' }, // method by default: use the first value.
+ * { from: 'dd', method: 'Q1', boundIQR: 1 },
+ * { from: 'tag' }
+ * ],
+ * groupBy: 'tag'
+ * }
+ * }
+ * // Then the result data will be:
+ * // [
+ * // ['aa', 'bb', 'cc', 'tag'],
+ * // [12, 0.33, 5200, 'AA'],
+ * // [21, 0.65, 8100, 'BB'],
+ * // ...
+ * // ]
+ * }]
+ * ```
+ *
+ * Current supported methods (case insensitive):
+ * 'sum'
+ * 'count'
+ * 'average'
+ * 'Q1'
+ * 'Q3'
+ * 'Q2' or 'median'
+ * 'min'
+ * 'max'
+ *
+ * Current supported other arguments:
+ * boundIQR:
+ * Data less than min bound is outlier.
+ * default 1.5, means Q1 - 1.5 * (Q3 - Q1).
+ * If 'none'/0 passed, min bound will not be used.
+ *
+ */
+
+export interface AggregateTransformOption extends DataTransformOption {
+ type: 'myTransform:aggregate';
+ config: {
+ // Mandatory
+ resultDimensions: {
+ // Optional. The name of the result dimensions.
+ // If not provided, inherit the name from `from`.
+ name: DimensionName;
+ // Mandatory. `from` is used to reference dimension from `source`.
+ from: DimensionLoose;
+ // Optional. Aggregate method. Currently only these method supported.
+ // If not provided, use `'first'`.
+ method: AggregateMethodLoose;
+ }[];
+ // Optional
+ groupBy: DimensionLoose;
+ };
+}
+
+const METHOD_INTERNAL = {
+ 'SUM': true,
+ 'COUNT': true,
+ 'FIRST': true,
+ 'AVERAGE': true,
+ 'Q1': true,
+ 'Q2': true,
+ 'Q3': true,
+ 'MIN': true,
+ 'MAX': true
+} as const;
+const METHOD_NEEDS_COLLECT = {
+ AVERAGE: true,
+ Q1: true,
+ Q2: true,
+ Q3: true
+} as const;
+const METHOD_ALIAS = {
+ MEDIAN: 'Q2'
+} as const;
+
+type AggregateMethodLoose =
+ AggregateMethodInternal
+ | 'sum' | 'count' | 'first' | 'average' | 'Q1' | 'Q2' | 'Q3' | 'median' | 'min' | 'max';
+type AggregateMethodInternal = keyof typeof METHOD_INTERNAL;
+
+interface ResultDimInfoInternal extends ExternalDimensionDefinition {
+ method: AggregateMethodInternal;
+}
+
+type CreateInTravel = (
+ upstream: ExternalSource,
+ dataIndex: number,
+ resultDimInfoList: ResultDimInfoInternal[],
+ groupByDimInfo?: ExternalDimensionDefinition,
+ groupByVal?: OptionDataValue
+) => void;
+type AggregateInTravel = (
+ upstream: ExternalSource,
+ dataIndex: number,
+ targetLine: unknown,
+ resultDimInfoList: ResultDimInfoInternal[],
+ groupByDimInfo?: ExternalDimensionDefinition
+) => void;
+
+export const transform: ExternalDataTransform<AggregateTransformOption> = {
+
+ type: 'myTransform:aggregate',
+
+ transform: function (params) {
+ const upstream = params.upstream;
+ const config = params.config;
+
+ const dimWrap = prepareDimensions(config, upstream);
+ const resultDimInfoList = dimWrap.resultDimInfoList;
+ const resultDimensions = dimWrap.resultDimensions;
+
+ const groupByDimInfo = prepareGroupByDimInfo(config, upstream);
+
+ // Collect
+ // const collectResult;
+ // const dimInfoListForCollect = makeDimInfoListForCollect(resultDimInfoList);
+ // if (dimInfoListForCollect.length) {
+ // collectResult = travel(groupByDimInfo, upstream, resultDimInfoList, doCreate, doAggregate);
+ // }
+
+ // Calculate
+ const finalResult = travel(
+ groupByDimInfo, upstream, resultDimInfoList, createResultLine, aggregateResultLine
+ );
+
+ return {
+ dimensions: resultDimensions,
+ data: finalResult.outList
+ };
+ }
+};
+
+function prepareDimensions(
+ config: AggregateTransformOption['config'],
+ upstream: ExternalSource
+): {
+ resultDimInfoList: ResultDimInfoInternal[];
+ resultDimensions: DimensionDefinitionLoose[];
+} {
+ const resultDimensionsConfig = config.resultDimensions;
+ const resultDimInfoList: ResultDimInfoInternal[] = [];
+ const resultDimensions: DimensionDefinitionLoose[] = [];
+
+ for (let i = 0; i < resultDimensionsConfig.length; i++) {
+ const resultDimInfoConfig = resultDimensionsConfig[i];
+
+ const resultDimInfo = upstream.getDimensionInfo(resultDimInfoConfig.from) as ResultDimInfoInternal;
+ assert(resultDimInfo, 'Can not find dimension by `from`: ' + resultDimInfoConfig.from);
+
+ resultDimInfo.method = normalizeMethod(resultDimInfoConfig.method);
+ assert(resultDimInfo.method, 'method is required');
+
+ resultDimInfoList.push(resultDimInfo);
+
+ if (resultDimInfoConfig.name != null) {
+ resultDimInfo.name = resultDimInfoConfig.name;
+ }
+
+ resultDimensions.push(resultDimInfo.name);
+ }
+
+ return { resultDimensions, resultDimInfoList };
+}
+
+function prepareGroupByDimInfo(
+ config: AggregateTransformOption['config'],
+ upstream: ExternalSource
+): ExternalDimensionDefinition {
+ const groupByConfig = config.groupBy;
+ let groupByDimInfo;
+ if (groupByConfig != null) {
+ groupByDimInfo = upstream.getDimensionInfo(groupByConfig);
+ assert(groupByDimInfo, 'Can not find dimension by `groupBy`: ' + groupByConfig);
+ }
+ return groupByDimInfo;
+}
+
+function travel(
+ groupByDimInfo: ExternalDimensionDefinition,
+ upstream: ExternalSource,
+ resultDimInfoList: ResultDimInfoInternal[],
+ doCreate: CreateInTravel,
+ doAggregate: AggregateInTravel
+): {
+ groupMap: { [groupVal in string]: unknown };
+ outList: unknown[];
+} {
+ const outList: unknown[] = [];
+ let groupMap: { [groupVal in string]: unknown };
+
+ if (groupByDimInfo) {
+ groupMap = {};
+
+ for (let dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
+ const groupByVal = upstream.retrieveValue(dataIndex, groupByDimInfo.index);
+
+ // PENDING: when value is null/undefined
+ if (groupByVal == null) {
+ continue;
+ }
+
+ const groupByValStr = groupByVal + '';
+
+ if (!hasOwn(groupMap, groupByValStr)) {
+ const newLine = doCreate(upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal);
+ outList.push(newLine);
+ groupMap[groupByValStr] = newLine;
+ }
+ else {
+ const targetLine = groupMap[groupByValStr];
+ doAggregate(upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo);
+ }
+ }
+ }
+ else {
+ const targetLine = doCreate(upstream, 0, resultDimInfoList);
+ outList.push(targetLine);
+ for (let dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
+ doAggregate(upstream, dataIndex, targetLine, resultDimInfoList);
+ }
+ }
+
+ return {
+ groupMap: groupMap,
+ outList: outList
+ };
+}
+
+// function makeDimInfoListForCollect(resultDimInfoList) {
+// const dimInfoListForCollect = [];
+// for (const j = 0; j < resultDimInfoList.length; j++) {
+// const resultDimInfo = resultDimInfoList[j];
+// const method = resultDimInfo.method;
+// if (hasOwn(METHOD_NEEDS_COLLECT, method)) {
+// dimInfoListForCollect.push(resultDimInfo);
+// }
+// }
+// return dimInfoListForCollect;
+// }
+
+function normalizeMethod(method: AggregateMethodLoose): AggregateMethodInternal {
+ if (method == null) {
+ return 'FIRST';
+ }
+ let methodInternal = method.toUpperCase() as AggregateMethodInternal;
+ methodInternal = hasOwn(METHOD_ALIAS, methodInternal)
+ ? METHOD_ALIAS[methodInternal as keyof typeof METHOD_ALIAS]
+ : methodInternal;
+ assert(hasOwn(METHOD_INTERNAL, methodInternal), `Illegal method ${method}.`);
+ return methodInternal;
+}
+
+const createResultLine: CreateInTravel = (
+ upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal
+) => {
+ const newLine = [];
+ for (let j = 0; j < resultDimInfoList.length; j++) {
+ const resultDimInfo = resultDimInfoList[j];
+ const method = resultDimInfo.method;
+ newLine[j] = (groupByDimInfo && resultDimInfo.index === groupByDimInfo.index)
+ ? groupByVal
+ : (method === 'SUM' || method === 'COUNT')
+ ? 0
+ // By default, method: 'first'
+ : upstream.retrieveValue(dataIndex, resultDimInfo.index);
+ }
+ return newLine;
+};
+
+const aggregateResultLine: AggregateInTravel = (
+ upstream, dataIndex, targetLine: number[], resultDimInfoList, groupByDimInfo
+) => {
+ for (let j = 0; j < resultDimInfoList.length; j++) {
+ const resultDimInfo = resultDimInfoList[j];
+ const method = resultDimInfo.method;
+
+ if (groupByDimInfo && resultDimInfo.index === groupByDimInfo.index) {
+ continue;
+ }
+
+ if (method === 'SUM') {
+ // FIXME: handle other types
+ targetLine[j] += upstream.retrieveValue(dataIndex, resultDimInfo.index) as number;
+ }
+ else if (method === 'COUNT') {
+ targetLine[j] += 1;
+ }
+ else if (method === 'AVERAGE') {
+ // FIXME: handle other types
+ targetLine[j] += upstream.retrieveValue(dataIndex, resultDimInfo.index) as number / 1;
+ }
+ }
+};
diff --git a/test/lib/myTransform/src/id.ts b/test/lib/myTransform/src/id.ts
new file mode 100644
index 0000000..d466d8b
--- /dev/null
+++ b/test/lib/myTransform/src/id.ts
@@ -0,0 +1,90 @@
+/*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+import { ExternalDataTransform, DataTransformOption } from '../../../../src/data/helper/transform';
+import { DimensionIndex, DimensionName, DimensionDefinitionLoose, OptionSourceDataArrayRows } from '../../../../src/util/types';
+
+
+/**
+ * @usage
+ *
+ * ```js
+ * dataset: [{
+ * source: [
+ * ['aa', 'bb', 'cc', 'tag'],
+ * [12, 0.33, 5200, 'AA'],
+ * [21, 0.65, 8100, 'AA'],
+ * ...
+ * ]
+ * }, {
+ * transform: {
+ * type: 'my:id',
+ * config: {
+ * dimensionIndex: 4,
+ * dimensionName: 'ID'
+ * }
+ * }
+ * // Then the result data will be:
+ * // [
+ * // ['aa', 'bb', 'cc', 'tag', 'ID'],
+ * // [12, 0.33, 5200, 'AA', 0],
+ * // [21, 0.65, 8100, 'BB', 1],
+ * // ...
+ * // ]
+ * }]
+ * ```
+ */
+
+export interface IdTransformOption extends DataTransformOption {
+ type: 'myTransform:id';
+ config: {
+ // Mandatory. Specify where to put the new id dimension.
+ dimensionIndex: DimensionIndex;
+ // Optional. If not provided, left the dimension name not defined.
+ dimensionName: DimensionName;
+ };
+}
+
+export const transform: ExternalDataTransform<IdTransformOption> = {
+
+ type: 'myTransform:id',
+
+ transform: function (params) {
+ const upstream = params.upstream;
+ const config = params.config;
+ const dimensionIndex = config.dimensionIndex;
+ const dimensionName = config.dimensionName;
+
+ const dimsDef = upstream.cloneAllDimensionInfo() as DimensionDefinitionLoose[];
+ dimsDef[dimensionIndex] = dimensionName;
+
+ const data = upstream.cloneRawData() as OptionSourceDataArrayRows;
+
+ // TODO: support objectRows
+ for (let i = 0, len = data.length; i < len; i++) {
+ const line = data[i];
+ line[dimensionIndex] = i;
+ }
+
+ return {
+ dimensions: dimsDef,
+ data: data
+ };
+ }
+};
diff --git a/test/lib/myTransform/src/index.ts b/test/lib/myTransform/src/index.ts
new file mode 100644
index 0000000..a8138ad
--- /dev/null
+++ b/test/lib/myTransform/src/index.ts
@@ -0,0 +1,3 @@
+
+export { transform as id } from './id';
+export { transform as aggregate } from './aggregate';
diff --git a/tsconfig.json b/tsconfig.json
index adedaa4..5c9fc9b 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -22,6 +22,7 @@
},
"include": [
"src/**/*.ts",
- "extension-src/**/*.ts"
+ "extension-src/**/*.ts",
+ "test/lib/myTransform/src/**/*.ts"
]
}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org