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/03/07 06:43:42 UTC

[incubator-echarts] branch typescript updated: ts: add types for lines

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 5b930fa  ts: add types for lines
5b930fa is described below

commit 5b930facb5a0f458754ed79f4f93c616a591ae20
Author: pissang <bm...@gmail.com>
AuthorDate: Sat Mar 7 14:43:20 2020 +0800

    ts: add types for lines
---
 src/chart/effectScatter/EffectScatterSeries.ts |  19 +-
 src/chart/helper/EffectLine.ts                 | 334 +++++++++++++------------
 src/chart/helper/EffectPolyline.ts             | 182 +++++++-------
 src/chart/helper/EffectSymbol.ts               |  11 +-
 src/chart/helper/LargeLineDraw.ts              | 294 ++++++++++++----------
 src/chart/helper/Line.ts                       |  22 +-
 src/chart/helper/LineDraw.ts                   |  75 ++++--
 src/chart/helper/Polyline.ts                   | 123 +++++----
 src/chart/helper/Symbol.ts                     |  27 +-
 src/chart/helper/SymbolDraw.ts                 |  73 +++++-
 src/chart/lines/LinesSeries.ts                 |  25 +-
 src/chart/lines/LinesView.ts                   |  90 ++++---
 src/model/Series.ts                            |   4 +-
 13 files changed, 684 insertions(+), 595 deletions(-)

diff --git a/src/chart/effectScatter/EffectScatterSeries.ts b/src/chart/effectScatter/EffectScatterSeries.ts
index 9d1196c..7a634fe 100644
--- a/src/chart/effectScatter/EffectScatterSeries.ts
+++ b/src/chart/effectScatter/EffectScatterSeries.ts
@@ -29,25 +29,14 @@ import {
     SymbolOptionMixin,
     OptionDataValue,
     ItemStyleOption,
-    LabelOption,
-    ZRColor
+    LabelOption
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import List from '../../data/List';
+import type { SymbolDrawItemModelOption } from '../helper/SymbolDraw';
 
 type ScatterDataValue = OptionDataValue | OptionDataValue[]
 
-interface RippleEffect {
-    period?: number
-    /**
-     * Scale of ripple
-     */
-    scale?: number
-
-    brushType?: 'fill' | 'stroke'
-
-    color?: ZRColor
-}
 export interface EffectScatterDataItemOption extends SymbolOptionMixin {
     name?: string
 
@@ -61,7 +50,7 @@ export interface EffectScatterDataItemOption extends SymbolOptionMixin {
         label?: LabelOption
     }
 
-    rippleEffect?: RippleEffect
+    rippleEffect?: SymbolDrawItemModelOption['rippleEffect']
 }
 
 export interface EffectScatterSeriesOption extends SeriesOption,
@@ -80,7 +69,7 @@ export interface EffectScatterSeriesOption extends SeriesOption,
     /**
      * Ripple effect config
      */
-    rippleEffect?: RippleEffect
+    rippleEffect?: SymbolDrawItemModelOption['rippleEffect']
 
     data?: (EffectScatterDataItemOption | OptionDataValue)[]
 }
diff --git a/src/chart/helper/EffectLine.ts b/src/chart/helper/EffectLine.ts
index 7c505ba..07a4e2a 100644
--- a/src/chart/helper/EffectLine.ts
+++ b/src/chart/helper/EffectLine.ts
@@ -17,8 +17,6 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 /**
  * Provide effect for line
  * @module echarts/chart/helper/EffectLine
@@ -30,199 +28,215 @@ import * as zrUtil from 'zrender/src/core/util';
 import {createSymbol} from '../../util/symbol';
 import * as vec2 from 'zrender/src/core/vector';
 import * as curveUtil from 'zrender/src/core/curve';
+import type List from '../../data/List';
+import { LineDrawSeriesScope, LineDrawModelOption } from './LineDraw';
+import Model from '../../model/Model';
+
+export type ECSymbolOnEffectLine = ReturnType<typeof createSymbol> & {
+    __t: number
+    __lastT: number
+    __p1: number[]
+    __p2: number[]
+    __cp1: number[]
+}
+class EffectLine extends graphic.Group {
 
-/**
- * @constructor
- * @extends {module:zrender/graphic/Group}
- * @alias {module:echarts/chart/helper/Line}
- */
-function EffectLine(lineData, idx, seriesScope) {
-    graphic.Group.call(this);
+    private _symbolType: string
 
-    this.add(this.createLine(lineData, idx, seriesScope));
+    private _period: number
 
-    this._updateEffectSymbol(lineData, idx);
-}
+    private _loop: boolean
 
-var effectLineProto = EffectLine.prototype;
+    private _symbolScale: number[]
 
-effectLineProto.createLine = function (lineData, idx, seriesScope) {
-    return new Line(lineData, idx, seriesScope);
-};
+    constructor(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
+        super();
+        this.add(this.createLine(lineData, idx, seriesScope));
 
-effectLineProto._updateEffectSymbol = function (lineData, idx) {
-    var itemModel = lineData.getItemModel(idx);
-    var effectModel = itemModel.getModel('effect');
-    var size = effectModel.get('symbolSize');
-    var symbolType = effectModel.get('symbol');
-    if (!zrUtil.isArray(size)) {
-        size = [size, size];
+        this._updateEffectSymbol(lineData, idx);
     }
-    var color = effectModel.get('color') || lineData.getItemVisual(idx, 'color');
-    var symbol = this.childAt(1);
 
-    if (this._symbolType !== symbolType) {
-        // Remove previous
-        this.remove(symbol);
+    createLine(lineData: List, idx: number, seriesScope: LineDrawSeriesScope): graphic.Group {
+        return new Line(lineData, idx, seriesScope);
+    }
 
-        symbol = createSymbol(
-            symbolType, -0.5, -0.5, 1, 1, color
-        );
-        symbol.z2 = 100;
-        symbol.culling = true;
+    _updateEffectSymbol(lineData: List, idx: number) {
+        var itemModel = lineData.getItemModel<LineDrawModelOption>(idx);
+        var effectModel = itemModel.getModel('effect');
+        var size = effectModel.get('symbolSize');
+        var symbolType = effectModel.get('symbol');
+        if (!zrUtil.isArray(size)) {
+            size = [size, size];
+        }
+        var color = effectModel.get('color') || lineData.getItemVisual(idx, 'color');
+        var symbol = this.childAt(1) as ECSymbolOnEffectLine;
 
-        this.add(symbol);
-    }
+        if (this._symbolType !== symbolType) {
+            // Remove previous
+            this.remove(symbol);
 
-    // Symbol may be removed if loop is false
-    if (!symbol) {
-        return;
-    }
+            symbol = createSymbol(
+                symbolType, -0.5, -0.5, 1, 1, color
+            ) as ECSymbolOnEffectLine;
+            symbol.z2 = 100;
+            symbol.culling = true;
 
-    // Shadow color is same with color in default
-    symbol.setStyle('shadowColor', color);
-    symbol.setStyle(effectModel.getItemStyle(['color']));
+            this.add(symbol);
+        }
 
-    symbol.attr('scale', size);
+        // Symbol may be removed if loop is false
+        if (!symbol) {
+            return;
+        }
 
-    symbol.setColor(color);
-    symbol.attr('scale', size);
+        // Shadow color is same with color in default
+        symbol.setStyle('shadowColor', color);
+        symbol.setStyle(effectModel.getItemStyle(['color']));
 
-    this._symbolType = symbolType;
-    this._symbolScale = size;
+        symbol.attr('scale', size);
 
-    this._updateEffectAnimation(lineData, effectModel, idx);
-};
+        symbol.setColor(color);
+        symbol.attr('scale', size);
 
-effectLineProto._updateEffectAnimation = function (lineData, effectModel, idx) {
+        this._symbolType = symbolType;
+        this._symbolScale = size;
 
-    var symbol = this.childAt(1);
-    if (!symbol) {
-        return;
+        this._updateEffectAnimation(lineData, effectModel, idx);
     }
 
-    var self = this;
+    _updateEffectAnimation(
+        lineData: List,
+        effectModel: Model<LineDrawModelOption['effect']>,
+        idx: number
+    ) {
 
-    var points = lineData.getItemLayout(idx);
+        var symbol = this.childAt(1) as ECSymbolOnEffectLine;
+        if (!symbol) {
+            return;
+        }
 
-    var period = effectModel.get('period') * 1000;
-    var loop = effectModel.get('loop');
-    var constantSpeed = effectModel.get('constantSpeed');
-    var delayExpr = zrUtil.retrieve(effectModel.get('delay'), function (idx) {
-        return idx / lineData.count() * period / 3;
-    });
-    var isDelayFunc = typeof delayExpr === 'function';
+        var self = this;
 
-    // Ignore when updating
-    symbol.ignore = true;
+        var points = lineData.getItemLayout(idx);
 
-    this.updateAnimationPoints(symbol, points);
+        var period = effectModel.get('period') * 1000;
+        var loop = effectModel.get('loop');
+        var constantSpeed = effectModel.get('constantSpeed');
+        var delayExpr = zrUtil.retrieve(effectModel.get('delay'), function (idx) {
+            return idx / lineData.count() * period / 3;
+        });
 
-    if (constantSpeed > 0) {
-        period = this.getLineLength(symbol) / constantSpeed * 1000;
-    }
+        // Ignore when updating
+        symbol.ignore = true;
 
-    if (period !== this._period || loop !== this._loop) {
+        this._updateAnimationPoints(symbol, points);
 
-        symbol.stopAnimation();
-
-        var delay = delayExpr;
-        if (isDelayFunc) {
-            delay = delayExpr(idx);
-        }
-        if (symbol.__t > 0) {
-            delay = -period * symbol.__t;
+        if (constantSpeed > 0) {
+            period = this._getLineLength(symbol) / constantSpeed * 1000;
         }
-        symbol.__t = 0;
-        var animator = symbol.animate('', loop)
-            .when(period, {
-                __t: 1
-            })
-            .delay(delay)
-            .during(function () {
-                self.updateSymbolPosition(symbol);
-            });
-        if (!loop) {
-            animator.done(function () {
-                self.remove(symbol);
-            });
-        }
-        animator.start();
-    }
 
-    this._period = period;
-    this._loop = loop;
-};
-
-effectLineProto.getLineLength = function (symbol) {
-    // Not so accurate
-    return (vec2.dist(symbol.__p1, symbol.__cp1)
-        + vec2.dist(symbol.__cp1, symbol.__p2));
-};
-
-effectLineProto.updateAnimationPoints = function (symbol, points) {
-    symbol.__p1 = points[0];
-    symbol.__p2 = points[1];
-    symbol.__cp1 = points[2] || [
-        (points[0][0] + points[1][0]) / 2,
-        (points[0][1] + points[1][1]) / 2
-    ];
-};
-
-effectLineProto.updateData = function (lineData, idx, seriesScope) {
-    this.childAt(0).updateData(lineData, idx, seriesScope);
-    this._updateEffectSymbol(lineData, idx);
-};
-
-effectLineProto.updateSymbolPosition = function (symbol) {
-    var p1 = symbol.__p1;
-    var p2 = symbol.__p2;
-    var cp1 = symbol.__cp1;
-    var t = symbol.__t;
-    var pos = symbol.position;
-    var lastPos = [pos[0], pos[1]];
-    var quadraticAt = curveUtil.quadraticAt;
-    var quadraticDerivativeAt = curveUtil.quadraticDerivativeAt;
-    pos[0] = quadraticAt(p1[0], cp1[0], p2[0], t);
-    pos[1] = quadraticAt(p1[1], cp1[1], p2[1], t);
-
-    // Tangent
-    var tx = quadraticDerivativeAt(p1[0], cp1[0], p2[0], t);
-    var ty = quadraticDerivativeAt(p1[1], cp1[1], p2[1], t);
-
-    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;
-    // enable continuity trail for 'line', 'rect', 'roundRect' symbolType
-    if (this._symbolType === 'line' || this._symbolType === 'rect' || this._symbolType === 'roundRect') {
-        if (symbol.__lastT !== undefined && symbol.__lastT < symbol.__t) {
-            var scaleY = vec2.dist(lastPos, pos) * 1.05;
-            symbol.attr('scale', [symbol.scale[0], scaleY]);
-            // make sure the last segment render within endPoint
-            if (t === 1) {
-                pos[0] = lastPos[0] + (pos[0] - lastPos[0]) / 2;
-                pos[1] = lastPos[1] + (pos[1] - lastPos[1]) / 2;
+        if (period !== this._period || loop !== this._loop) {
+
+            symbol.stopAnimation();
+
+            var delayNum: number;
+            if (typeof delayExpr === 'function') {
+                delayNum = delayExpr(idx);
             }
+            else {
+                delayNum = delayExpr;
+            }
+            if (symbol.__t > 0) {
+                delayNum = -period * symbol.__t;
+            }
+            symbol.__t = 0;
+            var animator = symbol.animate('', loop)
+                .when(period, {
+                    __t: 1
+                })
+                .delay(delayNum)
+                .during(function () {
+                    self.updateSymbolPosition(symbol);
+                });
+            if (!loop) {
+                animator.done(function () {
+                    self.remove(symbol);
+                });
+            }
+            animator.start();
         }
-        else if (symbol.__lastT === 1) {
-            // After first loop, symbol.__t does NOT start with 0, so connect p1 to pos directly.
-            var scaleY = 2 * vec2.dist(p1, pos);
-            symbol.attr('scale', [symbol.scale[0], scaleY ]);
-        }
-        else {
-            symbol.attr('scale', this._symbolScale);
-        }
+
+        this._period = period;
+        this._loop = loop;
+    }
+
+    private _getLineLength(symbol: ECSymbolOnEffectLine) {
+        // Not so accurate
+        return (vec2.dist(symbol.__p1, symbol.__cp1)
+            + vec2.dist(symbol.__cp1, symbol.__p2));
+    }
+
+    private _updateAnimationPoints(symbol: ECSymbolOnEffectLine, points: number[][]) {
+        symbol.__p1 = points[0];
+        symbol.__p2 = points[1];
+        symbol.__cp1 = points[2] || [
+            (points[0][0] + points[1][0]) / 2,
+            (points[0][1] + points[1][1]) / 2
+        ];
     }
-    symbol.__lastT = symbol.__t;
-    symbol.ignore = false;
-};
 
+    updateData(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
+        (this.childAt(0) as Line).updateData(lineData, idx, seriesScope);
+        this._updateEffectSymbol(lineData, idx);
+    }
 
-effectLineProto.updateLayout = function (lineData, idx) {
-    this.childAt(0).updateLayout(lineData, idx);
+    updateSymbolPosition(symbol: ECSymbolOnEffectLine) {
+        var p1 = symbol.__p1;
+        var p2 = symbol.__p2;
+        var cp1 = symbol.__cp1;
+        var t = symbol.__t;
+        var pos = symbol.position;
+        var lastPos = [pos[0], pos[1]];
+        var quadraticAt = curveUtil.quadraticAt;
+        var quadraticDerivativeAt = curveUtil.quadraticDerivativeAt;
+        pos[0] = quadraticAt(p1[0], cp1[0], p2[0], t);
+        pos[1] = quadraticAt(p1[1], cp1[1], p2[1], t);
+
+        // Tangent
+        var tx = quadraticDerivativeAt(p1[0], cp1[0], p2[0], t);
+        var ty = quadraticDerivativeAt(p1[1], cp1[1], p2[1], t);
+
+        symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;
+        // enable continuity trail for 'line', 'rect', 'roundRect' symbolType
+        if (this._symbolType === 'line' || this._symbolType === 'rect' || this._symbolType === 'roundRect') {
+            if (symbol.__lastT !== undefined && symbol.__lastT < symbol.__t) {
+                var scaleY = vec2.dist(lastPos, pos) * 1.05;
+                symbol.attr('scale', [symbol.scale[0], scaleY]);
+                // make sure the last segment render within endPoint
+                if (t === 1) {
+                    pos[0] = lastPos[0] + (pos[0] - lastPos[0]) / 2;
+                    pos[1] = lastPos[1] + (pos[1] - lastPos[1]) / 2;
+                }
+            }
+            else if (symbol.__lastT === 1) {
+                // After first loop, symbol.__t does NOT start with 0, so connect p1 to pos directly.
+                var scaleY = 2 * vec2.dist(p1, pos);
+                symbol.attr('scale', [symbol.scale[0], scaleY ]);
+            }
+            else {
+                symbol.attr('scale', this._symbolScale);
+            }
+        }
+        symbol.__lastT = symbol.__t;
+        symbol.ignore = false;
+    }
 
-    var effectModel = lineData.getItemModel(idx).getModel('effect');
-    this._updateEffectAnimation(lineData, effectModel, idx);
-};
 
-zrUtil.inherits(EffectLine, graphic.Group);
+    updateLayout(lineData: List, idx: number) {
+        (this.childAt(0) as Line).updateLayout(lineData, idx);
 
+        var effectModel = lineData.getItemModel<LineDrawModelOption>(idx).getModel('effect');
+        this._updateEffectAnimation(lineData, effectModel, idx);
+    }
+}
 export default EffectLine;
\ No newline at end of file
diff --git a/src/chart/helper/EffectPolyline.ts b/src/chart/helper/EffectPolyline.ts
index 2e71676..3bb93e8 100644
--- a/src/chart/helper/EffectPolyline.ts
+++ b/src/chart/helper/EffectPolyline.ts
@@ -17,114 +17,104 @@
 * under the License.
 */
 
-// @ts-nocheck
-
-/**
- * Provide effect for line
- * @module echarts/chart/helper/EffectLine
- */
-
 import Polyline from './Polyline';
-import * as zrUtil from 'zrender/src/core/util';
-import EffectLine from './EffectLine';
+import EffectLine, {ECSymbolOnEffectLine} from './EffectLine';
 import * as vec2 from 'zrender/src/core/vector';
+import { LineDrawSeriesScope } from './LineDraw';
+import List from '../../data/List';
+
+
+class EffectPolyline extends EffectLine {
+    private _lastFrame = 0
+    private _lastFramePercent = 0
+    private _length: number
+
+    private _points: number[][]
+    private _offsets: number[]
+
+    // Override
+    createLine(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
+        return new Polyline(lineData, idx, seriesScope);
+    };
+
+    // Override
+    updateAnimationPoints(symbol: ECSymbolOnEffectLine, points: number[][]) {
+        this._points = points;
+        var accLenArr = [0];
+        var len = 0;
+        for (var i = 1; i < points.length; i++) {
+            var p1 = points[i - 1];
+            var p2 = points[i];
+            len += vec2.dist(p1, p2);
+            accLenArr.push(len);
+        }
+        if (len === 0) {
+            return;
+        }
 
-/**
- * @constructor
- * @extends {module:echarts/chart/helper/EffectLine}
- * @alias {module:echarts/chart/helper/Polyline}
- */
-function EffectPolyline(lineData, idx, seriesScope) {
-    EffectLine.call(this, lineData, idx, seriesScope);
-    this._lastFrame = 0;
-    this._lastFramePercent = 0;
-}
+        for (var i = 0; i < accLenArr.length; i++) {
+            accLenArr[i] /= len;
+        }
+        this._offsets = accLenArr;
+        this._length = len;
+    };
+
+    // Override
+    getLineLength() {
+        return this._length;
+    };
+
+    // Override
+    updateSymbolPosition(symbol: ECSymbolOnEffectLine) {
+        var t = symbol.__t;
+        var points = this._points;
+        var offsets = this._offsets;
+        var len = points.length;
+
+        if (!offsets) {
+            // Has length 0
+            return;
+        }
 
-var effectPolylineProto = EffectPolyline.prototype;
-
-// Overwrite
-effectPolylineProto.createLine = function (lineData, idx, seriesScope) {
-    return new Polyline(lineData, idx, seriesScope);
-};
-
-// Overwrite
-effectPolylineProto.updateAnimationPoints = function (symbol, points) {
-    this._points = points;
-    var accLenArr = [0];
-    var len = 0;
-    for (var i = 1; i < points.length; i++) {
-        var p1 = points[i - 1];
-        var p2 = points[i];
-        len += vec2.dist(p1, p2);
-        accLenArr.push(len);
-    }
-    if (len === 0) {
-        return;
-    }
-
-    for (var i = 0; i < accLenArr.length; i++) {
-        accLenArr[i] /= len;
-    }
-    this._offsets = accLenArr;
-    this._length = len;
-};
-
-// Overwrite
-effectPolylineProto.getLineLength = function (symbol) {
-    return this._length;
-};
-
-// Overwrite
-effectPolylineProto.updateSymbolPosition = function (symbol) {
-    var t = symbol.__t;
-    var points = this._points;
-    var offsets = this._offsets;
-    var len = points.length;
-
-    if (!offsets) {
-        // Has length 0
-        return;
-    }
-
-    var lastFrame = this._lastFrame;
-    var frame;
-
-    if (t < this._lastFramePercent) {
-        // Start from the next frame
-        // PENDING start from lastFrame ?
-        var start = Math.min(lastFrame + 1, len - 1);
-        for (frame = start; frame >= 0; frame--) {
-            if (offsets[frame] <= t) {
-                break;
+        var lastFrame = this._lastFrame;
+        var frame: number;
+
+        if (t < this._lastFramePercent) {
+            // Start from the next frame
+            // PENDING start from lastFrame ?
+            var start = Math.min(lastFrame + 1, len - 1);
+            for (frame = start; frame >= 0; frame--) {
+                if (offsets[frame] <= t) {
+                    break;
+                }
             }
+            // PENDING really need to do this ?
+            frame = Math.min(frame, len - 2);
         }
-        // PENDING really need to do this ?
-        frame = Math.min(frame, len - 2);
-    }
-    else {
-        for (var frame = lastFrame; frame < len; frame++) {
-            if (offsets[frame] > t) {
-                break;
+        else {
+            for (frame = lastFrame; frame < len; frame++) {
+                if (offsets[frame] > t) {
+                    break;
+                }
             }
+            frame = Math.min(frame - 1, len - 2);
         }
-        frame = Math.min(frame - 1, len - 2);
-    }
 
-    vec2.lerp(
-        symbol.position, points[frame], points[frame + 1],
-        (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame])
-    );
+        vec2.lerp(
+            symbol.position, points[frame], points[frame + 1],
+            (t - offsets[frame]) / (offsets[frame + 1] - offsets[frame])
+        );
 
-    var tx = points[frame + 1][0] - points[frame][0];
-    var ty = points[frame + 1][1] - points[frame][1];
-    symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;
+        var tx = points[frame + 1][0] - points[frame][0];
+        var ty = points[frame + 1][1] - points[frame][1];
+        symbol.rotation = -Math.atan2(ty, tx) - Math.PI / 2;
 
-    this._lastFrame = frame;
-    this._lastFramePercent = t;
+        this._lastFrame = frame;
+        this._lastFramePercent = t;
 
-    symbol.ignore = false;
-};
+        symbol.ignore = false;
+    };
 
-zrUtil.inherits(EffectPolyline, EffectLine);
+}
 
 export default EffectPolyline;
\ No newline at end of file
diff --git a/src/chart/helper/EffectSymbol.ts b/src/chart/helper/EffectSymbol.ts
index 618e368..fcaa8f4 100644
--- a/src/chart/helper/EffectSymbol.ts
+++ b/src/chart/helper/EffectSymbol.ts
@@ -17,11 +17,6 @@
 * under the License.
 */
 
-/**
- * Symbol with ripple effect
- * @module echarts/chart/helper/EffectSymbol
- */
-
 import * as zrUtil from 'zrender/src/core/util';
 import {createSymbol} from '../../util/symbol';
 import {Group, Path} from '../../util/graphic';
@@ -30,7 +25,7 @@ import SymbolClz from './Symbol';
 import List from '../../data/List';
 import type { ZRColor } from '../../util/types';
 import type Displayable from 'zrender/src/graphic/Displayable';
-import { EffectScatterDataItemOption } from '../effectScatter/EffectScatterSeries';
+import { SymbolDrawItemModelOption } from './SymbolDraw';
 
 var EFFECT_RIPPLE_NUMBER = 3;
 
@@ -167,8 +162,6 @@ class EffectSymbol extends Group {
 
     /**
      * Update symbol properties
-     * @param  {module:echarts/data/List} data
-     * @param  {number} idx
      */
     updateData(data: List, idx: number) {
         var seriesModel = data.hostModel;
@@ -176,7 +169,7 @@ class EffectSymbol extends Group {
         (this.childAt(0) as SymbolClz).updateData(data, idx);
 
         var rippleGroup = this.childAt(1);
-        var itemModel = data.getItemModel<EffectScatterDataItemOption>(idx);
+        var itemModel = data.getItemModel<SymbolDrawItemModelOption>(idx);
         var symbolType = data.getItemVisual(idx, 'symbol');
         var symbolSize = normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
         var color = data.getItemVisual(idx, 'color');
diff --git a/src/chart/helper/LargeLineDraw.ts b/src/chart/helper/LargeLineDraw.ts
index ee31e37..fa46af4 100644
--- a/src/chart/helper/LargeLineDraw.ts
+++ b/src/chart/helper/LargeLineDraw.ts
@@ -17,24 +17,56 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 // TODO Batch by color
 
 import * as graphic from '../../util/graphic';
 import IncrementalDisplayable from 'zrender/src/graphic/IncrementalDisplayable';
 import * as lineContain from 'zrender/src/contain/line';
 import * as quadraticContain from 'zrender/src/contain/quadratic';
+import { PathProps } from 'zrender/src/graphic/Path';
+import List from '../../data/List';
+import { StageHandlerProgressParams, LineStyleOption } from '../../util/types';
+import Model from '../../model/Model';
+
+class LargeLinesPathShape {
+    polyline = false
+    curveness = 0
+    segs: ArrayLike<number> = []
+}
 
-var LargeLineShape = graphic.extendShape({
+interface LargeLinesPathProps extends PathProps {
+    shape?: Partial<LargeLinesPathShape>
+}
 
-    shape: {
-        polyline: false,
-        curveness: 0,
-        segs: []
-    },
+interface LargeLinesCommonOption {
+    polyline?: boolean
+    lineStyle?: LineStyleOption & {
+        curveness?: number
+    }
+}
+
+/**
+ * Data which can support large lines.
+ */
+type LargeLinesData = List<Model<LargeLinesCommonOption> & {
+    seriesIndex?: number
+}>
+
+class LargeLinesPath extends graphic.Path {
+    shape: LargeLinesPathShape
+
+    seriesIndex: number
+    dataIndex: number
+    __startIndex: number
+
+    constructor(opts?: LargeLinesPathProps) {
+        super(opts, {
+            stroke: '#000',
+            fill: null
+        }, new LargeLinesPathShape());
+    }
 
-    buildPath: function (path, shape) {
+    buildPath(ctx: CanvasRenderingContext2D, shape: LargeLinesPathShape) {
         var segs = shape.segs;
         var curveness = shape.curveness;
 
@@ -42,9 +74,9 @@ var LargeLineShape = graphic.extendShape({
             for (var i = 0; i < segs.length;) {
                 var count = segs[i++];
                 if (count > 0) {
-                    path.moveTo(segs[i++], segs[i++]);
+                    ctx.moveTo(segs[i++], segs[i++]);
                     for (var k = 1; k < count; k++) {
-                        path.lineTo(segs[i++], segs[i++]);
+                        ctx.lineTo(segs[i++], segs[i++]);
                     }
                 }
             }
@@ -55,24 +87,25 @@ var LargeLineShape = graphic.extendShape({
                 var y0 = segs[i++];
                 var x1 = segs[i++];
                 var y1 = segs[i++];
-                path.moveTo(x0, y0);
+                ctx.moveTo(x0, y0);
                 if (curveness > 0) {
                     var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;
                     var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;
-                    path.quadraticCurveTo(x2, y2, x1, y1);
+                    ctx.quadraticCurveTo(x2, y2, x1, y1);
                 }
                 else {
-                    path.lineTo(x1, y1);
+                    ctx.lineTo(x1, y1);
                 }
             }
         }
-    },
+    }
 
-    findDataIndex: function (x, y) {
+    findDataIndex(x: number, y: number) {
 
         var shape = this.shape;
         var segs = shape.segs;
         var curveness = shape.curveness;
+        var lineWidth = this.style.lineWidth;
 
         if (shape.polyline) {
             var dataIndex = 0;
@@ -84,7 +117,7 @@ var LargeLineShape = graphic.extendShape({
                     for (var k = 1; k < count; k++) {
                         var x1 = segs[i++];
                         var y1 = segs[i++];
-                        if (lineContain.containStroke(x0, y0, x1, y1)) {
+                        if (lineContain.containStroke(x0, y0, x1, y1, lineWidth, x, y)) {
                             return dataIndex;
                         }
                     }
@@ -104,12 +137,16 @@ var LargeLineShape = graphic.extendShape({
                     var x2 = (x0 + x1) / 2 - (y0 - y1) * curveness;
                     var y2 = (y0 + y1) / 2 - (x1 - x0) * curveness;
 
-                    if (quadraticContain.containStroke(x0, y0, x2, y2, x1, y1)) {
+                    if (quadraticContain.containStroke(
+                        x0, y0, x2, y2, x1, y1, lineWidth, x, y
+                    )) {
                         return dataIndex;
                     }
                 }
                 else {
-                    if (lineContain.containStroke(x0, y0, x1, y1)) {
+                    if (lineContain.containStroke(
+                        x0, y0, x1, y1, lineWidth, x, y
+                    )) {
                         return dataIndex;
                     }
                 }
@@ -120,132 +157,133 @@ var LargeLineShape = graphic.extendShape({
 
         return -1;
     }
-});
-
-function LargeLineDraw() {
-    this.group = new graphic.Group();
 }
 
-var largeLineProto = LargeLineDraw.prototype;
+class LargeLineDraw {
+    group = new graphic.Group()
 
-largeLineProto.isPersistent = function () {
-    return !this._incremental;
-};
+    _incremental?: IncrementalDisplayable
 
-/**
- * Update symbols draw by new data
- * @param {module:echarts/data/List} data
- */
-largeLineProto.updateData = function (data) {
-    this.group.removeAll();
+    isPersistent() {
+        return !this._incremental;
+    };
 
-    var lineEl = new LargeLineShape({
-        rectHover: true,
-        cursor: 'default'
-    });
-    lineEl.setShape({
-        segs: data.getLayout('linesPoints')
-    });
+    /**
+     * Update symbols draw by new data
+     */
+    updateData(data: LargeLinesData) {
+        this.group.removeAll();
 
-    this._setCommon(lineEl, data);
+        var lineEl = new LargeLinesPath({
+            rectHover: true,
+            cursor: 'default'
+        });
+        lineEl.setShape({
+            segs: data.getLayout('linesPoints')
+        });
 
-    // Add back
-    this.group.add(lineEl);
+        this._setCommon(lineEl, data);
 
-    this._incremental = null;
-};
+        // Add back
+        this.group.add(lineEl);
 
-/**
- * @override
- */
-largeLineProto.incrementalPrepareUpdate = function (data) {
-    this.group.removeAll();
+        this._incremental = null;
+    };
+
+    /**
+     * @override
+     */
+    incrementalPrepareUpdate(data: LargeLinesData) {
+        this.group.removeAll();
+
+        this._clearIncremental();
+
+        if (data.count() > 5e5) {
+            if (!this._incremental) {
+                this._incremental = new IncrementalDisplayable({
+                    silent: true
+                });
+            }
+            this.group.add(this._incremental);
+        }
+        else {
+            this._incremental = null;
+        }
+    };
+
+    /**
+     * @override
+     */
+    incrementalUpdate(taskParams: StageHandlerProgressParams, data: LargeLinesData) {
+        var lineEl = new LargeLinesPath();
+        lineEl.setShape({
+            segs: data.getLayout('linesPoints')
+        });
 
-    this._clearIncremental();
+        this._setCommon(lineEl, data, !!this._incremental);
 
-    if (data.count() > 5e5) {
         if (!this._incremental) {
-            this._incremental = new IncrementalDisplayable({
-                silent: true
-            });
+            lineEl.rectHover = true;
+            lineEl.cursor = 'default';
+            lineEl.__startIndex = taskParams.start;
+            this.group.add(lineEl);
         }
-        this.group.add(this._incremental);
-    }
-    else {
+        else {
+            this._incremental.addDisplayable(lineEl, true);
+        }
+    };
+
+    /**
+     * @override
+     */
+    remove() {
+        this._clearIncremental();
         this._incremental = null;
-    }
-};
+        this.group.removeAll();
+    };
 
-/**
- * @override
- */
-largeLineProto.incrementalUpdate = function (taskParams, data) {
-    var lineEl = new LargeLineShape();
-    lineEl.setShape({
-        segs: data.getLayout('linesPoints')
-    });
-
-    this._setCommon(lineEl, data, !!this._incremental);
-
-    if (!this._incremental) {
-        lineEl.rectHover = true;
-        lineEl.cursor = 'default';
-        lineEl.__startIndex = taskParams.start;
-        this.group.add(lineEl);
-    }
-    else {
-        this._incremental.addDisplayable(lineEl, true);
-    }
-};
+    _setCommon(lineEl: LargeLinesPath, data: LargeLinesData, isIncremental?: boolean) {
+        var hostModel = data.hostModel;
 
-/**
- * @override
- */
-largeLineProto.remove = function () {
-    this._clearIncremental();
-    this._incremental = null;
-    this.group.removeAll();
-};
-
-largeLineProto._setCommon = function (lineEl, data, isIncremental) {
-    var hostModel = data.hostModel;
-
-    lineEl.setShape({
-        polyline: hostModel.get('polyline'),
-        curveness: hostModel.get('lineStyle.curveness')
-    });
-
-    lineEl.useStyle(
-        hostModel.getModel('lineStyle').getLineStyle()
-    );
-    lineEl.style.strokeNoScale = true;
-
-    var visualColor = data.getVisual('color');
-    if (visualColor) {
-        lineEl.setStyle('stroke', visualColor);
-    }
-    lineEl.setStyle('fill');
-
-    if (!isIncremental) {
-        // Enable tooltip
-        // PENDING May have performance issue when path is extremely large
-        lineEl.seriesIndex = hostModel.seriesIndex;
-        lineEl.on('mousemove', function (e) {
-            lineEl.dataIndex = null;
-            var dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY);
-            if (dataIndex > 0) {
-                // Provide dataIndex for tooltip
-                lineEl.dataIndex = dataIndex + lineEl.__startIndex;
-            }
+        lineEl.setShape({
+            polyline: hostModel.get('polyline'),
+            curveness: hostModel.get(['lineStyle', 'curveness'])
         });
-    }
-};
 
-largeLineProto._clearIncremental = function () {
-    var incremental = this._incremental;
-    if (incremental) {
-        incremental.clearDisplaybles();
-    }
-};
+        lineEl.useStyle(
+            hostModel.getModel('lineStyle').getLineStyle()
+        );
+        lineEl.style.strokeNoScale = true;
+
+        var visualColor = data.getVisual('color');
+        if (visualColor) {
+            lineEl.setStyle('stroke', visualColor);
+        }
+        lineEl.setStyle('fill');
+
+        if (!isIncremental) {
+            // Enable tooltip
+            // PENDING May have performance issue when path is extremely large
+            lineEl.seriesIndex = hostModel.seriesIndex;
+            lineEl.on('mousemove', function (e) {
+                lineEl.dataIndex = null;
+                var dataIndex = lineEl.findDataIndex(e.offsetX, e.offsetY);
+                if (dataIndex > 0) {
+                    // Provide dataIndex for tooltip
+                    lineEl.dataIndex = dataIndex + lineEl.__startIndex;
+                }
+            });
+        }
+    };
+
+    _clearIncremental() {
+        var incremental = this._incremental;
+        if (incremental) {
+            incremental.clearDisplaybles();
+        }
+    };
+
+
+}
 
 export default LargeLineDraw;
\ No newline at end of file
diff --git a/src/chart/helper/Line.ts b/src/chart/helper/Line.ts
index 969789e..84edda9 100644
--- a/src/chart/helper/Line.ts
+++ b/src/chart/helper/Line.ts
@@ -25,9 +25,9 @@ import * as graphic from '../../util/graphic';
 import {round} from '../../util/number';
 import List from '../../data/List';
 import { StyleProps } from 'zrender/src/graphic/Style';
-import { LineLabelOption, ZRTextAlign, ZRTextVerticalAlign } from '../../util/types';
-import Model from '../../model/Model';
+import { ZRTextAlign, ZRTextVerticalAlign } from '../../util/types';
 import SeriesModel from '../../model/Series';
+import type { LineDrawSeriesScope, LineDrawModelOption } from './LineDraw';
 
 var SYMBOL_CATEGORIES = ['fromSymbol', 'toSymbol'] as const;
 
@@ -48,13 +48,6 @@ function makeSymbolTypeKey(symbolCategory: string) {
     return '_' + symbolCategory + 'Type' as '_fromSymbolType' | '_toSymbolType';
 }
 
-export interface SeriesScope {
-    lineStyle?: StyleProps
-    hoverLineStyle?: StyleProps
-
-    labelModel?: Model<LineLabelOption>
-    hoverLabelModel?: Model<LineLabelOption>
-}
 /**
  * @inner
  */
@@ -112,17 +105,18 @@ function setLinePoints(targetShape: ECLinePath['shape'], points: number[][]) {
     }
 }
 
+
 class Line extends graphic.Group {
 
     private _fromSymbolType: string
     private _toSymbolType: string
 
-    constructor(lineData: List, idx: number, seriesScope?: SeriesScope) {
+    constructor(lineData: List, idx: number, seriesScope?: LineDrawSeriesScope) {
         super();
         this._createLine(lineData, idx, seriesScope);
     }
 
-    _createLine(lineData: List, idx: number, seriesScope?: SeriesScope) {
+    _createLine(lineData: List, idx: number, seriesScope?: LineDrawSeriesScope) {
         var seriesModel = lineData.hostModel;
         var linePoints = lineData.getItemLayout(idx);
         var line = createLine(linePoints);
@@ -156,7 +150,7 @@ class Line extends graphic.Group {
         this._updateCommonStl(lineData, idx, seriesScope);
     }
 
-    updateData(lineData: List, idx: number, seriesScope: SeriesScope) {
+    updateData(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
         var seriesModel = lineData.hostModel;
 
         var line = this.childOfName('line') as ECLinePath;
@@ -183,7 +177,7 @@ class Line extends graphic.Group {
         this._updateCommonStl(lineData, idx, seriesScope);
     };
 
-    _updateCommonStl(lineData: List, idx: number, seriesScope?: SeriesScope) {
+    _updateCommonStl(lineData: List, idx: number, seriesScope?: LineDrawSeriesScope) {
         var seriesModel = lineData.hostModel as SeriesModel;
 
         var line = this.childOfName('line') as ECLinePath;
@@ -195,7 +189,7 @@ class Line extends graphic.Group {
 
         // Optimization for large dataset
         if (!seriesScope || lineData.hasItemOption) {
-            var itemModel = lineData.getItemModel(idx);
+            var itemModel = lineData.getItemModel<LineDrawModelOption>(idx);
 
             lineStyle = itemModel.getModel('lineStyle').getLineStyle();
             hoverLineStyle = itemModel.getModel(['emphasis', 'lineStyle']).getLineStyle();
diff --git a/src/chart/helper/LineDraw.ts b/src/chart/helper/LineDraw.ts
index eb241fb..0afcbbc 100644
--- a/src/chart/helper/LineDraw.ts
+++ b/src/chart/helper/LineDraw.ts
@@ -18,29 +18,70 @@
 */
 
 import * as graphic from '../../util/graphic';
-import LineGroup, {SeriesScope} from './Line';
+import LineGroup from './Line';
 import List from '../../data/List';
-import { StageHandlerProgressParams, LineStyleOption, LineLabelOption } from '../../util/types';
+import {
+    StageHandlerProgressParams,
+    LineStyleOption,
+    LineLabelOption,
+    ColorString,
+    AnimationOptionMixin
+} from '../../util/types';
 import Displayable from 'zrender/src/graphic/Displayable';
 import Model from '../../model/Model';
+import { StyleProps } from 'zrender/src/graphic/Style';
 
 interface LineLike extends graphic.Group {
-    updateData(data: List, idx: number, scope?: SeriesScope): void
+    updateData(data: List, idx: number, scope?: LineDrawSeriesScope): void
     updateLayout(data: List, idx: number): void
     fadeOut?(cb: () => void): void
 }
 
 interface LineLikeCtor {
-    new(data: List, idx: number, scope?: SeriesScope): LineLike
+    new(data: List, idx: number, scope?: LineDrawSeriesScope): LineLike
 }
 
-interface LineOption {
+export interface LineDrawModelOption {
     lineStyle?: LineStyleOption
     label?: LineLabelOption
-    emphasis: {
+    emphasis?: {
         lineStyle?: LineStyleOption
         label?: LineLabelOption
     }
+
+    // If has effect
+    effect?: {
+        show?: boolean
+        period?: number
+        delay?: number | ((idx: number) => number)
+        /**
+         * If move with constant speed px/sec
+         * period will be ignored if this property is > 0,
+         */
+        constantSpeed?: number
+
+        symbol?: string
+        symbolSize?: number | number[]
+        loop?: boolean
+        /**
+         * Length of trail, 0 - 1
+         */
+        trailLength?: number
+        /**
+         * Default to be same with lineStyle.color
+         */
+        color?: ColorString
+    }
+}
+
+type ListForLineDraw = List<Model<LineDrawModelOption & AnimationOptionMixin>>
+
+export interface LineDrawSeriesScope {
+    lineStyle?: StyleProps
+    hoverLineStyle?: StyleProps
+
+    labelModel?: Model<LineLabelOption>
+    hoverLabelModel?: Model<LineLabelOption>
 }
 
 class LineDraw {
@@ -48,9 +89,9 @@ class LineDraw {
 
     private _LineCtor: LineLikeCtor
 
-    private _lineData: List
+    private _lineData: ListForLineDraw
 
-    private _seriesScope: SeriesScope
+    private _seriesScope: LineDrawSeriesScope
 
     constructor(LineCtor?: LineLikeCtor) {
         this._LineCtor = LineCtor || LineGroup;
@@ -60,7 +101,7 @@ class LineDraw {
         return true;
     };
 
-    updateData(lineData: List<Model<LineOption>>) {
+    updateData(lineData: ListForLineDraw) {
         var lineDraw = this;
         var group = lineDraw.group;
 
@@ -101,13 +142,13 @@ class LineDraw {
         }, this);
     };
 
-    incrementalPrepareUpdate(lineData: List) {
+    incrementalPrepareUpdate(lineData: ListForLineDraw) {
         this._seriesScope = makeSeriesScope(lineData);
         this._lineData = null;
         this.group.removeAll();
     };
 
-    incrementalUpdate(taskParams: StageHandlerProgressParams, lineData: List) {
+    incrementalUpdate(taskParams: StageHandlerProgressParams, lineData: ListForLineDraw) {
         function updateIncrementalAndHover(el: Displayable) {
             if (!el.isGroup) {
                 el.incremental = el.useHoverLayer = true;
@@ -132,9 +173,9 @@ class LineDraw {
     };
 
     private _doAdd(
-        lineData: List,
+        lineData: ListForLineDraw,
         idx: number,
-        seriesScope: SeriesScope
+        seriesScope: LineDrawSeriesScope
     ) {
         var itemLayout = lineData.getItemLayout(idx);
 
@@ -147,11 +188,11 @@ class LineDraw {
         this.group.add(el);
     }
     private _doUpdate(
-        oldLineData: List,
-        newLineData: List,
+        oldLineData: ListForLineDraw,
+        newLineData: ListForLineDraw,
         oldIdx: number,
         newIdx: number,
-        seriesScope: SeriesScope
+        seriesScope: LineDrawSeriesScope
     ) {
         var itemEl = oldLineData.getItemGraphicEl(oldIdx) as LineLike;
 
@@ -173,7 +214,7 @@ class LineDraw {
     }
 }
 
-function makeSeriesScope(lineData: List<Model<LineOption>>) {
+function makeSeriesScope(lineData: ListForLineDraw) {
     var hostModel = lineData.hostModel;
     return {
         lineStyle: hostModel.getModel('lineStyle').getLineStyle(),
diff --git a/src/chart/helper/Polyline.ts b/src/chart/helper/Polyline.ts
index 82d89b2..3efeb39 100644
--- a/src/chart/helper/Polyline.ts
+++ b/src/chart/helper/Polyline.ts
@@ -17,88 +17,77 @@
 * under the License.
 */
 
-// @ts-nocheck
-
-/**
- * @module echarts/chart/helper/Line
- */
-
 import * as graphic from '../../util/graphic';
 import * as zrUtil from 'zrender/src/core/util';
+import type { LineDrawSeriesScope, LineDrawModelOption } from './LineDraw';
+import type List from '../../data/List';
 
-/**
- * @constructor
- * @extends {module:zrender/graphic/Group}
- * @alias {module:echarts/chart/helper/Polyline}
- */
-function Polyline(lineData, idx, seriesScope) {
-    graphic.Group.call(this);
-
-    this._createPolyline(lineData, idx, seriesScope);
-}
+class Polyline extends graphic.Group {
+    constructor(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
+        super();
+        this._createPolyline(lineData, idx, seriesScope);
+    }
 
-var polylineProto = Polyline.prototype;
+    private _createPolyline(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
+        // var seriesModel = lineData.hostModel;
+        var points = lineData.getItemLayout(idx);
 
-polylineProto._createPolyline = function (lineData, idx, seriesScope) {
-    // var seriesModel = lineData.hostModel;
-    var points = lineData.getItemLayout(idx);
+        var line = new graphic.Polyline({
+            shape: {
+                points: points
+            }
+        });
 
-    var line = new graphic.Polyline({
-        shape: {
-            points: points
-        }
-    });
+        this.add(line);
 
-    this.add(line);
+        this._updateCommonStl(lineData, idx, seriesScope);
+    };
 
-    this._updateCommonStl(lineData, idx, seriesScope);
-};
+    updateData(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
+        var seriesModel = lineData.hostModel;
 
-polylineProto.updateData = function (lineData, idx, seriesScope) {
-    var seriesModel = lineData.hostModel;
+        var line = this.childAt(0) as graphic.Polyline;
+        var target = {
+            shape: {
+                points: lineData.getItemLayout(idx) as number[][]
+            }
+        };
+        graphic.updateProps(line, target, seriesModel, idx);
 
-    var line = this.childAt(0);
-    var target = {
-        shape: {
-            points: lineData.getItemLayout(idx)
-        }
+        this._updateCommonStl(lineData, idx, seriesScope);
     };
-    graphic.updateProps(line, target, seriesModel, idx);
 
-    this._updateCommonStl(lineData, idx, seriesScope);
-};
+    _updateCommonStl(lineData: List, idx: number, seriesScope: LineDrawSeriesScope) {
+        var line = this.childAt(0) as graphic.Polyline;
+        var itemModel = lineData.getItemModel<LineDrawModelOption>(idx);
 
-polylineProto._updateCommonStl = function (lineData, idx, seriesScope) {
-    var line = this.childAt(0);
-    var itemModel = lineData.getItemModel(idx);
+        var visualColor = lineData.getItemVisual(idx, 'color');
 
-    var visualColor = lineData.getItemVisual(idx, 'color');
+        var lineStyle = seriesScope && seriesScope.lineStyle;
+        var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;
 
-    var lineStyle = seriesScope && seriesScope.lineStyle;
-    var hoverLineStyle = seriesScope && seriesScope.hoverLineStyle;
+        if (!seriesScope || lineData.hasItemOption) {
+            lineStyle = itemModel.getModel('lineStyle').getLineStyle();
+            hoverLineStyle = itemModel.getModel(['emphasis', 'lineStyle']).getLineStyle();
+        }
+        line.useStyle(zrUtil.defaults(
+            {
+                strokeNoScale: true,
+                fill: 'none',
+                stroke: visualColor
+            },
+            lineStyle
+        ));
+        line.hoverStyle = hoverLineStyle;
+
+        graphic.setHoverStyle(this);
+    };
 
-    if (!seriesScope || lineData.hasItemOption) {
-        lineStyle = itemModel.getModel('lineStyle').getLineStyle();
-        hoverLineStyle = itemModel.getModel('emphasis.lineStyle').getLineStyle();
-    }
-    line.useStyle(zrUtil.defaults(
-        {
-            strokeNoScale: true,
-            fill: 'none',
-            stroke: visualColor
-        },
-        lineStyle
-    ));
-    line.hoverStyle = hoverLineStyle;
-
-    graphic.setHoverStyle(this);
-};
-
-polylineProto.updateLayout = function (lineData, idx) {
-    var polyline = this.childAt(0);
-    polyline.setShape('points', lineData.getItemLayout(idx));
-};
-
-zrUtil.inherits(Polyline, graphic.Group);
+    updateLayout(lineData: List, idx: number) {
+        var polyline = this.childAt(0) as graphic.Polyline;
+        polyline.setShape('points', lineData.getItemLayout(idx));
+    };
+
+}
 
 export default Polyline;
\ No newline at end of file
diff --git a/src/chart/helper/Symbol.ts b/src/chart/helper/Symbol.ts
index b9bc623..d51da2a 100644
--- a/src/chart/helper/Symbol.ts
+++ b/src/chart/helper/Symbol.ts
@@ -23,11 +23,10 @@ import * as graphic from '../../util/graphic';
 import {parsePercent} from '../../util/number';
 import {getDefaultLabel} from './labelHelper';
 import List from '../../data/List';
-import { StyleProps } from 'zrender/src/graphic/Style';
-import { LabelOption, ItemStyleOption, ColorString, DisplayState } from '../../util/types';
-import Model from '../../model/Model';
+import { DisplayState } from '../../util/types';
 import SeriesModel from '../../model/Series';
 import { PathProps } from 'zrender/src/graphic/Path';
+import { SymbolDrawSeriesScope, SymbolDrawItemModelOption } from './SymbolDraw';
 
 // Update common properties
 const normalStyleAccessPath = ['itemStyle'] as const;
@@ -41,20 +40,6 @@ type ECSymbol = ReturnType<typeof createSymbol> & {
     highDownOnUpdate(fromState: DisplayState, toState: DisplayState): void
 }
 
-export interface SeriesScope {
-    itemStyle?: StyleProps
-    hoverItemStyle?: StyleProps
-    symbolRotate?: number
-    symbolOffset?: [number, number]
-    labelModel?: Model<LabelOption>
-    hoverLabelModel?: Model<LabelOption>
-    hoverAnimation?: boolean
-    itemModel?: Model<ItemStyleOption>
-    symbolInnerColor?: ColorString
-    cursorStyle?: string
-    fadeIn?: boolean
-    useNameLabel?: boolean
-}
 class Symbol extends graphic.Group {
 
     dataIndex: number
@@ -63,7 +48,7 @@ class Symbol extends graphic.Group {
 
     private _symbolType: string
 
-    constructor(data: List, idx: number, seriesScope?: SeriesScope) {
+    constructor(data: List, idx: number, seriesScope?: SymbolDrawSeriesScope) {
         super();
         this.updateData(data, idx, seriesScope);
     }
@@ -165,7 +150,7 @@ class Symbol extends graphic.Group {
     /**
      * Update symbol properties
      */
-    updateData(data: List, idx: number, seriesScope?: SeriesScope) {
+    updateData(data: List, idx: number, seriesScope?: SymbolDrawSeriesScope) {
         this.silent = false;
 
         var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';
@@ -211,7 +196,7 @@ class Symbol extends graphic.Group {
         data: List,
         idx: number,
         symbolSize: number[],
-        seriesScope?: SeriesScope
+        seriesScope?: SymbolDrawSeriesScope
     ) {
         var symbolPath = this.childAt(0) as ECSymbol;
         var seriesModel = data.hostModel as SeriesModel;
@@ -244,7 +229,7 @@ class Symbol extends graphic.Group {
 
         if (!seriesScope || data.hasItemOption) {
             var itemModel = (seriesScope && seriesScope.itemModel)
-                ? seriesScope.itemModel : data.getItemModel(idx);
+                ? seriesScope.itemModel : data.getItemModel<SymbolDrawItemModelOption>(idx);
 
             // Color must be excluded.
             // Because symbol provide setColor individually to set fill and stroke
diff --git a/src/chart/helper/SymbolDraw.ts b/src/chart/helper/SymbolDraw.ts
index 4eccd20..8547efd 100644
--- a/src/chart/helper/SymbolDraw.ts
+++ b/src/chart/helper/SymbolDraw.ts
@@ -18,12 +18,22 @@
 */
 
 import * as graphic from '../../util/graphic';
-import SymbolClz, {SeriesScope} from './Symbol';
+import SymbolClz from './Symbol';
 import { isObject } from 'zrender/src/core/util';
 import List from '../../data/List';
 import type Displayable from 'zrender/src/graphic/Displayable';
-import { StageHandlerProgressParams } from '../../util/types';
+import {
+    StageHandlerProgressParams,
+    LabelOption,
+    ColorString,
+    SymbolOptionMixin,
+    ItemStyleOption,
+    ZRColor,
+    AnimationOptionMixin
+} from '../../util/types';
 import { CoordinateSystemClipArea } from '../../coord/CoordinateSystem';
+import { StyleProps } from 'zrender/src/graphic/Style';
+import Model from '../../model/Model';
 
 interface UpdateOpt {
     isIgnore?(idx: number): boolean
@@ -31,12 +41,12 @@ interface UpdateOpt {
 }
 
 interface SymbolLike extends graphic.Group {
-    updateData(data: List, idx: number, scope?: SeriesScope): void
+    updateData(data: List, idx: number, scope?: SymbolDrawSeriesScope): void
     fadeOut?(cb: () => void): void
 }
 
 interface SymbolLikeCtor {
-    new(data: List, idx: number, scope?: SeriesScope): SymbolLike
+    new(data: List, idx: number, scope?: SymbolDrawSeriesScope): SymbolLike
 }
 
 function symbolNeedsDraw(data: List, point: number[], idx: number, opt: UpdateOpt) {
@@ -56,8 +66,49 @@ function normalizeUpdateOpt(opt: UpdateOpt) {
     return opt || {};
 }
 
+interface RippleEffectOption {
+    period?: number
+    /**
+     * Scale of ripple
+     */
+    scale?: number
+
+    brushType?: 'fill' | 'stroke'
+
+    color?: ZRColor
+}
+
+// TODO Separate series and item?
+export interface SymbolDrawItemModelOption extends SymbolOptionMixin {
+    itemStyle?: ItemStyleOption
+    label?: LabelOption
+    emphasis?: {
+        itemStyle?: ItemStyleOption
+        label?: LabelOption
+    }
+    hoverAnimation?: boolean
+    cursor?: string
+
+    // If has ripple effect
+    rippleEffect?: RippleEffectOption
+}
 
-function makeSeriesScope(data: List): SeriesScope {
+export interface SymbolDrawSeriesScope {
+    itemStyle?: StyleProps
+    hoverItemStyle?: StyleProps
+    symbolRotate?: number
+    symbolOffset?: number[]
+    labelModel?: Model<LabelOption>
+    hoverLabelModel?: Model<LabelOption>
+    hoverAnimation?: boolean
+    itemModel?: Model<SymbolDrawItemModelOption>
+    symbolInnerColor?: ColorString
+    cursorStyle?: string
+    fadeIn?: boolean
+    useNameLabel?: boolean
+}
+
+function makeSeriesScope(data: List): SymbolDrawSeriesScope {
     var seriesModel = data.hostModel;
     return {
         itemStyle: seriesModel.getModel('itemStyle').getItemStyle(['color']),
@@ -71,14 +122,16 @@ function makeSeriesScope(data: List): SeriesScope {
     };
 }
 
+type ListForSymbolDraw = List<Model<SymbolDrawItemModelOption & AnimationOptionMixin>>
+
 class SymbolDraw {
     group = new graphic.Group();
 
-    private _data: List
+    private _data: ListForSymbolDraw
 
     private _SymbolCtor: SymbolLikeCtor
 
-    private _seriesScope: SeriesScope
+    private _seriesScope: SymbolDrawSeriesScope
 
     constructor(SymbolCtor?: SymbolLikeCtor) {
         this._SymbolCtor = SymbolCtor || SymbolClz;
@@ -87,7 +140,7 @@ class SymbolDraw {
     /**
      * Update symbols draw by new data
      */
-    updateData(data: List, opt?: UpdateOpt) {
+    updateData(data: ListForSymbolDraw, opt?: UpdateOpt) {
         opt = normalizeUpdateOpt(opt);
 
         var group = this.group;
@@ -162,7 +215,7 @@ class SymbolDraw {
         }
     };
 
-    incrementalPrepareUpdate(data: List) {
+    incrementalPrepareUpdate(data: ListForSymbolDraw) {
         this._seriesScope = makeSeriesScope(data);
         this._data = null;
         this.group.removeAll();
@@ -171,7 +224,7 @@ class SymbolDraw {
     /**
      * Update symbols draw by new data
      */
-    incrementalUpdate(taskParams: StageHandlerProgressParams, data: List, opt?: UpdateOpt) {
+    incrementalUpdate(taskParams: StageHandlerProgressParams, data: ListForSymbolDraw, opt?: UpdateOpt) {
         opt = normalizeUpdateOpt(opt);
 
         function updateIncrementalAndHover(el: Displayable) {
diff --git a/src/chart/lines/LinesSeries.ts b/src/chart/lines/LinesSeries.ts
index 40f79af..dfbb0c6 100644
--- a/src/chart/lines/LinesSeries.ts
+++ b/src/chart/lines/LinesSeries.ts
@@ -31,13 +31,13 @@ import {
     SeriesOnGeoOptionMixin,
     SeriesOnPolarOptionMixin,
     SeriesOnCalendarOptionMixin,
-    ColorString,
     SeriesLargeOptionMixin,
     LabelOption,
     LineStyleOption,
     OptionDataValue
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
+import type { LineDrawModelOption } from '../helper/LineDraw';
 
 var Uint32Arr = typeof Uint32Array === 'undefined' ? Array : Uint32Array;
 var Float64Arr = typeof Float64Array === 'undefined' ? Array : Float64Array;
@@ -113,28 +113,7 @@ export interface LinesSeriesOption extends SeriesOption,
     symbol?: string[] | string
     symbolSize?: number[] | number
 
-    effect?: {
-        show?: boolean
-        period?: number
-        delay?: number | ((idx: number) => number)
-        /**
-         * If move with constant speed px/sec
-         * period will be ignored if this property is > 0,
-         */
-        constantSpeed?: number
-
-        symbol?: string
-        symbolSize?: number | number[]
-        loop?: boolean
-        /**
-         * Length of trail, 0 - 1
-         */
-        trailLength?: number
-        /**
-         * Default to be same with lineStyle.color
-         */
-        color?: ColorString
-    }
+    effect?: LineDrawModelOption['effect']
 
     /**
      * If lines are polyline
diff --git a/src/chart/lines/LinesView.ts b/src/chart/lines/LinesView.ts
index c9020c6..5a3e91e 100644
--- a/src/chart/lines/LinesView.ts
+++ b/src/chart/lines/LinesView.ts
@@ -17,10 +17,7 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import {__DEV__} from '../../config';
-import * as echarts from '../../echarts';
 import LineDraw from '../helper/LineDraw';
 import EffectLine from '../helper/EffectLine';
 import Line from '../helper/Line';
@@ -29,20 +26,35 @@ import EffectPolyline from '../helper/EffectPolyline';
 import LargeLineDraw from '../helper/LargeLineDraw';
 import linesLayout from './linesLayout';
 import {createClipPath} from '../helper/createClipPathFromCoordSys';
+import ChartView from '../../view/Chart';
+import LinesSeriesModel from './LinesSeries';
+import GlobalModel from '../../model/Global';
+import ExtensionAPI from '../../ExtensionAPI';
+import CanvasPainter from 'zrender/src/canvas/Painter';
+import { StageHandlerProgressParams, StageHandlerProgressExecutor } from '../../util/types';
+import List from '../../data/List';
+
+class LinesView extends ChartView {
+
+    static readonly type = 'lines'
+    readonly type = LinesView.type
 
-export default echarts.extendChartView({
+    private _lastZlevel: number
+    private _finished: boolean
 
-    type: 'lines',
+    private _lineDraw: LineDraw | LargeLineDraw
 
-    init: function () {},
+    private _hasEffet: boolean
+    private _isPolyline: boolean
+    private _isLargeDraw: boolean
 
-    render: function (seriesModel, ecModel, api) {
+    render(seriesModel: LinesSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) {
         var data = seriesModel.getData();
 
         var lineDraw = this._updateLineDraw(data, seriesModel);
 
         var zlevel = seriesModel.get('zlevel');
-        var trailLength = seriesModel.get('effect.trailLength');
+        var trailLength = seriesModel.get(['effect', 'trailLength']);
 
         var zr = api.getZr();
         // Avoid the drag cause ghost shadow
@@ -50,7 +62,7 @@ export default echarts.extendChartView({
         // SVG doesn't support
         var isSvg = zr.painter.getType() === 'svg';
         if (!isSvg) {
-            zr.painter.getLayer(zlevel).clear(true);
+            (zr.painter as CanvasPainter).getLayer(zlevel).clear(true);
         }
         // Config layer with motion blur
         if (this._lastZlevel != null && !isSvg) {
@@ -77,7 +89,7 @@ export default echarts.extendChartView({
             }
         }
 
-        lineDraw.updateData(data);
+        lineDraw.updateData(data as List);
 
         var clipPath = seriesModel.get('clip', true) && createClipPath(
             seriesModel.coordinateSystem, false, seriesModel
@@ -92,9 +104,9 @@ export default echarts.extendChartView({
         this._lastZlevel = zlevel;
 
         this._finished = true;
-    },
+    }
 
-    incrementalPrepareRender: function (seriesModel, ecModel, api) {
+    incrementalPrepareRender(seriesModel: LinesSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) {
         var data = seriesModel.getData();
 
         var lineDraw = this._updateLineDraw(data, seriesModel);
@@ -104,15 +116,19 @@ export default echarts.extendChartView({
         this._clearLayer(api);
 
         this._finished = false;
-    },
+    }
 
-    incrementalRender: function (taskParams, seriesModel, ecModel) {
+    incrementalRender(
+        taskParams: StageHandlerProgressParams,
+        seriesModel: LinesSeriesModel,
+        ecModel: GlobalModel
+    ) {
         this._lineDraw.incrementalUpdate(taskParams, seriesModel.getData());
 
         this._finished = taskParams.end === seriesModel.getData().count();
-    },
+    }
 
-    updateTransform: function (seriesModel, ecModel, api) {
+    updateTransform(seriesModel: LinesSeriesModel, ecModel: GlobalModel, api: ExtensionAPI) {
         var data = seriesModel.getData();
         var pipelineContext = seriesModel.pipelineContext;
 
@@ -120,21 +136,26 @@ export default echarts.extendChartView({
             // TODO Don't have to do update in large mode. Only do it when there are millions of data.
             return {
                 update: true
-            };
+            } as const;
         }
         else {
             // TODO Use same logic with ScatterView.
             // Manually update layout
-            var res = linesLayout.reset(seriesModel);
+            var res = linesLayout.reset(seriesModel, ecModel, api) as StageHandlerProgressExecutor;
             if (res.progress) {
-                res.progress({ start: 0, end: data.count() }, data);
+                res.progress({
+                    start: 0,
+                    end: data.count(),
+                    count: data.count()
+                }, data);
             }
-            this._lineDraw.updateLayout();
+            // Not in large mode
+            (this._lineDraw as LineDraw).updateLayout();
             this._clearLayer(api);
         }
-    },
+    }
 
-    _updateLineDraw: function (data, seriesModel) {
+    _updateLineDraw(data: List, seriesModel: LinesSeriesModel) {
         var lineDraw = this._lineDraw;
         var hasEffect = this._showEffect(seriesModel);
         var isPolyline = !!seriesModel.get('polyline');
@@ -170,27 +191,30 @@ export default echarts.extendChartView({
         this.group.add(lineDraw.group);
 
         return lineDraw;
-    },
+    }
 
-    _showEffect: function (seriesModel) {
-        return !!seriesModel.get('effect.show');
-    },
+    private _showEffect(seriesModel: LinesSeriesModel) {
+        return !!seriesModel.get(['effect', 'show']);
+    }
 
-    _clearLayer: function (api) {
+    _clearLayer(api: ExtensionAPI) {
         // Not use motion when dragging or zooming
         var zr = api.getZr();
         var isSvg = zr.painter.getType() === 'svg';
         if (!isSvg && this._lastZlevel != null) {
-            zr.painter.getLayer(this._lastZlevel).clear(true);
+            (zr.painter as CanvasPainter).getLayer(this._lastZlevel).clear(true);
         }
-    },
+    }
 
-    remove: function (ecModel, api) {
+    remove(ecModel: GlobalModel, api: ExtensionAPI) {
         this._lineDraw && this._lineDraw.remove();
         this._lineDraw = null;
         // Clear motion when lineDraw is removed
         this._clearLayer(api);
-    },
+    }
+
+}
+
+ChartView.registerClass(LinesView);
 
-    dispose: function () {}
-});
+export default LinesView;
\ No newline at end of file
diff --git a/src/model/Series.ts b/src/model/Series.ts
index 027614c..27f2de6 100644
--- a/src/model/Series.ts
+++ b/src/model/Series.ts
@@ -257,7 +257,7 @@ class SeriesModel<Opt extends SeriesOption = SeriesOption> extends ComponentMode
      * data in the stream procedure. So we fetch data from upstream
      * each time `task.perform` called.
      */
-    getData(dataType?: string): List<SeriesModel<Opt>> {
+    getData(dataType?: string): List<this> {
         var task = getCurrentTask(this);
         if (task) {
             var data = task.context.data;
@@ -268,7 +268,7 @@ class SeriesModel<Opt extends SeriesOption = SeriesOption> extends ComponentMode
             // restore or setOption with not merge mode), series data may
             // be still need to judge animation or something when graphic
             // elements want to know whether fade out.
-            return inner(this).data as List<SeriesModel<Opt>>;
+            return inner(this).data as List<this>;
         }
     }
 


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