You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2020/02/28 08:35:07 UTC

[incubator-echarts] branch typescript updated: ts: types of dataZoom

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

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


The following commit(s) were added to refs/heads/typescript by this push:
     new a1dc608  ts: types of dataZoom
a1dc608 is described below

commit a1dc608e518bb61efdcb6f5a1d69725808ccca98
Author: pissang <bm...@gmail.com>
AuthorDate: Fri Feb 28 16:34:35 2020 +0800

    ts: types of dataZoom
---
 src/component/dataZoom/DataZoomModel.ts   |   3 +-
 src/component/dataZoom/DataZoomView.ts    |  48 +++-
 src/component/dataZoom/InsideZoomView.ts  | 171 ++++++++-----
 src/component/dataZoom/SelectZoomModel.ts |  12 +-
 src/component/dataZoom/SelectZoomView.ts  |  10 +-
 src/component/dataZoom/SliderZoomModel.ts |   2 +-
 src/component/dataZoom/SliderZoomView.ts  | 349 ++++++++++++-------------
 src/component/dataZoom/helper.ts          |   8 +
 src/component/dataZoom/history.ts         |  78 +++---
 src/component/dataZoom/roams.ts           | 122 ++++-----
 src/component/helper/RoamController.ts    | 410 +++++++++++++++++-------------
 src/component/visualMap/ContinuousView.ts |   2 +-
 src/coord/Axis.ts                         |  11 +-
 src/coord/CoordinateSystem.ts             |  10 +-
 src/coord/axisModelCommonMixin.ts         |   5 +-
 src/coord/cartesian/Axis2D.ts             |   9 -
 src/coord/polar/AngleAxis.ts              |   2 -
 src/coord/polar/RadiusAxis.ts             |   2 -
 src/coord/single/SingleAxis.ts            |   2 -
 src/model/Model.ts                        |   2 +-
 src/model/Series.ts                       |   9 +-
 21 files changed, 691 insertions(+), 576 deletions(-)

diff --git a/src/component/dataZoom/DataZoomModel.ts b/src/component/dataZoom/DataZoomModel.ts
index a1b7e4c..e508b21 100644
--- a/src/component/dataZoom/DataZoomModel.ts
+++ b/src/component/dataZoom/DataZoomModel.ts
@@ -21,7 +21,6 @@ import {__DEV__} from '../../config';
 import * as zrUtil from 'zrender/src/core/util';
 import env from 'zrender/src/core/env';
 import * as modelUtil from '../../util/model';
-import * as helper from './helper';
 import AxisProxy from './AxisProxy';
 import ComponentModel from '../../model/Component';
 import {
@@ -39,9 +38,9 @@ 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';
 
 var each = zrUtil.each;
-var eachAxisDim = helper.eachAxisDim;
 
 export interface DataZoomOption extends ComponentOption {
 
diff --git a/src/component/dataZoom/DataZoomView.ts b/src/component/dataZoom/DataZoomView.ts
index cd9d99e..1aa2bcd 100644
--- a/src/component/dataZoom/DataZoomView.ts
+++ b/src/component/dataZoom/DataZoomView.ts
@@ -17,19 +17,33 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import ComponentView from '../../view/Component';
+import DataZoomModel from './DataZoomModel';
+import GlobalModel from '../../model/Global';
+import ExtensionAPI from '../../ExtensionAPI';
+import { AxisBaseModel } from '../../coord/AxisBaseModel';
+import { Dictionary } from '../../util/types';
+import { CoordinateSystemHostModel } from '../../coord/CoordinateSystem';
+
+export interface CoordInfo {
+    model: CoordinateSystemHostModel
+    axisModels: AxisBaseModel[]
+    coordIndex: number
+}
 
-export default ComponentView.extend({
+class DataZoomView extends ComponentView {
+    static type = 'dataZoom'
+    type = DataZoomView.type
 
-    type: 'dataZoom',
+    dataZoomModel: DataZoomModel
+    ecModel: GlobalModel
+    api: ExtensionAPI
 
-    render: function (dataZoomModel, ecModel, api, payload) {
+    render(dataZoomModel: DataZoomModel, ecModel: GlobalModel, api: ExtensionAPI, payload: any) {
         this.dataZoomModel = dataZoomModel;
         this.ecModel = ecModel;
         this.api = api;
-    },
+    }
 
     /**
      * Find the first target coordinate system.
@@ -49,13 +63,13 @@ export default ComponentView.extend({
      *                       {model: coord0, axisModels: [], coordIndex: 0}
      *                   ]
      */
-    getTargetCoordInfo: function () {
+    getTargetCoordInfo() {
         var dataZoomModel = this.dataZoomModel;
         var ecModel = this.ecModel;
-        var coordSysLists = {};
+        var coordSysLists: Dictionary<CoordInfo[]> = {};
 
         dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
-            var axisModel = ecModel.getComponent(dimNames.axis, axisIndex);
+            var axisModel = ecModel.getComponent(dimNames.axis, axisIndex) as AxisBaseModel;
             if (axisModel) {
                 var coordModel = axisModel.getCoordSysModel();
                 coordModel && save(
@@ -67,7 +81,12 @@ export default ComponentView.extend({
             }
         }, this);
 
-        function save(coordModel, axisModel, store, coordIndex) {
+        function save(
+            coordModel: CoordinateSystemHostModel,
+            axisModel: AxisBaseModel,
+            store: CoordInfo[],
+            coordIndex: number
+        ) {
             var item;
             for (var i = 0; i < store.length; i++) {
                 if (store[i].model === coordModel) {
@@ -77,7 +96,9 @@ export default ComponentView.extend({
             }
             if (!item) {
                 store.push(item = {
-                    model: coordModel, axisModels: [], coordIndex: coordIndex
+                    model: coordModel,
+                    axisModels: [],
+                    coordIndex: coordIndex
                 });
             }
             item.axisModels.push(axisModel);
@@ -85,5 +106,8 @@ export default ComponentView.extend({
 
         return coordSysLists;
     }
+}
+
+ComponentView.registerClass(DataZoomView);
 
-});
+export default DataZoomView;
\ No newline at end of file
diff --git a/src/component/dataZoom/InsideZoomView.ts b/src/component/dataZoom/InsideZoomView.ts
index 951aea7..45366ec 100644
--- a/src/component/dataZoom/InsideZoomView.ts
+++ b/src/component/dataZoom/InsideZoomView.ts
@@ -17,95 +17,105 @@
 * under the License.
 */
 
-// @ts-nocheck
-
-import * as zrUtil from 'zrender/src/core/util';
-import DataZoomView from './DataZoomView';
+import DataZoomView, {CoordInfo} from './DataZoomView';
 import sliderMove from '../helper/sliderMove';
 import * as roams from './roams';
+import InsideZoomModel from './InsideZoomModel';
+import GlobalModel from '../../model/Global';
+import ExtensionAPI from '../../ExtensionAPI';
+import ComponentView from '../../view/Component';
+import { each, map, bind } from 'zrender/src/core/util';
+import RoamController, {RoamEventParams} from '../helper/RoamController';
+import { ZRElementEvent } from '../../util/types';
+import { AxisBaseModel } from '../../coord/AxisBaseModel';
+import Polar from '../../coord/polar/Polar';
+import SingleAxis from '../../coord/single/SingleAxis';
+import { CoordinateSystem } from '../../coord/CoordinateSystem';
 
-var bind = zrUtil.bind;
 
-var InsideZoomView = DataZoomView.extend({
+type SupportedCoordSysName = 'polar' | 'grid' | 'singleAxis';
 
-    type: 'dataZoom.inside',
+class InsideZoomView extends DataZoomView {
+    static type = 'dataZoom.inside'
+    type = 'dataZoom.inside'
 
     /**
-     * @override
+     * 'throttle' is used in this.dispatchAction, so we save range
+     * to avoid missing some 'pan' info.
      */
-    init: function (ecModel, api) {
-        /**
-         * 'throttle' is used in this.dispatchAction, so we save range
-         * to avoid missing some 'pan' info.
-         * @private
-         * @type {Array.<number>}
-         */
-        this._range;
-    },
+    range: [number, number]
 
     /**
      * @override
      */
-    render: function (dataZoomModel, ecModel, api, payload) {
-        InsideZoomView.superApply(this, 'render', arguments);
+    render(dataZoomModel: InsideZoomModel, ecModel: GlobalModel, api: ExtensionAPI, payload: any) {
+        super.render.apply(this, arguments as any);
 
         // Hence the `throttle` util ensures to preserve command order,
         // here simply updating range all the time will not cause missing
         // any of the the roam change.
-        this._range = dataZoomModel.getPercentRange();
+        this.range = dataZoomModel.getPercentRange();
 
         // Reset controllers.
-        zrUtil.each(this.getTargetCoordInfo(), function (coordInfoList, coordSysName) {
+        each(this.getTargetCoordInfo(), function (coordInfoList, coordSysName: SupportedCoordSysName) {
 
-            var allCoordIds = zrUtil.map(coordInfoList, function (coordInfo) {
+            var allCoordIds = map(coordInfoList, function (coordInfo) {
                 return roams.generateCoordId(coordInfo.model);
             });
 
-            zrUtil.each(coordInfoList, function (coordInfo) {
+            each(coordInfoList, function (coordInfo) {
                 var coordModel = coordInfo.model;
 
-                var getRange = {};
-                zrUtil.each(['pan', 'zoom', 'scrollMove'], function (eventName) {
-                    getRange[eventName] = bind(roamHandlers[eventName], this, coordInfo, coordSysName);
-                }, this);
-
                 roams.register(
                     api,
                     {
                         coordId: roams.generateCoordId(coordModel),
                         allCoordIds: allCoordIds,
-                        containsPoint: function (e, x, y) {
+                        containsPoint(e, x, y) {
                             return coordModel.coordinateSystem.containPoint([x, y]);
                         },
                         dataZoomId: dataZoomModel.id,
                         dataZoomModel: dataZoomModel,
-                        getRange: getRange
+                        getRange: {
+                            pan: bind(roamHandlers.pan, this, coordInfo, coordSysName),
+                            zoom: bind(roamHandlers.zoom, this, coordInfo, coordSysName),
+                            scrollMove: bind(roamHandlers.scrollMove, this, coordInfo, coordSysName)
+                        }
                     }
                 );
             }, this);
 
         }, this);
-    },
+    }
 
     /**
      * @override
      */
-    dispose: function () {
+    dispose() {
         roams.unregister(this.api, this.dataZoomModel.id);
-        InsideZoomView.superApply(this, 'dispose', arguments);
-        this._range = null;
+        super.dispose.apply(this, arguments as any);
+        this.range = null;
     }
+}
 
-});
+interface RoamHandler<T extends RoamEventParams['zoom'] | RoamEventParams['scrollMove'] | RoamEventParams['pan']> {
+    (
+        coordInfo: CoordInfo,
+        coordSysName: SupportedCoordSysName,
+        controller: RoamController,
+        e: T
+    ): [number, number]
+}
 
-var roamHandlers = {
+var roamHandlers: {
+    pan: RoamHandler<RoamEventParams['pan']>
+    zoom: RoamHandler<RoamEventParams['zoom']>
+    scrollMove: RoamHandler<RoamEventParams['scrollMove']>
+} & ThisType<InsideZoomView> = {
 
-    /**
-     * @this {module:echarts/component/dataZoom/InsideZoomView}
-     */
-    zoom: function (coordInfo, coordSysName, controller, e) {
-        var lastRange = this._range;
-        var range = lastRange.slice();
+    zoom(coordInfo, coordSysName, controller, e: RoamEventParams['zoom']) {
+        var lastRange = this.range;
+        var range = lastRange.slice() as [number, number];
 
         // Calculate transform by the first axis.
         var axisModel = coordInfo.axisModels[0];
@@ -131,17 +141,14 @@ var roamHandlers = {
 
         sliderMove(0, range, [0, 100], 0, minMaxSpan.minSpan, minMaxSpan.maxSpan);
 
-        this._range = range;
+        this.range = range;
 
         if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {
             return range;
         }
     },
 
-    /**
-     * @this {module:echarts/component/dataZoom/InsideZoomView}
-     */
-    pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {
+    pan: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e: RoamEventParams['pan']) {
         var directionInfo = getDirectionInfo[coordSysName](
             [e.oldX, e.oldY], [e.newX, e.newY], axisModel, controller, coordInfo
         );
@@ -151,10 +158,9 @@ var roamHandlers = {
             * directionInfo.pixel / directionInfo.pixelLength;
     }),
 
-    /**
-     * @this {module:echarts/component/dataZoom/InsideZoomView}
-     */
-    scrollMove: makeMover(function (range, axisModel, coordInfo, coordSysName, controller, e) {
+    scrollMove: makeMover(
+        function (range, axisModel, coordInfo, coordSysName, controller, e: RoamEventParams['scrollMove']
+    ) {
         var directionInfo = getDirectionInfo[coordSysName](
             [0, 0], [e.scrollDelta, e.scrollDelta], axisModel, controller, coordInfo
         );
@@ -162,10 +168,25 @@ var roamHandlers = {
     })
 };
 
-function makeMover(getPercentDelta) {
-    return function (coordInfo, coordSysName, controller, e) {
-        var lastRange = this._range;
-        var range = lastRange.slice();
+function makeMover(
+    getPercentDelta: (
+        range: [number, number],
+        axisModel: AxisBaseModel,
+        coordInfo: CoordInfo,
+        coordSysName: SupportedCoordSysName,
+        controller: RoamController,
+        e: RoamEventParams['scrollMove']| RoamEventParams['pan']
+    ) => number
+) {
+    return function (
+        this: InsideZoomView,
+        coordInfo: CoordInfo,
+        coordSysName: SupportedCoordSysName,
+        controller: RoamController,
+        e: RoamEventParams['scrollMove']| RoamEventParams['pan']
+    ): [number, number] {
+        var lastRange = this.range;
+        var range = lastRange.slice() as [number, number];
 
         // Calculate transform by the first axis.
         var axisModel = coordInfo.axisModels[0];
@@ -179,7 +200,7 @@ function makeMover(getPercentDelta) {
 
         sliderMove(percentDelta, range, [0, 100], 'all');
 
-        this._range = range;
+        this.range = range;
 
         if (lastRange[0] !== range[0] || lastRange[1] !== range[1]) {
             return range;
@@ -187,11 +208,29 @@ function makeMover(getPercentDelta) {
     };
 }
 
-var getDirectionInfo = {
+interface DirectionInfo {
+    pixel: number
+    pixelLength: number
+    pixelStart: number
+    signal: -1 | 1
+}
+interface GetDirectionInfo {
+    (
+        oldPoint: number[],
+        newPoint: number[],
+        axisModel: AxisBaseModel,
+        controller: RoamController,
+        coordInfo: CoordInfo
+    ): DirectionInfo
+}
+
+var getDirectionInfo: {
+    [key in 'grid' | 'polar' | 'singleAxis']: GetDirectionInfo
+} = {
 
-    grid: function (oldPoint, newPoint, axisModel, controller, coordInfo) {
+    grid(oldPoint, newPoint, axisModel, controller, coordInfo) {
         var axis = axisModel.axis;
-        var ret = {};
+        var ret = {} as DirectionInfo;
         var rect = coordInfo.model.coordinateSystem.getRect();
         oldPoint = oldPoint || [0, 0];
 
@@ -211,10 +250,10 @@ var getDirectionInfo = {
         return ret;
     },
 
-    polar: function (oldPoint, newPoint, axisModel, controller, coordInfo) {
+    polar(oldPoint, newPoint, axisModel, controller, coordInfo) {
         var axis = axisModel.axis;
-        var ret = {};
-        var polar = coordInfo.model.coordinateSystem;
+        var ret = {} as DirectionInfo;
+        var polar = coordInfo.model.coordinateSystem as Polar;
         var radiusExtent = polar.getRadiusAxis().getExtent();
         var angleExtent = polar.getAngleAxis().getExtent();
 
@@ -241,10 +280,10 @@ var getDirectionInfo = {
         return ret;
     },
 
-    singleAxis: function (oldPoint, newPoint, axisModel, controller, coordInfo) {
-        var axis = axisModel.axis;
+    singleAxis(oldPoint, newPoint, axisModel, controller, coordInfo) {
+        var axis = axisModel.axis as SingleAxis;
         var rect = coordInfo.model.coordinateSystem.getRect();
-        var ret = {};
+        var ret = {} as DirectionInfo;
 
         oldPoint = oldPoint || [0, 0];
 
@@ -265,4 +304,6 @@ var getDirectionInfo = {
     }
 };
 
+ComponentView.registerClass(InsideZoomView);
+
 export default InsideZoomView;
diff --git a/src/component/dataZoom/SelectZoomModel.ts b/src/component/dataZoom/SelectZoomModel.ts
index c720cfb..84eb5f5 100644
--- a/src/component/dataZoom/SelectZoomModel.ts
+++ b/src/component/dataZoom/SelectZoomModel.ts
@@ -17,10 +17,12 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import DataZoomModel from './DataZoomModel';
+import ComponentModel from '../../model/Component';
+
+class SelectDataZoomModel extends DataZoomModel {
+    static type = 'dataZoom.select'
+    type = SelectDataZoomModel.type
+}
 
-export default DataZoomModel.extend({
-    type: 'dataZoom.select'
-});
+ComponentModel.registerClass(SelectDataZoomModel);
diff --git a/src/component/dataZoom/SelectZoomView.ts b/src/component/dataZoom/SelectZoomView.ts
index be05fa2..7ac3ce8 100644
--- a/src/component/dataZoom/SelectZoomView.ts
+++ b/src/component/dataZoom/SelectZoomView.ts
@@ -18,7 +18,11 @@
 */
 
 import DataZoomView from './DataZoomView';
+import ComponentView from '../../view/Component';
 
-export default DataZoomView.extend({
-    type: 'dataZoom.select'
-});
\ No newline at end of file
+class SelectDataZoomView extends DataZoomView {
+    static type = 'dataZoom.select'
+    type = SelectDataZoomView.type
+}
+
+ComponentView.registerClass(SelectDataZoomView);
\ No newline at end of file
diff --git a/src/component/dataZoom/SliderZoomModel.ts b/src/component/dataZoom/SliderZoomModel.ts
index 66e4be0..bed625b 100644
--- a/src/component/dataZoom/SliderZoomModel.ts
+++ b/src/component/dataZoom/SliderZoomModel.ts
@@ -76,7 +76,7 @@ interface SliderDataZoomOption extends DataZoomOption, BoxLayoutOptionMixin {
 
     handleStyle?: ItemStyleOption
 
-    labelPrecision?: number
+    labelPrecision?: number | 'auto'
 
     labelFormatter?: string | ((value: number, valueStr: string) => string)
 
diff --git a/src/component/dataZoom/SliderZoomView.ts b/src/component/dataZoom/SliderZoomView.ts
index 432d3be..140d654 100644
--- a/src/component/dataZoom/SliderZoomView.ts
+++ b/src/component/dataZoom/SliderZoomView.ts
@@ -17,104 +17,100 @@
 * under the License.
 */
 
-// @ts-nocheck
-
-import * as zrUtil from 'zrender/src/core/util';
+import {bind, each, defaults, isFunction, isString, indexOf} from 'zrender/src/core/util';
 import * as eventTool from 'zrender/src/core/event';
 import * as graphic from '../../util/graphic';
 import * as throttle from '../../util/throttle';
 import DataZoomView from './DataZoomView';
-import * as numberUtil from '../../util/number';
+import {linearMap, asc} from '../../util/number';
 import * as layout from '../../util/layout';
 import sliderMove from '../helper/sliderMove';
-
-var Rect = graphic.Rect;
-var linearMap = numberUtil.linearMap;
-var asc = numberUtil.asc;
-var bind = zrUtil.bind;
-var each = zrUtil.each;
+import GlobalModel from '../../model/Global';
+import ExtensionAPI from '../../ExtensionAPI';
+import { LayoutOrient, Payload, ZRTextVerticalAlign, ZRTextAlign, ZRElementEvent, ParsedValue } from '../../util/types';
+import SliderZoomModel from './SliderZoomModel';
+import ComponentView from '../../view/Component';
+import { parsePercent } from 'zrender/src/graphic/helper/text';
+import { RectLike } from 'zrender/src/core/BoundingRect';
+import Axis from '../../coord/Axis';
+import SeriesModel from '../../model/Series';
+import { AxisBaseModel } from '../../coord/AxisBaseModel';
+
+const Rect = graphic.Rect;
 
 // Constants
-var DEFAULT_LOCATION_EDGE_GAP = 7;
-var DEFAULT_FRAME_BORDER_WIDTH = 1;
-var DEFAULT_FILLER_SIZE = 30;
-var HORIZONTAL = 'horizontal';
-var VERTICAL = 'vertical';
-var LABEL_GAP = 5;
-var SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];
-
-var SliderZoomView = DataZoomView.extend({
-
-    type: 'dataZoom.slider',
-
-    init: function (ecModel, api) {
-
-        /**
-         * @private
-         * @type {Object}
-         */
-        this._displayables = {};
-
-        /**
-         * @private
-         * @type {string}
-         */
-        this._orient;
-
-        /**
-         * [0, 100]
-         * @private
-         */
-        this._range;
-
-        /**
-         * [coord of the first handle, coord of the second handle]
-         * @private
-         */
-        this._handleEnds;
-
-        /**
-         * [length, thick]
-         * @private
-         * @type {Array.<number>}
-         */
-        this._size;
-
-        /**
-         * @private
-         * @type {number}
-         */
-        this._handleWidth;
-
-        /**
-         * @private
-         * @type {number}
-         */
-        this._handleHeight;
-
-        /**
-         * @private
-         */
-        this._location;
-
-        /**
-         * @private
-         */
-        this._dragging;
-
-        /**
-         * @private
-         */
-        this._dataShadowInfo;
+const DEFAULT_LOCATION_EDGE_GAP = 7;
+const DEFAULT_FRAME_BORDER_WIDTH = 1;
+const DEFAULT_FILLER_SIZE = 30;
+const HORIZONTAL = 'horizontal';
+const VERTICAL = 'vertical';
+const LABEL_GAP = 5;
+const SHOW_DATA_SHADOW_SERIES_TYPE = ['line', 'bar', 'candlestick', 'scatter'];
+
+
+type Icon = ReturnType<typeof graphic.createIcon>
+interface Displayables {
+    barGroup: graphic.Group
+    handles: [Icon, Icon]
+    handleLabels: [graphic.Text, graphic.Text]
+    filler: graphic.Rect
+}
+class SliderZoomView extends DataZoomView {
+    static type = 'dataZoom.slider'
+    type = SliderZoomView.type
+
+    dataZoomModel: SliderZoomModel
+
+    private _displayables = {} as Displayables
+
+    private _orient: LayoutOrient
+
+    private _range: [number, number]
+
+    /**
+     * [coord of the first handle, coord of the second handle]
+     */
+    private _handleEnds: [number, number]
+
+    /**
+     * [length, thick]
+     */
+    private _size: [number, number]
+
+    private _handleWidth: number
+
+    private _handleHeight: number
 
+    private _location: {x: number, y: number}
+
+    private _dragging: boolean
+
+    private _dataShadowInfo: {
+        thisAxis: Axis
+        series: SeriesModel
+        thisDim: string
+        otherDim: string
+        otherAxisInverse: boolean
+    }
+
+    init(ecModel: GlobalModel, api: ExtensionAPI) {
         this.api = api;
-    },
+    }
+
 
     /**
      * @override
      */
-    render: function (dataZoomModel, ecModel, api, payload) {
-        SliderZoomView.superApply(this, 'render', arguments);
+    render(
+        dataZoomModel: SliderZoomModel,
+        ecModel: GlobalModel,
+        api: ExtensionAPI,
+        payload: Payload & {
+            from: string
+            type: string
+        }
+    ) {
+        super.render.apply(this, arguments as any);
 
         throttle.createOrUpdate(
             this,
@@ -138,25 +134,24 @@ var SliderZoomView = DataZoomView.extend({
         }
 
         this._updateView();
-    },
+    }
 
     /**
      * @override
      */
-    remove: function () {
-        SliderZoomView.superApply(this, 'remove', arguments);
+    remove() {
         throttle.clear(this, '_dispatchZoomAction');
-    },
+    }
 
     /**
      * @override
      */
-    dispose: function () {
-        SliderZoomView.superApply(this, 'dispose', arguments);
+    dispose() {
+        super.dispose.apply(this, arguments as any);
         throttle.clear(this, '_dispatchZoomAction');
-    },
+    }
 
-    _buildView: function () {
+    _buildView() {
         var thisGroup = this.group;
 
         thisGroup.removeAll();
@@ -175,12 +170,12 @@ var SliderZoomView = DataZoomView.extend({
         thisGroup.add(barGroup);
 
         this._positionGroup();
-    },
+    }
 
     /**
      * @private
      */
-    _resetLocation: function () {
+    _resetLocation() {
         var dataZoomModel = this.dataZoomModel;
         var api = this.api;
 
@@ -210,7 +205,7 @@ var SliderZoomView = DataZoomView.extend({
         var layoutParams = layout.getLayoutParams(dataZoomModel.option);
 
         // Replace the placeholder value.
-        zrUtil.each(['right', 'top', 'width', 'height'], function (name) {
+        each(['right', 'top', 'width', 'height'] as const, function (name) {
             if (layoutParams[name] === 'auto') {
                 layoutParams[name] = positionInfo[name];
             }
@@ -218,19 +213,18 @@ var SliderZoomView = DataZoomView.extend({
 
         var layoutRect = layout.getLayoutRect(
             layoutParams,
-            ecSize,
-            dataZoomModel.padding
+            ecSize
         );
 
         this._location = {x: layoutRect.x, y: layoutRect.y};
         this._size = [layoutRect.width, layoutRect.height];
         this._orient === VERTICAL && this._size.reverse();
-    },
+    }
 
     /**
      * @private
      */
-    _positionGroup: function () {
+    _positionGroup() {
         var thisGroup = this.group;
         var location = this._location;
         var orient = this._orient;
@@ -257,16 +251,16 @@ var SliderZoomView = DataZoomView.extend({
         // Position barGroup
         var rect = thisGroup.getBoundingRect([barGroup]);
         thisGroup.attr('position', [location.x - rect.x, location.y - rect.y]);
-    },
+    }
 
     /**
      * @private
      */
-    _getViewExtent: function () {
+    _getViewExtent() {
         return [0, this._size[0]];
-    },
+    }
 
-    _renderBackground: function () {
+    _renderBackground() {
         var dataZoomModel = this.dataZoomModel;
         var size = this._size;
         var barGroup = this._displayables.barGroup;
@@ -291,11 +285,11 @@ var SliderZoomView = DataZoomView.extend({
                 fill: 'transparent'
             },
             z2: 0,
-            onclick: zrUtil.bind(this._onClickPanelClick, this)
+            onclick: bind(this._onClickPanelClick, this)
         }));
-    },
+    }
 
-    _renderDataShadow: function () {
+    _renderDataShadow() {
         var info = this._dataShadowInfo = this._prepareDataShadowInfo();
 
         if (!info) {
@@ -306,7 +300,7 @@ var SliderZoomView = DataZoomView.extend({
         var seriesModel = info.series;
         var data = seriesModel.getRawData();
 
-        var otherDim = seriesModel.getShadowDim
+        var otherDim: string = seriesModel.getShadowDim
             ? seriesModel.getShadowDim() // @see candlestick
             : info.otherDim;
 
@@ -326,14 +320,14 @@ var SliderZoomView = DataZoomView.extend({
         var thisShadowExtent = [0, size[0]];
 
         var areaPoints = [[size[0], 0], [0, 0]];
-        var linePoints = [];
+        var linePoints: number[][] = [];
         var step = thisShadowExtent[1] / (data.count() - 1);
         var thisCoord = 0;
 
         // Optimize for large data shadow
         var stride = Math.round(data.count() / size[0]);
-        var lastIsEmpty;
-        data.each([otherDim], function (value, index) {
+        var lastIsEmpty: boolean;
+        data.each([otherDim], function (value: ParsedValue, index) {
             if (stride > 0 && (index % stride)) {
                 thisCoord += step;
                 return;
@@ -344,10 +338,10 @@ var SliderZoomView = DataZoomView.extend({
 
             // FIXME
             // 应该使用统一的空判断?还是在list里进行空判断?
-            var isEmpty = value == null || isNaN(value) || value === '';
+            var isEmpty = value == null || isNaN(value as number) || value === '';
             // See #4235.
             var otherCoord = isEmpty
-                ? 0 : linearMap(value, otherDataExtent, otherShadowExtent, true);
+                ? 0 : linearMap(value as number, otherDataExtent, otherShadowExtent, true);
 
             // Attempt to draw data shadow precisely when there are empty value.
             if (isEmpty && !lastIsEmpty && index) {
@@ -370,22 +364,22 @@ var SliderZoomView = DataZoomView.extend({
         // var dataBackgroundModel = dataZoomModel.getModel('dataBackground');
         this._displayables.barGroup.add(new graphic.Polygon({
             shape: {points: areaPoints},
-            style: zrUtil.defaults(
-                {fill: dataZoomModel.get('dataBackgroundColor')},
-                dataZoomModel.getModel('dataBackground.areaStyle').getAreaStyle()
+            style: defaults(
+                {fill: dataZoomModel.get('dataBackgroundColor' as any)},
+                dataZoomModel.getModel(['dataBackground', 'areaStyle']).getAreaStyle()
             ),
             silent: true,
             z2: -20
         }));
         this._displayables.barGroup.add(new graphic.Polyline({
             shape: {points: linePoints},
-            style: dataZoomModel.getModel('dataBackground.lineStyle').getLineStyle(),
+            style: dataZoomModel.getModel(['dataBackground', 'lineStyle']).getLineStyle(),
             silent: true,
             z2: -19
         }));
-    },
+    }
 
-    _prepareDataShadowInfo: function () {
+    _prepareDataShadowInfo() {
         var dataZoomModel = this.dataZoomModel;
         var showDataShadow = dataZoomModel.get('showDataShadow');
 
@@ -394,7 +388,7 @@ var SliderZoomView = DataZoomView.extend({
         }
 
         // Find a representative series.
-        var result;
+        var result: SliderZoomView['_dataShadowInfo'];
         var ecModel = this.ecModel;
 
         dataZoomModel.eachTargetAxis(function (dimNames, axisIndex) {
@@ -402,19 +396,19 @@ var SliderZoomView = DataZoomView.extend({
                 .getAxisProxy(dimNames.name, axisIndex)
                 .getTargetSeriesModels();
 
-            zrUtil.each(seriesModels, function (seriesModel) {
+            each(seriesModels, function (seriesModel) {
                 if (result) {
                     return;
                 }
 
-                if (showDataShadow !== true && zrUtil.indexOf(
+                if (showDataShadow !== true && indexOf(
                         SHOW_DATA_SHADOW_SERIES_TYPE, seriesModel.get('type')
                     ) < 0
                 ) {
                     return;
                 }
 
-                var thisAxis = ecModel.getComponent(dimNames.axis, axisIndex).axis;
+                var thisAxis = (ecModel.getComponent(dimNames.axis, axisIndex) as AxisBaseModel).axis;
                 var otherDim = getOtherDim(dimNames.name);
                 var otherAxisInverse;
                 var coordSys = seriesModel.coordinateSystem;
@@ -438,12 +432,12 @@ var SliderZoomView = DataZoomView.extend({
         }, this);
 
         return result;
-    },
+    }
 
-    _renderHandle: function () {
+    _renderHandle() {
         var displaybles = this._displayables;
-        var handles = displaybles.handles = [];
-        var handleLabels = displaybles.handleLabels = [];
+        var handles: [Icon, Icon] = displaybles.handles = [null, null];
+        var handleLabels: [graphic.Text, graphic.Text] = displaybles.handleLabels = [null, null];
         var barGroup = this._displayables.barGroup;
         var size = this._size;
         var dataZoomModel = this.dataZoomModel;
@@ -473,14 +467,14 @@ var SliderZoomView = DataZoomView.extend({
                 height: size[1]
             },
             style: {
-                stroke: dataZoomModel.get('dataBackgroundColor')
+                stroke: dataZoomModel.get('dataBackgroundColor' as any) // deprecated option
                     || dataZoomModel.get('borderColor'),
                 lineWidth: DEFAULT_FRAME_BORDER_WIDTH,
                 fill: 'rgba(0,0,0,0)'
             }
         }));
 
-        each([0, 1], function (handleIndex) {
+        each([0, 1] as const, function (handleIndex) {
             var path = graphic.createIcon(
                 dataZoomModel.get('handleIcon'),
                 {
@@ -495,11 +489,11 @@ var SliderZoomView = DataZoomView.extend({
             );
 
             var bRect = path.getBoundingRect();
-            this._handleHeight = numberUtil.parsePercent(dataZoomModel.get('handleSize'), this._size[1]);
+            this._handleHeight = parsePercent(dataZoomModel.get('handleSize'), this._size[1]);
             this._handleWidth = bRect.width / bRect.height * this._handleHeight;
 
             path.setStyle(dataZoomModel.getModel('handleStyle').getItemStyle());
-            var handleColor = dataZoomModel.get('handleColor');
+            var handleColor = dataZoomModel.get('handleColor' as any); // deprecated option
             // Compatitable with previous version
             if (handleColor != null) {
                 path.style.fill = handleColor;
@@ -524,12 +518,9 @@ var SliderZoomView = DataZoomView.extend({
             }));
 
         }, this);
-    },
+    }
 
-    /**
-     * @private
-     */
-    _resetInterval: function () {
+    private _resetInterval() {
         var range = this._range = this.dataZoomModel.getPercentRange();
         var viewExtent = this._getViewExtent();
 
@@ -537,15 +528,9 @@ var SliderZoomView = DataZoomView.extend({
             linearMap(range[0], [0, 100], viewExtent, true),
             linearMap(range[1], [0, 100], viewExtent, true)
         ];
-    },
+    }
 
-    /**
-     * @private
-     * @param {(number|string)} handleIndex 0 or 1 or 'all'
-     * @param {number} delta
-     * @return {boolean} changed
-     */
-    _updateInterval: function (handleIndex, delta) {
+    private _updateInterval(handleIndex: 0 | 1 | 'all', delta: number): boolean {
         var dataZoomModel = this.dataZoomModel;
         var handleEnds = this._handleEnds;
         var viewExtend = this._getViewExtent();
@@ -570,22 +555,19 @@ var SliderZoomView = DataZoomView.extend({
         ]);
 
         return !lastRange || lastRange[0] !== range[0] || lastRange[1] !== range[1];
-    },
+    }
 
-    /**
-     * @private
-     */
-    _updateView: function (nonRealtime) {
+    private _updateView(nonRealtime?: boolean) {
         var displaybles = this._displayables;
         var handleEnds = this._handleEnds;
         var handleInterval = asc(handleEnds.slice());
         var size = this._size;
 
-        each([0, 1], function (handleIndex) {
+        each([0, 1] as const, function (handleIndex) {
             // Handles
             var handle = displaybles.handles[handleIndex];
             var handleHeight = this._handleHeight;
-            handle.attr({
+            (handle as graphic.Path).attr({
                 scale: [handleHeight / 2, handleHeight / 2],
                 position: [handleEnds[handleIndex], size[1] / 2 - handleHeight / 2]
             });
@@ -600,12 +582,12 @@ var SliderZoomView = DataZoomView.extend({
         });
 
         this._updateDataInfo(nonRealtime);
-    },
+    }
 
     /**
      * @private
      */
-    _updateDataInfo: function (nonRealtime) {
+    _updateDataInfo(nonRealtime?: boolean) {
         var dataZoomModel = this.dataZoomModel;
         var displaybles = this._displayables;
         var handleLabels = displaybles.handleLabels;
@@ -640,7 +622,7 @@ var SliderZoomView = DataZoomView.extend({
         setLabel.call(this, 0);
         setLabel.call(this, 1);
 
-        function setLabel(handleIndex) {
+        function setLabel(this: SliderZoomView, handleIndex: 0 | 1) {
             // Label
             // Text should not transform by barGroup.
             // Ignore handlers transform
@@ -661,17 +643,14 @@ var SliderZoomView = DataZoomView.extend({
             handleLabels[handleIndex].setStyle({
                 x: textPoint[0],
                 y: textPoint[1],
-                textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction,
-                textAlign: orient === HORIZONTAL ? direction : 'center',
+                textVerticalAlign: orient === HORIZONTAL ? 'middle' : direction as ZRTextVerticalAlign,
+                textAlign: orient === HORIZONTAL ? direction as ZRTextAlign : 'center',
                 text: labelTexts[handleIndex]
             });
         }
-    },
+    }
 
-    /**
-     * @private
-     */
-    _formatLabel: function (value, axis) {
+    _formatLabel(value: ParsedValue, axis: Axis) {
         var dataZoomModel = this.dataZoomModel;
         var labelFormatter = dataZoomModel.get('labelFormatter');
 
@@ -680,35 +659,35 @@ var SliderZoomView = DataZoomView.extend({
             labelPrecision = axis.getPixelPrecision();
         }
 
-        var valueStr = (value == null || isNaN(value))
+        var valueStr = (value == null || isNaN(value as number))
             ? ''
             // FIXME Glue code
             : (axis.type === 'category' || axis.type === 'time')
-                ? axis.scale.getLabel(Math.round(value))
+                ? axis.scale.getLabel(Math.round(value as number))
                 // param of toFixed should less then 20.
-                : value.toFixed(Math.min(labelPrecision, 20));
+                : (value as number).toFixed(Math.min(labelPrecision as number, 20));
 
-        return zrUtil.isFunction(labelFormatter)
-            ? labelFormatter(value, valueStr)
-            : zrUtil.isString(labelFormatter)
+        return isFunction(labelFormatter)
+            ? labelFormatter(value as number, valueStr)
+            : isString(labelFormatter)
             ? labelFormatter.replace('{value}', valueStr)
             : valueStr;
-    },
+    }
 
     /**
      * @private
-     * @param {boolean} showOrHide true: show, false: hide
+     * @param showOrHide true: show, false: hide
      */
-    _showDataInfo: function (showOrHide) {
+    _showDataInfo(showOrHide?: boolean) {
         // Always show when drgging.
         showOrHide = this._dragging || showOrHide;
 
         var handleLabels = this._displayables.handleLabels;
         handleLabels[0].attr('invisible', !showOrHide);
         handleLabels[1].attr('invisible', !showOrHide);
-    },
+    }
 
-    _onDragMove: function (handleIndex, dx, dy, event) {
+    _onDragMove(handleIndex: 0 | 1 | 'all', dx: number, dy: number, event: ZRElementEvent) {
         this._dragging = true;
 
         // For mobile device, prevent screen slider on the button.
@@ -727,9 +706,9 @@ var SliderZoomView = DataZoomView.extend({
         // Avoid dispatch dataZoom repeatly but range not changed,
         // which cause bad visual effect when progressive enabled.
         changed && realtime && this._dispatchZoomAction();
-    },
+    }
 
-    _onDragEnd: function () {
+    _onDragEnd() {
         this._dragging = false;
         this._showDataInfo(false);
 
@@ -737,9 +716,9 @@ var SliderZoomView = DataZoomView.extend({
         // drag end will cause the whole view rerender, which is unnecessary.
         var realtime = this.dataZoomModel.get('realtime');
         !realtime && this._dispatchZoomAction();
-    },
+    }
 
-    _onClickPanelClick: function (e) {
+    _onClickPanelClick(e: ZRElementEvent) {
         var size = this._size;
         var localPoint = this._displayables.barGroup.transformCoordToLocal(e.offsetX, e.offsetY);
 
@@ -755,13 +734,13 @@ var SliderZoomView = DataZoomView.extend({
         var changed = this._updateInterval('all', localPoint[0] - center);
         this._updateView();
         changed && this._dispatchZoomAction();
-    },
+    }
 
     /**
      * This action will be throttled.
      * @private
      */
-    _dispatchZoomAction: function () {
+    _dispatchZoomAction() {
         var range = this._range;
 
         this.api.dispatchAction({
@@ -771,14 +750,14 @@ var SliderZoomView = DataZoomView.extend({
             start: range[0],
             end: range[1]
         });
-    },
+    }
 
     /**
      * @private
      */
-    _findCoordRect: function () {
+    _findCoordRect() {
         // Find the grid coresponding to the first axis referred by dataZoom.
-        var rect;
+        var rect: RectLike;
         each(this.getTargetCoordInfo(), function (coordInfoList) {
             if (!rect && coordInfoList.length) {
                 var coordSys = coordInfoList[0].model.coordinateSystem;
@@ -799,17 +778,19 @@ var SliderZoomView = DataZoomView.extend({
         return rect;
     }
 
-});
+}
 
-function getOtherDim(thisDim) {
+function getOtherDim(thisDim: 'x' | 'y' | 'radius' | 'angle' | 'single' | 'z') {
     // FIXME
     // 这个逻辑和getOtherAxis里一致,但是写在这里是否不好
     var map = {x: 'y', y: 'x', radius: 'angle', angle: 'radius'};
-    return map[thisDim];
+    return map[thisDim as 'x' | 'y' | 'radius' | 'angle'];
 }
 
-function getCursor(orient) {
+function getCursor(orient: LayoutOrient) {
     return orient === 'vertical' ? 'ns-resize' : 'ew-resize';
 }
 
+ComponentView.registerClass(SliderZoomView);
+
 export default SliderZoomView;
diff --git a/src/component/dataZoom/helper.ts b/src/component/dataZoom/helper.ts
index 6fd31a3..5014e4f 100644
--- a/src/component/dataZoom/helper.ts
+++ b/src/component/dataZoom/helper.ts
@@ -22,6 +22,14 @@ import * as formatUtil from '../../util/format';
 import { Dictionary } from '../../util/types';
 
 
+export interface DataZoomPayloadBatchItem {
+    dataZoomId: string
+    start?: number
+    end?: number
+    startValue?: number
+    endValue?: number
+}
+
 const AXIS_DIMS = ['x', 'y', 'z', 'radius', 'angle', 'single'] as const;
 // Supported coords.
 const COORDS = ['cartesian2d', 'polar', 'singleAxis'] as const;
diff --git a/src/component/dataZoom/history.ts b/src/component/dataZoom/history.ts
index 3953b51..ed2ee5a 100644
--- a/src/component/dataZoom/history.ts
+++ b/src/component/dataZoom/history.ts
@@ -17,27 +17,36 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import * as zrUtil from 'zrender/src/core/util';
+import GlobalModel from '../../model/Global';
+import { Dictionary } from '../../util/types';
+import DataZoomModel from './DataZoomModel';
+import { makeInner } from '../../util/model';
+import { DataZoomPayloadBatchItem } from './helper';
 
 var each = zrUtil.each;
 
-var ATTR = '\0_ec_hist_store';
+type StoreSnapshot = Dictionary<DataZoomPayloadBatchItem>
+
+type Store = {
+    snapshots: StoreSnapshot[]
+}
+
+const inner = makeInner<Store>();
 
 /**
- * @param {module:echarts/model/Global} ecModel
- * @param {Object} newSnapshot {dataZoomId, batch: [payloadInfo, ...]}
+ * @param ecModel
+ * @param newSnapshot key is dataZoomId
  */
-export function push(ecModel, newSnapshot) {
-    var store = giveStore(ecModel);
+export function push(ecModel: GlobalModel, newSnapshot: StoreSnapshot) {
+    var storedSnapshots = getStoreSnapshots(ecModel);
 
     // If previous dataZoom can not be found,
     // complete an range with current range.
     each(newSnapshot, function (batchItem, dataZoomId) {
-        var i = store.length - 1;
+        var i = storedSnapshots.length - 1;
         for (; i >= 0; i--) {
-            var snapshot = store[i];
+            var snapshot = storedSnapshots[i];
             if (snapshot[dataZoomId]) {
                 break;
             }
@@ -46,10 +55,10 @@ export function push(ecModel, newSnapshot) {
             // No origin range set, create one by current range.
             var dataZoomModel = ecModel.queryComponents(
                 {mainType: 'dataZoom', subType: 'select', id: dataZoomId}
-            )[0];
+            )[0] as DataZoomModel;
             if (dataZoomModel) {
                 var percentRange = dataZoomModel.getPercentRange();
-                store[0][dataZoomId] = {
+                storedSnapshots[0][dataZoomId] = {
                     dataZoomId: dataZoomId,
                     start: percentRange[0],
                     end: percentRange[1]
@@ -58,23 +67,19 @@ export function push(ecModel, newSnapshot) {
         }
     });
 
-    store.push(newSnapshot);
+    storedSnapshots.push(newSnapshot);
 }
 
-/**
- * @param {module:echarts/model/Global} ecModel
- * @return {Object} snapshot
- */
-export function pop(ecModel) {
-    var store = giveStore(ecModel);
-    var head = store[store.length - 1];
-    store.length > 1 && store.pop();
+export function pop(ecModel: GlobalModel) {
+    var storedSnapshots = getStoreSnapshots(ecModel);
+    var head = storedSnapshots[storedSnapshots.length - 1];
+    storedSnapshots.length > 1 && storedSnapshots.pop();
 
     // Find top for all dataZoom.
-    var snapshot = {};
+    var snapshot: StoreSnapshot = {};
     each(head, function (batchItem, dataZoomId) {
-        for (var i = store.length - 1; i >= 0; i--) {
-            var batchItem = store[i][dataZoomId];
+        for (var i = storedSnapshots.length - 1; i >= 0; i--) {
+            var batchItem = storedSnapshots[i][dataZoomId];
             if (batchItem) {
                 snapshot[dataZoomId] = batchItem;
                 break;
@@ -85,31 +90,22 @@ export function pop(ecModel) {
     return snapshot;
 }
 
-/**
- * @param {module:echarts/model/Global} ecModel
- */
-export function clear(ecModel) {
-    ecModel[ATTR] = null;
+export function clear(ecModel: GlobalModel) {
+    inner(ecModel).snapshots = null;
 }
 
-/**
- * @param {module:echarts/model/Global} ecModel
- * @return {number} records. always >= 1.
- */
-export function count(ecModel) {
-    return giveStore(ecModel).length;
+export function count(ecModel: GlobalModel) {
+    return getStoreSnapshots(ecModel).length;
 }
 
 /**
- * [{key: dataZoomId, value: {dataZoomId, range}}, ...]
  * History length of each dataZoom may be different.
  * this._history[0] is used to store origin range.
- * @type {Array.<Object>}
  */
-function giveStore(ecModel) {
-    var store = ecModel[ATTR];
-    if (!store) {
-        store = ecModel[ATTR] = [{}];
+function getStoreSnapshots(ecModel: GlobalModel) {
+    var store = inner(ecModel);
+    if (!store.snapshots) {
+        store.snapshots = [{}];
     }
-    return store;
+    return store.snapshots;
 }
diff --git a/src/component/dataZoom/roams.ts b/src/component/dataZoom/roams.ts
index b841973..7d5e836 100644
--- a/src/component/dataZoom/roams.ts
+++ b/src/component/dataZoom/roams.ts
@@ -17,47 +17,63 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 // Only create one roam controller for each coordinate system.
 // one roam controller might be refered by two inside data zoom
 // components (for example, one for x and one for y). When user
 // pan or zoom, only dispatch one action for those data zoom
 // components.
 
-import * as zrUtil from 'zrender/src/core/util';
-import RoamController from '../../component/helper/RoamController';
+import RoamController, { RoamType, RoamEventParams } from '../../component/helper/RoamController';
 import * as throttleUtil from '../../util/throttle';
+import { makeInner } from '../../util/model';
+import { Dictionary, ZRElementEvent } from '../../util/types';
+import DataZoomModel from './DataZoomModel';
+import ExtensionAPI from '../../ExtensionAPI';
+import InsideZoomModel from './InsideZoomModel';
+import { each, indexOf, curry, Curry1 } from 'zrender/src/core/util';
+import ComponentModel from '../../model/Component';
+import { DataZoomPayloadBatchItem } from './helper';
+
+interface DataZoomInfo {
+    coordId: string
+    containsPoint: (e: ZRElementEvent, x: number, y: number) => boolean
+    allCoordIds: string[]
+    dataZoomId: string
+    getRange: {
+        pan: (controller: RoamController, e: RoamEventParams['pan']) => [number, number]
+        zoom: (controller: RoamController, e: RoamEventParams['zoom']) => [number, number]
+        scrollMove: (controller: RoamController, e: RoamEventParams['scrollMove']) => [number, number]
+    }
+    dataZoomModel: DataZoomModel
+}
+interface Record {
+    // key is dataZoomId
+    dataZoomInfos: Dictionary<DataZoomInfo>
+    count: number
+    coordId: string
+    controller: RoamController
+    dispatchAction: Curry1<typeof dispatchAction, ExtensionAPI>
+}
 
+interface PayloadBatch {
+    dataZoomId: string
+}
 
-var ATTR = '\0_ec_dataZoom_roams';
+type Store = Dictionary<Record>
 
+const inner = makeInner<Store>();
 
-/**
- * @public
- * @param {module:echarts/ExtensionAPI} api
- * @param {Object} dataZoomInfo
- * @param {string} dataZoomInfo.coordId
- * @param {Function} dataZoomInfo.containsPoint
- * @param {Array.<string>} dataZoomInfo.allCoordIds
- * @param {string} dataZoomInfo.dataZoomId
- * @param {Object} dataZoomInfo.getRange
- * @param {Function} dataZoomInfo.getRange.pan
- * @param {Function} dataZoomInfo.getRange.zoom
- * @param {Function} dataZoomInfo.getRange.scrollMove
- * @param {boolean} dataZoomInfo.dataZoomModel
- */
-export function register(api, dataZoomInfo) {
-    var store = giveStore(api);
+export function register(api: ExtensionAPI, dataZoomInfo: DataZoomInfo) {
+    var store = inner(api);
     var theDataZoomId = dataZoomInfo.dataZoomId;
     var theCoordId = dataZoomInfo.coordId;
 
     // Do clean when a dataZoom changes its target coordnate system.
     // Avoid memory leak, dispose all not-used-registered.
-    zrUtil.each(store, function (record, coordId) {
+    each(store, function (record, coordId) {
         var dataZoomInfos = record.dataZoomInfos;
         if (dataZoomInfos[theDataZoomId]
-            && zrUtil.indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0
+            && indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0
         ) {
             delete dataZoomInfos[theDataZoomId];
             record.count--;
@@ -72,10 +88,11 @@ export function register(api, dataZoomInfo) {
         record = store[theCoordId] = {
             coordId: theCoordId,
             dataZoomInfos: {},
-            count: 0
+            count: 0,
+            controller: null,
+            dispatchAction: curry(dispatchAction, api)
         };
         record.controller = createController(api, record);
-        record.dispatchAction = zrUtil.curry(dispatchAction, api);
     }
 
     // Update reference of dataZoom.
@@ -97,15 +114,10 @@ export function register(api, dataZoomInfo) {
     );
 }
 
-/**
- * @public
- * @param {module:echarts/ExtensionAPI} api
- * @param {string} dataZoomId
- */
-export function unregister(api, dataZoomId) {
-    var store = giveStore(api);
+export function unregister(api: ExtensionAPI, dataZoomId: string) {
+    var store = inner(api);
 
-    zrUtil.each(store, function (record) {
+    each(store, function (record) {
         record.controller.dispose();
         var dataZoomInfos = record.dataZoomInfos;
         if (dataZoomInfos[dataZoomId]) {
@@ -120,29 +132,18 @@ export function unregister(api, dataZoomId) {
 /**
  * @public
  */
-export function generateCoordId(coordModel) {
+export function generateCoordId(coordModel: ComponentModel) {
     return coordModel.type + '\0_' + coordModel.id;
 }
 
-/**
- * Key: coordId, value: {dataZoomInfos: [], count, controller}
- * @type {Array.<Object>}
- */
-function giveStore(api) {
-    // Mount store on zrender instance, so that we do not
-    // need to worry about dispose.
-    var zr = api.getZr();
-    return zr[ATTR] || (zr[ATTR] = {});
-}
-
-function createController(api, newRecord) {
+function createController(api: ExtensionAPI, newRecord: Record) {
     var controller = new RoamController(api.getZr());
 
-    zrUtil.each(['pan', 'zoom', 'scrollMove'], function (eventName) {
+    each(['pan', 'zoom', 'scrollMove'] as const, function (eventName) {
         controller.on(eventName, function (event) {
-            var batch = [];
+            var batch: DataZoomPayloadBatchItem[] = [];
 
-            zrUtil.each(newRecord.dataZoomInfos, function (info) {
+            each(newRecord.dataZoomInfos, function (info) {
                 // Check whether the behaviors (zoomOnMouseWheel, moveOnMouseMove,
                 // moveOnMouseWheel, ...) enabled.
                 if (!event.isAvailableBehavior(info.dataZoomModel.option)) {
@@ -152,7 +153,7 @@ function createController(api, newRecord) {
                 var method = (info.getRange || {})[eventName];
                 var range = method && method(newRecord.controller, event);
 
-                !info.dataZoomModel.get('disabled', true) && range && batch.push({
+                !(info.dataZoomModel as InsideZoomModel).get('disabled', true) && range && batch.push({
                     dataZoomId: info.dataZoomId,
                     start: range[0],
                     end: range[1]
@@ -166,8 +167,8 @@ function createController(api, newRecord) {
     return controller;
 }
 
-function cleanStore(store) {
-    zrUtil.each(store, function (record, coordId) {
+function cleanStore(store: Store) {
+    each(store, function (record, coordId) {
         if (!record.count) {
             record.controller.dispose();
             delete store[coordId];
@@ -178,7 +179,7 @@ function cleanStore(store) {
 /**
  * This action will be throttled.
  */
-function dispatchAction(api, batch) {
+function dispatchAction(api: ExtensionAPI, batch: DataZoomPayloadBatchItem[]) {
     api.dispatchAction({
         type: 'dataZoom',
         batch: batch
@@ -188,12 +189,12 @@ function dispatchAction(api, batch) {
 /**
  * Merge roamController settings when multiple dataZooms share one roamController.
  */
-function mergeControllerParams(dataZoomInfos) {
-    var controlType;
+function mergeControllerParams(dataZoomInfos: Dictionary<DataZoomInfo>) {
+    var controlType: RoamType;
     // DO NOT use reserved word (true, false, undefined) as key literally. Even if encapsulated
     // as string, it is probably revert to reserved word by compress tool. See #7411.
     var prefix = 'type_';
-    var typePriority = {
+    var typePriority: Dictionary<number> = {
         'type_true': 2,
         'type_move': 1,
         'type_false': 0,
@@ -201,12 +202,12 @@ function mergeControllerParams(dataZoomInfos) {
     };
     var preventDefaultMouseMove = true;
 
-    zrUtil.each(dataZoomInfos, function (dataZoomInfo) {
-        var dataZoomModel = dataZoomInfo.dataZoomModel;
+    each(dataZoomInfos, function (dataZoomInfo) {
+        var dataZoomModel = dataZoomInfo.dataZoomModel as InsideZoomModel;
         var oneType = dataZoomModel.get('disabled', true)
             ? false
             : dataZoomModel.get('zoomLock', true)
-            ? 'move'
+            ? 'move' as const
             : true;
         if (typePriority[prefix + oneType] > typePriority[prefix + controlType]) {
             controlType = oneType;
@@ -214,7 +215,8 @@ function mergeControllerParams(dataZoomInfos) {
 
         // Prevent default move event by default. If one false, do not prevent. Otherwise
         // users may be confused why it does not work when multiple insideZooms exist.
-        preventDefaultMouseMove &= dataZoomModel.get('preventDefaultMouseMove', true);
+        preventDefaultMouseMove = preventDefaultMouseMove
+            && dataZoomModel.get('preventDefaultMouseMove', true);
     });
 
     return {
diff --git a/src/component/helper/RoamController.ts b/src/component/helper/RoamController.ts
index 1b1f00d..91a65e2 100644
--- a/src/component/helper/RoamController.ts
+++ b/src/component/helper/RoamController.ts
@@ -17,229 +17,267 @@
 * under the License.
 */
 
-// @ts-nocheck
-
-import * as zrUtil from 'zrender/src/core/util';
 import Eventful from 'zrender/src/core/Eventful';
 import * as eventTool from 'zrender/src/core/event';
 import * as interactionMutex from './interactionMutex';
-
-/**
- * @alias module:echarts/component/helper/RoamController
- * @constructor
- * @mixin {module:zrender/mixin/Eventful}
- *
- * @param {module:zrender/zrender~ZRender} zr
- */
-function RoamController(zr) {
-
+import { ZRenderType } from 'zrender/src/zrender';
+import { ZRElementEvent } from '../../util/types';
+import { Bind3, isString, bind, defaults, clone } from 'zrender/src/core/util';
+
+// Can be null/undefined or true/false
+// or 'pan/move' or 'zoom'/'scale'
+export type RoamType = boolean | 'pan' | 'move' | 'zoom' | 'scale';
+
+interface RoamOption {
+    zoomOnMouseWheel?: boolean | 'ctrl' | 'shift' | 'alt'
+    moveOnMouseMove?: boolean | 'ctrl' | 'shift' | 'alt'
+    moveOnMouseWheel?: boolean | 'ctrl' | 'shift' | 'alt'
     /**
-     * @type {Function}
+     * If fixed the page when pan
      */
-    this.pointerChecker;
+    preventDefaultMouseMove?: boolean
+}
 
-    /**
-     * @type {module:zrender}
-     */
-    this._zr = zr;
+type RoamEventType = 'zoom' | 'scrollMove' | 'pan'
 
-    /**
-     * @type {Object}
-     */
-    this._opt = {};
+type RoamBehavior = 'zoomOnMouseWheel' | 'moveOnMouseMove' | 'moveOnMouseWheel'
 
-    // Avoid two roamController bind the same handler
-    var bind = zrUtil.bind;
-    var mousedownHandler = bind(mousedown, this);
-    var mousemoveHandler = bind(mousemove, this);
-    var mouseupHandler = bind(mouseup, this);
-    var mousewheelHandler = bind(mousewheel, this);
-    var pinchHandler = bind(pinch, this);
+export type RoamEventParams = {
+    'zoom': {
+        scale: number
+        originX: number
+        originY: number
 
-    Eventful.call(this);
+        isAvailableBehavior: Bind3<typeof isAvailableBehavior, null, RoamBehavior, ZRElementEvent>
+    }
+    'scrollMove': {
+        scrollDelta: number
+        originX: number
+        originY: number
 
-    /**
-     * @param {Function} pointerChecker
-     *                   input: x, y
-     *                   output: boolean
-     */
-    this.setPointerChecker = function (pointerChecker) {
-        this.pointerChecker = pointerChecker;
-    };
+        isAvailableBehavior: Bind3<typeof isAvailableBehavior, null, RoamBehavior, ZRElementEvent>
+    }
+    'pan': {
+        dx: number
+        dy: number
+        oldX: number
+        oldY: number
+        newX: number
+        newY: number
+
+        isAvailableBehavior: Bind3<typeof isAvailableBehavior, null, RoamBehavior, ZRElementEvent>
+    }
+}
 
-    /**
-     * Notice: only enable needed types. For example, if 'zoom'
-     * is not needed, 'zoom' should not be enabled, otherwise
-     * default mousewheel behaviour (scroll page) will be disabled.
-     *
-     * @param  {boolean|string} [controlType=true] Specify the control type,
-     *                          which can be null/undefined or true/false
-     *                          or 'pan/move' or 'zoom'/'scale'
-     * @param {Object} [opt]
-     * @param {Object} [opt.zoomOnMouseWheel=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
-     * @param {Object} [opt.moveOnMouseMove=true] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
-     * @param {Object} [opt.moveOnMouseWheel=false] The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
-     * @param {Object} [opt.preventDefaultMouseMove=true] When pan.
-     */
-    this.enable = function (controlType, opt) {
+class RoamController extends Eventful {
 
-        // Disable previous first
-        this.disable();
+    pointerChecker: (e: ZRElementEvent, x: number, y: number) => boolean
 
-        this._opt = zrUtil.defaults(zrUtil.clone(opt) || {}, {
-            zoomOnMouseWheel: true,
-            moveOnMouseMove: true,
-            // By default, wheel do not trigger move.
-            moveOnMouseWheel: false,
-            preventDefaultMouseMove: true
-        });
+    private _zr: ZRenderType
 
-        if (controlType == null) {
-            controlType = true;
-        }
+    private _opt: Required<RoamOption>
 
-        if (controlType === true || (controlType === 'move' || controlType === 'pan')) {
-            zr.on('mousedown', mousedownHandler);
-            zr.on('mousemove', mousemoveHandler);
-            zr.on('mouseup', mouseupHandler);
-        }
-        if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {
-            zr.on('mousewheel', mousewheelHandler);
-            zr.on('pinch', pinchHandler);
-        }
-    };
+    private _dragging: boolean
 
-    this.disable = function () {
-        zr.off('mousedown', mousedownHandler);
-        zr.off('mousemove', mousemoveHandler);
-        zr.off('mouseup', mouseupHandler);
-        zr.off('mousewheel', mousewheelHandler);
-        zr.off('pinch', pinchHandler);
-    };
+    private _pinching: boolean
 
-    this.dispose = this.disable;
+    private _x: number
 
-    this.isDragging = function () {
-        return this._dragging;
-    };
+    private _y: number
 
-    this.isPinching = function () {
-        return this._pinching;
-    };
-}
+    readonly enable: (this: this, controlType?: RoamType, opt?: RoamOption) => void
 
-zrUtil.mixin(RoamController, Eventful);
+    readonly disable: () => void
 
 
-function mousedown(e) {
-    if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e)
-        || (e.target && e.target.draggable)
-    ) {
-        return;
+    constructor(zr: ZRenderType) {
+        super();
+
+        this._zr = zr;
+
+        // Avoid two roamController bind the same handler
+        const mousedownHandler = bind(this._mousedownHandler, this);
+        const mousemoveHandler = bind(this._mousemoveHandler, this);
+        const mouseupHandler = bind(this._mouseupHandler, this);
+        const mousewheelHandler = bind(this._mousewheelHandler, this);
+        const pinchHandler = bind(this._pinchHandler, this);
+
+
+        /**
+         * Notice: only enable needed types. For example, if 'zoom'
+         * is not needed, 'zoom' should not be enabled, otherwise
+         * default mousewheel behaviour (scroll page) will be disabled.
+         */
+        this.enable = function (controlType, opt) {
+
+            // Disable previous first
+            this.disable();
+
+            this._opt = defaults(clone(opt) || {}, {
+                zoomOnMouseWheel: true,
+                moveOnMouseMove: true,
+                // By default, wheel do not trigger move.
+                moveOnMouseWheel: false,
+                preventDefaultMouseMove: true
+            });
+
+            if (controlType == null) {
+                controlType = true;
+            }
+
+            if (controlType === true || (controlType === 'move' || controlType === 'pan')) {
+                zr.on('mousedown', mousedownHandler);
+                zr.on('mousemove', mousemoveHandler);
+                zr.on('mouseup', mouseupHandler);
+            }
+            if (controlType === true || (controlType === 'scale' || controlType === 'zoom')) {
+                zr.on('mousewheel', mousewheelHandler);
+                zr.on('pinch', pinchHandler);
+            }
+        };
+
+        this.disable = function () {
+            zr.off('mousedown', mousedownHandler);
+            zr.off('mousemove', mousemoveHandler);
+            zr.off('mouseup', mouseupHandler);
+            zr.off('mousewheel', mousewheelHandler);
+            zr.off('pinch', pinchHandler);
+        };
     }
 
-    var x = e.offsetX;
-    var y = e.offsetY;
+    isDragging() {
+        return this._dragging;
+    }
 
-    // Only check on mosedown, but not mousemove.
-    // Mouse can be out of target when mouse moving.
-    if (this.pointerChecker && this.pointerChecker(e, x, y)) {
-        this._x = x;
-        this._y = y;
-        this._dragging = true;
+    isPinching() {
+        return this._pinching;
     }
-}
 
-function mousemove(e) {
-    if (!this._dragging
-        || !isAvailableBehavior('moveOnMouseMove', e, this._opt)
-        || e.gestureEvent === 'pinch'
-        || interactionMutex.isTaken(this._zr, 'globalPan')
-    ) {
-        return;
+    setPointerChecker(pointerChecker: RoamController['pointerChecker']) {
+        this.pointerChecker = pointerChecker;
     }
 
-    var x = e.offsetX;
-    var y = e.offsetY;
+    dispose() {
+        this.disable();
+    }
+
+    private _mousedownHandler(e: ZRElementEvent) {
+        if (eventTool.isMiddleOrRightButtonOnMouseUpDown(e)
+            || (e.target && e.target.draggable)
+        ) {
+            return;
+        }
 
-    var oldX = this._x;
-    var oldY = this._y;
+        var x = e.offsetX;
+        var y = e.offsetY;
 
-    var dx = x - oldX;
-    var dy = y - oldY;
+        // Only check on mosedown, but not mousemove.
+        // Mouse can be out of target when mouse moving.
+        if (this.pointerChecker && this.pointerChecker(e, x, y)) {
+            this._x = x;
+            this._y = y;
+            this._dragging = true;
+        }
+    }
 
-    this._x = x;
-    this._y = y;
+    private _mousemoveHandler(e: ZRElementEvent) {
+        if (!this._dragging
+            || !isAvailableBehavior('moveOnMouseMove', e, this._opt)
+            || e.gestureEvent === 'pinch'
+            || interactionMutex.isTaken(this._zr, 'globalPan')
+        ) {
+            return;
+        }
 
-    this._opt.preventDefaultMouseMove && eventTool.stop(e.event);
+        var x = e.offsetX;
+        var y = e.offsetY;
 
-    trigger(this, 'pan', 'moveOnMouseMove', e, {
-        dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y
-    });
-}
+        var oldX = this._x;
+        var oldY = this._y;
 
-function mouseup(e) {
-    if (!eventTool.isMiddleOrRightButtonOnMouseUpDown(e)) {
-        this._dragging = false;
+        var dx = x - oldX;
+        var dy = y - oldY;
+
+        this._x = x;
+        this._y = y;
+
+        this._opt.preventDefaultMouseMove && eventTool.stop(e.event);
+
+        trigger(this, 'pan', 'moveOnMouseMove', e, {
+            dx: dx, dy: dy, oldX: oldX, oldY: oldY, newX: x, newY: y, isAvailableBehavior: null
+        });
     }
-}
 
-function mousewheel(e) {
-    var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);
-    var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);
-    var wheelDelta = e.wheelDelta;
-    var absWheelDeltaDelta = Math.abs(wheelDelta);
-    var originX = e.offsetX;
-    var originY = e.offsetY;
-
-    // wheelDelta maybe -0 in chrome mac.
-    if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {
-        return;
+    private _mouseupHandler(e: ZRElementEvent) {
+        if (!eventTool.isMiddleOrRightButtonOnMouseUpDown(e)) {
+            this._dragging = false;
+        }
     }
 
-    // If both `shouldZoom` and `shouldMove` is true, trigger
-    // their event both, and the final behavior is determined
-    // by event listener themselves.
-
-    if (shouldZoom) {
-        // Convenience:
-        // Mac and VM Windows on Mac: scroll up: zoom out.
-        // Windows: scroll up: zoom in.
-
-        // FIXME: Should do more test in different environment.
-        // wheelDelta is too complicated in difference nvironment
-        // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),
-        // although it has been normallized by zrender.
-        // wheelDelta of mouse wheel is bigger than touch pad.
-        var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;
-        var scale = wheelDelta > 0 ? factor : 1 / factor;
-        checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {
-            scale: scale, originX: originX, originY: originY
-        });
+    private _mousewheelHandler(e: ZRElementEvent) {
+        var shouldZoom = isAvailableBehavior('zoomOnMouseWheel', e, this._opt);
+        var shouldMove = isAvailableBehavior('moveOnMouseWheel', e, this._opt);
+        var wheelDelta = e.wheelDelta;
+        var absWheelDeltaDelta = Math.abs(wheelDelta);
+        var originX = e.offsetX;
+        var originY = e.offsetY;
+
+        // wheelDelta maybe -0 in chrome mac.
+        if (wheelDelta === 0 || (!shouldZoom && !shouldMove)) {
+            return;
+        }
+
+        // If both `shouldZoom` and `shouldMove` is true, trigger
+        // their event both, and the final behavior is determined
+        // by event listener themselves.
+
+        if (shouldZoom) {
+            // Convenience:
+            // Mac and VM Windows on Mac: scroll up: zoom out.
+            // Windows: scroll up: zoom in.
+
+            // FIXME: Should do more test in different environment.
+            // wheelDelta is too complicated in difference nvironment
+            // (https://developer.mozilla.org/en-US/docs/Web/Events/mousewheel),
+            // although it has been normallized by zrender.
+            // wheelDelta of mouse wheel is bigger than touch pad.
+            var factor = absWheelDeltaDelta > 3 ? 1.4 : absWheelDeltaDelta > 1 ? 1.2 : 1.1;
+            var scale = wheelDelta > 0 ? factor : 1 / factor;
+            checkPointerAndTrigger(this, 'zoom', 'zoomOnMouseWheel', e, {
+                scale: scale, originX: originX, originY: originY, isAvailableBehavior: null
+            });
+        }
+
+        if (shouldMove) {
+            // FIXME: Should do more test in different environment.
+            var absDelta = Math.abs(wheelDelta);
+            // wheelDelta of mouse wheel is bigger than touch pad.
+            var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);
+            checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {
+                scrollDelta: scrollDelta, originX: originX, originY: originY, isAvailableBehavior: null
+            });
+        }
     }
 
-    if (shouldMove) {
-        // FIXME: Should do more test in different environment.
-        var absDelta = Math.abs(wheelDelta);
-        // wheelDelta of mouse wheel is bigger than touch pad.
-        var scrollDelta = (wheelDelta > 0 ? 1 : -1) * (absDelta > 3 ? 0.4 : absDelta > 1 ? 0.15 : 0.05);
-        checkPointerAndTrigger(this, 'scrollMove', 'moveOnMouseWheel', e, {
-            scrollDelta: scrollDelta, originX: originX, originY: originY
+    private _pinchHandler(e: ZRElementEvent) {
+        if (interactionMutex.isTaken(this._zr, 'globalPan')) {
+            return;
+        }
+        var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;
+        checkPointerAndTrigger(this, 'zoom', null, e, {
+            scale: scale, originX: e.pinchX, originY: e.pinchY, isAvailableBehavior: null
         });
     }
 }
 
-function pinch(e) {
-    if (interactionMutex.isTaken(this._zr, 'globalPan')) {
-        return;
-    }
-    var scale = e.pinchScale > 1 ? 1.1 : 1 / 1.1;
-    checkPointerAndTrigger(this, 'zoom', null, e, {
-        scale: scale, originX: e.pinchX, originY: e.pinchY
-    });
-}
 
-function checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, contollerEvent) {
+function checkPointerAndTrigger<T extends 'scrollMove' | 'zoom'>(
+    controller: RoamController,
+    eventName: T,
+    behaviorToCheck: RoamBehavior,
+    e: ZRElementEvent,
+    contollerEvent: RoamEventParams[T]
+) {
     if (controller.pointerChecker
         && controller.pointerChecker(e, contollerEvent.originX, contollerEvent.originY)
     ) {
@@ -252,10 +290,16 @@ function checkPointerAndTrigger(controller, eventName, behaviorToCheck, e, conto
     }
 }
 
-function trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {
+function trigger<T extends RoamEventType>(
+    controller: RoamController,
+    eventName: T,
+    behaviorToCheck: RoamBehavior,
+    e: ZRElementEvent,
+    contollerEvent: RoamEventParams[T]
+) {
     // Also provide behavior checker for event listener, for some case that
     // multiple components share one listener.
-    contollerEvent.isAvailableBehavior = zrUtil.bind(isAvailableBehavior, null, behaviorToCheck, e);
+    contollerEvent.isAvailableBehavior = bind(isAvailableBehavior, null, behaviorToCheck, e);
     controller.trigger(eventName, contollerEvent);
 }
 
@@ -265,10 +309,14 @@ function trigger(controller, eventName, behaviorToCheck, e, contollerEvent) {
 //     moveOnMouseWheel
 // }
 // The value can be: true / false / 'shift' / 'ctrl' / 'alt'.
-function isAvailableBehavior(behaviorToCheck, e, settings) {
+function isAvailableBehavior(
+    behaviorToCheck: RoamBehavior,
+    e: ZRElementEvent,
+    settings: Pick<RoamOption, RoamBehavior>
+) {
     var setting = settings[behaviorToCheck];
     return !behaviorToCheck || (
-        setting && (!zrUtil.isString(setting) || e.event[setting + 'Key'])
+        setting && (!isString(setting) || e.event[setting + 'Key' as 'shiftKey' | 'ctrlKey' | 'altKey'])
     );
 }
 
diff --git a/src/component/visualMap/ContinuousView.ts b/src/component/visualMap/ContinuousView.ts
index 6732caf..1fbba1a 100644
--- a/src/component/visualMap/ContinuousView.ts
+++ b/src/component/visualMap/ContinuousView.ts
@@ -32,7 +32,7 @@ import ContinuousModel from './ContinuousModel';
 import GlobalModel from '../../model/Global';
 import ExtensionAPI from '../../ExtensionAPI';
 import Element, { ElementEvent } from 'zrender/src/Element';
-import { Dictionary, TextVerticalAlign, TextAlign } from 'zrender/src/core/types';
+import { TextVerticalAlign, TextAlign } from 'zrender/src/core/types';
 import { ColorString, Payload, ECElement } from '../../util/types';
 
 var linearMap = numberUtil.linearMap;
diff --git a/src/coord/Axis.ts b/src/coord/Axis.ts
index 99e8a98..90a0f1c 100644
--- a/src/coord/Axis.ts
+++ b/src/coord/Axis.ts
@@ -28,7 +28,7 @@ import Scale from '../scale/Scale';
 import { DimensionName, ScaleDataValue } from '../util/types';
 import OrdinalScale from '../scale/Ordinal';
 import Model from '../model/Model';
-import { AxisBaseOption } from './axisCommonTypes';
+import { AxisBaseOption, OptionAxisType } from './axisCommonTypes';
 
 var NORMALIZED_EXTENT = [0, 1] as [number, number];
 
@@ -43,6 +43,15 @@ interface TickCoord {
  */
 class Axis {
 
+    /**
+     * Axis type
+     *  - 'category'
+     *  - 'value'
+     *  - 'time'
+     *  - 'log'
+     */
+    type: OptionAxisType;
+
     // Axis dimension. Such as 'x', 'y', 'z', 'angle', 'radius'.
     readonly dim: DimensionName;
 
diff --git a/src/coord/CoordinateSystem.ts b/src/coord/CoordinateSystem.ts
index 327e0a9..1dead51 100644
--- a/src/coord/CoordinateSystem.ts
+++ b/src/coord/CoordinateSystem.ts
@@ -25,6 +25,8 @@ import { DimensionDefinitionLoose, ScaleDataValue, DimensionName } from '../util
 import Axis from './Axis';
 import { BoundingRect } from '../util/graphic';
 import { MatrixArray } from 'zrender/src/core/matrix';
+import ComponentModel from '../model/Component';
+import { RectLike } from 'zrender/src/core/BoundingRect';
 
 
 export interface CoordinateSystemCreator {
@@ -80,6 +82,12 @@ export interface CoordinateSystemMaster {
     axisPointerEnabled?: boolean;
 
     getTooltipAxes?: (dim: DimensionName | 'auto') => {baseAxes: Axis[], otherAxes: Axis[]};
+
+    /**
+     * Get layout rect or coordinate system
+     */
+    getRect?: () => RectLike
+
 }
 
 /**
@@ -145,6 +153,6 @@ export interface CoordinateSystem {
 /**
  * Like GridModel, PolarModel, ...
  */
-export interface CoordinateSystemHostModel {
+export interface CoordinateSystemHostModel extends ComponentModel {
     coordinateSystem?: CoordinateSystemMaster
 }
diff --git a/src/coord/axisModelCommonMixin.ts b/src/coord/axisModelCommonMixin.ts
index 7e37ccd..d041f52 100644
--- a/src/coord/axisModelCommonMixin.ts
+++ b/src/coord/axisModelCommonMixin.ts
@@ -22,6 +22,7 @@ import Model from '../model/Model';
 import Axis from './Axis';
 import ComponentModel from '../model/Component';
 import { AxisBaseOption } from './axisCommonTypes';
+import { CoordinateSystemHostModel } from './CoordinateSystem';
 
 
 interface AxisModelCommonMixin<Opt extends AxisBaseOption> extends Pick<Model<Opt>, 'option'> {
@@ -76,9 +77,9 @@ class AxisModelCommonMixin<Opt extends AxisBaseOption> {
 
     /**
      * Should be implemented by each axis model if necessary.
-     * @return {module:echarts/model/Component} coordinate system model
+     * @return coordinate system model
      */
-    getCoordSysModel(): ComponentModel {
+    getCoordSysModel(): CoordinateSystemHostModel {
         return;
     }
 
diff --git a/src/coord/cartesian/Axis2D.ts b/src/coord/cartesian/Axis2D.ts
index 6253cb0..c610a76 100644
--- a/src/coord/cartesian/Axis2D.ts
+++ b/src/coord/cartesian/Axis2D.ts
@@ -41,15 +41,6 @@ interface Axis2D {
 class Axis2D extends Axis {
 
     /**
-     * Axis type
-     *  - 'category'
-     *  - 'value'
-     *  - 'time'
-     *  - 'log'
-     */
-    readonly type: OptionAxisType;
-
-    /**
      * Axis position
      *  - 'top'
      *  - 'bottom'
diff --git a/src/coord/polar/AngleAxis.ts b/src/coord/polar/AngleAxis.ts
index cbcffcc..b5dbaa4 100644
--- a/src/coord/polar/AngleAxis.ts
+++ b/src/coord/polar/AngleAxis.ts
@@ -20,7 +20,6 @@
 import * as textContain from 'zrender/src/contain/text';
 import Axis from '../Axis';
 import {makeInner} from '../../util/model';
-import { OptionAxisType } from '../axisCommonTypes';
 import Scale from '../../scale/Scale';
 import OrdinalScale from '../../scale/Ordinal';
 import Polar from './Polar';
@@ -36,7 +35,6 @@ interface AngleAxis {
     angleToData: Axis['coordToData']
 }
 class AngleAxis extends Axis {
-    type: OptionAxisType
 
     polar: Polar
 
diff --git a/src/coord/polar/RadiusAxis.ts b/src/coord/polar/RadiusAxis.ts
index 0784816..d9623a1 100644
--- a/src/coord/polar/RadiusAxis.ts
+++ b/src/coord/polar/RadiusAxis.ts
@@ -18,7 +18,6 @@
 */
 
 import Axis from '../Axis';
-import { OptionAxisType } from '../axisCommonTypes';
 import Scale from '../../scale/Scale';
 import Polar from './Polar';
 import { RadiusAxisModel } from './AxisModel';
@@ -29,7 +28,6 @@ interface RadiusAxis {
 }
 
 class RadiusAxis extends Axis {
-    type: OptionAxisType
 
     polar: Polar
 
diff --git a/src/coord/single/SingleAxis.ts b/src/coord/single/SingleAxis.ts
index f0a6df8..4d04827 100644
--- a/src/coord/single/SingleAxis.ts
+++ b/src/coord/single/SingleAxis.ts
@@ -39,8 +39,6 @@ interface SingleAxis {
 }
 class SingleAxis extends Axis {
 
-    type: OptionAxisType
-
     position: SingleAxisPosition
 
     orient: LayoutOrient
diff --git a/src/model/Model.ts b/src/model/Model.ts
index 04cf072..e814590 100644
--- a/src/model/Model.ts
+++ b/src/model/Model.ts
@@ -263,7 +263,7 @@ type ModelConstructor = typeof Model
 enableClassExtend(Model as ModelConstructor);
 enableClassCheck(Model as ModelConstructor);
 
-interface Model extends LineStyleMixin, ItemStyleMixin, TextStyleMixin {}
+interface Model extends LineStyleMixin, ItemStyleMixin, TextStyleMixin, AreaStyleMixin {}
 mixin(Model, LineStyleMixin);
 mixin(Model, ItemStyleMixin);
 mixin(Model, AreaStyleMixin);
diff --git a/src/model/Series.ts b/src/model/Series.ts
index 32cc466..3c20b0f 100644
--- a/src/model/Series.ts
+++ b/src/model/Series.ts
@@ -1,4 +1,4 @@
-/*
+    /*
 * 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
@@ -59,6 +59,13 @@ var inner = modelUtil.makeInner<{
     dataBeforeProcessed: List
 }>();
 
+// methods that can be implemented optionally to provide to components
+interface SeriesModel {
+    /**
+     * Get dimension to render shadow in dataZoom component
+     */
+    getShadowDim?(): string
+}
 class SeriesModel<Opt extends SeriesOption = SeriesOption> extends ComponentModel<Opt> {
 
     // [Caution]: for compat the previous "class extend"


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