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

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

commit 32a4b6626858207865a555874e774e3941c14883
Author: 100pah <sushuang0...@gmail.com>
AuthorDate: Tue Jul 14 17:38:24 2020 +0800

    feature:
    (1) support axis id reference in dataZoom. (except toolbox dataZoom)
    (2) enhance dataZoom auto choose axis logic to support multiple setOption. 
(except toolbox dataZoom)
    (3) enhance dataZoom to enable axis and dataZoom removal. (except toolbox 
dataZoom)
    (4) simplify the code of dataZoom.
---
 src/component/dataZoom/AxisProxy.ts         |  13 +-
 src/component/dataZoom/DataZoomModel.ts     | 432 +++++++++++-----------------
 src/component/dataZoom/DataZoomView.ts      |   5 +-
 src/component/dataZoom/InsideZoomView.ts    |   2 +-
 src/component/dataZoom/SliderZoomView.ts    |  27 +-
 src/component/dataZoom/dataZoomAction.ts    |  25 +-
 src/component/dataZoom/dataZoomProcessor.ts |  75 +++--
 src/component/dataZoom/helper.ts            | 209 ++++++--------
 test/dataZoom-feature.html                  | 256 +++++++++++++++++
 9 files changed, 594 insertions(+), 450 deletions(-)

diff --git a/src/component/dataZoom/AxisProxy.ts 
b/src/component/dataZoom/AxisProxy.ts
index b322d91..196c71d 100644
--- a/src/component/dataZoom/AxisProxy.ts
+++ b/src/component/dataZoom/AxisProxy.ts
@@ -105,17 +105,12 @@ class AxisProxy {
 
     getTargetSeriesModels() {
         const seriesModels: SeriesModel[] = [];
-        const ecModel = this.ecModel;
 
-        ecModel.eachSeries(function (seriesModel) {
+        this.ecModel.eachSeries(function (seriesModel) {
             if (helper.isCoordSupported(seriesModel.get('coordinateSystem'))) {
-                const dimName = this._dimName;
-                const axisModel = ecModel.queryComponents({
-                    mainType: dimName + 'Axis',
-                    index: seriesModel.get(dimName + 'AxisIndex' as any),
-                    id: seriesModel.get(dimName + 'AxisId' as any)
-                })[0];
-                if (this._axisIndex === (axisModel && 
axisModel.componentIndex)) {
+                const axisMainType = helper.getAxisMainType(this._dimName);
+                const axisModel = 
seriesModel.getReferringComponents(axisMainType, true).models[0];
+                if (axisModel && this._axisIndex === axisModel.componentIndex) 
{
                     seriesModels.push(seriesModel);
                 }
             }
diff --git a/src/component/dataZoom/DataZoomModel.ts 
b/src/component/dataZoom/DataZoomModel.ts
index 48ec294..d1fadbe 100644
--- a/src/component/dataZoom/DataZoomModel.ts
+++ b/src/component/dataZoom/DataZoomModel.ts
@@ -17,30 +17,24 @@
 * under the License.
 */
 
-import {__DEV__} from '../../config';
-import * as zrUtil from 'zrender/src/core/util';
+import { each, createHashMap, merge, HashMap, assert } from 
'zrender/src/core/util';
 import env from 'zrender/src/core/env';
-import * as modelUtil from '../../util/model';
 import AxisProxy from './AxisProxy';
 import ComponentModel from '../../model/Component';
 import {
     LayoutOrient,
     ComponentOption,
-    Dictionary,
-    LabelOption,
-    SeriesOption,
-    SeriesOnCartesianOptionMixin,
-    SeriesOnPolarOptionMixin,
-    SeriesOnSingleOptionMixin
+    LabelOption
 } from '../../util/types';
 import Model from '../../model/Model';
 import GlobalModel from '../../model/Global';
-import SeriesModel from '../../model/Series';
 import { AxisBaseModel } from '../../coord/AxisBaseModel';
-import { OptionAxisType, AxisBaseOption } from '../../coord/axisCommonTypes';
-import { eachAxisDim } from './helper';
+import {
+    getAxisMainType, DATA_ZOOM_AXIS_DIMENSIONS, DataZoomAxisDimension
+} from './helper';
+import SingleAxisModel from '../../coord/single/AxisModel';
+import { __DEV__ } from '../../config';
 
-const each = zrUtil.each;
 
 export interface DataZoomOption extends ComponentOption {
 
@@ -53,16 +47,21 @@ export interface DataZoomOption extends ComponentOption {
      * Default the first horizontal category axis.
      */
     xAxisIndex?: number | number[]
+    xAxisId?: string | string[]
 
     /**
      * Default the first vertical category axis.
      */
     yAxisIndex?: number | number[]
+    yAxisId?: string | string[]
 
     radiusAxisIndex?: number | number[]
+    radiusAxisId?: string | string[]
     angleAxisIndex?: number | number[]
+    angleAxisId?: string | string[]
 
     singleAxisIndex?: number | number[]
+    singleAxisId?: string | string[]
 
     /**
      * Possible values: 'filter' or 'empty' or 'weakFilter'.
@@ -131,20 +130,27 @@ export interface DataZoomOption extends ComponentOption {
 
 type RangeOption = Pick<DataZoomOption, 'start' | 'end' | 'startValue' | 
'endValue'>;
 
-type ExtendedAxisBaseModel = AxisBaseModel & {
+export type DataZoomExtendedAxisBaseModel = AxisBaseModel & {
     __dzAxisProxy: AxisProxy
 };
 
-interface SeriesModelOnAxis extends SeriesModel<
-    SeriesOption & SeriesOnCartesianOptionMixin & SeriesOnPolarOptionMixin & 
SeriesOnSingleOptionMixin
-> {}
+class DataZoomAxisInfo {
+    indexList: number[] = [];
+    indexMap: boolean[] = [];
+
+    add(axisCmptIdx: number) {
+        this.indexList.push(axisCmptIdx);
+        this.indexMap[axisCmptIdx] = true;
+    }
+}
+export type DataZoomTargetAxisInfoMap = HashMap<DataZoomAxisInfo, 
DataZoomAxisDimension>;
 
 class DataZoomModel<Opts extends DataZoomOption = DataZoomOption> extends 
ComponentModel<Opts> {
     static type = 'dataZoom';
     type = DataZoomModel.type;
 
     static dependencies = [
-        'xAxis', 'yAxis', 'zAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 
'series'
+        'xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'series'
     ];
 
 
@@ -158,16 +164,11 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
         end: 100
     };
 
-    /**
-     * key like x_0, y_1
-     */
-    private _dataIntervalByAxis: Dictionary<[number, number]> = {};
-
-    private _dataInfo = {};
+    private _autoThrottle = true;
 
-    private _axisProxies: Dictionary<AxisProxy> = {};
+    private _orient: LayoutOrient;
 
-    private _autoThrottle = true;
+    private _targetAxisInfoMap: DataZoomTargetAxisInfoMap;
 
     /**
      * It is `[rangeModeForMin, rangeModeForMax]`.
@@ -187,11 +188,12 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
      */
     private _rangePropMode: DataZoomOption['rangeMode'] = ['percent', 
'percent'];
 
-    textStyleModel: Model<DataZoomOption['textStyle']>;
-
+    /**
+     * @readonly
+     */
     settledOption: Opts;
 
-    init(option: Opts, parentModel: Model, ecModel: GlobalModel) {
+    init(option: Opts, parentModel: Model, ecModel: GlobalModel): void {
 
         const inputRawOption = retrieveRawOption(option);
 
@@ -215,33 +217,25 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
          * (Step)2) click the legend to hide and show a series,
          *     where the new range is calculated by the earsed `startValue` 
and `endValue`,
          *     which brings incorrect result.
-         *
-         * @readOnly
          */
         this.settledOption = inputRawOption;
 
         this.mergeDefaultAndTheme(option, ecModel);
 
-        this.doInit(inputRawOption);
+        this._doInit(inputRawOption);
     }
 
-    /**
-     * @override
-     */
-    mergeOption(newOption: Opts) {
+    mergeOption(newOption: Opts): void {
         const inputRawOption = retrieveRawOption(newOption);
 
         //FIX #2591
-        zrUtil.merge(this.option, newOption, true);
-        zrUtil.merge(this.settledOption, inputRawOption, true);
+        merge(this.option, newOption, true);
+        merge(this.settledOption, inputRawOption, true);
 
-        this.doInit(inputRawOption);
+        this._doInit(inputRawOption);
     }
 
-    /**
-     * @protected
-     */
-    doInit(inputRawOption: Opts) {
+    private _doInit(inputRawOption: Opts): void {
         const thisOption = this.option;
 
         // Disable realtime view update if canvas is not supported.
@@ -264,201 +258,121 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
             // Otherwise do nothing and use the merge result.
         }, this);
 
-        this.textStyleModel = this.getModel('textStyle');
-
         this._resetTarget();
-
-        this._prepareAxisProxies();
-    }
-
-    private _prepareAxisProxies() {
-        const axisProxies = this._axisProxies;
-
-        this.eachTargetAxis(function (dimNames, axisIndex, dataZoomModel, 
ecModel) {
-            const axisModel = this.ecModel.getComponent(dimNames.axis, 
axisIndex);
-
-            // If exists, share axisProxy with other dataZoomModels.
-            const axisProxy = (axisModel as 
ExtendedAxisBaseModel).__dzAxisProxy || (
-                // Use the first dataZoomModel as the main model of axisProxy.
-                (axisModel as ExtendedAxisBaseModel).__dzAxisProxy = new 
AxisProxy(
-                    dimNames.name, axisIndex, this, ecModel
-                )
-            );
-            // FIXME
-            // dispose __dzAxisProxy
-
-            axisProxies[dimNames.name + '_' + axisIndex] = axisProxy;
-        }, this);
     }
 
     private _resetTarget() {
-        const thisOption = this.option;
+        const optionOrient = this.get('orient', true);
+        const targetAxisIndexMap = this._targetAxisInfoMap = 
createHashMap<DataZoomAxisInfo, DataZoomAxisDimension>();
 
-        const autoMode = this._judgeAutoMode();
-
-        eachAxisDim(function (dimNames) {
-            const axisIndexName = dimNames.axisIndex;
-            thisOption[axisIndexName] = modelUtil.normalizeToArray(
-                thisOption[axisIndexName]
-            );
-        }, this);
+        const hasAxisSpecified = 
this._fillSpecifiedTargetAxis(targetAxisIndexMap);
 
-        if (autoMode === 'axisIndex') {
-            this._autoSetAxisIndex();
+        if (hasAxisSpecified) {
+            this._orient = optionOrient || this._makeAutoOrientByTargetAxis();
         }
-        else if (autoMode === 'orient') {
-            this._autoSetOrient();
+        else {
+            this._orient = optionOrient || 'horizontal';
+            this._fillAutoTargetAxisByOrient(targetAxisIndexMap, this._orient);
         }
     }
 
-    private _judgeAutoMode() {
-        // Auto set only works for setOption at the first time.
-        // The following is user's reponsibility. So using merged
-        // option is OK.
-        const thisOption = this.option;
+    private _fillSpecifiedTargetAxis(targetAxisIndexMap: 
DataZoomTargetAxisInfoMap): boolean {
+        let hasAxisSpecified = false;
 
-        let hasIndexSpecified = false;
-        eachAxisDim(function (dimNames) {
+        each(DATA_ZOOM_AXIS_DIMENSIONS, function (axisDim) {
+            const refering = 
this.getReferringComponents(getAxisMainType(axisDim), false);
             // When user set axisIndex as a empty array, we think that user 
specify axisIndex
             // but do not want use auto mode. Because empty array may be 
encountered when
             // some error occured.
-            if (thisOption[dimNames.axisIndex] != null) {
-                hasIndexSpecified = true;
+            if (!refering.specified) {
+                return;
             }
+            hasAxisSpecified = true;
+            const axisInfo = new DataZoomAxisInfo();
+            each(refering.models, function (axisModel) {
+                axisInfo.add(axisModel.componentIndex);
+            });
+            targetAxisIndexMap.set(axisDim, axisInfo);
         }, this);
 
-        const orient = thisOption.orient;
-
-        if (orient == null && hasIndexSpecified) {
-            return 'orient';
-        }
-        else if (!hasIndexSpecified) {
-            if (orient == null) {
-                thisOption.orient = 'horizontal';
-            }
-            return 'axisIndex';
-        }
+        return hasAxisSpecified;
     }
 
-    private _autoSetAxisIndex() {
-        let autoAxisIndex = true;
-        const orient = this.get('orient', true);
-        const thisOption = this.option;
+    private _fillAutoTargetAxisByOrient(targetAxisIndexMap: 
DataZoomTargetAxisInfoMap, orient: LayoutOrient): void {
+        const ecModel = this.ecModel;
+        let needAuto = true;
 
-        if (autoAxisIndex) {
-            // Find axis that parallel to dataZoom as default.
-            const dimName = orient === 'vertical' ? 'y' : 'x';
+        // Find axis that parallel to dataZoom as default.
+        if (needAuto) {
+            const axisDim = orient === 'vertical' ? 'y' : 'x';
+            const axisModels = ecModel.findComponents({ mainType: axisDim + 
'Axis' });
+            setParallelAxis(axisModels, axisDim);
+        }
+        // Find axis that parallel to dataZoom as default.
+        if (needAuto) {
+            const axisModels = ecModel.findComponents({
+                mainType: 'singleAxis',
+                filter: (axisModel: SingleAxisModel) => 
axisModel.get('orient', true) === orient
+            });
+            setParallelAxis(axisModels, 'single');
+        }
 
-            if (this.ecModel.queryComponents({ mainType: dimName + 'Axis' 
}).length) {
-                thisOption[dimName + 'AxisIndex' as 'xAxisIndex' | 
'yAxisIndex'] = [0];
-                autoAxisIndex = false;
+        function setParallelAxis(axisModels: ComponentModel[], axisDim: 
DataZoomAxisDimension): void {
+            // At least use the first parallel axis as the target axis.
+            const axisModel = axisModels[0];
+            if (!axisModel) {
+                return;
             }
-            else {
-                each(this.ecModel.queryComponents({ mainType: 'singleAxis' }), 
function (
-                    singleAxisModel: AxisBaseModel<{'orient': LayoutOrient} & 
AxisBaseOption>
-                ) {
-                    if (autoAxisIndex && singleAxisModel.get('orient', true) 
=== orient) {
-                        thisOption.singleAxisIndex = 
[singleAxisModel.componentIndex];
-                        autoAxisIndex = false;
+
+            const axisInfo = new DataZoomAxisInfo();
+            axisInfo.add(axisModel.componentIndex);
+            targetAxisIndexMap.set(axisDim, axisInfo);
+            needAuto = false;
+
+            // Find parallel axes in the same grid.
+            if (axisDim === 'x' || axisDim === 'y') {
+                const gridModel = axisModel.getReferringComponents('grid', 
true).models[0];
+                gridModel && each(axisModels, function (axModel) {
+                    if (axisModel.componentIndex !== axModel.componentIndex
+                        && gridModel === 
axModel.getReferringComponents('grid', true).models[0]
+                    ) {
+                        axisInfo.add(axModel.componentIndex);
                     }
                 });
             }
         }
 
-        if (autoAxisIndex) {
-            // Find the first category axis as default. (consider polar)
-            eachAxisDim(function (dimNames) {
-                if (!autoAxisIndex) {
+        if (needAuto) {
+            // If no parallel axis, find the first category axis as default. 
(Also consider polar).
+            each(DATA_ZOOM_AXIS_DIMENSIONS, function (axisDim) {
+                if (needAuto) {
                     return;
                 }
-                const axisIndices = [];
-                const axisModels = this.ecModel.queryComponents({ mainType: 
dimNames.axis });
-                if (axisModels.length && !axisIndices.length) {
-                    for (let i = 0, len = axisModels.length; i < len; i++) {
-                        if (axisModels[i].get('type') === 'category') {
-                            axisIndices.push(i);
-                        }
-                    }
-                }
-                thisOption[dimNames.axisIndex] = axisIndices;
-                if (axisIndices.length) {
-                    autoAxisIndex = false;
-                }
-            }, this);
-        }
-
-        if (autoAxisIndex) {
-            // FIXME
-            // 
这里是兼容ec2的写法(没指定xAxisIndex和yAxisIndex时把scatter和双数值轴折柱纳入dataZoom控制),
-            // 但是实际是否需要Grid.js#getScaleByOption来判断(考虑time,log等axis type)?
-
-            // If both dataZoom.xAxisIndex and dataZoom.yAxisIndex is not 
specified,
-            // dataZoom component auto adopts series that reference to
-            // both xAxis and yAxis which type is 'value'.
-            this.ecModel.eachSeries(function (seriesModel: SeriesModelOnAxis) {
-                if (this._isSeriesHasAllAxesTypeOf(seriesModel, 'value')) {
-                    eachAxisDim(function (dimNames) {
-                        const axisIndices = thisOption[dimNames.axisIndex] as 
number[]; // Has been normalized to array
-
-                        let axisIndex = seriesModel.get(dimNames.axisIndex);
-                        const axisId = seriesModel.get(dimNames.axisId);
-
-                        const axisModel = seriesModel.ecModel.queryComponents({
-                            mainType: dimNames.axis,
-                            index: axisIndex,
-                            id: axisId
-                        })[0];
-
-                        if (__DEV__) {
-                            if (!axisModel) {
-                                throw new Error(
-                                    dimNames.axis + ' "' + 
zrUtil.retrieve<number | string>(
-                                        axisIndex,
-                                        axisId,
-                                        0
-                                    ) + '" not found'
-                                );
-                            }
-                        }
-                        axisIndex = axisModel.componentIndex;
-
-                        if (zrUtil.indexOf(axisIndices, axisIndex) < 0) {
-                            axisIndices.push(axisIndex);
-                        }
-                    });
+                const axisModels = ecModel.findComponents({
+                    mainType: getAxisMainType(axisDim),
+                    filter: (axisModel: SingleAxisModel) => 
axisModel.get('type', true) === 'category'
+                });
+                if (axisModels[0]) {
+                    const axisInfo = new DataZoomAxisInfo();
+                    axisInfo.add(axisModels[0].componentIndex);
+                    targetAxisIndexMap.set(axisDim, axisInfo);
                 }
             }, this);
         }
     }
 
-    private _autoSetOrient() {
+    private _makeAutoOrientByTargetAxis(): LayoutOrient {
         let dim: string;
 
         // Find the first axis
-        this.eachTargetAxis(function (dimNames) {
-            !dim && (dim = dimNames.name);
+        this.eachTargetAxis(function (axisDim) {
+            !dim && (dim = axisDim);
         }, this);
 
-        this.option.orient = dim === 'y' ? 'vertical' : 'horizontal';
+        return dim === 'y' ? 'vertical' : 'horizontal';
     }
 
-    private _isSeriesHasAllAxesTypeOf(seriesModel: SeriesModelOnAxis, 
axisType: OptionAxisType) {
-        // FIXME
-        // Depends on that series.xAxisIndex series.yAxisIndex are specified.
-
-        let is = true;
-        eachAxisDim(function (dimNames) {
-            const seriesAxisIndex = seriesModel.get(dimNames.axisIndex);
-            const axisModel = this.ecModel.getComponent(dimNames.axis, 
seriesAxisIndex);
-
-            if (!axisModel || axisModel.get('type') !== axisType) {
-                is = false;
-            }
-        }, this);
-        return is;
-    }
-
-    private _setDefaultThrottle(inputRawOption: DataZoomOption) {
+    private _setDefaultThrottle(inputRawOption: DataZoomOption): void {
         // When first time user set throttle, auto throttle ends.
         if (inputRawOption.hasOwnProperty('throttle')) {
             this._autoThrottle = false;
@@ -471,7 +385,7 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
         }
     }
 
-    private _updateRangeUse(inputRawOption: RangeOption) {
+    private _updateRangeUse(inputRawOption: RangeOption): void {
         const rangePropMode = this._rangePropMode;
         const rangeModeInOption = this.get('rangeMode');
 
@@ -494,17 +408,13 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
         });
     }
 
-    /**
-     * @public
-     */
-    getFirstTargetAxisModel() {
+    getFirstTargetAxisModel(): AxisBaseModel {
         let firstAxisModel: AxisBaseModel;
-        eachAxisDim(function (dimNames) {
+        this.eachTargetAxis(function (axisDim, axisIndex) {
             if (firstAxisModel == null) {
-                const indices = this.get(dimNames.axisIndex) as number[]; // 
Has been normalized to array
-                if (indices.length) {
-                    firstAxisModel = this.ecModel.getComponent(dimNames.axis, 
indices[0]) as AxisBaseModel;
-                }
+                firstAxisModel = this.ecModel.getComponent(
+                    getAxisMainType(axisDim), axisIndex
+                ) as AxisBaseModel;
             }
         }, this);
 
@@ -512,50 +422,50 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
     }
 
     /**
-     * @public
      * @param {Function} callback param: axisModel, dimNames, axisIndex, 
dataZoomModel, ecModel
      */
     eachTargetAxis<Ctx>(
         callback: (
             this: Ctx,
-            dimNames: Parameters<Parameters<typeof eachAxisDim>[0]>[0],
-            axisIndex: number,
-            dataZoomModel: this,
-            ecModel: GlobalModel
+            axisDim: DataZoomAxisDimension,
+            axisIndex: number
         ) => void,
         context?: Ctx
-    ) {
-        const ecModel = this.ecModel;
-        eachAxisDim(function (dimNames) {
-            each(
-                this.get(dimNames.axisIndex) as number[],   // Has been 
normalized to array
-                function (axisIndex) {
-                    callback.call(context, dimNames, axisIndex, this, ecModel);
-                },
-                this
-            );
-        }, this);
+    ): void {
+        this._targetAxisInfoMap.each(function (axisInfo, axisDim) {
+            each(axisInfo.indexList, function (axisIndex) {
+                callback.call(context, axisDim, axisIndex);
+            });
+        });
     }
 
     /**
      * @return If not found, return null/undefined.
      */
-    getAxisProxy(dimName: string, axisIndex: number): AxisProxy {
-        return this._axisProxies[dimName + '_' + axisIndex];
+    getAxisProxy(axisDim: DataZoomAxisDimension, axisIndex: number): AxisProxy 
{
+        const axisModel = this.getAxisModel(axisDim, axisIndex);
+        if (axisModel) {
+            return (axisModel as DataZoomExtendedAxisBaseModel).__dzAxisProxy;
+        }
     }
 
     /**
      * @return If not found, return null/undefined.
      */
-    getAxisModel(dimName: string, axisIndex: number): AxisBaseModel {
-        const axisProxy = this.getAxisProxy(dimName, axisIndex);
-        return axisProxy && axisProxy.getAxisModel();
+    getAxisModel(axisDim: DataZoomAxisDimension, axisIndex: number): 
AxisBaseModel {
+        if (__DEV__) {
+            assert(axisDim && axisIndex != null);
+        }
+        const axisInfo = this._targetAxisInfoMap.get(axisDim);
+        if (axisInfo && axisInfo.indexMap[axisIndex]) {
+            return this.ecModel.getComponent(getAxisMainType(axisDim), 
axisIndex) as AxisBaseModel;
+        }
     }
 
     /**
      * If not specified, set to undefined.
      */
-    setRawRange(opt: RangeOption) {
+    setRawRange(opt: RangeOption): void {
         const thisOption = this.option;
         const settledOption = this.settledOption;
         each([['start', 'startValue'], ['end', 'endValue']] as const, function 
(names) {
@@ -577,18 +487,14 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
         this._updateRangeUse(opt);
     }
 
-    setCalculatedRange(opt: RangeOption) {
+    setCalculatedRange(opt: RangeOption): void {
         const option = this.option;
         each(['start', 'startValue', 'end', 'endValue'] as const, function 
(name) {
             option[name] = opt[name];
         });
     }
 
-    /**
-     * @public
-     * @return {Array.<number>} [startPercent, endPercent]
-     */
-    getPercentRange() {
+    getPercentRange(): number[] {
         const axisProxy = this.findRepresentativeAxisProxy();
         if (axisProxy) {
             return axisProxy.getDataPercentWindow();
@@ -596,58 +502,64 @@ class DataZoomModel<Opts extends DataZoomOption = 
DataZoomOption> extends Compon
     }
 
     /**
-     * @public
      * For example, 
chart.getModel().getComponent('dataZoom').getValueRange('y', 0);
      *
      * @return [startValue, endValue] value can only be '-' or finite number.
      */
-    getValueRange(axisDimName: string, axisIndex: number): [number, number] {
-        if (axisDimName == null && axisIndex == null) {
+    getValueRange(axisDim: DataZoomAxisDimension, axisIndex: number): number[] 
{
+        if (axisDim == null && axisIndex == null) {
             const axisProxy = this.findRepresentativeAxisProxy();
             if (axisProxy) {
                 return axisProxy.getDataValueWindow();
             }
         }
         else {
-            return this.getAxisProxy(axisDimName, 
axisIndex).getDataValueWindow();
+            return this.getAxisProxy(axisDim, axisIndex).getDataValueWindow();
         }
     }
 
     /**
-     * @public
      * @param axisModel If axisModel given, find axisProxy
      *      corresponding to the axisModel
      */
     findRepresentativeAxisProxy(axisModel?: AxisBaseModel): AxisProxy {
         if (axisModel) {
-            return (axisModel as ExtendedAxisBaseModel).__dzAxisProxy;
+            return (axisModel as DataZoomExtendedAxisBaseModel).__dzAxisProxy;
         }
 
         // Find the first hosted axisProxy
-        const axisProxies = this._axisProxies;
-        for (const key in axisProxies) {
-            if (axisProxies.hasOwnProperty(key) && 
axisProxies[key].hostedBy(this)) {
-                return axisProxies[key];
+        let firstProxy;
+        const axisDimList = this._targetAxisInfoMap.keys();
+        for (let i = 0; i < axisDimList.length; i++) {
+            const axisDim = axisDimList[i];
+            const axisInfo = this._targetAxisInfoMap.get(axisDim);
+            for (let j = 0; j < axisInfo.indexList.length; j++) {
+                const proxy = this.getAxisProxy(axisDim, 
axisInfo.indexList[j]);
+                if (proxy.hostedBy(this)) {
+                    return proxy;
+                }
+                if (!firstProxy) {
+                    firstProxy = proxy;
+                }
             }
         }
 
-        // If no hosted axis find not hosted axisProxy.
-        // Consider this case: dataZoomModel1 and dataZoomModel2 control the 
same axis,
-        // and the option.start or option.end settings are different. The 
percentRange
-        // should follow axisProxy.
-        // (We encounter this problem in toolbox data zoom.)
-        for (const key in axisProxies) {
-            if (axisProxies.hasOwnProperty(key) && 
!axisProxies[key].hostedBy(this)) {
-                return axisProxies[key];
-            }
-        }
+        // If no hosted proxy found, still need to return a proxy.
+        // This case always happens in toolbox dataZoom, where axes are all 
hosted by
+        // other dataZooms.
+        return firstProxy;
     }
 
-    /**
-     * @return {Array.<string>}
-     */
-    getRangePropMode() {
-        return this._rangePropMode.slice();
+    getRangePropMode(): DataZoomModel['_rangePropMode'] {
+        return this._rangePropMode.slice() as DataZoomModel['_rangePropMode'];
+    }
+
+    getOrient(): LayoutOrient {
+        if (__DEV__) {
+            // Should not be called before initialized.
+            assert(this._orient);
+        }
+        return this._orient;
     }
 
 }
diff --git a/src/component/dataZoom/DataZoomView.ts 
b/src/component/dataZoom/DataZoomView.ts
index 85d291f..8f9b285 100644
--- a/src/component/dataZoom/DataZoomView.ts
+++ b/src/component/dataZoom/DataZoomView.ts
@@ -24,6 +24,7 @@ import ExtensionAPI from '../../ExtensionAPI';
 import { AxisBaseModel } from '../../coord/AxisBaseModel';
 import { Dictionary } from '../../util/types';
 import { CoordinateSystemHostModel } from '../../coord/CoordinateSystem';
+import { getAxisMainType } from './helper';
 
 export interface CoordInfo {
     model: CoordinateSystemHostModel
@@ -68,8 +69,8 @@ class DataZoomView extends ComponentView {
         const ecModel = this.ecModel;
         const coordSysLists: Dictionary<CoordInfo[]> = {};
 
-        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
-            const axisModel = ecModel.getComponent(dimNames.axis, axisIndex) 
as AxisBaseModel;
+        dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
+            const axisModel = ecModel.getComponent(getAxisMainType(axisDim), 
axisIndex) as AxisBaseModel;
             if (axisModel) {
                 const coordModel = axisModel.getCoordSysModel();
                 coordModel && save(
diff --git a/src/component/dataZoom/InsideZoomView.ts 
b/src/component/dataZoom/InsideZoomView.ts
index 634ccbf..41f99e7 100644
--- a/src/component/dataZoom/InsideZoomView.ts
+++ b/src/component/dataZoom/InsideZoomView.ts
@@ -41,7 +41,7 @@ class InsideZoomView extends DataZoomView {
      * 'throttle' is used in this.dispatchAction, so we save range
      * to avoid missing some 'pan' info.
      */
-    range: [number, number];
+    range: number[];
 
     /**
      * @override
diff --git a/src/component/dataZoom/SliderZoomView.ts 
b/src/component/dataZoom/SliderZoomView.ts
index bfd3d7f..1b47172 100644
--- a/src/component/dataZoom/SliderZoomView.ts
+++ b/src/component/dataZoom/SliderZoomView.ts
@@ -27,13 +27,16 @@ import * as layout from '../../util/layout';
 import sliderMove from '../helper/sliderMove';
 import GlobalModel from '../../model/Global';
 import ExtensionAPI from '../../ExtensionAPI';
-import { LayoutOrient, Payload, ZRTextVerticalAlign, ZRTextAlign, 
ZRElementEvent, ParsedValue } from '../../util/types';
+import {
+    LayoutOrient, Payload, ZRTextVerticalAlign, ZRTextAlign, ZRElementEvent, 
ParsedValue
+} from '../../util/types';
 import SliderZoomModel from './SliderZoomModel';
 import ComponentView from '../../view/Component';
 import { RectLike } from 'zrender/src/core/BoundingRect';
 import Axis from '../../coord/Axis';
 import SeriesModel from '../../model/Series';
 import { AxisBaseModel } from '../../coord/AxisBaseModel';
+import { getAxisMainType } from './helper';
 
 const Rect = graphic.Rect;
 
@@ -64,17 +67,17 @@ class SliderZoomView extends DataZoomView {
 
     private _orient: LayoutOrient;
 
-    private _range: [number, number];
+    private _range: number[];
 
     /**
      * [coord of the first handle, coord of the second handle]
      */
-    private _handleEnds: [number, number];
+    private _handleEnds: number[];
 
     /**
      * [length, thick]
      */
-    private _size: [number, number];
+    private _size: number[];
 
     private _handleWidth: number;
 
@@ -118,7 +121,7 @@ class SliderZoomView extends DataZoomView {
             'fixRate'
         );
 
-        this._orient = dataZoomModel.get('orient');
+        this._orient = dataZoomModel.getOrient();
 
         if (this.dataZoomModel.get('show') === false) {
             this.group.removeAll();
@@ -392,9 +395,9 @@ class SliderZoomView extends DataZoomView {
         let result: SliderZoomView['_dataShadowInfo'];
         const ecModel = this.ecModel;
 
-        dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
+        dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
             const seriesModels = dataZoomModel
-                .getAxisProxy(dimNames.name, axisIndex)
+                .getAxisProxy(axisDim, axisIndex)
                 .getTargetSeriesModels();
 
             each(seriesModels, function (seriesModel) {
@@ -409,8 +412,10 @@ class SliderZoomView extends DataZoomView {
                     return;
                 }
 
-                const thisAxis = (ecModel.getComponent(dimNames.axis, 
axisIndex) as AxisBaseModel).axis;
-                let otherDim = getOtherDim(dimNames.name);
+                const thisAxis = (
+                    ecModel.getComponent(getAxisMainType(axisDim), axisIndex) 
as AxisBaseModel
+                ).axis;
+                let otherDim = getOtherDim(axisDim);
                 let otherAxisInverse;
                 const coordSys = seriesModel.coordinateSystem;
 
@@ -423,7 +428,7 @@ class SliderZoomView extends DataZoomView {
                 result = {
                     thisAxis: thisAxis,
                     series: seriesModel,
-                    thisDim: dimNames.name,
+                    thisDim: axisDim,
                     otherDim: otherDim,
                     otherAxisInverse: otherAxisInverse
                 };
@@ -504,7 +509,7 @@ class SliderZoomView extends DataZoomView {
 
             barGroup.add(handles[handleIndex] = path);
 
-            const textStyleModel = dataZoomModel.textStyleModel;
+            const textStyleModel = dataZoomModel.getModel('textStyle');
 
             this.group.add(
                 handleLabels[handleIndex] = new graphic.Text({
diff --git a/src/component/dataZoom/dataZoomAction.ts 
b/src/component/dataZoom/dataZoomAction.ts
index 5223b0d..11c50f2 100644
--- a/src/component/dataZoom/dataZoomAction.ts
+++ b/src/component/dataZoom/dataZoomAction.ts
@@ -20,33 +20,14 @@
 import * as echarts from '../../echarts';
 import * as zrUtil from 'zrender/src/core/util';
 import GlobalModel from '../../model/Global';
-import { createLinkedNodesFinder, eachAxisDim } from './helper';
-import DataZoomModel from './DataZoomModel';
+import { findEffectedDataZooms } from './helper';
 
 
 echarts.registerAction('dataZoom', function (payload, ecModel: GlobalModel) {
 
-    const linkedNodesFinder = createLinkedNodesFinder(
-        zrUtil.bind(ecModel.eachComponent, ecModel, 'dataZoom' as any),
-        eachAxisDim,
-        function (model: DataZoomModel, dimNames) {
-            // Has been normalized to array
-            return model.get(dimNames.axisIndex) as number[];
-        }
-    );
+    const effectedModels = findEffectedDataZooms(ecModel, payload);
 
-    const effectedModels: DataZoomModel[] = [];
-
-    ecModel.eachComponent(
-        {mainType: 'dataZoom', query: payload},
-        function (model: DataZoomModel, index: number) {
-            effectedModels.push.apply(
-                effectedModels, linkedNodesFinder(model).nodes
-            );
-        }
-    );
-
-    zrUtil.each(effectedModels, function (dataZoomModel, index) {
+    zrUtil.each(effectedModels, function (dataZoomModel) {
         dataZoomModel.setRawRange({
             start: payload.start,
             end: payload.end,
diff --git a/src/component/dataZoom/dataZoomProcessor.ts 
b/src/component/dataZoom/dataZoomProcessor.ts
index 960d62c..7404abf 100644
--- a/src/component/dataZoom/dataZoomProcessor.ts
+++ b/src/component/dataZoom/dataZoomProcessor.ts
@@ -20,7 +20,10 @@
 import * as echarts from '../../echarts';
 import {createHashMap, each} from 'zrender/src/core/util';
 import SeriesModel from '../../model/Series';
-import DataZoomModel from './DataZoomModel';
+import DataZoomModel, { DataZoomExtendedAxisBaseModel } from './DataZoomModel';
+import { getAxisMainType, DataZoomAxisDimension } from './helper';
+import AxisProxy from './AxisProxy';
+
 
 echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER, {
 
@@ -28,23 +31,49 @@ 
echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER, {
     // there is a line series and a pie series, it is better not to update the
     // line series if only pie series is needed to be updated.
     getTargetSeries: function (ecModel) {
-        const seriesModelMap = createHashMap<SeriesModel>();
 
-        ecModel.eachComponent('dataZoom', function (dataZoomModel: 
DataZoomModel) {
-            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, 
dataZoomModel) {
-                const axisProxy = dataZoomModel.getAxisProxy(dimNames.name, 
axisIndex);
-                each(axisProxy.getTargetSeriesModels(), function (seriesModel) 
{
-                    seriesModelMap.set(seriesModel.uid, seriesModel);
+        function eachAxisModel(
+            cb: (
+                axisDim: DataZoomAxisDimension,
+                axisIndex: number,
+                axisModel: DataZoomExtendedAxisBaseModel,
+                dataZoomModel: DataZoomModel
+            ) => void
+        ) {
+            ecModel.eachComponent('dataZoom', function (dataZoomModel: 
DataZoomModel) {
+                dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
+                    const axisModel = 
ecModel.getComponent(getAxisMainType(axisDim), axisIndex);
+                    cb(axisDim, axisIndex, axisModel as 
DataZoomExtendedAxisBaseModel, dataZoomModel);
                 });
             });
+        }
+        // FIXME: it brings side-effect to `getTargetSeries`.
+        // Prepare axis proxies.
+        eachAxisModel(function (axisDim, axisIndex, axisModel, dataZoomModel) {
+            // dispose all last axis proxy, in case that some axis are deleted.
+            axisModel.__dzAxisProxy = null;
+        });
+        const proxyList: AxisProxy[] = [];
+        eachAxisModel(function (axisDim, axisIndex, axisModel, dataZoomModel) {
+            // Different dataZooms may constrol the same axis. In that case,
+            // an axisProxy serves both of them.
+            if (!axisModel.__dzAxisProxy) {
+                // Use the first dataZoomModel as the main model of axisProxy.
+                axisModel.__dzAxisProxy = new AxisProxy(axisDim, axisIndex, 
dataZoomModel, ecModel);
+                proxyList.push(axisModel.__dzAxisProxy);
+            }
+        });
+
+        const seriesModelMap = createHashMap<SeriesModel>();
+        each(proxyList, function (axisProxy) {
+            each(axisProxy.getTargetSeriesModels(), function (seriesModel) {
+                seriesModelMap.set(seriesModel.uid, seriesModel);
+            });
         });
 
         return seriesModelMap;
     },
 
-    // FIXME:TS never used, so comment it
-    // modifyOutputEnd: true,
-
     // Consider appendData, where filter should be performed. Because data 
process is
     // in block mode currently, it is not need to worry about that the 
overallProgress
     // execute every frame.
@@ -54,8 +83,8 @@ echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER, {
             // We calculate window and reset axis here but not in model
             // init stage and not after action dispatch handler, because
             // reset should be called after seriesData.restoreData.
-            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, 
dataZoomModel) {
-                dataZoomModel.getAxisProxy(dimNames.name, 
axisIndex).reset(dataZoomModel);
+            dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
+                dataZoomModel.getAxisProxy(axisDim, 
axisIndex).reset(dataZoomModel);
             });
 
             // Caution: data zoom filtering is order sensitive when using
@@ -72,8 +101,8 @@ echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER, 
{
             // while sliding y-dataZoom will only change the range of yAxis.
             // So we should filter x-axis after reset x-axis immediately,
             // and then reset y-axis and filter y-axis.
-            dataZoomModel.eachTargetAxis(function (dimNames, axisIndex, 
dataZoomModel) {
-                dataZoomModel.getAxisProxy(dimNames.name, 
axisIndex).filterData(dataZoomModel, api);
+            dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
+                dataZoomModel.getAxisProxy(axisDim, 
axisIndex).filterData(dataZoomModel, api);
             });
         });
 
@@ -81,15 +110,17 @@ 
echarts.registerProcessor(echarts.PRIORITY.PROCESSOR.FILTER, {
             // Fullfill all of the range props so that user
             // is able to get them from chart.getOption().
             const axisProxy = dataZoomModel.findRepresentativeAxisProxy();
-            const percentRange = axisProxy.getDataPercentWindow();
-            const valueRange = axisProxy.getDataValueWindow();
+            if (axisProxy) {
+                const percentRange = axisProxy.getDataPercentWindow();
+                const valueRange = axisProxy.getDataValueWindow();
 
-            dataZoomModel.setCalculatedRange({
-                start: percentRange[0],
-                end: percentRange[1],
-                startValue: valueRange[0],
-                endValue: valueRange[1]
-            });
+                dataZoomModel.setCalculatedRange({
+                    start: percentRange[0],
+                    end: percentRange[1],
+                    startValue: valueRange[0],
+                    endValue: valueRange[1]
+                });
+            }
         });
     }
 });
diff --git a/src/component/dataZoom/helper.ts b/src/component/dataZoom/helper.ts
index ef364b1..d36a783 100644
--- a/src/component/dataZoom/helper.ts
+++ b/src/component/dataZoom/helper.ts
@@ -17,9 +17,11 @@
 * under the License.
 */
 
-import * as zrUtil from 'zrender/src/core/util';
-import * as formatUtil from '../../util/format';
-import { Dictionary } from '../../util/types';
+import { Payload, DimensionName } from '../../util/types';
+import GlobalModel from '../../model/Global';
+import DataZoomModel from './DataZoomModel';
+import { indexOf, createHashMap, assert } from 'zrender/src/core/util';
+import { __DEV__ } from '../../config';
 
 
 export interface DataZoomPayloadBatchItem {
@@ -30,148 +32,109 @@ export interface DataZoomPayloadBatchItem {
     endValue?: number
 }
 
-const AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle', 'single'] as const;
+export const DATA_ZOOM_AXIS_DIMENSIONS = [
+    'x', 'y', 'radius', 'angle', 'single'
+] as const;
+export type DataZoomAxisDimension =
+    'x' | 'y' | 'radius' | 'angle' | 'single';
+type DataZoomAxisMainType =
+    'xAxis' | 'yAxis' | 'radiusAxis' | 'angleAxis' | 'singleAxis';
+type DataZoomAxisIndexPropName =
+    'xAxisIndex' | 'yAxisIndex' | 'radiusAxisIndex' | 'angleAxisIndex' | 
'singleAxisIndex';
+type DataZoomAxisIdPropName =
+    'xAxisId' | 'yAxisId' | 'radiusAxisId' | 'angleAxisId' | 'singleAxisId';
+
 // Supported coords.
 // FIXME: polar has been broken (but rarely used).
 const COORDS = ['cartesian2d', 'polar', 'singleAxis'] as const;
 
 export function isCoordSupported(coordType: string) {
-    return zrUtil.indexOf(COORDS, coordType) >= 0;
+    return indexOf(COORDS, coordType) >= 0;
 }
 
-type AxisAttrMap = {
-    // TODO zAxis ?
-    'axisIndex': 'xAxisIndex' | 'yAxisIndex' | 'radiusAxisIndex' | 
'angleAxisIndex' | 'singleAxisIndex'
-    'axis': 'xAxis' | 'yAxis' | 'radiusAxis' | 'angleAxis' | 'singleAxis'
-    'axisId': 'xAxisId' | 'yAxisId' | 'radiusAxisId' | 'angleAxisId' | 
'singleAxisId'
-};
-
-/**
- * Create "each" method to iterate names.
- */
-function createNameEach<T extends string>(names: readonly T[]) {
-    const attrs = ['axisIndex', 'axis', 'axisId'] as const;
-    const capitalNames = zrUtil.map(names.slice(), formatUtil.capitalFirst);
-    const capitalAttrs = zrUtil.map((attrs || []).slice(), 
formatUtil.capitalFirst);
-
-    type NameObj = {
-        name: T,
-        capital: string,
-        axisIndex: AxisAttrMap['axisIndex']
-        axis: AxisAttrMap['axis']
-        axisId: AxisAttrMap['axisId']
-    };
-    return function<Ctx> (
-        callback: (this: Ctx, nameObj: NameObj) => void,
-        context?: Ctx
-    ) {
-        zrUtil.each(names, function (name, index) {
-            const nameObj = {
-                name: name,
-                capital: capitalNames[index]
-            } as NameObj;
-
-            for (let j = 0; j < attrs.length; j++) {
-                nameObj[attrs[j]] = (name + capitalAttrs[j]) as never;
-            }
+export function getAxisMainType(axisDim: DimensionName): DataZoomAxisMainType {
+    if (__DEV__) {
+        assert(axisDim);
+    }
+    return axisDim + 'Axis' as DataZoomAxisMainType;
+}
 
-            callback.call(context, nameObj);
-        });
-    };
+export function getAxisIndexPropName(axisDim: DimensionName): 
DataZoomAxisIndexPropName {
+    if (__DEV__) {
+        assert(axisDim);
+    }
+    return axisDim + 'AxisIndex' as DataZoomAxisIndexPropName;
 }
 
-/**
- * Iterate each dimension name.
- *
- * @public
- * @param callback The parameter is like:
- *                            {
- *                                name: 'angle',
- *                                capital: 'Angle',
- *                                axis: 'angleAxis',
- *                                axisIndex: 'angleAxisIndex',
- *                                index: 'angleIndex'
- *                            }
- * @param context
- */
-export const eachAxisDim = createNameEach(AXIS_DIMS);
+export function getAxisIdPropName(axisDim: DimensionName): 
DataZoomAxisIdPropName {
+    if (__DEV__) {
+        assert(axisDim);
+    }
+    return axisDim + 'AxisId' as DataZoomAxisIdPropName;
+}
 
 /**
- * If tow dataZoomModels has the same axis controlled, we say that they are 
'linked'.
- * dataZoomModels and 'links' make up one or more graphics.
- * This function finds the graphic where the source dataZoomModel is in.
- *
- * @public
- * @param forEachNode Node iterator.
- * @param forEachEdgeType edgeType iterator
- * @param edgeIdGetter Giving node and edgeType, return an array of edge id.
- * @return Input: sourceNode, Output: Like {nodes: [], dims: {}}
+ * If two dataZoomModels has the same axis controlled, we say that they are 
'linked'.
+ * This function finds all linked dataZoomModels start from the given payload.
  */
-export function createLinkedNodesFinder<N, E extends {name: string}>(
-    forEachNode: (cb: (node: N) => void) => void,
-    forEachEdgeType: (cb: (edge: E) => void) => void,
-    edgeIdGetter: (node: N, edge: E) => number[]
-) {
-
-    type Result = {
-        nodes: N[]
-        // key: edgeType.name, value: Object (key: edge id, value: boolean).
-        records: Dictionary<Dictionary<boolean>>
-    };
-
-    return function (sourceNode: N) {
-        const result: Result = {
-            nodes: [],
-            records: {}
-        };
-
-        forEachEdgeType(function (edgeType) {
-            result.records[edgeType.name] = {};
-        });
-
-        if (!sourceNode) {
-            return result;
-        }
-
-        absorb(sourceNode, result);
-
-        let existsLink;
-        do {
-            existsLink = false;
-            forEachNode(processSingleNode);
-        }
-        while (existsLink);
-
-        function processSingleNode(node: N) {
-            if (!isNodeAbsorded(node, result) && isLinked(node, result)) {
-                absorb(node, result);
-                existsLink = true;
+export function findEffectedDataZooms(ecModel: GlobalModel, payload: Payload): 
DataZoomModel[] {
+
+    // Key: `DataZoomAxisDimension`
+    const axisRecords = createHashMap<boolean[], DataZoomAxisDimension>();
+    const effectedModels: DataZoomModel[] = [];
+    // Key: uid of dataZoomModel
+    const effectedModelMap = createHashMap<boolean>();
+
+    // Find the dataZooms specified by payload.
+    ecModel.eachComponent(
+        { mainType: 'dataZoom', query: payload },
+        function (dataZoomModel: DataZoomModel) {
+            if (!effectedModelMap.get(dataZoomModel.uid)) {
+                addToEffected(dataZoomModel);
             }
         }
+    );
+
+    // Start from the given dataZoomModels, travel the graph to find
+    // all of the linked dataZoom models.
+    let foundNewLink;
+    do {
+        foundNewLink = false;
+        ecModel.eachComponent('dataZoom', processSingle);
+    }
+    while (foundNewLink);
 
-        return result;
-    };
+    function processSingle(dataZoomModel: DataZoomModel): void {
+        if (!effectedModelMap.get(dataZoomModel.uid) && 
isLinked(dataZoomModel)) {
+            addToEffected(dataZoomModel);
+            foundNewLink = true;
+        }
+    }
 
-    function isNodeAbsorded(node: N, result: Result) {
-        return zrUtil.indexOf(result.nodes, node) >= 0;
+    function addToEffected(dataZoom: DataZoomModel): void {
+        effectedModelMap.set(dataZoom.uid, true);
+        effectedModels.push(dataZoom);
+        markAxisControlled(dataZoom);
     }
 
-    function isLinked(node: N, result: Result) {
-        let hasLink = false;
-        forEachEdgeType(function (edgeType: E) {
-            zrUtil.each(edgeIdGetter(node, edgeType) || [], function (edgeId) {
-                result.records[edgeType.name][edgeId] && (hasLink = true);
-            });
+    function isLinked(dataZoomModel: DataZoomModel): boolean {
+        let isLink = false;
+        dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
+            const axisIdxArr = axisRecords.get(axisDim);
+            if (axisIdxArr && axisIdxArr[axisIndex]) {
+                isLink = true;
+            }
         });
-        return hasLink;
+        return isLink;
     }
 
-    function absorb(node: N, result: Result) {
-        result.nodes.push(node);
-        forEachEdgeType(function (edgeType: E) {
-            zrUtil.each(edgeIdGetter(node, edgeType) || [], function (edgeId) {
-                result.records[edgeType.name][edgeId] = true;
-            });
+    function markAxisControlled(dataZoomModel: DataZoomModel) {
+        dataZoomModel.eachTargetAxis(function (axisDim, axisIndex) {
+            (
+                axisRecords.get(axisDim) || axisRecords.set(axisDim, [])
+            )[axisIndex] = true;
         });
     }
+
+    return effectedModels;
 }
diff --git a/test/dataZoom-feature.html b/test/dataZoom-feature.html
new file mode 100644
index 0000000..f93fc4b
--- /dev/null
+++ b/test/dataZoom-feature.html
@@ -0,0 +1,256 @@
+<!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="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <!-- <script src="ut/lib/canteen.js"></script> -->
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+        </style>
+
+
+
+        <div id="refer_by_id"></div>
+        <div id="auto_axis_second_setOption"></div>
+
+
+
+
+
+
+
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var option;
+
+            option = {
+                grid: [{
+                    bottom: '55%'
+                }, {
+                    id: 'g1',
+                    top: '55%'
+                }],
+                xAxis: [{
+
+                }, {
+                    id: 'x1',
+                    gridId: 'g1'
+                }],
+                yAxis: [{
+
+                }, {
+                    id: 'y1',
+                    gridId: 'g1'
+                }],
+                dataZoom: [{
+                    xAxisId: 'x1',
+                    type: 'slider'
+                }, {
+                    xAxisId: 'x1',
+                    type: 'inside'
+                }],
+                series: [{
+                    type: 'line',
+                    data: [[11, 22], [33, 44]]
+                }, {
+                    type: 'line',
+                    xAxisId: 'x1',
+                    yAxisId: 'y1',
+                    data: [[233, 432], [154, 552]]
+                }]
+            };
+
+            var chart = testHelper.create(echarts, 'refer_by_id', {
+                title: [
+                    'refer axis by id',
+                    'Two grids, dataZoom should refer to the second grid',
+                ],
+                option: option,
+                height: 300,
+            });
+        });
+        </script>
+
+
+
+
+
+
+
+
+
+
+        <script>
+        require(['echarts'], function (echarts) {
+            var option;
+
+            option = {
+                toolbox: {
+                    left: 'center',
+                    feature: {
+                        dataZoom: {}
+                    }
+                },
+                grid: [{
+                    bottom: '60%'
+                }, {
+                    id: 'gb',
+                    top: '60%'
+                }],
+                xAxis: [{
+                    type: 'category'
+                }, {
+                    type: 'category'
+                }, {
+                    id: 'xb0',
+                    type: 'category',
+                    gridIndex: 1
+                }, {
+                    id: 'xb1',
+                    type: 'category',
+                    gridIndex: 1
+                }],
+                yAxis: [{
+
+                }, {
+                    id: 'yb',
+                    gridIndex: 1
+                }],
+                dataZoom: [{
+                    type: 'slider'
+                }, {
+                    type: 'inside'
+                }],
+                series: [{
+                    type: 'line',
+                    data: [[11, 22], [33, 44]]
+                }, {
+                    type: 'line',
+                    xAxisIndex: 1,
+                    data: [[11111, 52], [21133, 74]]
+                }, {
+                    id: 'sb0',
+                    type: 'line',
+                    xAxisIndex: 2,
+                    yAxisIndex: 1,
+                    data: [[23, 432], [54, 552]]
+                }, {
+                    id: 'sb1',
+                    type: 'line',
+                    xAxisIndex: 3,
+                    yAxisIndex: 1,
+                    data: [[222233, 1432], [111154, 1552]]
+                }]
+            };
+
+            var chart = testHelper.create(echarts, 
'auto_axis_second_setOption', {
+                title: [
+                    'two grids, each has two xAxis.',
+                    'dataZoom should auto **control all of the two xAxis of 
the first** grid.',
+                    'Click btn "remove the first grid".',
+                    'dataZoom should auto **control all of the two xAxis of 
the second** grid.',
+                    '**inside dataZoom** on the first grid area **should be 
removed**.',
+                    '**toolbox zoom** should only control the second grid.',
+                    'Click btn "addback the first grid".',
+                    'dataZoom should auto **control all of the two xAxis of 
the first** grid.',
+                    '**inside dataZoom** on the second grid area **should be 
removed**.',
+                    'Click btn "remove all grids".',
+                    'Should no error.',
+                    'Click btn "addback the first grid".',
+                    'Functionalities should be OK.'
+                ],
+                option: option,
+                height: 350,
+                buttons: [{
+                    text: 'remove the first grid',
+                    onclick: function () {
+                        chart.setOption({
+                            grid: [{
+                                id: 'gb',
+                            }],
+                            xAxis: [{
+                                id: 'xb0',
+                            }, {
+                                id: 'xb1',
+                            }],
+                            yAxis: [{
+                                id: 'yb'
+                            }],
+                            series: [{
+                                id: 'sb0',
+                            }, {
+                                id: 'sb1',
+                            }]
+                        }, { replaceMerge: ['grid', 'xAxis', 'yAxis', 
'series'] });
+                    }
+                }, {
+                    text: 'addback the first grid',
+                    onclick: function () {
+                        chart.setOption({
+                            grid: [{
+                                bottom: '60%'
+                            }],
+                            xAxis: [{
+                            }, {
+                            }],
+                            yAxis: [{
+                            }],
+                            series: [{
+                                type: 'line',
+                                data: [[11, 22], [33, 44]]
+                            }, {
+                                type: 'line',
+                                xAxisIndex: 1,
+                                data: [[11111, 52], [21133, 74]]
+                            }]
+                        });
+                    }
+                }, {
+                    text: 'remove all grids',
+                    onclick: function () {
+                        chart.setOption({
+                            grid: [],
+                            xAxis: [],
+                            yAxis: [],
+                            series: []
+                        }, { replaceMerge: ['grid', 'xAxis', 'yAxis', 
'series'] });
+                    }
+                }]
+            });
+        });
+        </script>
+
+
+
+    </body>
+</html>
+


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

Reply via email to