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/09/27 17:46:56 UTC

[incubator-echarts] 05/05: test: add experimental transform.

This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch custom-morph2
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit 82f62ca7d20ec28a2134110a8f5ba3c7b237c44c
Author: 100pah <su...@gmail.com>
AuthorDate: Mon Sep 28 00:04:45 2020 +0800

    test: add experimental transform.
---
 test/custom-shape-morphing3.html   | 242 +++++++++++++++++++++++++++++++++++
 test/lib/ecStatTransform.js        |  48 -------
 test/lib/myTransform/aggregate.js  | 174 +++++++++++++++++++++++++
 test/lib/myTransform/identifier.js |  86 +++++++++++++
 test/lib/transitionPlayer.js       | 253 +++++++++++++++++++++++++++++++++++++
 5 files changed, 755 insertions(+), 48 deletions(-)

diff --git a/test/custom-shape-morphing3.html b/test/custom-shape-morphing3.html
new file mode 100644
index 0000000..b416ae3
--- /dev/null
+++ b/test/custom-shape-morphing3.html
@@ -0,0 +1,242 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+
+<html>
+    <head>
+        <meta charset='utf-8'>
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/esl.js"></script>
+        <script src="lib/config.js"></script>
+        <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/identifier.js"></script>
+        <script src="lib/transitionPlayer.js"></script>
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+        </style>
+
+        <div id="main0"></div>
+
+
+
+        <script>
+
+        require(['echarts', 'ecStat'], function (echarts, ecStat) {
+            $.get('data/life-expectancy-table.json', function (rawData) {
+
+                echarts.registerTransform(window.myTransform.aggregate);
+                echarts.registerTransform(window.myTransform.identifier);
+
+                const COLORS = [
+                    '#37A2DA', '#e06343', '#37a354', '#b55dba', '#b5bd48', '#8378EA', '#96BFFF'
+                ];
+                const CONTENT_COLOR = '#37a354';
+
+                // const COLORS = [
+                //     {name: 'Income', index: 0, text: '人均收入', unit: '美元'},
+                //     {name: 'LifeExpectancy', index: 1, text: '人均寿命', unit: '岁'},
+                //     {name: 'Population', index: 2, text: '总人口', unit: ''},
+                //     {name: 'Country', index: 3, text: '国家', unit: ''}
+                // ];
+
+                var RAW_DATA_DIMENSIONS = ['Income', 'Life Expectancy', 'Population', 'Country', 'Year'];
+                var ID_RAW_DATA_DIMENSIONS = ['Income', 'Life Expectancy', 'Population', 'Country', 'Year', 'Id'];
+
+                var baseOption = {
+                    dataset: [{
+                        id: 'RawData',
+                        source: rawData
+                    }, {
+                        id: 'IdRawData',
+                        transform: {
+                            type: 'myTransform:identifier',
+                            config: {
+                                dimensionIndex: ID_RAW_DATA_DIMENSIONS.indexOf('Id'),
+                                dimensionName: 'Id'
+                            }
+                        }
+                    }, {
+                        id: 'GermanyData',
+                        fromDatasetId: 'IdRawData',
+                        transform: {
+                            type: 'filter',
+                            config: {
+                                dimension: 'Country', '=': 'Germany'
+                            }
+                        }
+                    }],
+                    tooltip: {}
+                };
+
+                var optionCreators = {
+
+                    'Country_A_Year_Income_Bar': function (datasetId) {
+                        return {
+                            xAxis: {
+                                type: 'category'
+                            },
+                            yAxis: {
+                                name: 'Income',
+                                nameGap: 25,
+                                nameTextStyle: {
+                                    fontSize: 25
+                                }
+                            },
+                            series: {
+                                type: 'custom',
+                                coordinateSystem: 'cartesian2d',
+                                datasetId: datasetId,
+                                encode: {
+                                    x: 'Year',
+                                    y: 'Income'
+                                },
+                                renderItem: function (params, api) {
+                                    var valPos = api.coord([api.value('Year'), api.value('Income')]);
+                                    var basePos = api.coord([api.value('Year'), 0]);
+                                    var width = api.size([1, 0])[0] * 0.9;
+                                    return {
+                                        type: 'rect',
+                                        shape: {
+                                            x: basePos[0],
+                                            y: basePos[1],
+                                            width: width,
+                                            height: valPos[1] - basePos[1],
+                                            transition: ['x', 'y', 'width', 'height']
+                                        },
+                                        style: {
+                                            fill: CONTENT_COLOR
+                                        }
+                                    };
+                                }
+                            }
+                        };
+                    },
+
+                    'Country_A_Year_Population_Bar': function (datasetId) {
+                        return {
+                            xAxis: {
+                                type: 'category'
+                            },
+                            yAxis: {
+                                name: 'Income',
+                                nameGap: 25,
+                                nameTextStyle: {
+                                    fontSize: 25
+                                }
+                            },
+                            series: {
+                                type: 'custom',
+                                coordinateSystem: 'cartesian2d',
+                                datasetId: datasetId,
+                                encode: {
+                                    x: 'Year',
+                                    y: 'Population'
+                                },
+                                renderItem: function (params, api) {
+                                    var valPos = api.coord([api.value('Year'), api.value('Population')]);
+                                    var basePos = api.coord([api.value('Year'), 0]);
+                                    var width = api.size([1, 0])[0] * 0.9;
+                                    return {
+                                        type: 'rect',
+                                        shape: {
+                                            x: basePos[0],
+                                            y: basePos[1],
+                                            width: width,
+                                            height: valPos[1] - basePos[1],
+                                            transition: ['x', 'y', 'width', 'height']
+                                        },
+                                        style: {
+                                            fill: CONTENT_COLOR
+                                        }
+                                    };
+                                }
+                            }
+                        };
+                    }
+
+                };
+
+                var player = transitionPlayer.create({
+                    chart: function () {
+                        return chart;
+                    },
+                    seriesIndex: 0,
+                    replaceMerge: ['xAxis', 'yAxis'],
+                    dataMeta: {
+                        'IdRawData': {
+                            dimensions: ID_RAW_DATA_DIMENSIONS,
+                            uniqueDimension: 'Id'
+                        },
+                        'GermanyData': {
+                            dimensions: ID_RAW_DATA_DIMENSIONS,
+                            uniqueDimension: 'Id'
+                        }
+                    },
+                    optionList: [{
+                        key: 'Country_A_Year_Income_Bar',
+                        dataMetaKey: 'GermanyData',
+                        option: optionCreators['Country_A_Year_Income_Bar']('GermanyData')
+                    }, {
+                        key: 'Country_A_Year_Population_Bar',
+                        dataMetaKey: 'GermanyData',
+                        option: optionCreators['Country_A_Year_Population_Bar']('GermanyData')
+                    }]
+                });
+
+
+                var chart = testHelper.create(echarts, 'main0', {
+                    title: [
+                        'Test: buttons, should morph animation merge/split.',
+                        'Test: click buttons **before animation finished**, should no blink.',
+                        'Test: click buttons **twice**, should no blink.',
+                        'Test: use dataZoom, update animation should exist'
+                    ],
+                    option: baseOption,
+                    lazyUpdate: true,
+                    height: 600,
+                    buttons: [{
+                        text: 'next',
+                        onclick: function () {
+                            player.next();
+                        }
+                    }, {
+                        text: 'previous',
+                        onclick: function () {
+                            player.previous();
+                        }
+                    }]
+                });
+
+                player.next();
+
+            });
+
+        });
+
+        </script>
+
+
+
+    </body>
+</html>
\ No newline at end of file
diff --git a/test/lib/ecStatTransform.js b/test/lib/ecStatTransform.js
deleted file mode 100644
index e411eed..0000000
--- a/test/lib/ecStatTransform.js
+++ /dev/null
@@ -1,48 +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 (root) {
-
-    root.ecStatTransform = function (ecStat) {
-
-        var regression = {
-
-            type: 'ecStat:regression',
-
-            transform: function transform(params) {
-                var source = params.source;
-                var config = params.config || {};
-                var method = config.method || 'linear';
-                var result = ecStat.regression(method, source.data);
-
-                return [{
-                    data: result.points
-                }, {
-                    data: [[result.expression]]
-                }];
-            }
-        };
-
-
-        return {
-            regression: regression
-        }
-    };
-
-})(window);
diff --git a/test/lib/myTransform/aggregate.js b/test/lib/myTransform/aggregate.js
new file mode 100644
index 0000000..a5fd4eb
--- /dev/null
+++ b/test/lib/myTransform/aggregate.js
@@ -0,0 +1,174 @@
+/*
+* 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/identifier.js b/test/lib/myTransform/identifier.js
new file mode 100644
index 0000000..8ff2590
--- /dev/null
+++ b/test/lib/myTransform/identifier.js
@@ -0,0 +1,86 @@
+/*
+* 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:identifier',
+     *         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:identifier',
+
+        /**
+         * @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;
+
+            for (var i = 0, len = upstream.count(); i < len; i++) {
+                var line = upstream.getRawDataItem(i);
+                line[dimensionIndex] = i;
+            }
+
+            return {
+                dimensions: dimsDef,
+                data: upstream.data
+            };
+        }
+    };
+
+    var myTransform = exports.myTransform = exports.myTransform || {};
+    myTransform.identifier = transform;
+
+})(this);
+
diff --git a/test/lib/transitionPlayer.js b/test/lib/transitionPlayer.js
new file mode 100644
index 0000000..fae17c7
--- /dev/null
+++ b/test/lib/transitionPlayer.js
@@ -0,0 +1,253 @@
+/*
+* 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) {
+
+    var transitionPlayer = {};
+
+    /**
+     * @usage
+     * ```js
+     * // Initialize with an array of echarts option info:
+     * var player = transitionPlayer.create({
+     *
+     *     // The echarts instance or chart instance getter.
+     *     chart: function () {
+     *         return myChart;
+     *     },
+     *     seriesIndex: 0,
+     *     replaceMerge: ['xAxis', 'yAxis']
+     *
+     *     // The data meta info used to determine how to
+     *     // make transition mapping.
+     *     // The strategy: If `uniqueDimension` provided and is a common
+     *     // dimension, use `uniqueDimension`.
+     *     dataMeta: {
+     *         aaa: {
+     *             dimensions: ['qqq', 'www', 'eee', 'rrr']
+     *         },
+     *         bbb: {
+     *             dimensions: ['ccc', 'www', 'eee'],
+     *             uniqueDimension: 'www'
+     *         },
+     *         ...
+     *     },
+     *
+     *     // echarts option collection:
+     *     optionList: [
+     *         // dataMetaKey is the key of 'dataMeta'.
+     *         { key: 'Time_Income_Bar', option: option0, dataMetaKey: 'aaa' },
+     *         { key: 'Population_Income_Scatter', option: option1, dataMetaKey: 'bbb' },
+     *         { key: 'Time_Income_Pie', option: option2, dataMetaKey: 'aaa' },
+     *         ...
+     *     ]
+     * });
+     *
+     * // Then start to play:
+     * player.next(); // Display next option (from the first option).
+     * player.previous(); // Display previous optoin.
+     * player.go('Time_Income_Pie'); // Display the specified option.
+     * player.getOptionKeys(); // return `['Time_Income_Bar', 'Population_Income_Scatter', 'Time_Income_Pie']`
+     * ```
+     *
+     * @parma opt See the constructor of `TransitionPlayer`.
+     */
+    transitionPlayer.create = function (opt) {
+        return new TransitionPlayer(opt);
+    };
+
+    /**
+     * @param opt
+     * @param opt.chart
+     *        (EChartsInstance | () => EChartsInstance)
+     *        echarts instance or echarts instance getter.
+     * @param opt.dataMeta
+     *        {
+     *            [dataMetaKey in string]: {
+     *                dimensions: string[];
+     *                uniqueDimension?: string;
+     *            }
+     *        }
+     * @param opt.optionList
+     *        {
+     *            key: string;
+     *            option: EChartsOption;
+     *            dataMetaKey: string;
+     *        }[]
+     * @param opt.seriesIndex number
+     *        Target series index to be transitioned.
+     * @param opt.replaceMerge? string[]
+     */
+    function TransitionPlayer(opt) {
+        assert(
+            opt.chart
+            && isObject(opt.dataMeta)
+            && isArray(opt.optionList)
+            && opt.seriesIndex != null
+            && opt.optionList.length
+        );
+
+        this._chart = opt.chart;
+        this._dataMeta = opt.dataMeta;
+        var optionList = this._optionList = opt.optionList;
+        var optionMap = this._optionMap = {};
+        this._replaceMerge = opt.replaceMerge;
+        this._seriesIndex = opt.seriesIndex;
+        this._currOptionIdx = null;
+
+        for (var i = 0; i < optionList.length; i++) {
+            var optionWrap = optionList[i];
+            var optionKey = optionWrap.key;
+            if (optionKey != null) {
+                assert(!hasOwn(optionMap, optionKey), 'option key duplicat: ' + optionKey);
+                optionMap[optionKey] = i;
+            }
+        }
+    }
+
+    var proto = TransitionPlayer.prototype;
+
+    proto.next = function () {
+        var optionList = this._optionList;
+        var newOptionIdx = this._currOptionIdx == null
+            ? 0
+            : Math.min(optionList.length - 1, this._currOptionIdx + 1);
+
+        this._doChangeOption(newOptionIdx);
+    };
+
+    proto.previous = function () {
+        var optionList = this._optionList;
+        var newOptionIdx = this._currOptionIdx == null
+            ? optionList.length - 1
+            : Math.max(0, this._currOptionIdx - 1);
+
+        this._doChangeOption(newOptionIdx);
+    };
+
+    /**
+     * @param optionKey string
+     */
+    proto.go = function (optionKey) {
+        var newOptionIdx = getMapValue(this._optionMap, optionKey);
+        assert(newOptionIdx != null, 'Can not find option by option key: ' + optionKey);
+
+        this._doChangeOption(newOptionIdx);
+    };
+
+    proto._doChangeOption = function (newOptionIdx) {
+        var optionList = this._optionList;
+        var oldOptionWrap = this._currOptionIdx != null ? optionList[this._currOptionIdx] : null;
+        var newOptionWrap = optionList[newOptionIdx];
+        var dataMeta = this._dataMeta;
+        var targetSeriesIndex = this._seriesIndex;
+
+        var transitionOpt = {
+            // If can not find mapped dimensions, do not make transition animation
+            // by default, becuase this transition probably bring about misleading.
+            to: { seriesIndex: targetSeriesIndex }
+        };
+
+        if (oldOptionWrap) {
+            var commonDimension =
+                findCommonDimension(oldOptionWrap, newOptionWrap)
+                || findCommonDimension(newOptionWrap, oldOptionWrap);
+            if (commonDimension != null) {
+                transitionOpt = {
+                    from: {
+                        seriesIndex: targetSeriesIndex,
+                        dimension: commonDimension
+                    },
+                    to: {
+                        seriesIndex: targetSeriesIndex,
+                        dimension: commonDimension
+                    }
+                };
+            }
+        }
+
+        this._currOptionIdx = newOptionIdx;
+
+        this._getChart().setOption(newOptionWrap.option, {
+            replaceMerge: this._replaceMerge,
+            transition: transitionOpt
+        });
+
+        function findCommonDimension(optionWrapA, optionWrapB) {
+            var metaA = getMapValue(dataMeta, optionWrapA.dataMetaKey);
+            var metaB = getMapValue(dataMeta, optionWrapB.dataMetaKey);
+            var uniqueDimensionB = metaB.uniqueDimension;
+            if (uniqueDimensionB != null && metaA.dimensions.indexOf(uniqueDimensionB) >= 0) {
+                return uniqueDimensionB;
+            }
+        }
+
+    };
+
+    proto._getChart = function () {
+        return isFunction(this._chart) ? this._chart() : this._chart;
+    };
+
+    /**
+     * @return string[]
+     */
+    proto.getOptionKeys = function () {
+        var optionKeys = [];
+        var optionList = this._optionList;
+        for (var i = 0; i < optionList.length; i++) {
+            optionKeys.push(optionList[i].key);
+        }
+        return optionKeys;
+    };
+
+
+    function assert(cond, msg) {
+        if (!cond) {
+            throw new Error(msg || 'transition player error');
+        }
+    }
+
+    function isObject(value) {
+        const type = typeof value;
+        return type === 'function' || (!!value && type === 'object');
+    }
+
+    function isArray(value) {
+        if (Array.isArray) {
+            return Array.isArray(value);
+        }
+        return Object.prototype.toString.call(value) === '[object Array]';
+    }
+
+    function isFunction(value) {
+        return typeof value === 'function';
+    }
+
+    function hasOwn(obj, key) {
+        return obj.hasOwnProperty(key);
+    }
+
+    function getMapValue(map, key) {
+        return (key != null && hasOwn(map, key)) ? map[key] : null;
+    }
+
+
+    exports.transitionPlayer = transitionPlayer;
+
+})(this);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org