You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2021/08/28 09:36:39 UTC

[echarts] branch release-dev updated (6083ce5 -> fd9bf4a)

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

sushuang pushed a change to branch release-dev
in repository https://gitbox.apache.org/repos/asf/echarts.git.


    from 6083ce5  fix: fix lint.
     add 5fb2fab  Merge pull request #15618 from apache/release-dev
     new fd9bf4a  release 5.2.0

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 dist/echarts.common.js          | 12552 ++++++-------
 dist/echarts.common.js.map      |     2 +-
 dist/echarts.common.min.js      |     4 +-
 dist/echarts.esm.js             | 36040 +++++++++++++++++++------------------
 dist/echarts.esm.js.map         |     2 +-
 dist/echarts.esm.min.js         |     4 +-
 dist/echarts.js                 | 36041 ++++++++++++++++++++------------------
 dist/echarts.js.map             |     2 +-
 dist/echarts.min.js             |     4 +-
 dist/echarts.simple.js          | 11727 +++++++------
 dist/echarts.simple.js.map      |     2 +-
 dist/echarts.simple.min.js      |     4 +-
 package-lock.json               |     8 +-
 package.json                    |     4 +-
 src/core/echarts.ts             |     4 +-
 src/label/installLabelLayout.ts |    20 +
 src/label/sectorLabel.ts        |    20 +
 17 files changed, 50780 insertions(+), 45660 deletions(-)

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


[echarts] 01/01: release 5.2.0

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit fd9bf4affc8e0b59563340969aa1c158314f973f
Author: sushuang <su...@gmail.com>
AuthorDate: Sat Aug 28 17:34:19 2021 +0800

    release 5.2.0
---
 dist/echarts.common.js          | 12552 ++++++-------
 dist/echarts.common.js.map      |     2 +-
 dist/echarts.common.min.js      |     4 +-
 dist/echarts.esm.js             | 36040 +++++++++++++++++++------------------
 dist/echarts.esm.js.map         |     2 +-
 dist/echarts.esm.min.js         |     4 +-
 dist/echarts.js                 | 36041 ++++++++++++++++++++------------------
 dist/echarts.js.map             |     2 +-
 dist/echarts.min.js             |     4 +-
 dist/echarts.simple.js          | 11727 +++++++------
 dist/echarts.simple.js.map      |     2 +-
 dist/echarts.simple.min.js      |     4 +-
 package-lock.json               |     8 +-
 package.json                    |     4 +-
 src/core/echarts.ts             |     4 +-
 src/label/installLabelLayout.ts |    20 +
 src/label/sectorLabel.ts        |    20 +
 17 files changed, 50780 insertions(+), 45660 deletions(-)

diff --git a/dist/echarts.common.js b/dist/echarts.common.js
index 3aa78e6..2036b13 100644
--- a/dist/echarts.common.js
+++ b/dist/echarts.common.js
@@ -48,6 +48,8 @@
     };
 
     function __extends(d, b) {
+        if (typeof b !== "function" && b !== null)
+            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
         extendStatics(d, b);
         function __() { this.constructor = d; }
         d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
@@ -64,12 +66,14 @@
         return __assign.apply(this, arguments);
     };
 
-    function __spreadArrays() {
-        for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
-        for (var r = Array(s), k = 0, i = 0; i < il; i++)
-            for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
-                r[k] = a[j];
-        return r;
+    function __spreadArray(to, from, pack) {
+        if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
+            if (ar || !(i in from)) {
+                if (!ar) ar = Array.prototype.slice.call(from, 0, i);
+                ar[i] = from[i];
+            }
+        }
+        return to.concat(ar || from);
     }
 
     var Browser = (function () {
@@ -1026,13 +1030,16 @@
             return this;
         };
         Eventful.prototype.triggerWithContext = function (type) {
+            var args = [];
+            for (var _i = 1; _i < arguments.length; _i++) {
+                args[_i - 1] = arguments[_i];
+            }
             if (!this._$handlers) {
                 return this;
             }
             var _h = this._$handlers[type];
             var eventProcessor = this._$eventProcessor;
             if (_h) {
-                var args = arguments;
                 var argLen = args.length;
                 var ctx = args[argLen - 1];
                 var len = _h.length;
@@ -3291,7 +3298,10 @@
             }
         };
         Track.prototype.needsAnimate = function () {
-            return !this._isAllValueEqual && this.keyframes.length >= 2 && this.interpolable;
+            return !this._isAllValueEqual
+                && this.keyframes.length >= 2
+                && this.interpolable
+                && this.maxTime > 0;
         };
         Track.prototype.getAdditiveTrack = function () {
             return this._additiveTrack;
@@ -3397,8 +3407,8 @@
                 for (var i = 0; i < kfsLen; i++) {
                     if (arrDim === 0) {
                         if (this.isValueColor) {
-                            kfs[i].additiveValue
-                                = add1DArray([], kfs[i].value, startValue, -1);
+                            kfs[i].additiveValue =
+                                add1DArray([], kfs[i].value, startValue, -1);
                         }
                         else {
                             kfs[i].additiveValue = kfs[i].value - startValue;
@@ -3624,7 +3634,7 @@
         Animator.prototype._doneCallback = function () {
             this._setTracksFinished();
             this._clip = null;
-            var doneList = this._doneList;
+            var doneList = this._doneCbs;
             if (doneList) {
                 var len = doneList.length;
                 for (var i = 0; i < len; i++) {
@@ -3635,7 +3645,7 @@
         Animator.prototype._abortedCallback = function () {
             this._setTracksFinished();
             var animation = this.animation;
-            var abortedList = this._abortedList;
+            var abortedList = this._abortedCbs;
             if (animation) {
                 animation.removeClip(this._clip);
             }
@@ -3712,7 +3722,7 @@
                         for (var i = 0; i < tracks.length; i++) {
                             tracks[i].step(self._target, percent);
                         }
-                        var onframeList = self._onframeList;
+                        var onframeList = self._onframeCbs;
                         if (onframeList) {
                             for (var i = 0; i < onframeList.length; i++) {
                                 onframeList[i](self._target, percent);
@@ -3752,28 +3762,28 @@
         };
         Animator.prototype.during = function (cb) {
             if (cb) {
-                if (!this._onframeList) {
-                    this._onframeList = [];
+                if (!this._onframeCbs) {
+                    this._onframeCbs = [];
                 }
-                this._onframeList.push(cb);
+                this._onframeCbs.push(cb);
             }
             return this;
         };
         Animator.prototype.done = function (cb) {
             if (cb) {
-                if (!this._doneList) {
-                    this._doneList = [];
+                if (!this._doneCbs) {
+                    this._doneCbs = [];
                 }
-                this._doneList.push(cb);
+                this._doneCbs.push(cb);
             }
             return this;
         };
         Animator.prototype.aborted = function (cb) {
             if (cb) {
-                if (!this._abortedList) {
-                    this._abortedList = [];
+                if (!this._abortedCbs) {
+                    this._abortedCbs = [];
                 }
-                this._abortedList.push(cb);
+                this._abortedCbs.push(cb);
             }
             return this;
         };
@@ -4420,6 +4430,9 @@
     var Transformable = (function () {
         function Transformable() {
         }
+        Transformable.prototype.getLocalTransform = function (m) {
+            return Transformable.getLocalTransform(this, m);
+        };
         Transformable.prototype.setPosition = function (arr) {
             this.x = arr[0];
             this.y = arr[1];
@@ -4444,11 +4457,10 @@
                 || isNotAroundZero(this.scaleY - 1);
         };
         Transformable.prototype.updateTransform = function () {
-            var parent = this.parent;
-            var parentHasTransform = parent && parent.transform;
+            var parentTransform = this.parent && this.parent.transform;
             var needLocalTransform = this.needLocalTransform();
             var m = this.transform;
-            if (!(needLocalTransform || parentHasTransform)) {
+            if (!(needLocalTransform || parentTransform)) {
                 m && mIdentity(m);
                 return;
             }
@@ -4459,12 +4471,12 @@
             else {
                 mIdentity(m);
             }
-            if (parentHasTransform) {
+            if (parentTransform) {
                 if (needLocalTransform) {
-                    mul$1(m, parent.transform, m);
+                    mul$1(m, parentTransform, m);
                 }
                 else {
-                    copy$1(m, parent.transform);
+                    copy$1(m, parentTransform);
                 }
             }
             this.transform = m;
@@ -4486,9 +4498,6 @@
             this.invTransform = this.invTransform || create$1();
             invert(this.invTransform, m);
         };
-        Transformable.prototype.getLocalTransform = function (m) {
-            return Transformable.getLocalTransform(this, m);
-        };
         Transformable.prototype.getComputedTransform = function () {
             var transformNode = this;
             var ancestors = [];
@@ -4583,6 +4592,13 @@
                 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1]))
                 : 1;
         };
+        Transformable.prototype.copyTransform = function (source) {
+            var target = this;
+            for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) {
+                var propName = TRANSFORMABLE_PROPS[i];
+                target[propName] = source[propName];
+            }
+        };
         Transformable.getLocalTransform = function (target, m) {
             m = m || [];
             var ox = target.originX || 0;
@@ -4625,6 +4641,9 @@
         })();
         return Transformable;
     }());
+    var TRANSFORMABLE_PROPS = [
+        'x', 'y', 'originX', 'originY', 'rotation', 'scaleX', 'scaleY', 'skewX', 'skewY'
+    ];
 
     var Point = (function () {
         function Point(x, y) {
@@ -5207,24 +5226,13 @@
                 }
                 var textConfig = this.textConfig;
                 var isLocal = textConfig.local;
-                var attachedTransform = textEl.attachedTransform;
+                var innerTransformable = textEl.innerTransformable;
                 var textAlign = void 0;
                 var textVerticalAlign = void 0;
                 var textStyleChanged = false;
-                if (isLocal) {
-                    attachedTransform.parent = this;
-                }
-                else {
-                    attachedTransform.parent = null;
-                }
+                innerTransformable.parent = isLocal ? this : null;
                 var innerOrigin = false;
-                attachedTransform.x = textEl.x;
-                attachedTransform.y = textEl.y;
-                attachedTransform.originX = textEl.originX;
-                attachedTransform.originY = textEl.originY;
-                attachedTransform.rotation = textEl.rotation;
-                attachedTransform.scaleX = textEl.scaleX;
-                attachedTransform.scaleY = textEl.scaleY;
+                innerTransformable.copyTransform(textEl);
                 if (textConfig.position != null) {
                     var layoutRect = tmpBoundingRect;
                     if (textConfig.layoutRect) {
@@ -5242,8 +5250,8 @@
                     else {
                         calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
                     }
-                    attachedTransform.x = tmpTextPosCalcRes.x;
-                    attachedTransform.y = tmpTextPosCalcRes.y;
+                    innerTransformable.x = tmpTextPosCalcRes.x;
+                    innerTransformable.y = tmpTextPosCalcRes.y;
                     textAlign = tmpTextPosCalcRes.align;
                     textVerticalAlign = tmpTextPosCalcRes.verticalAlign;
                     var textOrigin = textConfig.origin;
@@ -5259,20 +5267,20 @@
                             relOriginY = parsePercent(textOrigin[1], layoutRect.height);
                         }
                         innerOrigin = true;
-                        attachedTransform.originX = -attachedTransform.x + relOriginX + (isLocal ? 0 : layoutRect.x);
-                        attachedTransform.originY = -attachedTransform.y + relOriginY + (isLocal ? 0 : layoutRect.y);
+                        innerTransformable.originX = -innerTransformable.x + relOriginX + (isLocal ? 0 : layoutRect.x);
+                        innerTransformable.originY = -innerTransformable.y + relOriginY + (isLocal ? 0 : layoutRect.y);
                     }
                 }
                 if (textConfig.rotation != null) {
-                    attachedTransform.rotation = textConfig.rotation;
+                    innerTransformable.rotation = textConfig.rotation;
                 }
                 var textOffset = textConfig.offset;
                 if (textOffset) {
-                    attachedTransform.x += textOffset[0];
-                    attachedTransform.y += textOffset[1];
+                    innerTransformable.x += textOffset[0];
+                    innerTransformable.y += textOffset[1];
                     if (!innerOrigin) {
-                        attachedTransform.originX = -textOffset[0];
-                        attachedTransform.originY = -textOffset[1];
+                        innerTransformable.originX = -textOffset[0];
+                        innerTransformable.originY = -textOffset[1];
                     }
                 }
                 var isInside = textConfig.inside == null
@@ -5719,7 +5727,7 @@
             if (textEl.__zr && !textEl.__hostTarget) {
                 throw new Error('Text element has been added to zrender.');
             }
-            textEl.attachedTransform = new Transformable();
+            textEl.innerTransformable = new Transformable();
             this._attachComponent(textEl);
             this._textContent = textEl;
             this.markRedraw();
@@ -5738,7 +5746,7 @@
         Element.prototype.removeTextContent = function () {
             var textEl = this._textContent;
             if (textEl) {
-                textEl.attachedTransform = null;
+                textEl.innerTransformable = null;
                 this._detachComponent(textEl);
                 this._textContent = null;
                 this._innerTextDefaultStyle = null;
@@ -5794,6 +5802,9 @@
             }
         };
         Element.prototype.addSelfToZr = function (zr) {
+            if (this.__zr === zr) {
+                return;
+            }
             this.__zr = zr;
             var animators = this.animators;
             if (animators) {
@@ -5812,6 +5823,9 @@
             }
         };
         Element.prototype.removeSelfFromZr = function (zr) {
+            if (!this.__zr) {
+                return;
+            }
             this.__zr = null;
             var animators = this.animators;
             if (animators) {
@@ -6204,6 +6218,13 @@
             }
             return this;
         };
+        Group.prototype.replace = function (oldChild, newChild) {
+            var idx = indexOf(this._children, oldChild);
+            if (idx >= 0) {
+                this.replaceAt(newChild, idx);
+            }
+            return this;
+        };
         Group.prototype.replaceAt = function (child, index) {
             var children = this._children;
             var old = children[index];
@@ -6572,7 +6593,7 @@
     function registerPainter(name, Ctor) {
         painterCtors[name] = Ctor;
     }
-    var version = '5.1.1';
+    var version = '5.2.0';
 
     var zrender = /*#__PURE__*/Object.freeze({
         __proto__: null,
@@ -6891,7 +6912,7 @@
         if (!match[8]) {
           // match[n] can only be string or undefined.
           // But take care of '12' + 1 => '121'.
-          return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, +match[7] || 0);
+          return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0);
         } // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,
         // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).
         // For example, system timezone is set as "Time Zone: America/Toronto",
@@ -6906,7 +6927,7 @@
               hour -= +match[8].slice(0, 3);
             }
 
-            return new Date(Date.UTC(+match[1], +(match[2] || 1) - 1, +match[3] || 1, hour, +(match[5] || 0), +match[6] || 0, +match[7] || 0));
+            return new Date(Date.UTC(+match[1], +(match[2] || 1) - 1, +match[3] || 1, hour, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0));
           }
       } else if (value == null) {
         return new Date(NaN);
@@ -7880,7 +7901,7 @@
         for (var i = 0; i < length_1; ++i) {
           var info = data.getDimensionInfo(i); // Don't interpolate ordinal dims
 
-          if (info.type === 'ordinal') {
+          if (info && info.type === 'ordinal') {
             // In init, there is no `sourceValue`, but should better not to get undefined result.
             interpolated[i] = (percent < 1 && leftArr ? leftArr : rightArr)[i];
           } else {
@@ -7972,7 +7993,7 @@
               superClass.apply(this, arguments);
             } else {
               var ins = createObject( // @ts-ignore
-              ExtendedClass.prototype, new (superClass.bind.apply(superClass, __spreadArrays([void 0], args)))());
+              ExtendedClass.prototype, new (superClass.bind.apply(superClass, __spreadArray([void 0], args)))());
               return ins;
             }
           } else {
@@ -9692,6 +9713,7 @@
             return this;
         };
         PathProxy.prototype.bezierCurveTo = function (x1, y1, x2, y2, x3, y3) {
+            this._drawPendingPt();
             this.addData(CMD.C, x1, y1, x2, y2, x3, y3);
             if (this._ctx) {
                 this._needsDash ? this._dashedBezierTo(x1, y1, x2, y2, x3, y3)
@@ -9702,6 +9724,7 @@
             return this;
         };
         PathProxy.prototype.quadraticCurveTo = function (x1, y1, x2, y2) {
+            this._drawPendingPt();
             this.addData(CMD.Q, x1, y1, x2, y2);
             if (this._ctx) {
                 this._needsDash ? this._dashedQuadraticTo(x1, y1, x2, y2)
@@ -9712,6 +9735,7 @@
             return this;
         };
         PathProxy.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) {
+            this._drawPendingPt();
             tmpAngles[0] = startAngle;
             tmpAngles[1] = endAngle;
             normalizeArcAngles(tmpAngles, anticlockwise);
@@ -9725,12 +9749,14 @@
             return this;
         };
         PathProxy.prototype.arcTo = function (x1, y1, x2, y2, radius) {
+            this._drawPendingPt();
             if (this._ctx) {
                 this._ctx.arcTo(x1, y1, x2, y2, radius);
             }
             return this;
         };
         PathProxy.prototype.rect = function (x, y, w, h) {
+            this._drawPendingPt();
             this._ctx && this._ctx.rect(x, y, w, h);
             this.addData(CMD.R, x, y, w, h);
             return this;
@@ -10174,12 +10200,12 @@
                     x0 = xi;
                     y0 = yi;
                 }
+                if (cmd !== CMD.L && pendingPtDist > 0) {
+                    ctx.lineTo(pendingPtX, pendingPtY);
+                    pendingPtDist = 0;
+                }
                 switch (cmd) {
                     case CMD.M:
-                        if (pendingPtDist > 0) {
-                            ctx.lineTo(pendingPtX, pendingPtY);
-                            pendingPtDist = 0;
-                        }
                         x0 = xi = d[i++];
                         y0 = yi = d[i++];
                         ctx.moveTo(xi, yi);
@@ -10327,10 +10353,6 @@
                         ctx.rect(x, y, width, height);
                         break;
                     case CMD.Z:
-                        if (pendingPtDist > 0) {
-                            ctx.lineTo(pendingPtX, pendingPtY);
-                            pendingPtDist = 0;
-                        }
                         if (drawPart) {
                             var l = pathSegLen[segCount++];
                             if (accumLength + l > displayedLength) {
@@ -10346,6 +10368,14 @@
                 }
             }
         };
+        PathProxy.prototype.clone = function () {
+            var newProxy = new PathProxy();
+            var data = this.data;
+            newProxy.data = data.slice ? data.slice()
+                : Array.prototype.slice.call(data);
+            newProxy._len = this._len;
+            return newProxy;
+        };
         PathProxy.CMD = CMD;
         PathProxy.initDefaultProps = (function () {
             var proto = PathProxy.prototype;
@@ -10914,10 +10944,16 @@
                 }
             }
         };
-        Path.prototype.buildPath = function (ctx, shapeCfg, inBundle) { };
+        Path.prototype.buildPath = function (ctx, shapeCfg, inBatch) { };
         Path.prototype.pathUpdated = function () {
             this.__dirty &= ~SHAPE_CHANGED_BIT;
         };
+        Path.prototype.getUpdatedPathProxy = function (inBatch) {
+            !this.path && this.createPathProxy();
+            this.path.beginPath();
+            this.buildPath(this.path, this.shape, inBatch);
+            return this.path;
+        };
         Path.prototype.createPathProxy = function () {
             this.path = new PathProxy(false);
         };
@@ -11513,6 +11549,7 @@
             return this._children;
         };
         ZRText.prototype.update = function () {
+            _super.prototype.update.call(this);
             if (this.styleChanged()) {
                 this._updateSubTexts();
             }
@@ -11525,29 +11562,31 @@
                 child.cursor = this.cursor;
                 child.invisible = this.invisible;
             }
-            var attachedTransform = this.attachedTransform;
-            if (attachedTransform) {
-                attachedTransform.updateTransform();
-                var m = attachedTransform.transform;
-                if (m) {
-                    this.transform = this.transform || [];
-                    copy$1(this.transform, m);
-                }
-                else {
-                    this.transform = null;
+        };
+        ZRText.prototype.updateTransform = function () {
+            var innerTransformable = this.innerTransformable;
+            if (innerTransformable) {
+                innerTransformable.updateTransform();
+                if (innerTransformable.transform) {
+                    this.transform = innerTransformable.transform;
                 }
             }
             else {
-                _super.prototype.update.call(this);
+                _super.prototype.updateTransform.call(this);
             }
         };
+        ZRText.prototype.getLocalTransform = function (m) {
+            var innerTransformable = this.innerTransformable;
+            return innerTransformable
+                ? innerTransformable.getLocalTransform(m)
+                : _super.prototype.getLocalTransform.call(this, m);
+        };
         ZRText.prototype.getComputedTransform = function () {
             if (this.__hostTarget) {
                 this.__hostTarget.getComputedTransform();
                 this.__hostTarget.updateInnerText(true);
             }
-            return this.attachedTransform ? this.attachedTransform.getComputedTransform()
-                : _super.prototype.getComputedTransform.call(this);
+            return _super.prototype.getComputedTransform.call(this);
         };
         ZRText.prototype._updateSubTexts = function () {
             this._childCursor = 0;
@@ -11816,7 +11855,7 @@
             var defaultStyle = this._defaultStyle;
             var useDefaultFill = false;
             var defaultLineWidth = 0;
-            var textFill = getStroke('fill' in tokenStyle ? tokenStyle.fill
+            var textFill = getFill('fill' in tokenStyle ? tokenStyle.fill
                 : 'fill' in style ? style.fill
                     : (useDefaultFill = true, defaultStyle.fill));
             var textStroke = getStroke('stroke' in tokenStyle ? tokenStyle.stroke
@@ -11863,7 +11902,7 @@
             var self = this;
             var rectEl;
             var imgEl;
-            if (isPlainOrGradientBg || (textBorderWidth && textBorderColor)) {
+            if (isPlainOrGradientBg || style.lineHeight || (textBorderWidth && textBorderColor)) {
                 rectEl = this._getOrCreateChild(Rect);
                 rectEl.useStyle(rectEl.createStyle());
                 rectEl.style.fill = null;
@@ -11989,10 +12028,30 @@
     }
     function needDrawBackground(style) {
         return !!(style.backgroundColor
+            || style.lineHeight
             || (style.borderWidth && style.borderColor));
     }
 
     var getECData = makeInner();
+    var setCommonECData = function (seriesIndex, dataType, dataIdx, el) {
+      if (el) {
+        var ecData = getECData(el); // Add data index and series index for indexing the data by element
+        // Useful in tooltip
+
+        ecData.dataIndex = dataIdx;
+        ecData.dataType = dataType;
+        ecData.seriesIndex = seriesIndex; // TODO: not store dataIndex on children.
+
+        if (el.type === 'group') {
+          el.traverse(function (child) {
+            var childECData = getECData(child);
+            childECData.seriesIndex = seriesIndex;
+            childECData.dataIndex = dataIdx;
+            childECData.dataType = dataType;
+          });
+        }
+      }
+    };
 
     var _highlightNextDigit = 1;
     var _highlightKeyMap = {};
@@ -12134,26 +12193,31 @@
         var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke;
 
         if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) {
-          state = state || {}; // Apply default color lift
+          state = state || {};
+          var emphasisStyle = state.style || {}; // inherit case
 
-          var emphasisStyle = state.style || {};
+          if (emphasisStyle.fill === 'inherit') {
+            cloned = true;
+            state = extend({}, state);
+            emphasisStyle = extend({}, emphasisStyle);
+            emphasisStyle.fill = fromFill;
+          } // Apply default color lift
+          else if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) {
+              cloned = true; // Not modify the original value.
 
-          if (!hasFillOrStroke(emphasisStyle.fill) && hasFillOrStroke(fromFill)) {
-            cloned = true; // Not modify the original value.
+              state = extend({}, state);
+              emphasisStyle = extend({}, emphasisStyle); // Already being applied 'emphasis'. DON'T lift color multiple times.
 
-            state = extend({}, state);
-            emphasisStyle = extend({}, emphasisStyle); // Already being applied 'emphasis'. DON'T lift color multiple times.
-
-            emphasisStyle.fill = liftColor(fromFill);
-          } // Not highlight stroke if fill has been highlighted.
-          else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) {
-              if (!cloned) {
-                state = extend({}, state);
-                emphasisStyle = extend({}, emphasisStyle);
-              }
+              emphasisStyle.fill = liftColor(fromFill);
+            } // Not highlight stroke if fill has been highlighted.
+            else if (!hasFillOrStroke(emphasisStyle.stroke) && hasFillOrStroke(fromStroke)) {
+                if (!cloned) {
+                  state = extend({}, state);
+                  emphasisStyle = extend({}, emphasisStyle);
+                }
 
-              emphasisStyle.stroke = liftColor(fromStroke);
-            }
+                emphasisStyle.stroke = liftColor(fromStroke);
+              }
 
           state.style = emphasisStyle;
         }
@@ -12686,6 +12750,9 @@
     var mathSqrt$2 = Math.sqrt;
     var mathAtan2 = Math.atan2;
     function transformPath(path, m) {
+        if (!m) {
+            return;
+        }
         var data = path.data;
         var len = path.len();
         var cmd;
@@ -13082,13 +13149,7 @@
         var len = pathEls.length;
         for (var i = 0; i < len; i++) {
             var pathEl = pathEls[i];
-            if (!pathEl.path) {
-                pathEl.createPathProxy();
-            }
-            if (pathEl.shapeChanged()) {
-                pathEl.buildPath(pathEl.path, pathEl.shape, true);
-            }
-            pathList.push(pathEl.path);
+            pathList.push(pathEl.getUpdatedPathProxy(true));
         }
         var pathBundle = new Path(opts);
         pathBundle.createPathProxy();
@@ -14116,195 +14177,66 @@
         return IncrementalDisplayable;
     }(Displayable));
 
-    var mathMax$4 = Math.max;
-    var mathMin$4 = Math.min;
-    var _customShapeMap = {};
-    /**
-     * Extend shape with parameters
-     */
-
-    function extendShape(opts) {
-      return Path.extend(opts);
-    }
-    var extendPathFromString = extendFromString;
-    /**
-     * Extend path
-     */
-
-    function extendPath(pathData, opts) {
-      return extendPathFromString(pathData, opts);
-    }
+    var transitionStore = makeInner();
     /**
-     * Register a user defined shape.
-     * The shape class can be fetched by `getShapeClass`
-     * This method will overwrite the registered shapes, including
-     * the registered built-in shapes, if using the same `name`.
-     * The shape can be used in `custom series` and
-     * `graphic component` by declaring `{type: name}`.
-     *
-     * @param name
-     * @param ShapeClass Can be generated by `extendShape`.
+     * Return null if animation is disabled.
      */
 
-    function registerShape(name, ShapeClass) {
-      _customShapeMap[name] = ShapeClass;
-    }
-    /**
-     * Find shape class registered by `registerShape`. Usually used in
-     * fetching user defined shape.
-     *
-     * [Caution]:
-     * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared
-     * to use user registered shapes.
-     * Because the built-in shape (see `getBuiltInShape`) will be registered by
-     * `registerShape` by default. That enables users to get both built-in
-     * shapes as well as the shapes belonging to themsleves. But users can overwrite
-     * the built-in shapes by using names like 'circle', 'rect' via calling
-     * `registerShape`. So the echarts inner featrues should not fetch shapes from here
-     * in case that it is overwritten by users, except that some features, like
-     * `custom series`, `graphic component`, do it deliberately.
-     *
-     * (2) In the features like `custom series`, `graphic component`, the user input
-     * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic
-     * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names
-     * are reserved names, that is, if some user register a shape named `'image'`,
-     * the shape will not be used. If we intending to add some more reserved names
-     * in feature, that might bring break changes (disable some existing user shape
-     * names). But that case probably rearly happen. So we dont make more mechanism
-     * to resolve this issue here.
-     *
-     * @param name
-     * @return The shape class. If not found, return nothing.
-     */
+    function getAnimationConfig(animationType, animatableModel, dataIndex, // Extra opts can override the option in animatable model.
+    extraOpts, // TODO It's only for pictorial bar now.
+    extraDelayParams) {
+      var animationPayload; // Check if there is global animation configuration from dataZoom/resize can override the config in option.
+      // If animation is enabled. Will use this animation config in payload.
+      // If animation is disabled. Just ignore it.
 
-    function getShapeClass(name) {
-      if (_customShapeMap.hasOwnProperty(name)) {
-        return _customShapeMap[name];
+      if (animatableModel && animatableModel.ecModel) {
+        var updatePayload = animatableModel.ecModel.getUpdatePayload();
+        animationPayload = updatePayload && updatePayload.animation;
       }
-    }
-    /**
-     * Create a path element from path data string
-     * @param pathData
-     * @param opts
-     * @param rect
-     * @param layout 'center' or 'cover' default to be cover
-     */
 
-    function makePath(pathData, opts, rect, layout) {
-      var path = createFromString(pathData, opts);
+      var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();
+      var isUpdate = animationType === 'update';
 
-      if (rect) {
-        if (layout === 'center') {
-          rect = centerGraphic(rect, path.getBoundingRect());
-        }
+      if (animationEnabled) {
+        var duration = void 0;
+        var easing = void 0;
+        var delay = void 0;
 
-        resizePath(path, rect);
-      }
+        if (extraOpts) {
+          duration = retrieve2(extraOpts.duration, 200);
+          easing = retrieve2(extraOpts.easing, 'cubicOut');
+          delay = 0;
+        } else {
+          duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration');
+          easing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing');
+          delay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay');
+        } // animation from payload has highest priority.
 
-      return path;
-    }
-    /**
-     * Create a image element from image url
-     * @param imageUrl image url
-     * @param opts options
-     * @param rect constrain rect
-     * @param layout 'center' or 'cover'. Default to be 'cover'
-     */
 
-    function makeImage(imageUrl, rect, layout) {
-      var zrImg = new ZRImage({
-        style: {
-          image: imageUrl,
-          x: rect.x,
-          y: rect.y,
-          width: rect.width,
-          height: rect.height
-        },
-        onload: function (img) {
-          if (layout === 'center') {
-            var boundingRect = {
-              width: img.width,
-              height: img.height
-            };
-            zrImg.setStyle(centerGraphic(rect, boundingRect));
-          }
+        if (animationPayload) {
+          animationPayload.duration != null && (duration = animationPayload.duration);
+          animationPayload.easing != null && (easing = animationPayload.easing);
+          animationPayload.delay != null && (delay = animationPayload.delay);
         }
-      });
-      return zrImg;
-    }
-    /**
-     * Get position of centered element in bounding box.
-     *
-     * @param  rect         element local bounding box
-     * @param  boundingRect constraint bounding box
-     * @return element position containing x, y, width, and height
-     */
-
-    function centerGraphic(rect, boundingRect) {
-      // Set rect to center, keep width / height ratio.
-      var aspect = boundingRect.width / boundingRect.height;
-      var width = rect.height * aspect;
-      var height;
-
-      if (width <= rect.width) {
-        height = rect.height;
-      } else {
-        width = rect.width;
-        height = width / aspect;
-      }
 
-      var cx = rect.x + rect.width / 2;
-      var cy = rect.y + rect.height / 2;
-      return {
-        x: cx - width / 2,
-        y: cy - height / 2,
-        width: width,
-        height: height
-      };
-    }
+        if (typeof delay === 'function') {
+          delay = delay(dataIndex, extraDelayParams);
+        }
 
-    var mergePath$1 = mergePath;
-    /**
-     * Resize a path to fit the rect
-     * @param path
-     * @param rect
-     */
+        if (typeof duration === 'function') {
+          duration = duration(dataIndex);
+        }
 
-    function resizePath(path, rect) {
-      if (!path.applyTransform) {
-        return;
+        var config = {
+          duration: duration || 0,
+          delay: delay,
+          easing: easing
+        };
+        return config;
+      } else {
+        return null;
       }
-
-      var pathRect = path.getBoundingRect();
-      var m = pathRect.calculateTransform(rect);
-      path.applyTransform(m);
-    }
-    /**
-     * Sub pixel optimize line for canvas
-     */
-
-    function subPixelOptimizeLine$1(param) {
-      subPixelOptimizeLine(param.shape, param.shape, param.style);
-      return param;
-    }
-    /**
-     * Sub pixel optimize rect for canvas
-     */
-
-    function subPixelOptimizeRect$1(param) {
-      subPixelOptimizeRect(param.shape, param.shape, param.style);
-      return param;
     }
-    /**
-     * Sub pixel optimize for canvas
-     *
-     * @param position Coordinate, such as x, y
-     * @param lineWidth Should be nonnegative integer.
-     * @param positiveOrNegative Default false (negative).
-     * @return Optimized position.
-     */
-
-    var subPixelOptimize$1 = subPixelOptimize;
 
     function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) {
       var isFrom = false;
@@ -14322,79 +14254,36 @@
         dataIndex = dataIndex.dataIndex;
       }
 
-      var isUpdate = animationType === 'update';
       var isRemove = animationType === 'remove';
-      var animationPayload; // Check if there is global animation configuration from dataZoom/resize can override the config in option.
-      // If animation is enabled. Will use this animation config in payload.
-      // If animation is disabled. Just ignore it.
-
-      if (animatableModel && animatableModel.ecModel) {
-        var updatePayload = animatableModel.ecModel.getUpdatePayload();
-        animationPayload = updatePayload && updatePayload.animation;
-      }
-
-      var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();
 
       if (!isRemove) {
         // Must stop the remove animation.
         el.stopAnimation('remove');
       }
 
-      if (animationEnabled) {
-        var duration = void 0;
-        var animationEasing = void 0;
-        var animationDelay = void 0;
-
-        if (animationPayload) {
-          duration = animationPayload.duration || 0;
-          animationEasing = animationPayload.easing || 'cubicOut';
-          animationDelay = animationPayload.delay || 0;
-        } else if (isRemove) {
-          removeOpt = removeOpt || {};
-          duration = retrieve2(removeOpt.duration, 200);
-          animationEasing = retrieve2(removeOpt.easing, 'cubicOut');
-          animationDelay = 0;
-        } else {
-          duration = animatableModel.getShallow(isUpdate ? 'animationDurationUpdate' : 'animationDuration');
-          animationEasing = animatableModel.getShallow(isUpdate ? 'animationEasingUpdate' : 'animationEasing');
-          animationDelay = animatableModel.getShallow(isUpdate ? 'animationDelayUpdate' : 'animationDelay');
-        }
-
-        if (typeof animationDelay === 'function') {
-          animationDelay = animationDelay(dataIndex, animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null);
-        }
-
-        if (typeof duration === 'function') {
-          duration = duration(dataIndex);
-        }
+      var animationConfig = getAnimationConfig(animationType, animatableModel, dataIndex, isRemove ? removeOpt || {} : null, animatableModel && animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null);
 
-        duration > 0 ? isFrom ? el.animateFrom(props, {
+      if (animationConfig && animationConfig.duration > 0) {
+        var duration = animationConfig.duration;
+        var animationDelay = animationConfig.delay;
+        var animationEasing = animationConfig.easing;
+        var animateConfig = {
           duration: duration,
           delay: animationDelay || 0,
           easing: animationEasing,
           done: cb,
           force: !!cb || !!during,
+          // Set to final state in update/init animation.
+          // So the post processing based on the path shape can be done correctly.
+          setToFinal: !isRemove,
           scope: animationType,
           during: during
-        }) : el.animateTo(props, {
-          duration: duration,
-          delay: animationDelay || 0,
-          easing: animationEasing,
-          done: cb,
-          force: !!cb || !!during,
-          setToFinal: true,
-          scope: animationType,
-          during: during
-        }) : ( // FIXME:
-        // If `duration` is 0, only the animation on props
-        // can be stoped, other animation should be continued?
-        // But at present using duration 0 in `animateTo`, `animateFrom`
-        // might cause unexpected behavior.
-        el.stopAnimation(), // If `isFrom`, the props is the "from" props.
-        !isFrom && el.attr(props), cb && cb());
+        };
+        isFrom ? el.animateFrom(props, animateConfig) : el.animateTo(props, animateConfig);
       } else {
-        el.stopAnimation();
-        !isFrom && el.attr(props); // Call during once.
+        el.stopAnimation(); // If `isFrom`, the props is the "from" props.
+
+        !isFrom && el.attr(props); // Call during at least once.
 
         during && during(1);
         cb && cb();
@@ -14435,6 +14324,26 @@
       animateOrSetProps('init', el, props, animatableModel, dataIndex, cb, during);
     }
     /**
+     * If element is removed.
+     * It can determine if element is having remove animation.
+     */
+
+    function isElementRemoved(el) {
+      if (!el.__zr) {
+        return true;
+      }
+
+      for (var i = 0; i < el.animators.length; i++) {
+        var animator = el.animators[i];
+
+        if (animator.scope === 'remove') {
+          return true;
+        }
+      }
+
+      return false;
+    }
+    /**
      * Remove graphic element
      */
 
@@ -14476,26 +14385,206 @@
       }
     }
     /**
-     * If element is removed.
-     * It can determine if element is having remove animation.
+     * Save old style for style transition in universalTransition module.
+     * It's used when element will be reused in each render.
+     * For chart like map, heatmap, which will always create new element.
+     * We don't need to save this because universalTransition can get old style from the old element
      */
 
-    function isElementRemoved(el) {
-      if (!el.__zr) {
-        return true;
+    function saveOldStyle(el) {
+      transitionStore(el).oldStyle = el.style;
+    }
+
+    var mathMax$4 = Math.max;
+    var mathMin$4 = Math.min;
+    var _customShapeMap = {};
+    /**
+     * Extend shape with parameters
+     */
+
+    function extendShape(opts) {
+      return Path.extend(opts);
+    }
+    var extendPathFromString = extendFromString;
+    /**
+     * Extend path
+     */
+
+    function extendPath(pathData, opts) {
+      return extendPathFromString(pathData, opts);
+    }
+    /**
+     * Register a user defined shape.
+     * The shape class can be fetched by `getShapeClass`
+     * This method will overwrite the registered shapes, including
+     * the registered built-in shapes, if using the same `name`.
+     * The shape can be used in `custom series` and
+     * `graphic component` by declaring `{type: name}`.
+     *
+     * @param name
+     * @param ShapeClass Can be generated by `extendShape`.
+     */
+
+    function registerShape(name, ShapeClass) {
+      _customShapeMap[name] = ShapeClass;
+    }
+    /**
+     * Find shape class registered by `registerShape`. Usually used in
+     * fetching user defined shape.
+     *
+     * [Caution]:
+     * (1) This method **MUST NOT be used inside echarts !!!**, unless it is prepared
+     * to use user registered shapes.
+     * Because the built-in shape (see `getBuiltInShape`) will be registered by
+     * `registerShape` by default. That enables users to get both built-in
+     * shapes as well as the shapes belonging to themsleves. But users can overwrite
+     * the built-in shapes by using names like 'circle', 'rect' via calling
+     * `registerShape`. So the echarts inner featrues should not fetch shapes from here
+     * in case that it is overwritten by users, except that some features, like
+     * `custom series`, `graphic component`, do it deliberately.
+     *
+     * (2) In the features like `custom series`, `graphic component`, the user input
+     * `{tpye: 'xxx'}` does not only specify shapes but also specify other graphic
+     * elements like `'group'`, `'text'`, `'image'` or event `'path'`. Those names
+     * are reserved names, that is, if some user register a shape named `'image'`,
+     * the shape will not be used. If we intending to add some more reserved names
+     * in feature, that might bring break changes (disable some existing user shape
+     * names). But that case probably rearly happen. So we dont make more mechanism
+     * to resolve this issue here.
+     *
+     * @param name
+     * @return The shape class. If not found, return nothing.
+     */
+
+    function getShapeClass(name) {
+      if (_customShapeMap.hasOwnProperty(name)) {
+        return _customShapeMap[name];
       }
+    }
+    /**
+     * Create a path element from path data string
+     * @param pathData
+     * @param opts
+     * @param rect
+     * @param layout 'center' or 'cover' default to be cover
+     */
 
-      for (var i = 0; i < el.animators.length; i++) {
-        var animator = el.animators[i];
+    function makePath(pathData, opts, rect, layout) {
+      var path = createFromString(pathData, opts);
 
-        if (animator.scope === 'remove') {
-          return true;
+      if (rect) {
+        if (layout === 'center') {
+          rect = centerGraphic(rect, path.getBoundingRect());
         }
+
+        resizePath(path, rect);
       }
 
-      return false;
+      return path;
     }
     /**
+     * Create a image element from image url
+     * @param imageUrl image url
+     * @param opts options
+     * @param rect constrain rect
+     * @param layout 'center' or 'cover'. Default to be 'cover'
+     */
+
+    function makeImage(imageUrl, rect, layout) {
+      var zrImg = new ZRImage({
+        style: {
+          image: imageUrl,
+          x: rect.x,
+          y: rect.y,
+          width: rect.width,
+          height: rect.height
+        },
+        onload: function (img) {
+          if (layout === 'center') {
+            var boundingRect = {
+              width: img.width,
+              height: img.height
+            };
+            zrImg.setStyle(centerGraphic(rect, boundingRect));
+          }
+        }
+      });
+      return zrImg;
+    }
+    /**
+     * Get position of centered element in bounding box.
+     *
+     * @param  rect         element local bounding box
+     * @param  boundingRect constraint bounding box
+     * @return element position containing x, y, width, and height
+     */
+
+    function centerGraphic(rect, boundingRect) {
+      // Set rect to center, keep width / height ratio.
+      var aspect = boundingRect.width / boundingRect.height;
+      var width = rect.height * aspect;
+      var height;
+
+      if (width <= rect.width) {
+        height = rect.height;
+      } else {
+        width = rect.width;
+        height = width / aspect;
+      }
+
+      var cx = rect.x + rect.width / 2;
+      var cy = rect.y + rect.height / 2;
+      return {
+        x: cx - width / 2,
+        y: cy - height / 2,
+        width: width,
+        height: height
+      };
+    }
+
+    var mergePath$1 = mergePath;
+    /**
+     * Resize a path to fit the rect
+     * @param path
+     * @param rect
+     */
+
+    function resizePath(path, rect) {
+      if (!path.applyTransform) {
+        return;
+      }
+
+      var pathRect = path.getBoundingRect();
+      var m = pathRect.calculateTransform(rect);
+      path.applyTransform(m);
+    }
+    /**
+     * Sub pixel optimize line for canvas
+     */
+
+    function subPixelOptimizeLine$1(param) {
+      subPixelOptimizeLine(param.shape, param.shape, param.style);
+      return param;
+    }
+    /**
+     * Sub pixel optimize rect for canvas
+     */
+
+    function subPixelOptimizeRect$1(param) {
+      subPixelOptimizeRect(param.shape, param.shape, param.style);
+      return param;
+    }
+    /**
+     * Sub pixel optimize for canvas
+     *
+     * @param position Coordinate, such as x, y
+     * @param lineWidth Should be nonnegative integer.
+     * @param positiveOrNegative Default false (negative).
+     * @return Optimized position.
+     */
+
+    var subPixelOptimize$1 = subPixelOptimize;
+    /**
      * Get transform matrix of target (param target),
      * in coordinate of its ancestor (param ancestor)
      *
@@ -14780,6 +14869,11 @@
 
     var graphic = /*#__PURE__*/Object.freeze({
         __proto__: null,
+        updateProps: updateProps,
+        initProps: initProps,
+        removeElement: removeElement,
+        removeElementWithFadeOut: removeElementWithFadeOut,
+        isElementRemoved: isElementRemoved,
         extendShape: extendShape,
         extendPath: extendPath,
         registerShape: registerShape,
@@ -14791,11 +14885,6 @@
         subPixelOptimizeLine: subPixelOptimizeLine$1,
         subPixelOptimizeRect: subPixelOptimizeRect$1,
         subPixelOptimize: subPixelOptimize$1,
-        updateProps: updateProps,
-        initProps: initProps,
-        removeElement: removeElement,
-        removeElementWithFadeOut: removeElementWithFadeOut,
-        isElementRemoved: isElementRemoved,
         getTransform: getTransform,
         applyTransform: applyTransform$1,
         transformDirection: transformDirection,
@@ -15316,32 +15405,6 @@
         obj.statesModels = labelStatesModels;
       }
     }
-    function animateLabelValue(textEl, dataIndex, data, animatableModel, labelFetcher) {
-      var labelInnerStore = labelInner(textEl);
-
-      if (!labelInnerStore.valueAnimation) {
-        return;
-      }
-
-      var defaultInterpolatedText = labelInnerStore.defaultInterpolatedText; // Consider the case that being animating, do not use the `obj.value`,
-      // Otherwise it will jump to the `obj.value` when this new animation started.
-
-      var currValue = retrieve2(labelInnerStore.interpolatedValue, labelInnerStore.prevValue);
-      var targetValue = labelInnerStore.value;
-
-      function during(percent) {
-        var interpolated = interpolateRawValues(data, labelInnerStore.precision, currValue, targetValue, percent);
-        labelInnerStore.interpolatedValue = percent === 1 ? null : interpolated;
-        var labelText = getLabelText({
-          labelDataIndex: dataIndex,
-          labelFetcher: labelFetcher,
-          defaultText: defaultInterpolatedText ? defaultInterpolatedText(interpolated) : interpolated + ''
-        }, labelInnerStore.statesModels, interpolated);
-        setLabelText(textEl, labelText);
-      }
-
-      (currValue == null ? initProps : updateProps)(textEl, {}, animatableModel, dataIndex, null, during);
-    }
 
     var PATH_COLOR = ['textStyle', 'color']; // TODO Performance improvement?
 
@@ -16151,8 +16214,8 @@
       hour: '{HH}:{mm}',
       minute: '{HH}:{mm}',
       second: '{HH}:{mm}:{ss}',
-      millisecond: '{hh}:{mm}:{ss} {SSS}',
-      none: '{yyyy}-{MM}-{dd} {hh}:{mm}:{ss} {SSS}'
+      millisecond: '{HH}:{mm}:{ss} {SSS}',
+      none: '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}'
     };
     var fullDayFormatter = '{yyyy}-{MM}-{dd}';
     var fullLeveledFormatter = {
@@ -16363,7 +16426,7 @@
       return isUTC ? 'getUTCSeconds' : 'getSeconds';
     }
     function millisecondsGetterName(isUTC) {
-      return isUTC ? 'getUTCSeconds' : 'getSeconds';
+      return isUTC ? 'getUTCMilliseconds' : 'getMilliseconds';
     }
     function fullYearSetterName(isUTC) {
       return isUTC ? 'setUTCFullYear' : 'setFullYear';
@@ -16384,7 +16447,7 @@
       return isUTC ? 'setUTCSeconds' : 'setSeconds';
     }
     function millisecondsSetterName(isUTC) {
-      return isUTC ? 'setUTCSeconds' : 'setSeconds';
+      return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds';
     }
 
     function getTextRect(text, font, align, verticalAlign, padding, rich, truncate, lineHeight) {
@@ -17291,18 +17354,8 @@
     var globalDefault = {
       darkMode: 'auto',
       // backgroundColor: 'rgba(0,0,0,0)',
-      // https://dribbble.com/shots/1065960-Infographic-Pie-chart-visualization
-      // color: ['#5793f3', '#d14a61', '#fd9c35', '#675bba', '#fec42c', '#dd4444', '#d4df5a', '#cd4870'],
-      // Light colors:
-      // color: ['#bcd3bb', '#e88f70', '#edc1a5', '#9dc5c8', '#e1e8c8', '#7b7c68', '#e5b5b5', '#f0b489', '#928ea8', '#bda29a'],
-      // color: ['#cc5664', '#9bd6ec', '#ea946e', '#8acaaa', '#f1ec64', '#ee8686', '#a48dc1', '#5da6bc', '#b9dcae'],
-      // Dark colors:
-      // color: [
-      //     '#c23531', '#2f4554', '#61a0a8', '#d48265', '#91c7ae', '#749f83',
-      //     '#ca8622', '#bda29a', '#6e7074', '#546570', '#c4ccd3'
-      // ],
-      color: [// '#51689b', '#ce5c5c', '#fbc357', '#8fbf8f', '#659d84', '#fb8e6a', '#c77288', '#786090', '#91c4c5', '#6890ba'
-      '#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
+      colorBy: 'series',
+      color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
       gradientColor: ['#f6efa6', '#d88273', '#bf444c'],
       aria: {
         decal: {
@@ -17380,7 +17433,7 @@
       useUTC: false
     };
 
-    var VISUAL_DIMENSIONS = createHashMap(['tooltip', 'label', 'itemName', 'itemId', 'seriesName']);
+    var VISUAL_DIMENSIONS = createHashMap(['tooltip', 'label', 'itemName', 'itemId', 'itemGroupId', 'seriesName']);
     var SOURCE_FORMAT_ORIGINAL = 'original';
     var SOURCE_FORMAT_ARRAY_ROWS = 'arrayRows';
     var SOURCE_FORMAT_OBJECT_ROWS = 'objectRows';
@@ -18215,11 +18268,6 @@
         return this._locale;
       };
 
-      GlobalModel.prototype.getLocale = function (localePosition) {
-        var locale = this.getLocaleModel();
-        return locale.get(localePosition);
-      };
-
       GlobalModel.prototype.setUpdatePayload = function (payload) {
         this._payload = payload;
       };
@@ -18395,7 +18443,7 @@
 
 
       GlobalModel.prototype.getSeries = function () {
-        return filter(this._componentsMap.get('series').slice(), function (oneSeries) {
+        return filter(this._componentsMap.get('series'), function (oneSeries) {
           return !!oneSeries;
         });
       };
@@ -19658,7 +19706,7 @@
         var isStackedByIndex = targetStackInfo.isStackedByIndex; // Should not write on raw data, because stack series model list changes
         // depending on legend selection.
 
-        var newData = targetData.map(dims, function (v0, v1, dataIndex) {
+        targetData.modify(dims, function (v0, v1, dataIndex) {
           var sum = targetData.get(targetStackInfo.stackedDimension, dataIndex); // Consider `connectNulls` of line area, if value is NaN, stackedOver
           // should also be NaN, to draw a appropriate belt area.
 
@@ -19705,26 +19753,33 @@
           resultVal[1] = stackedOver;
           return resultVal;
         });
-        targetData.hostModel.setData(newData); // Update for consequent calculation
-
-        targetStackInfo.data = newData;
       });
     }
 
     var SourceImpl =
     /** @class */
     function () {
-      // readonly frozen: boolean;
       function SourceImpl(fields) {
         this.data = fields.data || (fields.sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS ? {} : []);
         this.sourceFormat = fields.sourceFormat || SOURCE_FORMAT_UNKNOWN; // Visit config
 
         this.seriesLayoutBy = fields.seriesLayoutBy || SERIES_LAYOUT_BY_COLUMN;
         this.startIndex = fields.startIndex || 0;
-        this.dimensionsDefine = fields.dimensionsDefine;
         this.dimensionsDetectedCount = fields.dimensionsDetectedCount;
-        this.encodeDefine = fields.encodeDefine;
         this.metaRawOption = fields.metaRawOption;
+        var dimensionsDefine = this.dimensionsDefine = fields.dimensionsDefine;
+
+        if (dimensionsDefine) {
+          for (var i = 0; i < dimensionsDefine.length; i++) {
+            var dim = dimensionsDefine[i];
+
+            if (dim.type == null) {
+              if (guessOrdinal(this, i) === BE_ORDINAL.Must) {
+                dim.type = 'ordinal';
+              }
+            }
+          }
+        }
       }
 
       return SourceImpl;
@@ -19733,9 +19788,13 @@
     function isSourceInstance(val) {
       return val instanceof SourceImpl;
     }
+    /**
+     * Create a source from option.
+     * NOTE: Created source is immutable. Don't change any properties in it.
+     */
+
     function createSource(sourceData, thisMetaRawOption, // can be null. If not provided, auto detect it from `sourceData`.
-    sourceFormat, encodeDefine // can be null
-    ) {
+    sourceFormat) {
       sourceFormat = sourceFormat || detectSourceFormat(sourceData);
       var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy;
       var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions);
@@ -19746,7 +19805,6 @@
         dimensionsDefine: determined.dimensionsDefine,
         startIndex: determined.startIndex,
         dimensionsDetectedCount: determined.dimensionsDetectedCount,
-        encodeDefine: makeEncodeDefine(encodeDefine),
         metaRawOption: clone(thisMetaRawOption)
       });
       return source;
@@ -19772,20 +19830,13 @@
         seriesLayoutBy: source.seriesLayoutBy,
         dimensionsDefine: clone(source.dimensionsDefine),
         startIndex: source.startIndex,
-        dimensionsDetectedCount: source.dimensionsDetectedCount,
-        encodeDefine: makeEncodeDefine(source.encodeDefine)
+        dimensionsDetectedCount: source.dimensionsDetectedCount
       });
     }
-
-    function makeEncodeDefine(encodeDefine) {
-      // null means user not specify `series.encode`.
-      return encodeDefine ? createHashMap(encodeDefine) : null;
-    }
     /**
      * Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`.
      */
 
-
     function detectSourceFormat(data) {
       var sourceFormat = SOURCE_FORMAT_UNKNOWN;
 
@@ -19985,6 +20036,11 @@
       }
     }
 
+    function shouldRetrieveDataByName(source) {
+      var sourceFormat = source.sourceFormat;
+      return sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS;
+    }
+
     /*
     * Licensed to the Apache Software Foundation (ASF) under one
     * or more contributor license agreements.  See the NOTICE file
@@ -20213,19 +20269,19 @@
 
     var rawSourceItemGetterMap = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef, idx) {
       return rawData[idx + startIndex];
-    }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef, idx) {
+    }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef, idx, out) {
       idx += startIndex;
-      var item = [];
+      var item = out || [];
       var data = rawData;
 
       for (var i = 0; i < data.length; i++) {
         var row = data[i];
-        item.push(row ? row[idx] : null);
+        item[i] = row ? row[idx] : null;
       }
 
       return item;
-    }, _a[SOURCE_FORMAT_OBJECT_ROWS] = getItemSimply, _a[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef, idx) {
-      var item = [];
+    }, _a[SOURCE_FORMAT_OBJECT_ROWS] = getItemSimply, _a[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef, idx, out) {
+      var item = out || [];
 
       for (var i = 0; i < dimsDef.length; i++) {
         var dimName = dimsDef[i].name;
@@ -20237,7 +20293,7 @@
         }
 
         var col = rawData[dimName];
-        item.push(col ? col[idx] : null);
+        item[i] = col ? col[idx] : null;
       }
 
       return item;
@@ -20246,7 +20302,7 @@
       var method = rawSourceItemGetterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)];
 
       if ("development" !== 'production') {
-        assert(method, 'Do not suppport get item on "' + sourceFormat + '", "' + seriesLayoutBy + '".');
+        assert(method, 'Do not support get item on "' + sourceFormat + '", "' + seriesLayoutBy + '".');
       }
 
       return method;
@@ -20283,17 +20339,17 @@
       return method;
     }
 
-    var getRawValueSimply = function (dataItem, dimIndex, dimName) {
-      return dimIndex != null ? dataItem[dimIndex] : dataItem;
+    var getRawValueSimply = function (dataItem, dimIndex, property) {
+      return dataItem[dimIndex];
     };
 
-    var rawSourceValueGetterMap = (_c = {}, _c[SOURCE_FORMAT_ARRAY_ROWS] = getRawValueSimply, _c[SOURCE_FORMAT_OBJECT_ROWS] = function (dataItem, dimIndex, dimName) {
-      return dimIndex != null ? dataItem[dimName] : dataItem;
-    }, _c[SOURCE_FORMAT_KEYED_COLUMNS] = getRawValueSimply, _c[SOURCE_FORMAT_ORIGINAL] = function (dataItem, dimIndex, dimName) {
+    var rawSourceValueGetterMap = (_c = {}, _c[SOURCE_FORMAT_ARRAY_ROWS] = getRawValueSimply, _c[SOURCE_FORMAT_OBJECT_ROWS] = function (dataItem, dimIndex, property) {
+      return dataItem[property];
+    }, _c[SOURCE_FORMAT_KEYED_COLUMNS] = getRawValueSimply, _c[SOURCE_FORMAT_ORIGINAL] = function (dataItem, dimIndex, property) {
       // FIXME: In some case (markpoint in geo (geo-map.html)),
       // dataItem is {coord: [...]}
       var value = getDataItemValue(dataItem);
-      return dimIndex == null || !(value instanceof Array) ? value : value[dimIndex];
+      return !(value instanceof Array) ? value : value[dimIndex];
     }, _c[SOURCE_FORMAT_TYPED_ARRAY] = getRawValueSimply, _c);
     function getRawSourceValueGetter(sourceFormat) {
       var method = rawSourceValueGetterMap[sourceFormat];
@@ -20316,9 +20372,9 @@
     // TODO: consider how to treat null/undefined/NaN when display?
 
 
-    function retrieveRawValue(data, dataIndex, dim // If dimIndex is null/undefined, return OptionDataItem.
+    function retrieveRawValue(data, dataIndex, // If dimIndex is null/undefined, return OptionDataItem.
     // Otherwise, return OptionDataValue.
-    ) {
+    dim) {
       if (!data) {
         return;
       } // Consider data may be not persistent.
@@ -20330,17 +20386,22 @@
         return;
       }
 
-      var sourceFormat = data.getProvider().getSource().sourceFormat;
-      var dimName;
-      var dimIndex;
-      var dimInfo = data.getDimensionInfo(dim);
+      var store = data.getStore();
+      var sourceFormat = store.getSource().sourceFormat;
 
-      if (dimInfo) {
-        dimName = dimInfo.name;
-        dimIndex = dimInfo.index;
-      }
+      if (dim != null) {
+        var dimIndex = data.getDimensionIndex(dim);
+        var property = store.getDimensionProperty(dimIndex);
+        return getRawSourceValueGetter(sourceFormat)(dataItem, dimIndex, property);
+      } else {
+        var result = dataItem;
 
-      return getRawSourceValueGetter(sourceFormat)(dataItem, dimIndex, dimName);
+        if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
+          result = getDataItemValue(dataItem);
+        }
+
+        return result;
+      }
     }
 
     var DIMENSION_LABEL_REG = /\{@(.+?)\}/g;
@@ -20365,7 +20426,7 @@
         var borderColor = style && style.stroke;
         var mainType = this.mainType;
         var isSeries = mainType === 'series';
-        var userOutput = data.userOutput;
+        var userOutput = data.userOutput && data.userOutput.get();
         return {
           componentType: mainType,
           componentSubType: this.subType,
@@ -20381,7 +20442,7 @@
           value: rawValue,
           color: color,
           borderColor: borderColor,
-          dimensionNames: userOutput ? userOutput.dimensionNames : null,
+          dimensionNames: userOutput ? userOutput.fullDimensions : null,
           encode: userOutput ? userOutput.encode : null,
           // Param name list for mapping `a`, `b`, `c`, `d`, `e`
           $vars: ['seriesName', 'name', 'value']
@@ -20428,15 +20489,25 @@
 
           return str.replace(DIMENSION_LABEL_REG, function (origin, dimStr) {
             var len = dimStr.length;
-            var dimLoose = dimStr.charAt(0) === '[' && dimStr.charAt(len - 1) === ']' ? +dimStr.slice(1, len - 1) // Also support: '[]' => 0
-            : dimStr;
+            var dimLoose = dimStr;
+
+            if (dimLoose.charAt(0) === '[' && dimLoose.charAt(len - 1) === ']') {
+              dimLoose = +dimLoose.slice(1, len - 1); // Also support: '[]' => 0
+
+              if ("development" !== 'production') {
+                if (isNaN(dimLoose)) {
+                  error("Invalide label formatter: @" + dimStr + ", only support @[0], @[1], @[2], ...");
+                }
+              }
+            }
+
             var val = retrieveRawValue(data, dataIndex, dimLoose);
 
             if (extendParams && isArray(extendParams.interpolatedValue)) {
-              var dimInfo = data.getDimensionInfo(dimLoose);
+              var dimIndex = data.getDimensionIndex(dimLoose);
 
-              if (dimInfo) {
-                val = extendParams.interpolatedValue[dimInfo.index];
+              if (dimIndex >= 0) {
+                val = extendParams.interpolatedValue[dimIndex];
               }
             }
 
@@ -20873,8 +20944,7 @@
 
       if (dimType === 'ordinal') {
         // If given value is a category string
-        var ordinalMeta = opt && opt.ordinalMeta;
-        return ordinalMeta ? ordinalMeta.parseAndCollect(value) : value;
+        return value;
       }
 
       if (dimType === 'time' // spead up when using timestamp
@@ -21405,7 +21475,7 @@
           };
         }
 
-        return createSource(result.data, resultMetaRawOption, null, null);
+        return createSource(result.data, resultMetaRawOption, null);
       });
     }
 
@@ -21413,3021 +21483,2778 @@
       return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS || sourceFormat === SOURCE_FORMAT_OBJECT_ROWS;
     }
 
+    var UNDEFINED = 'undefined';
+    /* global Float64Array, Int32Array, Uint32Array, Uint16Array */
+    // Caution: MUST not use `new CtorUint32Array(arr, 0, len)`, because the Ctor of array is
+    // different from the Ctor of typed array.
+
+    var CtorUint32Array = typeof Uint32Array === UNDEFINED ? Array : Uint32Array;
+    var CtorUint16Array = typeof Uint16Array === UNDEFINED ? Array : Uint16Array;
+    var CtorInt32Array = typeof Int32Array === UNDEFINED ? Array : Int32Array;
+    var CtorFloat64Array = typeof Float64Array === UNDEFINED ? Array : Float64Array;
     /**
-     * [REQUIREMENT_MEMO]:
-     * (0) `metaRawOption` means `dimensions`/`sourceHeader`/`seriesLayoutBy` in raw option.
-     * (1) Keep support the feature: `metaRawOption` can be specified both on `series` and
-     * `root-dataset`. Them on `series` has higher priority.
-     * (2) Do not support to set `metaRawOption` on a `non-root-dataset`, because it might
-     * confuse users: whether those props indicate how to visit the upstream source or visit
-     * the transform result source, and some transforms has nothing to do with these props,
-     * and some transforms might have multiple upstream.
-     * (3) Transforms should specify `metaRawOption` in each output, just like they can be
-     * declared in `root-dataset`.
-     * (4) At present only support visit source in `SERIES_LAYOUT_BY_COLUMN` in transforms.
-     * That is for reducing complexity in transfroms.
-     * PENDING: Whether to provide transposition transform?
-     *
-     * [IMPLEMENTAION_MEMO]:
-     * "sourceVisitConfig" are calculated from `metaRawOption` and `data`.
-     * They will not be calculated until `source` is about to be visited (to prevent from
-     * duplicate calcuation). `source` is visited only in series and input to transforms.
-     *
-     * [DIMENSION_INHERIT_RULE]:
-     * By default the dimensions are inherited from ancestors, unless a transform return
-     * a new dimensions definition.
-     * Consider the case:
-     * ```js
-     * dataset: [{
-     *     source: [ ['Product', 'Sales', 'Prise'], ['Cookies', 321, 44.21], ...]
-     * }, {
-     *     transform: { type: 'filter', ... }
-     * }]
-     * dataset: [{
-     *     dimension: ['Product', 'Sales', 'Prise'],
-     *     source: [ ['Cookies', 321, 44.21], ...]
-     * }, {
-     *     transform: { type: 'filter', ... }
-     * }]
-     * ```
-     * The two types of option should have the same behavior after transform.
-     *
-     *
-     * [SCENARIO]:
-     * (1) Provide source data directly:
-     * ```js
-     * series: {
-     *     encode: {...},
-     *     dimensions: [...]
-     *     seriesLayoutBy: 'row',
-     *     data: [[...]]
-     * }
-     * ```
-     * (2) Series refer to dataset.
-     * ```js
-     * series: [{
-     *     encode: {...}
-     *     // Ignore datasetIndex means `datasetIndex: 0`
-     *     // and the dimensions defination in dataset is used
-     * }, {
-     *     encode: {...},
-     *     seriesLayoutBy: 'column',
-     *     datasetIndex: 1
-     * }]
-     * ```
-     * (3) dataset transform
-     * ```js
-     * dataset: [{
-     *     source: [...]
-     * }, {
-     *     source: [...]
-     * }, {
-     *     // By default from 0.
-     *     transform: { type: 'filter', config: {...} }
-     * }, {
-     *     // Piped.
-     *     transform: [
-     *         { type: 'filter', config: {...} },
-     *         { type: 'sort', config: {...} }
-     *     ]
-     * }, {
-     *     id: 'regressionData',
-     *     fromDatasetIndex: 1,
-     *     // Third-party transform
-     *     transform: { type: 'ecStat:regression', config: {...} }
-     * }, {
-     *     // retrieve the extra result.
-     *     id: 'regressionFormula',
-     *     fromDatasetId: 'regressionData',
-     *     fromTransformResult: 1
-     * }]
-     * ```
+     * Multi dimensional data store
      */
 
-    var SourceManager =
+    var dataCtors = {
+      'float': CtorFloat64Array,
+      'int': CtorInt32Array,
+      // Ordinal data type can be string or int
+      'ordinal': Array,
+      'number': Array,
+      'time': CtorFloat64Array
+    };
+    var defaultDimValueGetters;
+
+    function getIndicesCtor(rawCount) {
+      // The possible max value in this._indicies is always this._rawCount despite of filtering.
+      return rawCount > 65535 ? CtorUint32Array : CtorUint16Array;
+    }
+
+    function getInitialExtent() {
+      return [Infinity, -Infinity];
+    }
+
+    function cloneChunk(originalChunk) {
+      var Ctor = originalChunk.constructor; // Only shallow clone is enough when Array.
+
+      return Ctor === Array ? originalChunk.slice() : new Ctor(originalChunk);
+    }
+
+    function prepareStore(store, dimIdx, dimType, end, append) {
+      var DataCtor = dataCtors[dimType || 'float'];
+
+      if (append) {
+        var oldStore = store[dimIdx];
+        var oldLen = oldStore && oldStore.length;
+
+        if (!(oldLen === end)) {
+          var newStore = new DataCtor(end); // The cost of the copy is probably inconsiderable
+          // within the initial chunkSize.
+
+          for (var j = 0; j < oldLen; j++) {
+            newStore[j] = oldStore[j];
+          }
+
+          store[dimIdx] = newStore;
+        }
+      } else {
+        store[dimIdx] = new DataCtor(end);
+      }
+    }
+    /**
+     * Basically, DataStore API keep immutable.
+     */
+
+    var DataStore =
     /** @class */
     function () {
-      function SourceManager(sourceHost) {
-        // Cached source. Do not repeat calculating if not dirty.
-        this._sourceList = []; // version sign of each upstream source manager.
+      function DataStore() {
+        this._chunks = []; // It will not be calculated util needed.
 
-        this._upstreamSignList = [];
-        this._versionSignBase = 0;
-        this._sourceHost = sourceHost;
+        this._rawExtent = [];
+        this._extent = [];
+        this._count = 0;
+        this._rawCount = 0;
+        this._calcDimNameToIdx = createHashMap();
       }
       /**
-       * Mark dirty.
+       * Initialize from data
        */
 
 
-      SourceManager.prototype.dirty = function () {
-        this._setLocalSource([], []);
-      };
+      DataStore.prototype.initData = function (provider, inputDimensions, dimValueGetter) {
+        if ("development" !== 'production') {
+          assert(isFunction(provider.getItem) && isFunction(provider.count), 'Inavlid data provider.');
+        }
 
-      SourceManager.prototype._setLocalSource = function (sourceList, upstreamSignList) {
-        this._sourceList = sourceList;
-        this._upstreamSignList = upstreamSignList;
-        this._versionSignBase++;
+        this._provider = provider; // Clear
 
-        if (this._versionSignBase > 9e10) {
-          this._versionSignBase = 0;
-        }
+        this._chunks = [];
+        this._indices = null;
+        this.getRawIndex = this._getRawIdxIdentity;
+        var source = provider.getSource();
+        var defaultGetter = this.defaultDimValueGetter = defaultDimValueGetters[source.sourceFormat]; // Default dim value getter
+
+        this._dimValueGetter = dimValueGetter || defaultGetter; // Reset raw extent.
+
+        this._rawExtent = [];
+        var willRetrieveDataByName = shouldRetrieveDataByName(source);
+        this._dimensions = map(inputDimensions, function (dim) {
+          if ("development" !== 'production') {
+            if (willRetrieveDataByName) {
+              assert(dim.property != null);
+            }
+          }
+
+          return {
+            // Only pick these two props. Not leak other properties like orderMeta.
+            type: dim.type,
+            property: dim.property
+          };
+        });
+
+        this._initDataFromProvider(0, provider.count());
+      };
+
+      DataStore.prototype.getProvider = function () {
+        return this._provider;
       };
       /**
-       * For detecting whether the upstream source is dirty, so that
-       * the local cached source (in `_sourceList`) should be discarded.
+       * Caution: even when a `source` instance owned by a series, the created data store
+       * may still be shared by different sereis (the source hash does not use all `source`
+       * props, see `sourceManager`). In this case, the `source` props that are not used in
+       * hash (like `source.dimensionDefine`) probably only belongs to a certain series and
+       * thus should not be fetch here.
        */
 
 
-      SourceManager.prototype._getVersionSign = function () {
-        return this._sourceHost.uid + '_' + this._versionSignBase;
+      DataStore.prototype.getSource = function () {
+        return this._provider.getSource();
       };
       /**
-       * Always return a source instance. Otherwise throw error.
+       * @caution Only used in dataStack.
        */
 
 
-      SourceManager.prototype.prepareSource = function () {
-        // For the case that call `setOption` multiple time but no data changed,
-        // cache the result source to prevent from repeating transform.
-        if (this._isDirty()) {
-          this._createSource();
+      DataStore.prototype.ensureCalculationDimension = function (dimName, type) {
+        var calcDimNameToIdx = this._calcDimNameToIdx;
+        var dimensions = this._dimensions;
+        var calcDimIdx = calcDimNameToIdx.get(dimName);
+
+        if (calcDimIdx != null) {
+          if (dimensions[calcDimIdx].type === type) {
+            return calcDimIdx;
+          }
+        } else {
+          calcDimIdx = dimensions.length;
         }
-      };
 
-      SourceManager.prototype._createSource = function () {
-        this._setLocalSource([], []);
+        dimensions[calcDimIdx] = {
+          type: type
+        };
+        calcDimNameToIdx.set(dimName, calcDimIdx);
+        this._chunks[calcDimIdx] = new dataCtors[type || 'float'](this._rawCount);
+        this._rawExtent[calcDimIdx] = getInitialExtent();
+        return calcDimIdx;
+      };
 
-        var sourceHost = this._sourceHost;
+      DataStore.prototype.collectOrdinalMeta = function (dimIdx, ordinalMeta) {
+        var chunk = this._chunks[dimIdx];
+        var dim = this._dimensions[dimIdx];
+        var rawExtents = this._rawExtent;
+        var offset = dim.ordinalOffset || 0;
+        var len = chunk.length;
 
-        var upSourceMgrList = this._getUpstreamSourceManagers();
+        if (offset === 0) {
+          // We need to reset the rawExtent if collect is from start.
+          // Because this dimension may be guessed as number and calcuating a wrong extent.
+          rawExtents[dimIdx] = getInitialExtent();
+        }
 
-        var hasUpstream = !!upSourceMgrList.length;
-        var resultSourceList;
-        var upstreamSignList;
+        var dimRawExtent = rawExtents[dimIdx]; // Parse from previous data offset. len may be changed after appendData
 
-        if (isSeries(sourceHost)) {
-          var seriesModel = sourceHost;
-          var data = void 0;
-          var sourceFormat = void 0;
-          var upSource = void 0; // Has upstream dataset
+        for (var i = offset; i < len; i++) {
+          var val = chunk[i] = ordinalMeta.parseAndCollect(chunk[i]);
+          dimRawExtent[0] = Math.min(val, dimRawExtent[0]);
+          dimRawExtent[1] = Math.max(val, dimRawExtent[1]);
+        }
 
-          if (hasUpstream) {
-            var upSourceMgr = upSourceMgrList[0];
-            upSourceMgr.prepareSource();
-            upSource = upSourceMgr.getSource();
-            data = upSource.data;
-            sourceFormat = upSource.sourceFormat;
-            upstreamSignList = [upSourceMgr._getVersionSign()];
-          } // Series data is from own.
-          else {
-              data = seriesModel.get('data', true);
-              sourceFormat = isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;
-              upstreamSignList = [];
-            } // See [REQUIREMENT_MEMO], merge settings on series and parent dataset if it is root.
+        dim.ordinalMeta = ordinalMeta;
+        dim.ordinalOffset = len;
+        dim.type = 'ordinal'; // Force to be ordinal
+      };
 
+      DataStore.prototype.getOrdinalMeta = function (dimIdx) {
+        var dimInfo = this._dimensions[dimIdx];
+        var ordinalMeta = dimInfo.ordinalMeta;
+        return ordinalMeta;
+      };
 
-          var newMetaRawOption = this._getSourceMetaRawOption();
+      DataStore.prototype.getDimensionProperty = function (dimIndex) {
+        var item = this._dimensions[dimIndex];
+        return item && item.property;
+      };
+      /**
+       * Caution: Can be only called on raw data (before `this._indices` created).
+       */
 
-          var upMetaRawOption = upSource ? upSource.metaRawOption : null;
-          var seriesLayoutBy = retrieve2(newMetaRawOption.seriesLayoutBy, upMetaRawOption ? upMetaRawOption.seriesLayoutBy : null);
-          var sourceHeader = retrieve2(newMetaRawOption.sourceHeader, upMetaRawOption ? upMetaRawOption.sourceHeader : null); // Note here we should not use `upSource.dimensionsDefine`. Consider the case:
-          // `upSource.dimensionsDefine` is detected by `seriesLayoutBy: 'column'`,
-          // but series need `seriesLayoutBy: 'row'`.
 
-          var dimensions = retrieve2(newMetaRawOption.dimensions, upMetaRawOption ? upMetaRawOption.dimensions : null);
-          resultSourceList = [createSource(data, {
-            seriesLayoutBy: seriesLayoutBy,
-            sourceHeader: sourceHeader,
-            dimensions: dimensions
-          }, sourceFormat, seriesModel.get('encode', true))];
-        } else {
-          var datasetModel = sourceHost; // Has upstream dataset.
+      DataStore.prototype.appendData = function (data) {
+        if ("development" !== 'production') {
+          assert(!this._indices, 'appendData can only be called on raw data.');
+        }
 
-          if (hasUpstream) {
-            var result = this._applyTransform(upSourceMgrList);
+        var provider = this._provider;
+        var start = this.count();
+        provider.appendData(data);
+        var end = provider.count();
 
-            resultSourceList = result.sourceList;
-            upstreamSignList = result.upstreamSignList;
-          } // Is root dataset.
-          else {
-              var sourceData = datasetModel.get('source', true);
-              resultSourceList = [createSource(sourceData, this._getSourceMetaRawOption(), null, // Note: dataset option does not have `encode`.
-              null)];
-              upstreamSignList = [];
-            }
+        if (!provider.persistent) {
+          end += start;
         }
 
-        if ("development" !== 'production') {
-          assert(resultSourceList && upstreamSignList);
+        if (start < end) {
+          this._initDataFromProvider(start, end, true);
         }
 
-        this._setLocalSource(resultSourceList, upstreamSignList);
+        return [start, end];
       };
 
-      SourceManager.prototype._applyTransform = function (upMgrList) {
-        var datasetModel = this._sourceHost;
-        var transformOption = datasetModel.get('transform', true);
-        var fromTransformResult = datasetModel.get('fromTransformResult', true);
+      DataStore.prototype.appendValues = function (values, minFillLen) {
+        var chunks = this._chunks;
+        var dimensions = this._dimensions;
+        var dimLen = dimensions.length;
+        var rawExtent = this._rawExtent;
+        var start = this.count();
+        var end = start + Math.max(values.length, minFillLen || 0);
 
-        if ("development" !== 'production') {
-          assert(fromTransformResult != null || transformOption != null);
+        for (var i = 0; i < dimLen; i++) {
+          var dim = dimensions[i];
+          prepareStore(chunks, i, dim.type, end, true);
         }
 
-        if (fromTransformResult != null) {
-          var errMsg = '';
+        var emptyDataItem = [];
 
-          if (upMgrList.length !== 1) {
-            if ("development" !== 'production') {
-              errMsg = 'When using `fromTransformResult`, there should be only one upstream dataset';
-            }
+        for (var idx = start; idx < end; idx++) {
+          var sourceIdx = idx - start; // Store the data by dimensions
 
-            doThrow(errMsg);
+          for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) {
+            var dim = dimensions[dimIdx];
+            var val = defaultDimValueGetters.arrayRows.call(this, values[sourceIdx] || emptyDataItem, dim.property, sourceIdx, dimIdx);
+            chunks[dimIdx][idx] = val;
+            var dimRawExtent = rawExtent[dimIdx];
+            val < dimRawExtent[0] && (dimRawExtent[0] = val);
+            val > dimRawExtent[1] && (dimRawExtent[1] = val);
           }
         }
 
-        var sourceList;
-        var upSourceList = [];
-        var upstreamSignList = [];
-        each(upMgrList, function (upMgr) {
-          upMgr.prepareSource();
-          var upSource = upMgr.getSource(fromTransformResult || 0);
-          var errMsg = '';
+        this._rawCount = this._count = end;
+        return {
+          start: start,
+          end: end
+        };
+      };
 
-          if (fromTransformResult != null && !upSource) {
-            if ("development" !== 'production') {
-              errMsg = 'Can not retrieve result by `fromTransformResult`: ' + fromTransformResult;
-            }
+      DataStore.prototype._initDataFromProvider = function (start, end, append) {
+        var provider = this._provider;
+        var chunks = this._chunks;
+        var dimensions = this._dimensions;
+        var dimLen = dimensions.length;
+        var rawExtent = this._rawExtent;
+        var dimNames = map(dimensions, function (dim) {
+          return dim.property;
+        });
 
-            doThrow(errMsg);
+        for (var i = 0; i < dimLen; i++) {
+          var dim = dimensions[i];
+
+          if (!rawExtent[i]) {
+            rawExtent[i] = getInitialExtent();
           }
 
-          upSourceList.push(upSource);
-          upstreamSignList.push(upMgr._getVersionSign());
-        });
+          prepareStore(chunks, i, dim.type, end, append);
+        }
 
-        if (transformOption) {
-          sourceList = applyDataTransform(transformOption, upSourceList, {
-            datasetIndex: datasetModel.componentIndex
-          });
-        } else if (fromTransformResult != null) {
-          sourceList = [cloneSourceShallow(upSourceList[0])];
+        if (provider.fillStorage) {
+          provider.fillStorage(start, end, chunks, rawExtent);
+        } else {
+          var dataItem = [];
+
+          for (var idx = start; idx < end; idx++) {
+            // NOTICE: Try not to write things into dataItem
+            dataItem = provider.getItem(idx, dataItem); // Each data item is value
+            // [1, 2]
+            // 2
+            // Bar chart, line chart which uses category axis
+            // only gives the 'y' value. 'x' value is the indices of category
+            // Use a tempValue to normalize the value to be a (x, y) value
+            // Store the data by dimensions
+
+            for (var dimIdx = 0; dimIdx < dimLen; dimIdx++) {
+              var dimStorage = chunks[dimIdx]; // PENDING NULL is empty or zero
+
+              var val = this._dimValueGetter(dataItem, dimNames[dimIdx], idx, dimIdx);
+
+              dimStorage[idx] = val;
+              var dimRawExtent = rawExtent[dimIdx];
+              val < dimRawExtent[0] && (dimRawExtent[0] = val);
+              val > dimRawExtent[1] && (dimRawExtent[1] = val);
+            }
+          }
         }
 
-        return {
-          sourceList: sourceList,
-          upstreamSignList: upstreamSignList
-        };
+        if (!provider.persistent && provider.clean) {
+          // Clean unused data if data source is typed array.
+          provider.clean();
+        }
+
+        this._rawCount = this._count = end; // Reset data extent
+
+        this._extent = [];
       };
 
-      SourceManager.prototype._isDirty = function () {
-        var sourceList = this._sourceList;
+      DataStore.prototype.count = function () {
+        return this._count;
+      };
+      /**
+       * Get value. Return NaN if idx is out of range.
+       */
 
-        if (!sourceList.length) {
-          return true;
-        } // All sourceList is from the some upsteam.
 
+      DataStore.prototype.get = function (dim, idx) {
+        if (!(idx >= 0 && idx < this._count)) {
+          return NaN;
+        }
 
-        var upSourceMgrList = this._getUpstreamSourceManagers();
+        var dimStore = this._chunks[dim];
+        return dimStore ? dimStore[this.getRawIndex(idx)] : NaN;
+      };
 
-        for (var i = 0; i < upSourceMgrList.length; i++) {
-          var upSrcMgr = upSourceMgrList[i];
+      DataStore.prototype.getValues = function (dimensions, idx) {
+        var values = [];
+        var dimArr = [];
 
-          if ( // Consider the case that there is ancestor diry, call it recursively.
-          // The performance is probably not an issue because usually the chain is not long.
-          upSrcMgr._isDirty() || this._upstreamSignList[i] !== upSrcMgr._getVersionSign()) {
-            return true;
+        if (idx == null) {
+          idx = dimensions; // TODO get all from store?
+
+          dimensions = []; // All dimensions
+
+          for (var i = 0; i < this._dimensions.length; i++) {
+            dimArr.push(i);
           }
+        } else {
+          dimArr = dimensions;
+        }
+
+        for (var i = 0, len = dimArr.length; i < len; i++) {
+          values.push(this.get(dimArr[i], idx));
         }
+
+        return values;
       };
       /**
-       * @param sourceIndex By defualt 0, means "main source".
-       *                    Most cases there is only one source.
+       * @param dim concrete dim
        */
 
 
-      SourceManager.prototype.getSource = function (sourceIndex) {
-        return this._sourceList[sourceIndex || 0];
+      DataStore.prototype.getByRawIndex = function (dim, rawIdx) {
+        if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {
+          return NaN;
+        }
+
+        var dimStore = this._chunks[dim];
+        return dimStore ? dimStore[rawIdx] : NaN;
       };
       /**
-       * PEDING: Is it fast enough?
-       * If no upstream, return empty array.
+       * Get sum of data in one dimension
        */
 
 
-      SourceManager.prototype._getUpstreamSourceManagers = function () {
-        // Always get the relationship from the raw option.
-        // Do not cache the link of the dependency graph, so that
-        // no need to update them when change happen.
-        var sourceHost = this._sourceHost;
+      DataStore.prototype.getSum = function (dim) {
+        var dimData = this._chunks[dim];
+        var sum = 0;
 
-        if (isSeries(sourceHost)) {
-          var datasetModel = querySeriesUpstreamDatasetModel(sourceHost);
-          return !datasetModel ? [] : [datasetModel.getSourceManager()];
-        } else {
-          return map(queryDatasetUpstreamDatasetModels(sourceHost), function (datasetModel) {
-            return datasetModel.getSourceManager();
-          });
+        if (dimData) {
+          for (var i = 0, len = this.count(); i < len; i++) {
+            var value = this.get(dim, i);
+
+            if (!isNaN(value)) {
+              sum += value;
+            }
+          }
         }
+
+        return sum;
       };
+      /**
+       * Get median of data in one dimension
+       */
 
-      SourceManager.prototype._getSourceMetaRawOption = function () {
-        var sourceHost = this._sourceHost;
-        var seriesLayoutBy;
-        var sourceHeader;
-        var dimensions;
 
-        if (isSeries(sourceHost)) {
-          seriesLayoutBy = sourceHost.get('seriesLayoutBy', true);
-          sourceHeader = sourceHost.get('sourceHeader', true);
-          dimensions = sourceHost.get('dimensions', true);
-        } // See [REQUIREMENT_MEMO], `non-root-dataset` do not support them.
-        else if (!this._getUpstreamSourceManagers().length) {
-            var model = sourceHost;
-            seriesLayoutBy = model.get('seriesLayoutBy', true);
-            sourceHeader = model.get('sourceHeader', true);
-            dimensions = model.get('dimensions', true);
+      DataStore.prototype.getMedian = function (dim) {
+        var dimDataArray = []; // map all data of one dimension
+
+        this.each([dim], function (val) {
+          if (!isNaN(val)) {
+            dimDataArray.push(val);
           }
+        }); // TODO
+        // Use quick select?
 
-        return {
-          seriesLayoutBy: seriesLayoutBy,
-          sourceHeader: sourceHeader,
-          dimensions: dimensions
-        };
-      };
+        var sortedDimDataArray = dimDataArray.sort(function (a, b) {
+          return a - b;
+        });
+        var len = this.count(); // calculate median
 
-      return SourceManager;
-    }();
-    // disable the transform merge, but do not disable transfrom clone from rawOption.
+        return len === 0 ? 0 : len % 2 === 1 ? sortedDimDataArray[(len - 1) / 2] : (sortedDimDataArray[len / 2] + sortedDimDataArray[len / 2 - 1]) / 2;
+      };
+      /**
+       * Retreive the index with given raw data index
+       */
 
-    function disableTransformOptionMerge(datasetModel) {
-      var transformOption = datasetModel.option.transform;
-      transformOption && setAsPrimitive(datasetModel.option.transform);
-    }
 
-    function isSeries(sourceHost) {
-      // Avoid circular dependency with Series.ts
-      return sourceHost.mainType === 'series';
-    }
+      DataStore.prototype.indexOfRawIndex = function (rawIndex) {
+        if (rawIndex >= this._rawCount || rawIndex < 0) {
+          return -1;
+        }
 
-    function doThrow(errMsg) {
-      throw new Error(errMsg);
-    }
+        if (!this._indices) {
+          return rawIndex;
+        } // Indices are ascending
 
-    var TOOLTIP_LINE_HEIGHT_CSS = 'line-height:1'; // TODO: more textStyle option
 
-    function getTooltipTextStyle(textStyle, renderMode) {
-      var nameFontColor = textStyle.color || '#6e7079';
-      var nameFontSize = textStyle.fontSize || 12;
-      var nameFontWeight = textStyle.fontWeight || '400';
-      var valueFontColor = textStyle.color || '#464646';
-      var valueFontSize = textStyle.fontSize || 14;
-      var valueFontWeight = textStyle.fontWeight || '900';
+        var indices = this._indices; // If rawIndex === dataIndex
 
-      if (renderMode === 'html') {
-        // `textStyle` is probably from user input, should be encoded to reduce security risk.
-        return {
-          // eslint-disable-next-line max-len
-          nameStyle: "font-size:" + encodeHTML(nameFontSize + '') + "px;color:" + encodeHTML(nameFontColor) + ";font-weight:" + encodeHTML(nameFontWeight + ''),
-          // eslint-disable-next-line max-len
-          valueStyle: "font-size:" + encodeHTML(valueFontSize + '') + "px;color:" + encodeHTML(valueFontColor) + ";font-weight:" + encodeHTML(valueFontWeight + '')
-        };
-      } else {
-        return {
-          nameStyle: {
-            fontSize: nameFontSize,
-            fill: nameFontColor,
-            fontWeight: nameFontWeight
-          },
-          valueStyle: {
-            fontSize: valueFontSize,
-            fill: valueFontColor,
-            fontWeight: valueFontWeight
-          }
-        };
-      }
-    } // See `TooltipMarkupLayoutIntent['innerGapLevel']`.
-    // (value from UI design)
+        var rawDataIndex = indices[rawIndex];
 
+        if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {
+          return rawIndex;
+        }
 
-    var HTML_GAPS = [0, 10, 20, 30];
-    var RICH_TEXT_GAPS = ['', '\n', '\n\n', '\n\n\n']; // eslint-disable-next-line max-len
+        var left = 0;
+        var right = this._count - 1;
 
-    function createTooltipMarkup(type, option) {
-      option.type = type;
-      return option;
-    }
+        while (left <= right) {
+          var mid = (left + right) / 2 | 0;
 
-    function getBuilder(fragment) {
-      return hasOwn(builderMap, fragment.type) && builderMap[fragment.type];
-    }
+          if (indices[mid] < rawIndex) {
+            left = mid + 1;
+          } else if (indices[mid] > rawIndex) {
+            right = mid - 1;
+          } else {
+            return mid;
+          }
+        }
 
-    var builderMap = {
+        return -1;
+      };
       /**
-       * A `section` block is like:
-       * ```
-       * header
-       * subBlock
-       * subBlock
-       * ...
-       * ```
+       * Retreive the index of nearest value
+       * @param dim
+       * @param value
+       * @param [maxDistance=Infinity]
+       * @return If and only if multiple indices has
+       *         the same value, they are put to the result.
        */
-      section: {
-        planLayout: function (fragment) {
-          var subBlockLen = fragment.blocks.length;
-          var thisBlockHasInnerGap = subBlockLen > 1 || subBlockLen > 0 && !fragment.noHeader;
-          var thisGapLevelBetweenSubBlocks = 0;
-          each(fragment.blocks, function (subBlock) {
-            getBuilder(subBlock).planLayout(subBlock);
-            var subGapLevel = subBlock.__gapLevelBetweenSubBlocks; // If the some of the sub-blocks have some gaps (like 10px) inside, this block
-            // should use a larger gap (like 20px) to distinguish those sub-blocks.
 
-            if (subGapLevel >= thisGapLevelBetweenSubBlocks) {
-              thisGapLevelBetweenSubBlocks = subGapLevel + (thisBlockHasInnerGap && ( // 0 always can not be readable gap level.
-              !subGapLevel // If no header, always keep the sub gap level. Otherwise
-              // look weird in case `multipleSeries`.
-              || subBlock.type === 'section' && !subBlock.noHeader) ? 1 : 0);
+
+      DataStore.prototype.indicesOfNearest = function (dim, value, maxDistance) {
+        var chunks = this._chunks;
+        var dimData = chunks[dim];
+        var nearestIndices = [];
+
+        if (!dimData) {
+          return nearestIndices;
+        }
+
+        if (maxDistance == null) {
+          maxDistance = Infinity;
+        }
+
+        var minDist = Infinity;
+        var minDiff = -1;
+        var nearestIndicesLen = 0; // Check the test case of `test/ut/spec/data/SeriesData.js`.
+
+        for (var i = 0, len = this.count(); i < len; i++) {
+          var dataIndex = this.getRawIndex(i);
+          var diff = value - dimData[dataIndex];
+          var dist = Math.abs(diff);
+
+          if (dist <= maxDistance) {
+            // When the `value` is at the middle of `this.get(dim, i)` and `this.get(dim, i+1)`,
+            // we'd better not push both of them to `nearestIndices`, otherwise it is easy to
+            // get more than one item in `nearestIndices` (more specifically, in `tooltip`).
+            // So we chose the one that `diff >= 0` in this csae.
+            // But if `this.get(dim, i)` and `this.get(dim, j)` get the same value, both of them
+            // should be push to `nearestIndices`.
+            if (dist < minDist || dist === minDist && diff >= 0 && minDiff < 0) {
+              minDist = dist;
+              minDiff = diff;
+              nearestIndicesLen = 0;
             }
-          });
-          fragment.__gapLevelBetweenSubBlocks = thisGapLevelBetweenSubBlocks;
-        },
-        build: function (ctx, fragment, topMarginForOuterGap, toolTipTextStyle) {
-          var noHeader = fragment.noHeader;
-          var gaps = getGap(fragment);
-          var subMarkupText = buildSubBlocks(ctx, fragment, noHeader ? topMarginForOuterGap : gaps.html, toolTipTextStyle);
 
-          if (noHeader) {
-            return subMarkupText;
+            if (diff === minDiff) {
+              nearestIndices[nearestIndicesLen++] = i;
+            }
           }
+        }
 
-          var displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC);
-          var nameStyle = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode).nameStyle;
+        nearestIndices.length = nearestIndicesLen;
+        return nearestIndices;
+      };
 
-          if (ctx.renderMode === 'richText') {
-            return wrapInlineNameRichText(ctx, displayableHeader, nameStyle) + gaps.richText + subMarkupText;
+      DataStore.prototype.getIndices = function () {
+        var newIndices;
+        var indices = this._indices;
+
+        if (indices) {
+          var Ctor = indices.constructor;
+          var thisCount = this._count; // `new Array(a, b, c)` is different from `new Uint32Array(a, b, c)`.
+
+          if (Ctor === Array) {
+            newIndices = new Ctor(thisCount);
+
+            for (var i = 0; i < thisCount; i++) {
+              newIndices[i] = indices[i];
+            }
           } else {
-            return wrapBlockHTML("<div style=\"" + nameStyle + ";" + TOOLTIP_LINE_HEIGHT_CSS + ";\">" + encodeHTML(displayableHeader) + '</div>' + subMarkupText, topMarginForOuterGap);
+            newIndices = new Ctor(indices.buffer, 0, thisCount);
+          }
+        } else {
+          var Ctor = getIndicesCtor(this._rawCount);
+          newIndices = new Ctor(this.count());
+
+          for (var i = 0; i < newIndices.length; i++) {
+            newIndices[i] = i;
           }
         }
-      },
 
+        return newIndices;
+      };
       /**
-       * A `nameValue` block is like:
-       * ```
-       * marker  name  value
-       * ```
+       * Data filter.
        */
-      nameValue: {
-        planLayout: function (fragment) {
-          fragment.__gapLevelBetweenSubBlocks = 0;
-        },
-        build: function (ctx, fragment, topMarginForOuterGap, toolTipTextStyle) {
-          var renderMode = ctx.renderMode;
-          var noName = fragment.noName;
-          var noValue = fragment.noValue;
-          var noMarker = !fragment.markerType;
-          var name = fragment.name;
-          var value = fragment.value;
-          var useUTC = ctx.useUTC;
 
-          if (noName && noValue) {
-            return;
-          }
 
-          var markerStr = noMarker ? '' : ctx.markupStyleCreator.makeTooltipMarker(fragment.markerType, fragment.markerColor || '#333', renderMode);
-          var readableName = noName ? '' : makeValueReadable(name, 'ordinal', useUTC);
-          var valueTypeOption = fragment.valueType;
-          var readableValueList = noValue ? [] : isArray(value) ? map(value, function (val, idx) {
-            return makeValueReadable(val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, useUTC);
-          }) : [makeValueReadable(value, isArray(valueTypeOption) ? valueTypeOption[0] : valueTypeOption, useUTC)];
-          var valueAlignRight = !noMarker || !noName; // It little weird if only value next to marker but far from marker.
+      DataStore.prototype.filter = function (dims, cb) {
+        if (!this._count) {
+          return this;
+        }
 
-          var valueCloseToMarker = !noMarker && noName;
+        var newStore = this.clone();
+        var count = newStore.count();
+        var Ctor = getIndicesCtor(newStore._rawCount);
+        var newIndices = new Ctor(count);
+        var value = [];
+        var dimSize = dims.length;
+        var offset = 0;
+        var dim0 = dims[0];
+        var chunks = newStore._chunks;
 
-          var _a = getTooltipTextStyle(toolTipTextStyle, renderMode),
-              nameStyle = _a.nameStyle,
-              valueStyle = _a.valueStyle;
+        for (var i = 0; i < count; i++) {
+          var keep = void 0;
+          var rawIdx = newStore.getRawIndex(i); // Simple optimization
 
-          return renderMode === 'richText' ? (noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameRichText(ctx, readableName, nameStyle)) // Value has commas inside, so use ' ' as delimiter for multiple values.
-          + (noValue ? '' : wrapInlineValueRichText(ctx, readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)) : wrapBlockHTML((noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker, nameStyle)) + (noValue ? '' : wrapInlineValueHTML(readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)), topMarginForOuterGap);
-        }
-      }
-    };
+          if (dimSize === 0) {
+            keep = cb(i);
+          } else if (dimSize === 1) {
+            var val = chunks[dim0][rawIdx];
+            keep = cb(val, i);
+          } else {
+            var k = 0;
 
-    function buildSubBlocks(ctx, fragment, topMarginForOuterGap, tooltipTextStyle) {
-      var subMarkupTextList = [];
-      var subBlocks = fragment.blocks || [];
-      assert(!subBlocks || isArray(subBlocks));
-      subBlocks = subBlocks || [];
-      var orderMode = ctx.orderMode;
+            for (; k < dimSize; k++) {
+              value[k] = chunks[dims[k]][rawIdx];
+            }
 
-      if (fragment.sortBlocks && orderMode) {
-        subBlocks = subBlocks.slice();
-        var orderMap = {
-          valueAsc: 'asc',
-          valueDesc: 'desc'
-        };
+            value[k] = i;
+            keep = cb.apply(null, value);
+          }
 
-        if (hasOwn(orderMap, orderMode)) {
-          var comparator_1 = new SortOrderComparator(orderMap[orderMode], null);
-          subBlocks.sort(function (a, b) {
-            return comparator_1.evaluate(a.sortParam, b.sortParam);
-          });
-        } // FIXME 'seriesDesc' necessary?
-        else if (orderMode === 'seriesDesc') {
-            subBlocks.reverse();
+          if (keep) {
+            newIndices[offset++] = rawIdx;
           }
-      }
+        } // Set indices after filtered.
 
-      var gaps = getGap(fragment);
-      each(subBlocks, function (subBlock, idx) {
-        var subMarkupText = getBuilder(subBlock).build(ctx, subBlock, idx > 0 ? gaps.html : 0, tooltipTextStyle);
-        subMarkupText != null && subMarkupTextList.push(subMarkupText);
-      });
 
-      if (!subMarkupTextList.length) {
-        return;
-      }
+        if (offset < count) {
+          newStore._indices = newIndices;
+        }
 
-      return ctx.renderMode === 'richText' ? subMarkupTextList.join(gaps.richText) : wrapBlockHTML(subMarkupTextList.join(''), topMarginForOuterGap);
-    }
-    /**
-     * @return markupText. null/undefined means no content.
-     */
+        newStore._count = offset; // Reset data extent
 
+        newStore._extent = [];
 
-    function buildTooltipMarkup(fragment, markupStyleCreator, renderMode, orderMode, useUTC, toolTipTextStyle) {
-      if (!fragment) {
-        return;
-      }
+        newStore._updateGetRawIdx();
 
-      var builder = getBuilder(fragment);
-      builder.planLayout(fragment);
-      var ctx = {
-        useUTC: useUTC,
-        renderMode: renderMode,
-        orderMode: orderMode,
-        markupStyleCreator: markupStyleCreator
+        return newStore;
       };
-      return builder.build(ctx, fragment, 0, toolTipTextStyle);
-    }
+      /**
+       * Select data in range. (For optimization of filter)
+       * (Manually inline code, support 5 million data filtering in data zoom.)
+       */
 
-    function getGap(fragment) {
-      var gapLevelBetweenSubBlocks = fragment.__gapLevelBetweenSubBlocks;
-      return {
-        html: HTML_GAPS[gapLevelBetweenSubBlocks],
-        richText: RICH_TEXT_GAPS[gapLevelBetweenSubBlocks]
-      };
-    }
 
-    function wrapBlockHTML(encodedContent, topGap) {
-      var clearfix = '<div style="clear:both"></div>';
-      var marginCSS = "margin: " + topGap + "px 0 0";
-      return "<div style=\"" + marginCSS + ";" + TOOLTIP_LINE_HEIGHT_CSS + ";\">" + encodedContent + clearfix + '</div>';
-    }
+      DataStore.prototype.selectRange = function (range) {
+        var newStore = this.clone();
+        var len = newStore._count;
 
-    function wrapInlineNameHTML(name, leftHasMarker, style) {
-      var marginCss = leftHasMarker ? 'margin-left:2px' : '';
-      return "<span style=\"" + style + ";" + marginCss + "\">" + encodeHTML(name) + '</span>';
-    }
+        if (!len) {
+          return this;
+        }
 
-    function wrapInlineValueHTML(valueList, alignRight, valueCloseToMarker, style) {
-      // Do not too close to marker, considering there are multiple values separated by spaces.
-      var paddingStr = valueCloseToMarker ? '10px' : '20px';
-      var alignCSS = alignRight ? "float:right;margin-left:" + paddingStr : '';
-      return "<span style=\"" + alignCSS + ";" + style + "\">" // Value has commas inside, so use '  ' as delimiter for multiple values.
-      + map(valueList, function (value) {
-        return encodeHTML(value);
-      }).join('&nbsp;&nbsp;') + '</span>';
-    }
+        var dims = keys(range);
+        var dimSize = dims.length;
 
-    function wrapInlineNameRichText(ctx, name, style) {
-      return ctx.markupStyleCreator.wrapRichTextStyle(name, style);
-    }
+        if (!dimSize) {
+          return this;
+        }
 
-    function wrapInlineValueRichText(ctx, valueList, alignRight, valueCloseToMarker, style) {
-      var styles = [style];
-      var paddingLeft = valueCloseToMarker ? 10 : 20;
-      alignRight && styles.push({
-        padding: [0, 0, 0, paddingLeft],
-        align: 'right'
-      }); // Value has commas inside, so use '  ' as delimiter for multiple values.
+        var originalCount = newStore.count();
+        var Ctor = getIndicesCtor(newStore._rawCount);
+        var newIndices = new Ctor(originalCount);
+        var offset = 0;
+        var dim0 = dims[0];
+        var min = range[dim0][0];
+        var max = range[dim0][1];
+        var storeArr = newStore._chunks;
+        var quickFinished = false;
 
-      return ctx.markupStyleCreator.wrapRichTextStyle(valueList.join('  '), styles);
-    }
+        if (!newStore._indices) {
+          // Extreme optimization for common case. About 2x faster in chrome.
+          var idx = 0;
 
-    function retrieveVisualColorForTooltipMarker(series, dataIndex) {
-      var style = series.getData().getItemVisual(dataIndex, 'style');
-      var color = style[series.visualDrawType];
-      return convertToColorString(color);
-    }
-    function getPaddingFromTooltipModel(model, renderMode) {
-      var padding = model.get('padding');
-      return padding != null ? padding // We give slightly different to look pretty.
-      : renderMode === 'richText' ? [8, 10] : 10;
-    }
-    /**
-     * The major feature is generate styles for `renderMode: 'richText'`.
-     * But it also serves `renderMode: 'html'` to provide
-     * "renderMode-independent" API.
-     */
+          if (dimSize === 1) {
+            var dimStorage = storeArr[dims[0]];
 
-    var TooltipMarkupStyleCreator =
-    /** @class */
-    function () {
-      function TooltipMarkupStyleCreator() {
-        this.richTextStyles = {}; // Notice that "generate a style name" usuall happens repeatly when mouse moving and
-        // displaying a tooltip. So we put the `_nextStyleNameId` as a member of each creator
-        // rather than static shared by all creators (which will cause it increase to fast).
+            for (var i = 0; i < len; i++) {
+              var val = dimStorage[i]; // NaN will not be filtered. Consider the case, in line chart, empty
+              // value indicates the line should be broken. But for the case like
+              // scatter plot, a data item with empty value will not be rendered,
+              // but the axis extent may be effected if some other dim of the data
+              // item has value. Fortunately it is not a significant negative effect.
 
-        this._nextStyleNameId = getRandomIdBase();
-      }
+              if (val >= min && val <= max || isNaN(val)) {
+                newIndices[offset++] = idx;
+              }
 
-      TooltipMarkupStyleCreator.prototype._generateStyleName = function () {
-        return '__EC_aUTo_' + this._nextStyleNameId++;
-      };
+              idx++;
+            }
 
-      TooltipMarkupStyleCreator.prototype.makeTooltipMarker = function (markerType, colorStr, renderMode) {
-        var markerId = renderMode === 'richText' ? this._generateStyleName() : null;
-        var marker = getTooltipMarker({
-          color: colorStr,
-          type: markerType,
-          renderMode: renderMode,
-          markerId: markerId
-        });
+            quickFinished = true;
+          } else if (dimSize === 2) {
+            var dimStorage = storeArr[dims[0]];
+            var dimStorage2 = storeArr[dims[1]];
+            var min2 = range[dims[1]][0];
+            var max2 = range[dims[1]][1];
 
-        if (isString(marker)) {
-          return marker;
-        } else {
-          if ("development" !== 'production') {
-            assert(markerId);
-          }
+            for (var i = 0; i < len; i++) {
+              var val = dimStorage[i];
+              var val2 = dimStorage2[i]; // Do not filter NaN, see comment above.
 
-          this.richTextStyles[markerId] = marker.style;
-          return marker.content;
+              if ((val >= min && val <= max || isNaN(val)) && (val2 >= min2 && val2 <= max2 || isNaN(val2))) {
+                newIndices[offset++] = idx;
+              }
+
+              idx++;
+            }
+
+            quickFinished = true;
+          }
         }
-      };
-      /**
-       * @usage
-       * ```ts
-       * const styledText = markupStyleCreator.wrapRichTextStyle([
-       *     // The styles will be auto merged.
-       *     {
-       *         fontSize: 12,
-       *         color: 'blue'
-       *     },
-       *     {
-       *         padding: 20
-       *     }
-       * ]);
-       * ```
-       */
 
+        if (!quickFinished) {
+          if (dimSize === 1) {
+            for (var i = 0; i < originalCount; i++) {
+              var rawIndex = newStore.getRawIndex(i);
+              var val = storeArr[dims[0]][rawIndex]; // Do not filter NaN, see comment above.
 
-      TooltipMarkupStyleCreator.prototype.wrapRichTextStyle = function (text, styles) {
-        var finalStl = {};
+              if (val >= min && val <= max || isNaN(val)) {
+                newIndices[offset++] = rawIndex;
+              }
+            }
+          } else {
+            for (var i = 0; i < originalCount; i++) {
+              var keep = true;
+              var rawIndex = newStore.getRawIndex(i);
 
-        if (isArray(styles)) {
-          each(styles, function (stl) {
-            return extend(finalStl, stl);
-          });
-        } else {
-          extend(finalStl, styles);
-        }
+              for (var k = 0; k < dimSize; k++) {
+                var dimk = dims[k];
+                var val = storeArr[dimk][rawIndex]; // Do not filter NaN, see comment above.
 
-        var styleName = this._generateStyleName();
+                if (val < range[dimk][0] || val > range[dimk][1]) {
+                  keep = false;
+                }
+              }
 
-        this.richTextStyles[styleName] = finalStl;
-        return "{" + styleName + "|" + text + "}";
-      };
+              if (keep) {
+                newIndices[offset++] = newStore.getRawIndex(i);
+              }
+            }
+          }
+        } // Set indices after filtered.
 
-      return TooltipMarkupStyleCreator;
-    }();
 
-    function defaultSeriesFormatTooltip(opt) {
-      var series = opt.series;
-      var dataIndex = opt.dataIndex;
-      var multipleSeries = opt.multipleSeries;
-      var data = series.getData();
-      var tooltipDims = data.mapDimensionsAll('defaultedTooltip');
-      var tooltipDimLen = tooltipDims.length;
-      var value = series.getRawValue(dataIndex);
-      var isValueArr = isArray(value);
-      var markerColor = retrieveVisualColorForTooltipMarker(series, dataIndex); // Complicated rule for pretty tooltip.
+        if (offset < originalCount) {
+          newStore._indices = newIndices;
+        }
 
-      var inlineValue;
-      var inlineValueType;
-      var subBlocks;
-      var sortParam;
+        newStore._count = offset; // Reset data extent
 
-      if (tooltipDimLen > 1 || isValueArr && !tooltipDimLen) {
-        var formatArrResult = formatTooltipArrayValue(value, series, dataIndex, tooltipDims, markerColor);
-        inlineValue = formatArrResult.inlineValues;
-        inlineValueType = formatArrResult.inlineValueTypes;
-        subBlocks = formatArrResult.blocks; // Only support tooltip sort by the first inline value. It's enough in most cases.
+        newStore._extent = [];
 
-        sortParam = formatArrResult.inlineValues[0];
-      } else if (tooltipDimLen) {
-        var dimInfo = data.getDimensionInfo(tooltipDims[0]);
-        sortParam = inlineValue = retrieveRawValue(data, dataIndex, tooltipDims[0]);
-        inlineValueType = dimInfo.type;
-      } else {
-        sortParam = inlineValue = isValueArr ? value[0] : value;
-      } // Do not show generated series name. It might not be readable.
+        newStore._updateGetRawIdx();
 
+        return newStore;
+      }; // /**
+      //  * Data mapping to a plain array
+      //  */
+      // mapArray(dims: DimensionIndex[], cb: MapArrayCb): any[] {
+      //     const result: any[] = [];
+      //     this.each(dims, function () {
+      //         result.push(cb && (cb as MapArrayCb).apply(null, arguments));
+      //     });
+      //     return result;
+      // }
 
-      var seriesNameSpecified = isNameSpecified(series);
-      var seriesName = seriesNameSpecified && series.name || '';
-      var itemName = data.getName(dataIndex);
-      var inlineName = multipleSeries ? seriesName : itemName;
-      return createTooltipMarkup('section', {
-        header: seriesName,
-        // When series name not specified, do not show a header line with only '-'.
-        // This case alway happen in tooltip.trigger: 'item'.
-        noHeader: multipleSeries || !seriesNameSpecified,
-        sortParam: sortParam,
-        blocks: [createTooltipMarkup('nameValue', {
-          markerType: 'item',
-          markerColor: markerColor,
-          // Do not mix display seriesName and itemName in one tooltip,
-          // which might confuses users.
-          name: inlineName,
-          // name dimension might be auto assigned, where the name might
-          // be not readable. So we check trim here.
-          noName: !trim(inlineName),
-          value: inlineValue,
-          valueType: inlineValueType
-        })].concat(subBlocks || [])
-      });
-    }
+      /**
+       * Data mapping to a new List with given dimensions
+       */
 
-    function formatTooltipArrayValue(value, series, dataIndex, tooltipDims, colorStr) {
-      // check: category-no-encode-has-axis-data in dataset.html
-      var data = series.getData();
-      var isValueMultipleLine = reduce(value, function (isValueMultipleLine, val, idx) {
-        var dimItem = data.getDimensionInfo(idx);
-        return isValueMultipleLine = isValueMultipleLine || dimItem && dimItem.tooltip !== false && dimItem.displayName != null;
-      }, false);
-      var inlineValues = [];
-      var inlineValueTypes = [];
-      var blocks = [];
-      tooltipDims.length ? each(tooltipDims, function (dim) {
-        setEachItem(retrieveRawValue(data, dataIndex, dim), dim);
-      }) // By default, all dims is used on tooltip.
-      : each(value, setEachItem);
 
-      function setEachItem(val, dim) {
-        var dimInfo = data.getDimensionInfo(dim); // If `dimInfo.tooltip` is not set, show tooltip.
+      DataStore.prototype.map = function (dims, cb) {
+        // TODO only clone picked chunks.
+        var target = this.clone(dims);
 
-        if (!dimInfo || dimInfo.otherDims.tooltip === false) {
-          return;
-        }
+        this._updateDims(target, dims, cb);
 
-        if (isValueMultipleLine) {
-          blocks.push(createTooltipMarkup('nameValue', {
-            markerType: 'subItem',
-            markerColor: colorStr,
-            name: dimInfo.displayName,
-            value: val,
-            valueType: dimInfo.type
-          }));
-        } else {
-          inlineValues.push(val);
-          inlineValueTypes.push(dimInfo.type);
-        }
-      }
+        return target;
+      };
+      /**
+       * @caution Danger!! Only used in dataStack.
+       */
 
-      return {
-        inlineValues: inlineValues,
-        inlineValueTypes: inlineValueTypes,
-        blocks: blocks
+
+      DataStore.prototype.modify = function (dims, cb) {
+        this._updateDims(this, dims, cb);
       };
-    }
 
-    var inner$1 = makeInner();
+      DataStore.prototype._updateDims = function (target, dims, cb) {
+        var targetChunks = target._chunks;
+        var tmpRetValue = [];
+        var dimSize = dims.length;
+        var dataCount = target.count();
+        var values = [];
+        var rawExtent = target._rawExtent;
 
-    function getSelectionKey(data, dataIndex) {
-      return data.getName(dataIndex) || data.getId(dataIndex);
-    }
+        for (var i = 0; i < dims.length; i++) {
+          rawExtent[dims[i]] = getInitialExtent();
+        }
 
-    var SeriesModel =
-    /** @class */
-    function (_super) {
-      __extends(SeriesModel, _super);
+        for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {
+          var rawIndex = target.getRawIndex(dataIndex);
 
-      function SeriesModel() {
-        // [Caution]: Becuase this class or desecendants can be used as `XXX.extend(subProto)`,
-        // the class members must not be initialized in constructor or declaration place.
-        // Otherwise there is bad case:
-        //   class A {xxx = 1;}
-        //   enableClassExtend(A);
-        //   class B extends A {}
-        //   var C = B.extend({xxx: 5});
-        //   var c = new C();
-        //   console.log(c.xxx); // expect 5 but always 1.
-        var _this = _super !== null && _super.apply(this, arguments) || this; // ---------------------------------------
-        // Props about data selection
-        // ---------------------------------------
+          for (var k = 0; k < dimSize; k++) {
+            values[k] = targetChunks[dims[k]][rawIndex];
+          }
 
+          values[dimSize] = dataIndex;
+          var retValue = cb && cb.apply(null, values);
 
-        _this._selectedDataIndicesMap = {};
-        return _this;
-      }
+          if (retValue != null) {
+            // a number or string (in oridinal dimension)?
+            if (typeof retValue !== 'object') {
+              tmpRetValue[0] = retValue;
+              retValue = tmpRetValue;
+            }
 
-      SeriesModel.prototype.init = function (option, parentModel, ecModel) {
-        this.seriesIndex = this.componentIndex;
-        this.dataTask = createTask({
-          count: dataTaskCount,
-          reset: dataTaskReset
-        });
-        this.dataTask.context = {
-          model: this
-        };
-        this.mergeDefaultAndTheme(option, ecModel);
-        var sourceManager = inner$1(this).sourceManager = new SourceManager(this);
-        sourceManager.prepareSource();
-        var data = this.getInitialData(option, ecModel);
-        wrapData(data, this);
-        this.dataTask.context.data = data;
-
-        if ("development" !== 'production') {
-          assert(data, 'getInitialData returned invalid data.');
-        }
+            for (var i = 0; i < retValue.length; i++) {
+              var dim = dims[i];
+              var val = retValue[i];
+              var rawExtentOnDim = rawExtent[dim];
+              var dimStore = targetChunks[dim];
 
-        inner$1(this).dataBeforeProcessed = data; // If we reverse the order (make data firstly, and then make
-        // dataBeforeProcessed by cloneShallow), cloneShallow will
-        // cause data.graph.data !== data when using
-        // module:echarts/data/Graph or module:echarts/data/Tree.
-        // See module:echarts/data/helper/linkList
-        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model
-        // init or merge stage, because the data can be restored. So we do not `restoreData`
-        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.
-        // Call `seriesModel.getRawData()` instead.
-        // this.restoreData();
+              if (dimStore) {
+                dimStore[rawIndex] = val;
+              }
 
-        autoSeriesName(this);
+              if (val < rawExtentOnDim[0]) {
+                rawExtentOnDim[0] = val;
+              }
 
-        this._initSelectedMapFromData(data);
+              if (val > rawExtentOnDim[1]) {
+                rawExtentOnDim[1] = val;
+              }
+            }
+          }
+        }
       };
       /**
-       * Util for merge default and theme to option
+       * Large data down sampling using largest-triangle-three-buckets
+       * @param {string} valueDimension
+       * @param {number} targetCount
        */
 
 
-      SeriesModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
-        var layoutMode = fetchLayoutMode(this);
-        var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; // Backward compat: using subType on theme.
-        // But if name duplicate between series subType
-        // (for example: parallel) add component mainType,
-        // add suffix 'Series'.
+      DataStore.prototype.lttbDownSample = function (valueDimension, rate) {
+        var target = this.clone([valueDimension], true);
+        var targetStorage = target._chunks;
+        var dimStore = targetStorage[valueDimension];
+        var len = this.count();
+        var sampledIndex = 0;
+        var frameSize = Math.floor(1 / rate);
+        var currentRawIndex = this.getRawIndex(0);
+        var maxArea;
+        var area;
+        var nextRawIndex;
+        var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize) + 2); // First frame use the first data.
 
-        var themeSubType = this.subType;
+        newIndices[sampledIndex++] = currentRawIndex;
 
-        if (ComponentModel.hasClass(themeSubType)) {
-          themeSubType += 'Series';
-        }
+        for (var i = 1; i < len - 1; i += frameSize) {
+          var nextFrameStart = Math.min(i + frameSize, len - 1);
+          var nextFrameEnd = Math.min(i + frameSize * 2, len);
+          var avgX = (nextFrameEnd + nextFrameStart) / 2;
+          var avgY = 0;
 
-        merge(option, ecModel.getTheme().get(this.subType));
-        merge(option, this.getDefaultOption()); // Default label emphasis `show`
+          for (var idx = nextFrameStart; idx < nextFrameEnd; idx++) {
+            var rawIndex = this.getRawIndex(idx);
+            var y = dimStore[rawIndex];
 
-        defaultEmphasis(option, 'label', ['show']);
-        this.fillDataTextStyle(option.data);
+            if (isNaN(y)) {
+              continue;
+            }
 
-        if (layoutMode) {
-          mergeLayoutParam(option, inputPositionParams, layoutMode);
-        }
-      };
+            avgY += y;
+          }
 
-      SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) {
-        // this.settingTask.dirty();
-        newSeriesOption = merge(this.option, newSeriesOption, true);
-        this.fillDataTextStyle(newSeriesOption.data);
-        var layoutMode = fetchLayoutMode(this);
+          avgY /= nextFrameEnd - nextFrameStart;
+          var frameStart = i;
+          var frameEnd = Math.min(i + frameSize, len);
+          var pointAX = i - 1;
+          var pointAY = dimStore[currentRawIndex];
+          maxArea = -1;
+          nextRawIndex = frameStart; // Find a point from current frame that construct a triangel with largest area with previous selected point
+          // And the average of next frame.
 
-        if (layoutMode) {
-          mergeLayoutParam(this.option, newSeriesOption, layoutMode);
-        }
+          for (var idx = frameStart; idx < frameEnd; idx++) {
+            var rawIndex = this.getRawIndex(idx);
+            var y = dimStore[rawIndex];
 
-        var sourceManager = inner$1(this).sourceManager;
-        sourceManager.dirty();
-        sourceManager.prepareSource();
-        var data = this.getInitialData(newSeriesOption, ecModel);
-        wrapData(data, this);
-        this.dataTask.dirty();
-        this.dataTask.context.data = data;
-        inner$1(this).dataBeforeProcessed = data;
-        autoSeriesName(this);
+            if (isNaN(y)) {
+              continue;
+            } // Calculate triangle area over three buckets
 
-        this._initSelectedMapFromData(data);
-      };
 
-      SeriesModel.prototype.fillDataTextStyle = function (data) {
-        // Default data label emphasis `show`
-        // FIXME Tree structure data ?
-        // FIXME Performance ?
-        if (data && !isTypedArray(data)) {
-          var props = ['show'];
+            area = Math.abs((pointAX - avgX) * (y - pointAY) - (pointAX - idx) * (avgY - pointAY));
 
-          for (var i = 0; i < data.length; i++) {
-            if (data[i] && data[i].label) {
-              defaultEmphasis(data[i], 'label', props);
+            if (area > maxArea) {
+              maxArea = area;
+              nextRawIndex = rawIndex; // Next a is this b
             }
           }
-        }
-      };
-      /**
-       * Init a data structure from data related option in series
-       * Must be overriden.
-       */
-
 
-      SeriesModel.prototype.getInitialData = function (option, ecModel) {
-        return;
-      };
-      /**
-       * Append data to list
-       */
+          newIndices[sampledIndex++] = nextRawIndex;
+          currentRawIndex = nextRawIndex; // This a is the next a (chosen b)
+        } // First frame use the last data.
 
 
-      SeriesModel.prototype.appendData = function (params) {
-        // FIXME ???
-        // (1) If data from dataset, forbidden append.
-        // (2) support append data of dataset.
-        var data = this.getRawData();
-        data.appendData(params.data);
+        newIndices[sampledIndex++] = this.getRawIndex(len - 1);
+        target._count = sampledIndex;
+        target._indices = newIndices;
+        target.getRawIndex = this._getRawIdx;
+        return target;
       };
       /**
-       * Consider some method like `filter`, `map` need make new data,
-       * We should make sure that `seriesModel.getData()` get correct
-       * data in the stream procedure. So we fetch data from upstream
-       * each time `task.perform` called.
+       * Large data down sampling on given dimension
+       * @param sampleIndex Sample index for name and id
        */
 
 
-      SeriesModel.prototype.getData = function (dataType) {
-        var task = getCurrentTask(this);
+      DataStore.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) {
+        var target = this.clone([dimension], true);
+        var targetStorage = target._chunks;
+        var frameValues = [];
+        var frameSize = Math.floor(1 / rate);
+        var dimStore = targetStorage[dimension];
+        var len = this.count();
+        var rawExtentOnDim = target._rawExtent[dimension] = getInitialExtent();
+        var newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize));
+        var offset = 0;
 
-        if (task) {
-          var data = task.context.data;
-          return dataType == null ? data : data.getLinkedData(dataType);
-        } else {
-          // When series is not alive (that may happen when click toolbox
-          // 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$1(this).data;
-        }
-      };
+        for (var i = 0; i < len; i += frameSize) {
+          // Last frame
+          if (frameSize > len - i) {
+            frameSize = len - i;
+            frameValues.length = frameSize;
+          }
 
-      SeriesModel.prototype.getAllData = function () {
-        var mainData = this.getData();
-        return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{
-          data: mainData
-        }];
-      };
+          for (var k = 0; k < frameSize; k++) {
+            var dataIdx = this.getRawIndex(i + k);
+            frameValues[k] = dimStore[dataIdx];
+          }
 
-      SeriesModel.prototype.setData = function (data) {
-        var task = getCurrentTask(this);
+          var value = sampleValue(frameValues);
+          var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)); // Only write value on the filtered data
 
-        if (task) {
-          var context = task.context; // Consider case: filter, data sample.
-          // FIXME:TS never used, so comment it
-          // if (context.data !== data && task.modifyOutputEnd) {
-          //     task.setOutputEnd(data.count());
-          // }
+          dimStore[sampleFrameIdx] = value;
 
-          context.outputData = data; // Caution: setData should update context.data,
-          // Because getData may be called multiply in a
-          // single stage and expect to get the data just
-          // set. (For example, AxisProxy, x y both call
-          // getData and setDate sequentially).
-          // So the context.data should be fetched from
-          // upstream each time when a stage starts to be
-          // performed.
+          if (value < rawExtentOnDim[0]) {
+            rawExtentOnDim[0] = value;
+          }
 
-          if (task !== this.dataTask) {
-            context.data = data;
+          if (value > rawExtentOnDim[1]) {
+            rawExtentOnDim[1] = value;
           }
-        }
 
-        inner$1(this).data = data;
-      };
+          newIndices[offset++] = sampleFrameIdx;
+        }
 
-      SeriesModel.prototype.getSource = function () {
-        return inner$1(this).sourceManager.getSource();
-      };
-      /**
-       * Get data before processed
-       */
+        target._count = offset;
+        target._indices = newIndices;
 
+        target._updateGetRawIdx();
 
-      SeriesModel.prototype.getRawData = function () {
-        return inner$1(this).dataBeforeProcessed;
+        return target;
       };
       /**
-       * Get base axis if has coordinate system and has axis.
-       * By default use coordSys.getBaseAxis();
-       * Can be overrided for some chart.
-       * @return {type} description
+       * Data iteration
+       * @param ctx default this
+       * @example
+       *  list.each('x', function (x, idx) {});
+       *  list.each(['x', 'y'], function (x, y, idx) {});
+       *  list.each(function (idx) {})
        */
 
 
-      SeriesModel.prototype.getBaseAxis = function () {
-        var coordSys = this.coordinateSystem; // @ts-ignore
-
-        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();
-      };
-      /**
-       * Default tooltip formatter
-       *
-       * @param dataIndex
-       * @param multipleSeries
-       * @param dataType
-       * @param renderMode valid values: 'html'(by default) and 'richText'.
-       *        'html' is used for rendering tooltip in extra DOM form, and the result
-       *        string is used as DOM HTML content.
-       *        'richText' is used for rendering tooltip in rich text form, for those where
-       *        DOM operation is not supported.
-       * @return formatted tooltip with `html` and `markers`
-       *        Notice: The override method can also return string
-       */
-
+      DataStore.prototype.each = function (dims, cb) {
+        if (!this._count) {
+          return;
+        }
 
-      SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) {
-        return defaultSeriesFormatTooltip({
-          series: this,
-          dataIndex: dataIndex,
-          multipleSeries: multipleSeries
-        });
-      };
+        var dimSize = dims.length;
+        var chunks = this._chunks;
 
-      SeriesModel.prototype.isAnimationEnabled = function () {
-        if (env.node) {
-          return false;
-        }
+        for (var i = 0, len = this.count(); i < len; i++) {
+          var rawIdx = this.getRawIndex(i); // Simple optimization
 
-        var animationEnabled = this.getShallow('animation');
+          switch (dimSize) {
+            case 0:
+              cb(i);
+              break;
 
-        if (animationEnabled) {
-          if (this.getData().count() > this.getShallow('animationThreshold')) {
-            animationEnabled = false;
-          }
-        }
+            case 1:
+              cb(chunks[dims[0]][rawIdx], i);
+              break;
 
-        return !!animationEnabled;
-      };
+            case 2:
+              cb(chunks[dims[0]][rawIdx], chunks[dims[1]][rawIdx], i);
+              break;
 
-      SeriesModel.prototype.restoreData = function () {
-        this.dataTask.dirty();
-      };
+            default:
+              var k = 0;
+              var value = [];
 
-      SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) {
-        var ecModel = this.ecModel; // PENDING
+              for (; k < dimSize; k++) {
+                value[k] = chunks[dims[k]][rawIdx];
+              } // Index
 
-        var color = PaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum);
 
-        if (!color) {
-          color = ecModel.getColorFromPalette(name, scope, requestColorNum);
+              value[k] = i;
+              cb.apply(null, value);
+          }
         }
-
-        return color;
       };
       /**
-       * Use `data.mapDimensionsAll(coordDim)` instead.
-       * @deprecated
+       * Get extent of data in one dimension
        */
 
 
-      SeriesModel.prototype.coordDimToDataDim = function (coordDim) {
-        return this.getRawData().mapDimensionsAll(coordDim);
-      };
-      /**
-       * Get progressive rendering count each step
-       */
-
+      DataStore.prototype.getDataExtent = function (dim) {
+        // Make sure use concrete dim as cache name.
+        var dimData = this._chunks[dim];
+        var initialExtent = getInitialExtent();
 
-      SeriesModel.prototype.getProgressive = function () {
-        return this.get('progressive');
-      };
-      /**
-       * Get progressive rendering count each step
-       */
+        if (!dimData) {
+          return initialExtent;
+        } // Make more strict checkings to ensure hitting cache.
 
 
-      SeriesModel.prototype.getProgressiveThreshold = function () {
-        return this.get('progressiveThreshold');
-      }; // PENGING If selectedMode is null ?
+        var currEnd = this.count(); // Consider the most cases when using data zoom, `getDataExtent`
+        // happened before filtering. We cache raw extent, which is not
+        // necessary to be cleared and recalculated when restore data.
 
+        var useRaw = !this._indices;
+        var dimExtent;
 
-      SeriesModel.prototype.select = function (innerDataIndices, dataType) {
-        this._innerSelect(this.getData(dataType), innerDataIndices);
-      };
+        if (useRaw) {
+          return this._rawExtent[dim].slice();
+        }
 
-      SeriesModel.prototype.unselect = function (innerDataIndices, dataType) {
-        var selectedMap = this.option.selectedMap;
+        dimExtent = this._extent[dim];
 
-        if (!selectedMap) {
-          return;
+        if (dimExtent) {
+          return dimExtent.slice();
         }
 
-        var data = this.getData(dataType);
+        dimExtent = initialExtent;
+        var min = dimExtent[0];
+        var max = dimExtent[1];
 
-        for (var i = 0; i < innerDataIndices.length; i++) {
-          var dataIndex = innerDataIndices[i];
-          var nameOrId = getSelectionKey(data, dataIndex);
-          selectedMap[nameOrId] = false;
-          this._selectedDataIndicesMap[nameOrId] = -1;
+        for (var i = 0; i < currEnd; i++) {
+          var rawIdx = this.getRawIndex(i);
+          var value = dimData[rawIdx];
+          value < min && (min = value);
+          value > max && (max = value);
         }
+
+        dimExtent = [min, max];
+        this._extent[dim] = dimExtent;
+        return dimExtent;
       };
+      /**
+       * Get raw data item
+       */
 
-      SeriesModel.prototype.toggleSelect = function (innerDataIndices, dataType) {
-        var tmpArr = [];
 
-        for (var i = 0; i < innerDataIndices.length; i++) {
-          tmpArr[0] = innerDataIndices[i];
-          this.isSelected(innerDataIndices[i], dataType) ? this.unselect(tmpArr, dataType) : this.select(tmpArr, dataType);
+      DataStore.prototype.getRawDataItem = function (idx) {
+        var rawIdx = this.getRawIndex(idx);
+
+        if (!this._provider.persistent) {
+          var val = [];
+          var chunks = this._chunks;
+
+          for (var i = 0; i < chunks.length; i++) {
+            val.push(chunks[i][rawIdx]);
+          }
+
+          return val;
+        } else {
+          return this._provider.getItem(rawIdx);
         }
       };
+      /**
+       * Clone shallow.
+       *
+       * @param clonedDims Determine which dims to clone. Will share the data if not specified.
+       */
 
-      SeriesModel.prototype.getSelectedDataIndices = function () {
-        var selectedDataIndicesMap = this._selectedDataIndicesMap;
-        var nameOrIds = keys(selectedDataIndicesMap);
-        var dataIndices = [];
 
-        for (var i = 0; i < nameOrIds.length; i++) {
-          var dataIndex = selectedDataIndicesMap[nameOrIds[i]];
+      DataStore.prototype.clone = function (clonedDims, ignoreIndices) {
+        var target = new DataStore();
+        var chunks = this._chunks;
+        var clonedDimsMap = clonedDims && reduce(clonedDims, function (obj, dimIdx) {
+          obj[dimIdx] = true;
+          return obj;
+        }, {});
 
-          if (dataIndex >= 0) {
-            dataIndices.push(dataIndex);
+        if (clonedDimsMap) {
+          for (var i = 0; i < chunks.length; i++) {
+            // Not clone if dim is not picked.
+            target._chunks[i] = !clonedDimsMap[i] ? chunks[i] : cloneChunk(chunks[i]);
           }
+        } else {
+          target._chunks = chunks;
         }
 
-        return dataIndices;
-      };
-
-      SeriesModel.prototype.isSelected = function (dataIndex, dataType) {
-        var selectedMap = this.option.selectedMap;
+        this._copyCommonProps(target);
 
-        if (!selectedMap) {
-          return false;
+        if (!ignoreIndices) {
+          target._indices = this._cloneIndices();
         }
 
-        var data = this.getData(dataType);
-        var nameOrId = getSelectionKey(data, dataIndex);
-        return selectedMap[nameOrId] || false;
-      };
-
-      SeriesModel.prototype._innerSelect = function (data, innerDataIndices) {
-        var _a, _b;
+        target._updateGetRawIdx();
 
-        var selectedMode = this.option.selectedMode;
-        var len = innerDataIndices.length;
+        return target;
+      };
 
-        if (!selectedMode || !len) {
-          return;
-        }
+      DataStore.prototype._copyCommonProps = function (target) {
+        target._count = this._count;
+        target._rawCount = this._rawCount;
+        target._provider = this._provider;
+        target._dimensions = this._dimensions;
+        target._extent = clone(this._extent);
+        target._rawExtent = clone(this._rawExtent);
+      };
 
-        if (selectedMode === 'multiple') {
-          var selectedMap = this.option.selectedMap || (this.option.selectedMap = {});
+      DataStore.prototype._cloneIndices = function () {
+        if (this._indices) {
+          var Ctor = this._indices.constructor;
+          var indices = void 0;
 
-          for (var i = 0; i < len; i++) {
-            var dataIndex = innerDataIndices[i]; // TODO diffrent types of data share same object.
+          if (Ctor === Array) {
+            var thisCount = this._indices.length;
+            indices = new Ctor(thisCount);
 
-            var nameOrId = getSelectionKey(data, dataIndex);
-            selectedMap[nameOrId] = true;
-            this._selectedDataIndicesMap[nameOrId] = data.getRawIndex(dataIndex);
+            for (var i = 0; i < thisCount; i++) {
+              indices[i] = this._indices[i];
+            }
+          } else {
+            indices = new Ctor(this._indices);
           }
-        } else if (selectedMode === 'single' || selectedMode === true) {
-          var lastDataIndex = innerDataIndices[len - 1];
-          var nameOrId = getSelectionKey(data, lastDataIndex);
-          this.option.selectedMap = (_a = {}, _a[nameOrId] = true, _a);
-          this._selectedDataIndicesMap = (_b = {}, _b[nameOrId] = data.getRawIndex(lastDataIndex), _b);
-        }
-      };
 
-      SeriesModel.prototype._initSelectedMapFromData = function (data) {
-        // Ignore select info in data if selectedMap exists.
-        // NOTE It's only for legacy usage. edge data is not supported.
-        if (this.option.selectedMap) {
-          return;
+          return indices;
         }
 
-        var dataIndices = [];
-
-        if (data.hasItemOption) {
-          data.each(function (idx) {
-            var rawItem = data.getRawDataItem(idx);
+        return null;
+      };
 
-            if (rawItem && rawItem.selected) {
-              dataIndices.push(idx);
-            }
-          });
-        }
+      DataStore.prototype._getRawIdxIdentity = function (idx) {
+        return idx;
+      };
 
-        if (dataIndices.length > 0) {
-          this._innerSelect(data, dataIndices);
+      DataStore.prototype._getRawIdx = function (idx) {
+        if (idx < this._count && idx >= 0) {
+          return this._indices[idx];
         }
-      }; // /**
-      //  * @see {module:echarts/stream/Scheduler}
-      //  */
-      // abstract pipeTask: null
 
+        return -1;
+      };
 
-      SeriesModel.registerClass = function (clz) {
-        return ComponentModel.registerClass(clz);
+      DataStore.prototype._updateGetRawIdx = function () {
+        this.getRawIndex = this._indices ? this._getRawIdx : this._getRawIdxIdentity;
       };
 
-      SeriesModel.protoInitialize = function () {
-        var proto = SeriesModel.prototype;
-        proto.type = 'series.__base__';
-        proto.seriesIndex = 0;
-        proto.useColorPaletteOnData = false;
-        proto.ignoreStyleOnData = false;
-        proto.hasSymbolVisual = false;
-        proto.defaultSymbol = 'circle'; // Make sure the values can be accessed!
+      DataStore.internalField = function () {
+        function getDimValueSimply(dataItem, property, dataIndex, dimIndex) {
+          return parseDataValue(dataItem[dimIndex], this._dimensions[dimIndex]);
+        }
 
-        proto.visualStyleAccessPath = 'itemStyle';
-        proto.visualDrawType = 'fill';
+        defaultDimValueGetters = {
+          arrayRows: getDimValueSimply,
+          objectRows: function (dataItem, property, dataIndex, dimIndex) {
+            return parseDataValue(dataItem[property], this._dimensions[dimIndex]);
+          },
+          keyedColumns: getDimValueSimply,
+          original: function (dataItem, property, dataIndex, dimIndex) {
+            // Performance sensitive, do not use modelUtil.getDataItemValue.
+            // If dataItem is an plain object with no value field, the let `value`
+            // will be assigned with the object, but it will be tread correctly
+            // in the `convertValue`.
+            var value = dataItem && (dataItem.value == null ? dataItem : dataItem.value);
+            return parseDataValue(value instanceof Array ? value[dimIndex] // If value is a single number or something else not array.
+            : value, this._dimensions[dimIndex]);
+          },
+          typedArray: function (dataItem, property, dataIndex, dimIndex) {
+            return dataItem[dimIndex];
+          }
+        };
       }();
 
-      return SeriesModel;
-    }(ComponentModel);
+      return DataStore;
+    }();
 
-    mixin(SeriesModel, DataFormatMixin);
-    mixin(SeriesModel, PaletteMixin);
-    mountExtend(SeriesModel, ComponentModel);
     /**
-     * MUST be called after `prepareSource` called
-     * Here we need to make auto series, especially for auto legend. But we
-     * do not modify series.name in option to avoid side effects.
-     */
-
-    function autoSeriesName(seriesModel) {
-      // User specified name has higher priority, otherwise it may cause
-      // series can not be queried unexpectedly.
-      var name = seriesModel.name;
-
-      if (!isNameSpecified(seriesModel)) {
-        seriesModel.name = getSeriesAutoName(seriesModel) || name;
-      }
-    }
-
-    function getSeriesAutoName(seriesModel) {
-      var data = seriesModel.getRawData();
-      var dataDims = data.mapDimensionsAll('seriesName');
-      var nameArr = [];
-      each(dataDims, function (dataDim) {
-        var dimInfo = data.getDimensionInfo(dataDim);
-        dimInfo.displayName && nameArr.push(dimInfo.displayName);
-      });
-      return nameArr.join(' ');
-    }
-
-    function dataTaskCount(context) {
-      return context.model.getRawData().count();
-    }
+     * [REQUIREMENT_MEMO]:
+     * (0) `metaRawOption` means `dimensions`/`sourceHeader`/`seriesLayoutBy` in raw option.
+     * (1) Keep support the feature: `metaRawOption` can be specified both on `series` and
+     * `root-dataset`. Them on `series` has higher priority.
+     * (2) Do not support to set `metaRawOption` on a `non-root-dataset`, because it might
+     * confuse users: whether those props indicate how to visit the upstream source or visit
+     * the transform result source, and some transforms has nothing to do with these props,
+     * and some transforms might have multiple upstream.
+     * (3) Transforms should specify `metaRawOption` in each output, just like they can be
+     * declared in `root-dataset`.
+     * (4) At present only support visit source in `SERIES_LAYOUT_BY_COLUMN` in transforms.
+     * That is for reducing complexity in transfroms.
+     * PENDING: Whether to provide transposition transform?
+     *
+     * [IMPLEMENTAION_MEMO]:
+     * "sourceVisitConfig" are calculated from `metaRawOption` and `data`.
+     * They will not be calculated until `source` is about to be visited (to prevent from
+     * duplicate calcuation). `source` is visited only in series and input to transforms.
+     *
+     * [DIMENSION_INHERIT_RULE]:
+     * By default the dimensions are inherited from ancestors, unless a transform return
+     * a new dimensions definition.
+     * Consider the case:
+     * ```js
+     * dataset: [{
+     *     source: [ ['Product', 'Sales', 'Prise'], ['Cookies', 321, 44.21], ...]
+     * }, {
+     *     transform: { type: 'filter', ... }
+     * }]
+     * dataset: [{
+     *     dimension: ['Product', 'Sales', 'Prise'],
+     *     source: [ ['Cookies', 321, 44.21], ...]
+     * }, {
+     *     transform: { type: 'filter', ... }
+     * }]
+     * ```
+     * The two types of option should have the same behavior after transform.
+     *
+     *
+     * [SCENARIO]:
+     * (1) Provide source data directly:
+     * ```js
+     * series: {
+     *     encode: {...},
+     *     dimensions: [...]
+     *     seriesLayoutBy: 'row',
+     *     data: [[...]]
+     * }
+     * ```
+     * (2) Series refer to dataset.
+     * ```js
+     * series: [{
+     *     encode: {...}
+     *     // Ignore datasetIndex means `datasetIndex: 0`
+     *     // and the dimensions defination in dataset is used
+     * }, {
+     *     encode: {...},
+     *     seriesLayoutBy: 'column',
+     *     datasetIndex: 1
+     * }]
+     * ```
+     * (3) dataset transform
+     * ```js
+     * dataset: [{
+     *     source: [...]
+     * }, {
+     *     source: [...]
+     * }, {
+     *     // By default from 0.
+     *     transform: { type: 'filter', config: {...} }
+     * }, {
+     *     // Piped.
+     *     transform: [
+     *         { type: 'filter', config: {...} },
+     *         { type: 'sort', config: {...} }
+     *     ]
+     * }, {
+     *     id: 'regressionData',
+     *     fromDatasetIndex: 1,
+     *     // Third-party transform
+     *     transform: { type: 'ecStat:regression', config: {...} }
+     * }, {
+     *     // retrieve the extra result.
+     *     id: 'regressionFormula',
+     *     fromDatasetId: 'regressionData',
+     *     fromTransformResult: 1
+     * }]
+     * ```
+     */
 
-    function dataTaskReset(context) {
-      var seriesModel = context.model;
-      seriesModel.setData(seriesModel.getRawData().cloneShallow());
-      return dataTaskProgress;
-    }
+    var SourceManager =
+    /** @class */
+    function () {
+      function SourceManager(sourceHost) {
+        // Cached source. Do not repeat calculating if not dirty.
+        this._sourceList = [];
+        this._storeList = []; // version sign of each upstream source manager.
 
-    function dataTaskProgress(param, context) {
-      // Avoid repead cloneShallow when data just created in reset.
-      if (context.outputData && param.end > context.outputData.count()) {
-        context.model.getRawData().cloneShallow(context.outputData);
+        this._upstreamSignList = [];
+        this._versionSignBase = 0;
+        this._dirty = true;
+        this._sourceHost = sourceHost;
       }
-    } // TODO refactor
+      /**
+       * Mark dirty.
+       */
 
 
-    function wrapData(data, seriesModel) {
-      each(__spreadArrays(data.CHANGABLE_METHODS, data.DOWNSAMPLE_METHODS), function (methodName) {
-        data.wrapMethod(methodName, curry(onDataChange, seriesModel));
-      });
-    }
+      SourceManager.prototype.dirty = function () {
+        this._setLocalSource([], []);
 
-    function onDataChange(seriesModel, newList) {
-      var task = getCurrentTask(seriesModel);
+        this._storeList = [];
+        this._dirty = true;
+      };
 
-      if (task) {
-        // Consider case: filter, selectRange
-        task.setOutputEnd((newList || this).count());
-      }
+      SourceManager.prototype._setLocalSource = function (sourceList, upstreamSignList) {
+        this._sourceList = sourceList;
+        this._upstreamSignList = upstreamSignList;
+        this._versionSignBase++;
 
-      return newList;
-    }
+        if (this._versionSignBase > 9e10) {
+          this._versionSignBase = 0;
+        }
+      };
+      /**
+       * For detecting whether the upstream source is dirty, so that
+       * the local cached source (in `_sourceList`) should be discarded.
+       */
 
-    function getCurrentTask(seriesModel) {
-      var scheduler = (seriesModel.ecModel || {}).scheduler;
-      var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);
 
-      if (pipeline) {
-        // When pipline finished, the currrentTask keep the last
-        // task (renderTask).
-        var task = pipeline.currentTask;
+      SourceManager.prototype._getVersionSign = function () {
+        return this._sourceHost.uid + '_' + this._versionSignBase;
+      };
+      /**
+       * Always return a source instance. Otherwise throw error.
+       */
 
-        if (task) {
-          var agentStubMap = task.agentStubMap;
 
-          if (agentStubMap) {
-            task = agentStubMap.get(seriesModel.uid);
-          }
+      SourceManager.prototype.prepareSource = function () {
+        // For the case that call `setOption` multiple time but no data changed,
+        // cache the result source to prevent from repeating transform.
+        if (this._isDirty()) {
+          this._createSource();
+
+          this._dirty = false;
         }
+      };
 
-        return task;
-      }
-    }
+      SourceManager.prototype._createSource = function () {
+        this._setLocalSource([], []);
 
-    var ComponentView =
-    /** @class */
-    function () {
-      function ComponentView() {
-        this.group = new Group();
-        this.uid = getUID('viewComponent');
-      }
+        var sourceHost = this._sourceHost;
 
-      ComponentView.prototype.init = function (ecModel, api) {};
+        var upSourceMgrList = this._getUpstreamSourceManagers();
 
-      ComponentView.prototype.render = function (model, ecModel, api, payload) {};
+        var hasUpstream = !!upSourceMgrList.length;
+        var resultSourceList;
+        var upstreamSignList;
 
-      ComponentView.prototype.dispose = function (ecModel, api) {};
+        if (isSeries(sourceHost)) {
+          var seriesModel = sourceHost;
+          var data = void 0;
+          var sourceFormat = void 0;
+          var upSource = void 0; // Has upstream dataset
 
-      ComponentView.prototype.updateView = function (model, ecModel, api, payload) {// Do nothing;
-      };
+          if (hasUpstream) {
+            var upSourceMgr = upSourceMgrList[0];
+            upSourceMgr.prepareSource();
+            upSource = upSourceMgr.getSource();
+            data = upSource.data;
+            sourceFormat = upSource.sourceFormat;
+            upstreamSignList = [upSourceMgr._getVersionSign()];
+          } // Series data is from own.
+          else {
+              data = seriesModel.get('data', true);
+              sourceFormat = isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL;
+              upstreamSignList = [];
+            } // See [REQUIREMENT_MEMO], merge settings on series and parent dataset if it is root.
 
-      ComponentView.prototype.updateLayout = function (model, ecModel, api, payload) {// Do nothing;
-      };
 
-      ComponentView.prototype.updateVisual = function (model, ecModel, api, payload) {// Do nothing;
-      };
-      /**
-       * Hook for blur target series.
-       * Can be used in marker for blur the markers
-       */
+          var newMetaRawOption = this._getSourceMetaRawOption() || {};
+          var upMetaRawOption = upSource && upSource.metaRawOption || {};
+          var seriesLayoutBy = retrieve2(newMetaRawOption.seriesLayoutBy, upMetaRawOption.seriesLayoutBy) || null;
+          var sourceHeader = retrieve2(newMetaRawOption.sourceHeader, upMetaRawOption.sourceHeader) || null; // Note here we should not use `upSource.dimensionsDefine`. Consider the case:
+          // `upSource.dimensionsDefine` is detected by `seriesLayoutBy: 'column'`,
+          // but series need `seriesLayoutBy: 'row'`.
 
+          var dimensions = retrieve2(newMetaRawOption.dimensions, upMetaRawOption.dimensions); // We share source with dataset as much as possible
+          // to avoid extra memroy cost of high dimensional data.
 
-      ComponentView.prototype.blurSeries = function (seriesModels, ecModel) {// Do nothing;
-      };
+          var needsCreateSource = seriesLayoutBy !== upMetaRawOption.seriesLayoutBy || !!sourceHeader !== !!upMetaRawOption.sourceHeader || dimensions;
+          resultSourceList = needsCreateSource ? [createSource(data, {
+            seriesLayoutBy: seriesLayoutBy,
+            sourceHeader: sourceHeader,
+            dimensions: dimensions
+          }, sourceFormat)] : [];
+        } else {
+          var datasetModel = sourceHost; // Has upstream dataset.
 
-      return ComponentView;
-    }();
-    enableClassExtend(ComponentView);
-    enableClassManagement(ComponentView);
+          if (hasUpstream) {
+            var result = this._applyTransform(upSourceMgrList);
 
-    /**
-     * @return {string} If large mode changed, return string 'reset';
-     */
+            resultSourceList = result.sourceList;
+            upstreamSignList = result.upstreamSignList;
+          } // Is root dataset.
+          else {
+              var sourceData = datasetModel.get('source', true);
+              resultSourceList = [createSource(sourceData, this._getSourceMetaRawOption(), null)];
+              upstreamSignList = [];
+            }
+        }
 
-    function createRenderPlanner() {
-      var inner = makeInner();
-      return function (seriesModel) {
-        var fields = inner(seriesModel);
-        var pipelineContext = seriesModel.pipelineContext;
-        var originalLarge = !!fields.large;
-        var originalProgressive = !!fields.progressiveRender; // FIXME: if the planner works on a filtered series, `pipelineContext` does not
-        // exists. See #11611 . Probably we need to modify this structure, see the comment
-        // on `performRawSeries` in `Schedular.js`.
+        if ("development" !== 'production') {
+          assert(resultSourceList && upstreamSignList);
+        }
 
-        var large = fields.large = !!(pipelineContext && pipelineContext.large);
-        var progressive = fields.progressiveRender = !!(pipelineContext && pipelineContext.progressiveRender);
-        return !!(originalLarge !== large || originalProgressive !== progressive) && 'reset';
+        this._setLocalSource(resultSourceList, upstreamSignList);
       };
-    }
 
-    var inner$2 = makeInner();
-    var renderPlanner = createRenderPlanner();
+      SourceManager.prototype._applyTransform = function (upMgrList) {
+        var datasetModel = this._sourceHost;
+        var transformOption = datasetModel.get('transform', true);
+        var fromTransformResult = datasetModel.get('fromTransformResult', true);
 
-    var ChartView =
-    /** @class */
-    function () {
-      function ChartView() {
-        this.group = new Group();
-        this.uid = getUID('viewChart');
-        this.renderTask = createTask({
-          plan: renderTaskPlan,
-          reset: renderTaskReset
+        if ("development" !== 'production') {
+          assert(fromTransformResult != null || transformOption != null);
+        }
+
+        if (fromTransformResult != null) {
+          var errMsg = '';
+
+          if (upMgrList.length !== 1) {
+            if ("development" !== 'production') {
+              errMsg = 'When using `fromTransformResult`, there should be only one upstream dataset';
+            }
+
+            doThrow(errMsg);
+          }
+        }
+
+        var sourceList;
+        var upSourceList = [];
+        var upstreamSignList = [];
+        each(upMgrList, function (upMgr) {
+          upMgr.prepareSource();
+          var upSource = upMgr.getSource(fromTransformResult || 0);
+          var errMsg = '';
+
+          if (fromTransformResult != null && !upSource) {
+            if ("development" !== 'production') {
+              errMsg = 'Can not retrieve result by `fromTransformResult`: ' + fromTransformResult;
+            }
+
+            doThrow(errMsg);
+          }
+
+          upSourceList.push(upSource);
+          upstreamSignList.push(upMgr._getVersionSign());
         });
-        this.renderTask.context = {
-          view: this
+
+        if (transformOption) {
+          sourceList = applyDataTransform(transformOption, upSourceList, {
+            datasetIndex: datasetModel.componentIndex
+          });
+        } else if (fromTransformResult != null) {
+          sourceList = [cloneSourceShallow(upSourceList[0])];
+        }
+
+        return {
+          sourceList: sourceList,
+          upstreamSignList: upstreamSignList
         };
-      }
+      };
 
-      ChartView.prototype.init = function (ecModel, api) {};
+      SourceManager.prototype._isDirty = function () {
+        if (this._dirty) {
+          return true;
+        } // All sourceList is from the some upsteam.
 
-      ChartView.prototype.render = function (seriesModel, ecModel, api, payload) {};
-      /**
-       * Highlight series or specified data item.
-       */
 
+        var upSourceMgrList = this._getUpstreamSourceManagers();
 
-      ChartView.prototype.highlight = function (seriesModel, ecModel, api, payload) {
-        toggleHighlight(seriesModel.getData(), payload, 'emphasis');
+        for (var i = 0; i < upSourceMgrList.length; i++) {
+          var upSrcMgr = upSourceMgrList[i];
+
+          if ( // Consider the case that there is ancestor diry, call it recursively.
+          // The performance is probably not an issue because usually the chain is not long.
+          upSrcMgr._isDirty() || this._upstreamSignList[i] !== upSrcMgr._getVersionSign()) {
+            return true;
+          }
+        }
       };
       /**
-       * Downplay series or specified data item.
+       * @param sourceIndex By defualt 0, means "main source".
+       *                    Most cases there is only one source.
        */
 
 
-      ChartView.prototype.downplay = function (seriesModel, ecModel, api, payload) {
-        toggleHighlight(seriesModel.getData(), payload, 'normal');
+      SourceManager.prototype.getSource = function (sourceIndex) {
+        sourceIndex = sourceIndex || 0;
+        var source = this._sourceList[sourceIndex];
+
+        if (!source) {
+          // Series may share source instance with dataset.
+          var upSourceMgrList = this._getUpstreamSourceManagers();
+
+          return upSourceMgrList[0] && upSourceMgrList[0].getSource(sourceIndex);
+        }
+
+        return source;
       };
       /**
-       * Remove self.
+       *
+       * Get a data store which can be shared across series.
+       * Only available for series.
+       *
+       * @param seriesDimRequest Dimensions that are generated in series.
+       *        Should have been sorted by `storeDimIndex` asc.
        */
 
 
-      ChartView.prototype.remove = function (ecModel, api) {
-        this.group.removeAll();
+      SourceManager.prototype.getSharedDataStore = function (seriesDimRequest) {
+        if ("development" !== 'production') {
+          assert(isSeries(this._sourceHost), 'Can only call getDataStore on series source manager.');
+        }
+
+        var schema = seriesDimRequest.makeStoreSchema();
+        return this._innerGetDataStore(schema.dimensions, seriesDimRequest.source, schema.hash);
       };
-      /**
-       * Dispose self.
-       */
 
+      SourceManager.prototype._innerGetDataStore = function (storeDims, seriesSource, sourceReadKey) {
+        // TODO Can use other sourceIndex?
+        var sourceIndex = 0;
+        var storeList = this._storeList;
+        var cachedStoreMap = storeList[sourceIndex];
 
-      ChartView.prototype.dispose = function (ecModel, api) {};
+        if (!cachedStoreMap) {
+          cachedStoreMap = storeList[sourceIndex] = {};
+        }
 
-      ChartView.prototype.updateView = function (seriesModel, ecModel, api, payload) {
-        this.render(seriesModel, ecModel, api, payload);
-      }; // FIXME never used?
+        var cachedStore = cachedStoreMap[sourceReadKey];
 
+        if (!cachedStore) {
+          var upSourceMgr = this._getUpstreamSourceManagers()[0];
 
-      ChartView.prototype.updateLayout = function (seriesModel, ecModel, api, payload) {
-        this.render(seriesModel, ecModel, api, payload);
-      }; // FIXME never used?
+          if (isSeries(this._sourceHost) && upSourceMgr) {
+            cachedStore = upSourceMgr._innerGetDataStore(storeDims, seriesSource, sourceReadKey);
+          } else {
+            cachedStore = new DataStore(); // Always create store from source of series.
 
+            cachedStore.initData(new DefaultDataProvider(seriesSource, storeDims.length), storeDims);
+          }
 
-      ChartView.prototype.updateVisual = function (seriesModel, ecModel, api, payload) {
-        this.render(seriesModel, ecModel, api, payload);
+          cachedStoreMap[sourceReadKey] = cachedStore;
+        }
+
+        return cachedStore;
       };
+      /**
+       * PEDING: Is it fast enough?
+       * If no upstream, return empty array.
+       */
 
-      ChartView.markUpdateMethod = function (payload, methodName) {
-        inner$2(payload).updateMethod = methodName;
+
+      SourceManager.prototype._getUpstreamSourceManagers = function () {
+        // Always get the relationship from the raw option.
+        // Do not cache the link of the dependency graph, so that
+        // no need to update them when change happen.
+        var sourceHost = this._sourceHost;
+
+        if (isSeries(sourceHost)) {
+          var datasetModel = querySeriesUpstreamDatasetModel(sourceHost);
+          return !datasetModel ? [] : [datasetModel.getSourceManager()];
+        } else {
+          return map(queryDatasetUpstreamDatasetModels(sourceHost), function (datasetModel) {
+            return datasetModel.getSourceManager();
+          });
+        }
       };
 
-      ChartView.protoInitialize = function () {
-        var proto = ChartView.prototype;
-        proto.type = 'chart';
-      }();
+      SourceManager.prototype._getSourceMetaRawOption = function () {
+        var sourceHost = this._sourceHost;
+        var seriesLayoutBy;
+        var sourceHeader;
+        var dimensions;
 
-      return ChartView;
-    }();
-    /**
-     * Set state of single element
-     */
+        if (isSeries(sourceHost)) {
+          seriesLayoutBy = sourceHost.get('seriesLayoutBy', true);
+          sourceHeader = sourceHost.get('sourceHeader', true);
+          dimensions = sourceHost.get('dimensions', true);
+        } // See [REQUIREMENT_MEMO], `non-root-dataset` do not support them.
+        else if (!this._getUpstreamSourceManagers().length) {
+            var model = sourceHost;
+            seriesLayoutBy = model.get('seriesLayoutBy', true);
+            sourceHeader = model.get('sourceHeader', true);
+            dimensions = model.get('dimensions', true);
+          }
 
-    function elSetState(el, state, highlightDigit) {
-      if (el) {
-        (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit);
-      }
-    }
+        return {
+          seriesLayoutBy: seriesLayoutBy,
+          sourceHeader: sourceHeader,
+          dimensions: dimensions
+        };
+      };
 
-    function toggleHighlight(data, payload, state) {
-      var dataIndex = queryDataIndex(data, payload);
-      var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null;
+      return SourceManager;
+    }();
+    // disable the transform merge, but do not disable transfrom clone from rawOption.
 
-      if (dataIndex != null) {
-        each(normalizeToArray(dataIndex), function (dataIdx) {
-          elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit);
-        });
-      } else {
-        data.eachItemGraphicEl(function (el) {
-          elSetState(el, state, highlightDigit);
-        });
-      }
+    function disableTransformOptionMerge(datasetModel) {
+      var transformOption = datasetModel.option.transform;
+      transformOption && setAsPrimitive(datasetModel.option.transform);
     }
 
-    enableClassExtend(ChartView, ['dispose']);
-    enableClassManagement(ChartView);
+    function isSeries(sourceHost) {
+      // Avoid circular dependency with Series.ts
+      return sourceHost.mainType === 'series';
+    }
 
-    function renderTaskPlan(context) {
-      return renderPlanner(context.model);
+    function doThrow(errMsg) {
+      throw new Error(errMsg);
     }
 
-    function renderTaskReset(context) {
-      var seriesModel = context.model;
-      var ecModel = context.ecModel;
-      var api = context.api;
-      var payload = context.payload; // FIXME: remove updateView updateVisual
+    var TOOLTIP_LINE_HEIGHT_CSS = 'line-height:1'; // TODO: more textStyle option
 
-      var progressiveRender = seriesModel.pipelineContext.progressiveRender;
-      var view = context.view;
-      var updateMethod = payload && inner$2(payload).updateMethod;
-      var methodName = progressiveRender ? 'incrementalPrepareRender' : updateMethod && view[updateMethod] ? updateMethod // `appendData` is also supported when data amount
-      // is less than progressive threshold.
-      : 'render';
+    function getTooltipTextStyle(textStyle, renderMode) {
+      var nameFontColor = textStyle.color || '#6e7079';
+      var nameFontSize = textStyle.fontSize || 12;
+      var nameFontWeight = textStyle.fontWeight || '400';
+      var valueFontColor = textStyle.color || '#464646';
+      var valueFontSize = textStyle.fontSize || 14;
+      var valueFontWeight = textStyle.fontWeight || '900';
 
-      if (methodName !== 'render') {
-        view[methodName](seriesModel, ecModel, api, payload);
+      if (renderMode === 'html') {
+        // `textStyle` is probably from user input, should be encoded to reduce security risk.
+        return {
+          // eslint-disable-next-line max-len
+          nameStyle: "font-size:" + encodeHTML(nameFontSize + '') + "px;color:" + encodeHTML(nameFontColor) + ";font-weight:" + encodeHTML(nameFontWeight + ''),
+          // eslint-disable-next-line max-len
+          valueStyle: "font-size:" + encodeHTML(valueFontSize + '') + "px;color:" + encodeHTML(valueFontColor) + ";font-weight:" + encodeHTML(valueFontWeight + '')
+        };
+      } else {
+        return {
+          nameStyle: {
+            fontSize: nameFontSize,
+            fill: nameFontColor,
+            fontWeight: nameFontWeight
+          },
+          valueStyle: {
+            fontSize: valueFontSize,
+            fill: valueFontColor,
+            fontWeight: valueFontWeight
+          }
+        };
       }
+    } // See `TooltipMarkupLayoutIntent['innerGapLevel']`.
+    // (value from UI design)
 
-      return progressMethodMap[methodName];
-    }
 
-    var progressMethodMap = {
-      incrementalPrepareRender: {
-        progress: function (params, context) {
-          context.view.incrementalRender(params, context.model, context.ecModel, context.api, context.payload);
-        }
-      },
-      render: {
-        // Put view.render in `progress` to support appendData. But in this case
-        // view.render should not be called in reset, otherwise it will be called
-        // twise. Use `forceFirstProgress` to make sure that view.render is called
-        // in any cases.
-        forceFirstProgress: true,
-        progress: function (params, context) {
-          context.view.render(context.model, context.ecModel, context.api, context.payload);
-        }
-      }
-    };
-
-    /*
-    * Licensed to the Apache Software Foundation (ASF) under one
-    * or more contributor license agreements.  See the NOTICE file
-    * distributed with this work for additional information
-    * regarding copyright ownership.  The ASF licenses this file
-    * to you under the Apache License, Version 2.0 (the
-    * "License"); you may not use this file except in compliance
-    * with the License.  You may obtain a copy of the License at
-    *
-    *   http://www.apache.org/licenses/LICENSE-2.0
-    *
-    * Unless required by applicable law or agreed to in writing,
-    * software distributed under the License is distributed on an
-    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    * KIND, either express or implied.  See the License for the
-    * specific language governing permissions and limitations
-    * under the License.
-    */
-
-
-    /**
-     * AUTO-GENERATED FILE. DO NOT MODIFY.
-     */
+    var HTML_GAPS = [0, 10, 20, 30];
+    var RICH_TEXT_GAPS = ['', '\n', '\n\n', '\n\n\n']; // eslint-disable-next-line max-len
 
-    /*
-    * Licensed to the Apache Software Foundation (ASF) under one
-    * or more contributor license agreements.  See the NOTICE file
-    * distributed with this work for additional information
-    * regarding copyright ownership.  The ASF licenses this file
-    * to you under the Apache License, Version 2.0 (the
-    * "License"); you may not use this file except in compliance
-    * with the License.  You may obtain a copy of the License at
-    *
-    *   http://www.apache.org/licenses/LICENSE-2.0
-    *
-    * Unless required by applicable law or agreed to in writing,
-    * software distributed under the License is distributed on an
-    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    * KIND, either express or implied.  See the License for the
-    * specific language governing permissions and limitations
-    * under the License.
-    */
-    var ORIGIN_METHOD = '\0__throttleOriginMethod';
-    var RATE = '\0__throttleRate';
-    var THROTTLE_TYPE = '\0__throttleType';
-    /**
-     * @public
-     * @param {(Function)} fn
-     * @param {number} [delay=0] Unit: ms.
-     * @param {boolean} [debounce=false]
-     *        true: If call interval less than `delay`, only the last call works.
-     *        false: If call interval less than `delay, call works on fixed rate.
-     * @return {(Function)} throttled fn.
-     */
+    function createTooltipMarkup(type, option) {
+      option.type = type;
+      return option;
+    }
 
-    function throttle(fn, delay, debounce) {
-      var currCall;
-      var lastCall = 0;
-      var lastExec = 0;
-      var timer = null;
-      var diff;
-      var scope;
-      var args;
-      var debounceNextCall;
-      delay = delay || 0;
+    function getBuilder(fragment) {
+      return hasOwn(builderMap, fragment.type) && builderMap[fragment.type];
+    }
 
-      function exec() {
-        lastExec = new Date().getTime();
-        timer = null;
-        fn.apply(scope, args || []);
-      }
+    var builderMap = {
+      /**
+       * A `section` block is like:
+       * ```
+       * header
+       * subBlock
+       * subBlock
+       * ...
+       * ```
+       */
+      section: {
+        planLayout: function (fragment) {
+          var subBlockLen = fragment.blocks.length;
+          var thisBlockHasInnerGap = subBlockLen > 1 || subBlockLen > 0 && !fragment.noHeader;
+          var thisGapLevelBetweenSubBlocks = 0;
+          each(fragment.blocks, function (subBlock) {
+            getBuilder(subBlock).planLayout(subBlock);
+            var subGapLevel = subBlock.__gapLevelBetweenSubBlocks; // If the some of the sub-blocks have some gaps (like 10px) inside, this block
+            // should use a larger gap (like 20px) to distinguish those sub-blocks.
 
-      var cb = function () {
-        var cbArgs = [];
+            if (subGapLevel >= thisGapLevelBetweenSubBlocks) {
+              thisGapLevelBetweenSubBlocks = subGapLevel + (thisBlockHasInnerGap && ( // 0 always can not be readable gap level.
+              !subGapLevel // If no header, always keep the sub gap level. Otherwise
+              // look weird in case `multipleSeries`.
+              || subBlock.type === 'section' && !subBlock.noHeader) ? 1 : 0);
+            }
+          });
+          fragment.__gapLevelBetweenSubBlocks = thisGapLevelBetweenSubBlocks;
+        },
+        build: function (ctx, fragment, topMarginForOuterGap, toolTipTextStyle) {
+          var noHeader = fragment.noHeader;
+          var gaps = getGap(fragment);
+          var subMarkupText = buildSubBlocks(ctx, fragment, noHeader ? topMarginForOuterGap : gaps.html, toolTipTextStyle);
 
-        for (var _i = 0; _i < arguments.length; _i++) {
-          cbArgs[_i] = arguments[_i];
-        }
+          if (noHeader) {
+            return subMarkupText;
+          }
 
-        currCall = new Date().getTime();
-        scope = this;
-        args = cbArgs;
-        var thisDelay = debounceNextCall || delay;
-        var thisDebounce = debounceNextCall || debounce;
-        debounceNextCall = null;
-        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;
-        clearTimeout(timer); // Here we should make sure that: the `exec` SHOULD NOT be called later
-        // than a new call of `cb`, that is, preserving the command order. Consider
-        // calculating "scale rate" when roaming as an example. When a call of `cb`
-        // happens, either the `exec` is called dierectly, or the call is delayed.
-        // But the delayed call should never be later than next call of `cb`. Under
-        // this assurance, we can simply update view state each time `dispatchAction`
-        // triggered by user roaming, but not need to add extra code to avoid the
-        // state being "rolled-back".
+          var displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC);
+          var nameStyle = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode).nameStyle;
 
-        if (thisDebounce) {
-          timer = setTimeout(exec, thisDelay);
-        } else {
-          if (diff >= 0) {
-            exec();
+          if (ctx.renderMode === 'richText') {
+            return wrapInlineNameRichText(ctx, displayableHeader, nameStyle) + gaps.richText + subMarkupText;
           } else {
-            timer = setTimeout(exec, -diff);
+            return wrapBlockHTML("<div style=\"" + nameStyle + ";" + TOOLTIP_LINE_HEIGHT_CSS + ";\">" + encodeHTML(displayableHeader) + '</div>' + subMarkupText, topMarginForOuterGap);
           }
         }
+      },
 
-        lastCall = currCall;
-      };
       /**
-       * Clear throttle.
-       * @public
+       * A `nameValue` block is like:
+       * ```
+       * marker  name  value
+       * ```
        */
+      nameValue: {
+        planLayout: function (fragment) {
+          fragment.__gapLevelBetweenSubBlocks = 0;
+        },
+        build: function (ctx, fragment, topMarginForOuterGap, toolTipTextStyle) {
+          var renderMode = ctx.renderMode;
+          var noName = fragment.noName;
+          var noValue = fragment.noValue;
+          var noMarker = !fragment.markerType;
+          var name = fragment.name;
+          var value = fragment.value;
+          var useUTC = ctx.useUTC;
 
+          if (noName && noValue) {
+            return;
+          }
 
-      cb.clear = function () {
-        if (timer) {
-          clearTimeout(timer);
-          timer = null;
-        }
-      };
-      /**
-       * Enable debounce once.
-       */
+          var markerStr = noMarker ? '' : ctx.markupStyleCreator.makeTooltipMarker(fragment.markerType, fragment.markerColor || '#333', renderMode);
+          var readableName = noName ? '' : makeValueReadable(name, 'ordinal', useUTC);
+          var valueTypeOption = fragment.valueType;
+          var readableValueList = noValue ? [] : isArray(value) ? map(value, function (val, idx) {
+            return makeValueReadable(val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, useUTC);
+          }) : [makeValueReadable(value, isArray(valueTypeOption) ? valueTypeOption[0] : valueTypeOption, useUTC)];
+          var valueAlignRight = !noMarker || !noName; // It little weird if only value next to marker but far from marker.
 
+          var valueCloseToMarker = !noMarker && noName;
 
-      cb.debounceNextCall = function (debounceDelay) {
-        debounceNextCall = debounceDelay;
-      };
+          var _a = getTooltipTextStyle(toolTipTextStyle, renderMode),
+              nameStyle = _a.nameStyle,
+              valueStyle = _a.valueStyle;
 
-      return cb;
-    }
-    /**
-     * Create throttle method or update throttle rate.
-     *
-     * @example
-     * ComponentView.prototype.render = function () {
-     *     ...
-     *     throttle.createOrUpdate(
-     *         this,
-     *         '_dispatchAction',
-     *         this.model.get('throttle'),
-     *         'fixRate'
-     *     );
-     * };
-     * ComponentView.prototype.remove = function () {
-     *     throttle.clear(this, '_dispatchAction');
-     * };
-     * ComponentView.prototype.dispose = function () {
-     *     throttle.clear(this, '_dispatchAction');
-     * };
-     *
-     */
+          return renderMode === 'richText' ? (noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameRichText(ctx, readableName, nameStyle)) // Value has commas inside, so use ' ' as delimiter for multiple values.
+          + (noValue ? '' : wrapInlineValueRichText(ctx, readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)) : wrapBlockHTML((noMarker ? '' : markerStr) + (noName ? '' : wrapInlineNameHTML(readableName, !noMarker, nameStyle)) + (noValue ? '' : wrapInlineValueHTML(readableValueList, valueAlignRight, valueCloseToMarker, valueStyle)), topMarginForOuterGap);
+        }
+      }
+    };
 
-    function createOrUpdate(obj, fnAttr, rate, throttleType) {
-      var fn = obj[fnAttr];
+    function buildSubBlocks(ctx, fragment, topMarginForOuterGap, tooltipTextStyle) {
+      var subMarkupTextList = [];
+      var subBlocks = fragment.blocks || [];
+      assert(!subBlocks || isArray(subBlocks));
+      subBlocks = subBlocks || [];
+      var orderMode = ctx.orderMode;
 
-      if (!fn) {
-        return;
-      }
+      if (fragment.sortBlocks && orderMode) {
+        subBlocks = subBlocks.slice();
+        var orderMap = {
+          valueAsc: 'asc',
+          valueDesc: 'desc'
+        };
 
-      var originFn = fn[ORIGIN_METHOD] || fn;
-      var lastThrottleType = fn[THROTTLE_TYPE];
-      var lastRate = fn[RATE];
+        if (hasOwn(orderMap, orderMode)) {
+          var comparator_1 = new SortOrderComparator(orderMap[orderMode], null);
+          subBlocks.sort(function (a, b) {
+            return comparator_1.evaluate(a.sortParam, b.sortParam);
+          });
+        } // FIXME 'seriesDesc' necessary?
+        else if (orderMode === 'seriesDesc') {
+            subBlocks.reverse();
+          }
+      }
 
-      if (lastRate !== rate || lastThrottleType !== throttleType) {
-        if (rate == null || !throttleType) {
-          return obj[fnAttr] = originFn;
-        }
+      var gaps = getGap(fragment);
+      each(subBlocks, function (subBlock, idx) {
+        var subMarkupText = getBuilder(subBlock).build(ctx, subBlock, idx > 0 ? gaps.html : 0, tooltipTextStyle);
+        subMarkupText != null && subMarkupTextList.push(subMarkupText);
+      });
 
-        fn = obj[fnAttr] = throttle(originFn, rate, throttleType === 'debounce');
-        fn[ORIGIN_METHOD] = originFn;
-        fn[THROTTLE_TYPE] = throttleType;
-        fn[RATE] = rate;
+      if (!subMarkupTextList.length) {
+        return;
       }
 
-      return fn;
+      return ctx.renderMode === 'richText' ? subMarkupTextList.join(gaps.richText) : wrapBlockHTML(subMarkupTextList.join(''), topMarginForOuterGap);
     }
     /**
-     * Clear throttle. Example see throttle.createOrUpdate.
+     * @return markupText. null/undefined means no content.
      */
 
-    function clear(obj, fnAttr) {
-      var fn = obj[fnAttr];
 
-      if (fn && fn[ORIGIN_METHOD]) {
-        obj[fnAttr] = fn[ORIGIN_METHOD];
+    function buildTooltipMarkup(fragment, markupStyleCreator, renderMode, orderMode, useUTC, toolTipTextStyle) {
+      if (!fragment) {
+        return;
       }
-    }
-
-    var inner$3 = makeInner();
-    var defaultStyleMappers = {
-      itemStyle: makeStyleMapper(ITEM_STYLE_KEY_MAP, true),
-      lineStyle: makeStyleMapper(LINE_STYLE_KEY_MAP, true)
-    };
-    var defaultColorKey = {
-      lineStyle: 'stroke',
-      itemStyle: 'fill'
-    };
 
-    function getStyleMapper(seriesModel, stylePath) {
-      var styleMapper = seriesModel.visualStyleMapper || defaultStyleMappers[stylePath];
+      var builder = getBuilder(fragment);
+      builder.planLayout(fragment);
+      var ctx = {
+        useUTC: useUTC,
+        renderMode: renderMode,
+        orderMode: orderMode,
+        markupStyleCreator: markupStyleCreator
+      };
+      return builder.build(ctx, fragment, 0, toolTipTextStyle);
+    }
 
-      if (!styleMapper) {
-        console.warn("Unkown style type '" + stylePath + "'.");
-        return defaultStyleMappers.itemStyle;
-      }
+    function getGap(fragment) {
+      var gapLevelBetweenSubBlocks = fragment.__gapLevelBetweenSubBlocks;
+      return {
+        html: HTML_GAPS[gapLevelBetweenSubBlocks],
+        richText: RICH_TEXT_GAPS[gapLevelBetweenSubBlocks]
+      };
+    }
 
-      return styleMapper;
+    function wrapBlockHTML(encodedContent, topGap) {
+      var clearfix = '<div style="clear:both"></div>';
+      var marginCSS = "margin: " + topGap + "px 0 0";
+      return "<div style=\"" + marginCSS + ";" + TOOLTIP_LINE_HEIGHT_CSS + ";\">" + encodedContent + clearfix + '</div>';
     }
 
-    function getDefaultColorKey(seriesModel, stylePath) {
-      // return defaultColorKey[stylePath] ||
-      var colorKey = seriesModel.visualDrawType || defaultColorKey[stylePath];
+    function wrapInlineNameHTML(name, leftHasMarker, style) {
+      var marginCss = leftHasMarker ? 'margin-left:2px' : '';
+      return "<span style=\"" + style + ";" + marginCss + "\">" + encodeHTML(name) + '</span>';
+    }
 
-      if (!colorKey) {
-        console.warn("Unkown style type '" + stylePath + "'.");
-        return 'fill';
-      }
+    function wrapInlineValueHTML(valueList, alignRight, valueCloseToMarker, style) {
+      // Do not too close to marker, considering there are multiple values separated by spaces.
+      var paddingStr = valueCloseToMarker ? '10px' : '20px';
+      var alignCSS = alignRight ? "float:right;margin-left:" + paddingStr : '';
+      return "<span style=\"" + alignCSS + ";" + style + "\">" // Value has commas inside, so use '  ' as delimiter for multiple values.
+      + map(valueList, function (value) {
+        return encodeHTML(value);
+      }).join('&nbsp;&nbsp;') + '</span>';
+    }
 
-      return colorKey;
+    function wrapInlineNameRichText(ctx, name, style) {
+      return ctx.markupStyleCreator.wrapRichTextStyle(name, style);
     }
 
-    var seriesStyleTask = {
-      createOnAllSeries: true,
-      performRawSeries: true,
-      reset: function (seriesModel, ecModel) {
-        var data = seriesModel.getData();
-        var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle
+    function wrapInlineValueRichText(ctx, valueList, alignRight, valueCloseToMarker, style) {
+      var styles = [style];
+      var paddingLeft = valueCloseToMarker ? 10 : 20;
+      alignRight && styles.push({
+        padding: [0, 0, 0, paddingLeft],
+        align: 'right'
+      }); // Value has commas inside, so use '  ' as delimiter for multiple values.
 
-        var styleModel = seriesModel.getModel(stylePath);
-        var getStyle = getStyleMapper(seriesModel, stylePath);
-        var globalStyle = getStyle(styleModel);
-        var decalOption = styleModel.getShallow('decal');
+      return ctx.markupStyleCreator.wrapRichTextStyle(valueList.join('  '), styles);
+    }
 
-        if (decalOption) {
-          data.setVisual('decal', decalOption);
-          decalOption.dirty = true;
-        } // TODO
+    function retrieveVisualColorForTooltipMarker(series, dataIndex) {
+      var style = series.getData().getItemVisual(dataIndex, 'style');
+      var color = style[series.visualDrawType];
+      return convertToColorString(color);
+    }
+    function getPaddingFromTooltipModel(model, renderMode) {
+      var padding = model.get('padding');
+      return padding != null ? padding // We give slightly different to look pretty.
+      : renderMode === 'richText' ? [8, 10] : 10;
+    }
+    /**
+     * The major feature is generate styles for `renderMode: 'richText'`.
+     * But it also serves `renderMode: 'html'` to provide
+     * "renderMode-independent" API.
+     */
 
+    var TooltipMarkupStyleCreator =
+    /** @class */
+    function () {
+      function TooltipMarkupStyleCreator() {
+        this.richTextStyles = {}; // Notice that "generate a style name" usuall happens repeatly when mouse moving and
+        // displaying a tooltip. So we put the `_nextStyleNameId` as a member of each creator
+        // rather than static shared by all creators (which will cause it increase to fast).
 
-        var colorKey = getDefaultColorKey(seriesModel, stylePath);
-        var color = globalStyle[colorKey]; // TODO style callback
+        this._nextStyleNameId = getRandomIdBase();
+      }
 
-        var colorCallback = isFunction(color) ? color : null;
-        var hasAutoColor = globalStyle.fill === 'auto' || globalStyle.stroke === 'auto'; // Get from color palette by default.
+      TooltipMarkupStyleCreator.prototype._generateStyleName = function () {
+        return '__EC_aUTo_' + this._nextStyleNameId++;
+      };
 
-        if (!globalStyle[colorKey] || colorCallback || hasAutoColor) {
-          // Note: if some series has color specified (e.g., by itemStyle.color), we DO NOT
-          // make it effect palette. Bacause some scenarios users need to make some series
-          // transparent or as background, which should better not effect the palette.
-          var colorPalette = seriesModel.getColorFromPalette( // TODO series count changed.
-          seriesModel.name, null, ecModel.getSeriesCount());
+      TooltipMarkupStyleCreator.prototype.makeTooltipMarker = function (markerType, colorStr, renderMode) {
+        var markerId = renderMode === 'richText' ? this._generateStyleName() : null;
+        var marker = getTooltipMarker({
+          color: colorStr,
+          type: markerType,
+          renderMode: renderMode,
+          markerId: markerId
+        });
 
-          if (!globalStyle[colorKey]) {
-            globalStyle[colorKey] = colorPalette;
-            data.setVisual('colorFromPalette', true);
+        if (isString(marker)) {
+          return marker;
+        } else {
+          if ("development" !== 'production') {
+            assert(markerId);
           }
 
-          globalStyle.fill = globalStyle.fill === 'auto' || typeof globalStyle.fill === 'function' ? colorPalette : globalStyle.fill;
-          globalStyle.stroke = globalStyle.stroke === 'auto' || typeof globalStyle.stroke === 'function' ? colorPalette : globalStyle.stroke;
+          this.richTextStyles[markerId] = marker.style;
+          return marker.content;
         }
+      };
+      /**
+       * @usage
+       * ```ts
+       * const styledText = markupStyleCreator.wrapRichTextStyle([
+       *     // The styles will be auto merged.
+       *     {
+       *         fontSize: 12,
+       *         color: 'blue'
+       *     },
+       *     {
+       *         padding: 20
+       *     }
+       * ]);
+       * ```
+       */
 
-        data.setVisual('style', globalStyle);
-        data.setVisual('drawType', colorKey); // Only visible series has each data be visual encoded
 
-        if (!ecModel.isSeriesFiltered(seriesModel) && colorCallback) {
-          data.setVisual('colorFromPalette', false);
-          return {
-            dataEach: function (data, idx) {
-              var dataParams = seriesModel.getDataParams(idx);
-              var itemStyle = extend({}, globalStyle);
-              itemStyle[colorKey] = colorCallback(dataParams);
-              data.setItemVisual(idx, 'style', itemStyle);
-            }
-          };
-        }
-      }
-    };
-    var sharedModel = new Model();
-    var dataStyleTask = {
-      createOnAllSeries: true,
-      performRawSeries: true,
-      reset: function (seriesModel, ecModel) {
-        if (seriesModel.ignoreStyleOnData || ecModel.isSeriesFiltered(seriesModel)) {
-          return;
+      TooltipMarkupStyleCreator.prototype.wrapRichTextStyle = function (text, styles) {
+        var finalStl = {};
+
+        if (isArray(styles)) {
+          each(styles, function (stl) {
+            return extend(finalStl, stl);
+          });
+        } else {
+          extend(finalStl, styles);
         }
 
-        var data = seriesModel.getData();
-        var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle
+        var styleName = this._generateStyleName();
 
-        var getStyle = getStyleMapper(seriesModel, stylePath);
-        var colorKey = data.getVisual('drawType');
-        return {
-          dataEach: data.hasItemOption ? function (data, idx) {
-            // Not use getItemModel for performance considuration
-            var rawItem = data.getRawDataItem(idx);
+        this.richTextStyles[styleName] = finalStl;
+        return "{" + styleName + "|" + text + "}";
+      };
 
-            if (rawItem && rawItem[stylePath]) {
-              sharedModel.option = rawItem[stylePath];
-              var style = getStyle(sharedModel);
-              var existsStyle = data.ensureUniqueItemVisual(idx, 'style');
-              extend(existsStyle, style);
+      return TooltipMarkupStyleCreator;
+    }();
 
-              if (sharedModel.option.decal) {
-                data.setItemVisual(idx, 'decal', sharedModel.option.decal);
-                sharedModel.option.decal.dirty = true;
-              }
+    function defaultSeriesFormatTooltip(opt) {
+      var series = opt.series;
+      var dataIndex = opt.dataIndex;
+      var multipleSeries = opt.multipleSeries;
+      var data = series.getData();
+      var tooltipDims = data.mapDimensionsAll('defaultedTooltip');
+      var tooltipDimLen = tooltipDims.length;
+      var value = series.getRawValue(dataIndex);
+      var isValueArr = isArray(value);
+      var markerColor = retrieveVisualColorForTooltipMarker(series, dataIndex); // Complicated rule for pretty tooltip.
 
-              if (colorKey in style) {
-                data.setItemVisual(idx, 'colorFromPalette', false);
-              }
-            }
-          } : null
-        };
-      }
-    }; // Pick color from palette for the data which has not been set with color yet.
-    // Note: do not support stream rendering. No such cases yet.
+      var inlineValue;
+      var inlineValueType;
+      var subBlocks;
+      var sortParam;
 
-    var dataColorPaletteTask = {
-      performRawSeries: true,
-      overallReset: function (ecModel) {
-        // Each type of series use one scope.
-        // Pie and funnel are using diferrent scopes
-        var paletteScopeGroupByType = createHashMap();
-        ecModel.eachSeries(function (seriesModel) {
-          if (!seriesModel.useColorPaletteOnData) {
-            return;
-          }
+      if (tooltipDimLen > 1 || isValueArr && !tooltipDimLen) {
+        var formatArrResult = formatTooltipArrayValue(value, series, dataIndex, tooltipDims, markerColor);
+        inlineValue = formatArrResult.inlineValues;
+        inlineValueType = formatArrResult.inlineValueTypes;
+        subBlocks = formatArrResult.blocks; // Only support tooltip sort by the first inline value. It's enough in most cases.
 
-          var colorScope = paletteScopeGroupByType.get(seriesModel.type);
+        sortParam = formatArrResult.inlineValues[0];
+      } else if (tooltipDimLen) {
+        var dimInfo = data.getDimensionInfo(tooltipDims[0]);
+        sortParam = inlineValue = retrieveRawValue(data, dataIndex, tooltipDims[0]);
+        inlineValueType = dimInfo.type;
+      } else {
+        sortParam = inlineValue = isValueArr ? value[0] : value;
+      } // Do not show generated series name. It might not be readable.
 
-          if (!colorScope) {
-            colorScope = {};
-            paletteScopeGroupByType.set(seriesModel.type, colorScope);
-          }
 
-          inner$3(seriesModel).scope = colorScope;
-        });
-        ecModel.eachSeries(function (seriesModel) {
-          if (!seriesModel.useColorPaletteOnData || ecModel.isSeriesFiltered(seriesModel)) {
-            return;
-          }
+      var seriesNameSpecified = isNameSpecified(series);
+      var seriesName = seriesNameSpecified && series.name || '';
+      var itemName = data.getName(dataIndex);
+      var inlineName = multipleSeries ? seriesName : itemName;
+      return createTooltipMarkup('section', {
+        header: seriesName,
+        // When series name not specified, do not show a header line with only '-'.
+        // This case alway happen in tooltip.trigger: 'item'.
+        noHeader: multipleSeries || !seriesNameSpecified,
+        sortParam: sortParam,
+        blocks: [createTooltipMarkup('nameValue', {
+          markerType: 'item',
+          markerColor: markerColor,
+          // Do not mix display seriesName and itemName in one tooltip,
+          // which might confuses users.
+          name: inlineName,
+          // name dimension might be auto assigned, where the name might
+          // be not readable. So we check trim here.
+          noName: !trim(inlineName),
+          value: inlineValue,
+          valueType: inlineValueType
+        })].concat(subBlocks || [])
+      });
+    }
 
-          var dataAll = seriesModel.getRawData();
-          var idxMap = {};
-          var data = seriesModel.getData();
-          var colorScope = inner$3(seriesModel).scope;
-          var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle';
-          var colorKey = getDefaultColorKey(seriesModel, stylePath);
-          data.each(function (idx) {
-            var rawIdx = data.getRawIndex(idx);
-            idxMap[rawIdx] = idx;
-          }); // Iterate on data before filtered. To make sure color from palette can be
-          // Consistent when toggling legend.
+    function formatTooltipArrayValue(value, series, dataIndex, tooltipDims, colorStr) {
+      // check: category-no-encode-has-axis-data in dataset.html
+      var data = series.getData();
+      var isValueMultipleLine = reduce(value, function (isValueMultipleLine, val, idx) {
+        var dimItem = data.getDimensionInfo(idx);
+        return isValueMultipleLine = isValueMultipleLine || dimItem && dimItem.tooltip !== false && dimItem.displayName != null;
+      }, false);
+      var inlineValues = [];
+      var inlineValueTypes = [];
+      var blocks = [];
+      tooltipDims.length ? each(tooltipDims, function (dim) {
+        setEachItem(retrieveRawValue(data, dataIndex, dim), dim);
+      }) // By default, all dims is used on tooltip.
+      : each(value, setEachItem);
 
-          dataAll.each(function (rawIdx) {
-            var idx = idxMap[rawIdx];
-            var fromPalette = data.getItemVisual(idx, 'colorFromPalette'); // Get color from palette for each data only when the color is inherited from series color, which is
-            // also picked from color palette. So following situation is not in the case:
-            // 1. series.itemStyle.color is set
-            // 2. color is encoded by visualMap
+      function setEachItem(val, dim) {
+        var dimInfo = data.getDimensionInfo(dim); // If `dimInfo.tooltip` is not set, show tooltip.
 
-            if (fromPalette) {
-              var itemStyle = data.ensureUniqueItemVisual(idx, 'style');
-              var name_1 = dataAll.getName(rawIdx) || rawIdx + '';
-              var dataCount = dataAll.count();
-              itemStyle[colorKey] = seriesModel.getColorFromPalette(name_1, colorScope, dataCount);
-            }
-          });
-        });
-      }
-    };
+        if (!dimInfo || dimInfo.otherDims.tooltip === false) {
+          return;
+        }
 
-    var PI$3 = Math.PI;
-    /**
-     * @param {module:echarts/ExtensionAPI} api
-     * @param {Object} [opts]
-     * @param {string} [opts.text]
-     * @param {string} [opts.color]
-     * @param {string} [opts.textColor]
-     * @return {module:zrender/Element}
-     */
+        if (isValueMultipleLine) {
+          blocks.push(createTooltipMarkup('nameValue', {
+            markerType: 'subItem',
+            markerColor: colorStr,
+            name: dimInfo.displayName,
+            value: val,
+            valueType: dimInfo.type
+          }));
+        } else {
+          inlineValues.push(val);
+          inlineValueTypes.push(dimInfo.type);
+        }
+      }
 
-    function defaultLoading(api, opts) {
-      opts = opts || {};
-      defaults(opts, {
-        text: 'loading',
-        textColor: '#000',
-        fontSize: 12,
-        fontWeight: 'normal',
-        fontStyle: 'normal',
-        fontFamily: 'sans-serif',
-        maskColor: 'rgba(255, 255, 255, 0.8)',
-        showSpinner: true,
-        color: '#5470c6',
-        spinnerRadius: 10,
-        lineWidth: 5,
-        zlevel: 0
-      });
-      var group = new Group();
-      var mask = new Rect({
-        style: {
-          fill: opts.maskColor
-        },
-        zlevel: opts.zlevel,
-        z: 10000
-      });
-      group.add(mask);
-      var textContent = new ZRText({
-        style: {
-          text: opts.text,
-          fill: opts.textColor,
-          fontSize: opts.fontSize,
-          fontWeight: opts.fontWeight,
-          fontStyle: opts.fontStyle,
-          fontFamily: opts.fontFamily
-        },
-        zlevel: opts.zlevel,
-        z: 10001
-      });
-      var labelRect = new Rect({
-        style: {
-          fill: 'none'
-        },
-        textContent: textContent,
-        textConfig: {
-          position: 'right',
-          distance: 10
-        },
-        zlevel: opts.zlevel,
-        z: 10001
-      });
-      group.add(labelRect);
-      var arc;
+      return {
+        inlineValues: inlineValues,
+        inlineValueTypes: inlineValueTypes,
+        blocks: blocks
+      };
+    }
 
-      if (opts.showSpinner) {
-        arc = new Arc({
-          shape: {
-            startAngle: -PI$3 / 2,
-            endAngle: -PI$3 / 2 + 0.1,
-            r: opts.spinnerRadius
-          },
-          style: {
-            stroke: opts.color,
-            lineCap: 'round',
-            lineWidth: opts.lineWidth
-          },
-          zlevel: opts.zlevel,
-          z: 10001
-        });
-        arc.animateShape(true).when(1000, {
-          endAngle: PI$3 * 3 / 2
-        }).start('circularInOut');
-        arc.animateShape(true).when(1000, {
-          startAngle: PI$3 * 3 / 2
-        }).delay(300).start('circularInOut');
-        group.add(arc);
-      } // Inject resize
+    var inner$1 = makeInner();
 
+    function getSelectionKey(data, dataIndex) {
+      return data.getName(dataIndex) || data.getId(dataIndex);
+    }
 
-      group.resize = function () {
-        var textWidth = textContent.getBoundingRect().width;
-        var r = opts.showSpinner ? opts.spinnerRadius : 0; // cx = (containerWidth - arcDiameter - textDistance - textWidth) / 2
-        // textDistance needs to be calculated when both animation and text exist
+    var SERIES_UNIVERSAL_TRANSITION_PROP = '__universalTransitionEnabled';
 
-        var cx = (api.getWidth() - r * 2 - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2 - (opts.showSpinner && textWidth ? 0 : 5 + textWidth / 2) // only show the text
-        + (opts.showSpinner ? 0 : textWidth / 2) // only show the spinner
-        + (textWidth ? 0 : r);
-        var cy = api.getHeight() / 2;
-        opts.showSpinner && arc.setShape({
-          cx: cx,
-          cy: cy
-        });
-        labelRect.setShape({
-          x: cx - r,
-          y: cy - r,
-          width: r * 2,
-          height: r * 2
-        });
-        mask.setShape({
-          x: 0,
-          y: 0,
-          width: api.getWidth(),
-          height: api.getHeight()
-        });
-      };
+    var SeriesModel =
+    /** @class */
+    function (_super) {
+      __extends(SeriesModel, _super);
 
-      group.resize();
-      return group;
-    }
+      function SeriesModel() {
+        // [Caution]: Becuase this class or desecendants can be used as `XXX.extend(subProto)`,
+        // the class members must not be initialized in constructor or declaration place.
+        // Otherwise there is bad case:
+        //   class A {xxx = 1;}
+        //   enableClassExtend(A);
+        //   class B extends A {}
+        //   var C = B.extend({xxx: 5});
+        //   var c = new C();
+        //   console.log(c.xxx); // expect 5 but always 1.
+        var _this = _super !== null && _super.apply(this, arguments) || this; // ---------------------------------------
+        // Props about data selection
+        // ---------------------------------------
 
-    var Scheduler =
-    /** @class */
-    function () {
-      function Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {
-        // key: handlerUID
-        this._stageTaskMap = createHashMap();
-        this.ecInstance = ecInstance;
-        this.api = api; // Fix current processors in case that in some rear cases that
-        // processors might be registered after echarts instance created.
-        // Register processors incrementally for a echarts instance is
-        // not supported by this stream architecture.
 
-        dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();
-        visualHandlers = this._visualHandlers = visualHandlers.slice();
-        this._allHandlers = dataProcessorHandlers.concat(visualHandlers);
+        _this._selectedDataIndicesMap = {};
+        return _this;
       }
 
-      Scheduler.prototype.restoreData = function (ecModel, payload) {
-        // TODO: Only restore needed series and components, but not all components.
-        // Currently `restoreData` of all of the series and component will be called.
-        // But some independent components like `title`, `legend`, `graphic`, `toolbox`,
-        // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,
-        // and some components like coordinate system, axes, dataZoom, visualMap only
-        // need their target series refresh.
-        // (1) If we are implementing this feature some day, we should consider these cases:
-        // if a data processor depends on a component (e.g., dataZoomProcessor depends
-        // on the settings of `dataZoom`), it should be re-performed if the component
-        // is modified by `setOption`.
-        // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,
-        // it should be re-performed when the result array of `getTargetSeries` changed.
-        // We use `dependencies` to cover these issues.
-        // (3) How to update target series when coordinate system related components modified.
-        // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,
-        // and this case all of the tasks will be set as dirty.
-        ecModel.restoreData(payload); // Theoretically an overall task not only depends on each of its target series, but also
-        // depends on all of the series.
-        // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks
-        // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure
-        // that the overall task is set as dirty and to be performed, otherwise it probably cause
-        // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it
-        // probably cause state chaos (consider `dataZoomProcessor`).
-
-        this._stageTaskMap.each(function (taskRecord) {
-          var overallTask = taskRecord.overallTask;
-          overallTask && overallTask.dirty();
+      SeriesModel.prototype.init = function (option, parentModel, ecModel) {
+        this.seriesIndex = this.componentIndex;
+        this.dataTask = createTask({
+          count: dataTaskCount,
+          reset: dataTaskReset
         });
-      }; // If seriesModel provided, incremental threshold is check by series data.
-
+        this.dataTask.context = {
+          model: this
+        };
+        this.mergeDefaultAndTheme(option, ecModel);
+        var sourceManager = inner$1(this).sourceManager = new SourceManager(this);
+        sourceManager.prepareSource();
+        var data = this.getInitialData(option, ecModel);
+        wrapData(data, this);
+        this.dataTask.context.data = data;
 
-      Scheduler.prototype.getPerformArgs = function (task, isBlock) {
-        // For overall task
-        if (!task.__pipeline) {
-          return;
+        if ("development" !== 'production') {
+          assert(data, 'getInitialData returned invalid data.');
         }
 
-        var pipeline = this._pipelineMap.get(task.__pipeline.id);
+        inner$1(this).dataBeforeProcessed = data; // If we reverse the order (make data firstly, and then make
+        // dataBeforeProcessed by cloneShallow), cloneShallow will
+        // cause data.graph.data !== data when using
+        // module:echarts/data/Graph or module:echarts/data/Tree.
+        // See module:echarts/data/helper/linkSeriesData
+        // Theoretically, it is unreasonable to call `seriesModel.getData()` in the model
+        // init or merge stage, because the data can be restored. So we do not `restoreData`
+        // and `setData` here, which forbids calling `seriesModel.getData()` in this stage.
+        // Call `seriesModel.getRawData()` instead.
+        // this.restoreData();
 
-        var pCtx = pipeline.context;
-        var incremental = !isBlock && pipeline.progressiveEnabled && (!pCtx || pCtx.progressiveRender) && task.__idxInPipeline > pipeline.blockIndex;
-        var step = incremental ? pipeline.step : null;
-        var modDataCount = pCtx && pCtx.modDataCount;
-        var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;
-        return {
-          step: step,
-          modBy: modBy,
-          modDataCount: modDataCount
-        };
-      };
+        autoSeriesName(this);
 
-      Scheduler.prototype.getPipeline = function (pipelineId) {
-        return this._pipelineMap.get(pipelineId);
+        this._initSelectedMapFromData(data);
       };
       /**
-       * Current, progressive rendering starts from visual and layout.
-       * Always detect render mode in the same stage, avoiding that incorrect
-       * detection caused by data filtering.
-       * Caution:
-       * `updateStreamModes` use `seriesModel.getData()`.
+       * Util for merge default and theme to option
        */
 
 
-      Scheduler.prototype.updateStreamModes = function (seriesModel, view) {
-        var pipeline = this._pipelineMap.get(seriesModel.uid);
+      SeriesModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
+        var layoutMode = fetchLayoutMode(this);
+        var inputPositionParams = layoutMode ? getLayoutParams(option) : {}; // Backward compat: using subType on theme.
+        // But if name duplicate between series subType
+        // (for example: parallel) add component mainType,
+        // add suffix 'Series'.
 
-        var data = seriesModel.getData();
-        var dataLen = data.count(); // `progressiveRender` means that can render progressively in each
-        // animation frame. Note that some types of series do not provide
-        // `view.incrementalPrepareRender` but support `chart.appendData`. We
-        // use the term `incremental` but not `progressive` to describe the
-        // case that `chart.appendData`.
+        var themeSubType = this.subType;
 
-        var progressiveRender = pipeline.progressiveEnabled && view.incrementalPrepareRender && dataLen >= pipeline.threshold;
-        var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold'); // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.
-        // see `test/candlestick-large3.html`
+        if (ComponentModel.hasClass(themeSubType)) {
+          themeSubType += 'Series';
+        }
 
-        var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;
-        seriesModel.pipelineContext = pipeline.context = {
-          progressiveRender: progressiveRender,
-          modDataCount: modDataCount,
-          large: large
-        };
-      };
+        merge(option, ecModel.getTheme().get(this.subType));
+        merge(option, this.getDefaultOption()); // Default label emphasis `show`
 
-      Scheduler.prototype.restorePipelines = function (ecModel) {
-        var scheduler = this;
-        var pipelineMap = scheduler._pipelineMap = createHashMap();
-        ecModel.eachSeries(function (seriesModel) {
-          var progressive = seriesModel.getProgressive();
-          var pipelineId = seriesModel.uid;
-          pipelineMap.set(pipelineId, {
-            id: pipelineId,
-            head: null,
-            tail: null,
-            threshold: seriesModel.getProgressiveThreshold(),
-            progressiveEnabled: progressive && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),
-            blockIndex: -1,
-            step: Math.round(progressive || 700),
-            count: 0
-          });
+        defaultEmphasis(option, 'label', ['show']);
+        this.fillDataTextStyle(option.data);
 
-          scheduler._pipe(seriesModel, seriesModel.dataTask);
-        });
+        if (layoutMode) {
+          mergeLayoutParam(option, inputPositionParams, layoutMode);
+        }
       };
 
-      Scheduler.prototype.prepareStageTasks = function () {
-        var stageTaskMap = this._stageTaskMap;
-        var ecModel = this.api.getModel();
-        var api = this.api;
-        each(this._allHandlers, function (handler) {
-          var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, {});
-          var errMsg = '';
+      SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) {
+        // this.settingTask.dirty();
+        newSeriesOption = merge(this.option, newSeriesOption, true);
+        this.fillDataTextStyle(newSeriesOption.data);
+        var layoutMode = fetchLayoutMode(this);
 
-          if ("development" !== 'production') {
-            // Currently do not need to support to sepecify them both.
-            errMsg = '"reset" and "overallReset" must not be both specified.';
-          }
+        if (layoutMode) {
+          mergeLayoutParam(this.option, newSeriesOption, layoutMode);
+        }
 
-          assert(!(handler.reset && handler.overallReset), errMsg);
-          handler.reset && this._createSeriesStageTask(handler, record, ecModel, api);
-          handler.overallReset && this._createOverallStageTask(handler, record, ecModel, api);
-        }, this);
+        var sourceManager = inner$1(this).sourceManager;
+        sourceManager.dirty();
+        sourceManager.prepareSource();
+        var data = this.getInitialData(newSeriesOption, ecModel);
+        wrapData(data, this);
+        this.dataTask.dirty();
+        this.dataTask.context.data = data;
+        inner$1(this).dataBeforeProcessed = data;
+        autoSeriesName(this);
+
+        this._initSelectedMapFromData(data);
       };
 
-      Scheduler.prototype.prepareView = function (view, model, ecModel, api) {
-        var renderTask = view.renderTask;
-        var context = renderTask.context;
-        context.model = model;
-        context.ecModel = ecModel;
-        context.api = api;
-        renderTask.__block = !view.incrementalPrepareRender;
+      SeriesModel.prototype.fillDataTextStyle = function (data) {
+        // Default data label emphasis `show`
+        // FIXME Tree structure data ?
+        // FIXME Performance ?
+        if (data && !isTypedArray(data)) {
+          var props = ['show'];
 
-        this._pipe(model, renderTask);
+          for (var i = 0; i < data.length; i++) {
+            if (data[i] && data[i].label) {
+              defaultEmphasis(data[i], 'label', props);
+            }
+          }
+        }
       };
+      /**
+       * Init a data structure from data related option in series
+       * Must be overriden.
+       */
 
-      Scheduler.prototype.performDataProcessorTasks = function (ecModel, payload) {
-        // If we do not use `block` here, it should be considered when to update modes.
-        this._performStageTasks(this._dataProcessorHandlers, ecModel, payload, {
-          block: true
-        });
-      };
 
-      Scheduler.prototype.performVisualTasks = function (ecModel, payload, opt) {
-        this._performStageTasks(this._visualHandlers, ecModel, payload, opt);
+      SeriesModel.prototype.getInitialData = function (option, ecModel) {
+        return;
       };
+      /**
+       * Append data to list
+       */
 
-      Scheduler.prototype._performStageTasks = function (stageHandlers, ecModel, payload, opt) {
-        opt = opt || {};
-        var unfinished = false;
-        var scheduler = this;
-        each(stageHandlers, function (stageHandler, idx) {
-          if (opt.visualType && opt.visualType !== stageHandler.visualType) {
-            return;
-          }
 
-          var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);
+      SeriesModel.prototype.appendData = function (params) {
+        // FIXME ???
+        // (1) If data from dataset, forbidden append.
+        // (2) support append data of dataset.
+        var data = this.getRawData();
+        data.appendData(params.data);
+      };
+      /**
+       * Consider some method like `filter`, `map` need make new data,
+       * We should make sure that `seriesModel.getData()` get correct
+       * data in the stream procedure. So we fetch data from upstream
+       * each time `task.perform` called.
+       */
 
-          var seriesTaskMap = stageHandlerRecord.seriesTaskMap;
-          var overallTask = stageHandlerRecord.overallTask;
 
-          if (overallTask) {
-            var overallNeedDirty_1;
-            var agentStubMap = overallTask.agentStubMap;
-            agentStubMap.each(function (stub) {
-              if (needSetDirty(opt, stub)) {
-                stub.dirty();
-                overallNeedDirty_1 = true;
-              }
-            });
-            overallNeedDirty_1 && overallTask.dirty();
-            scheduler.updatePayload(overallTask, payload);
-            var performArgs_1 = scheduler.getPerformArgs(overallTask, opt.block); // Execute stubs firstly, which may set the overall task dirty,
-            // then execute the overall task. And stub will call seriesModel.setData,
-            // which ensures that in the overallTask seriesModel.getData() will not
-            // return incorrect data.
+      SeriesModel.prototype.getData = function (dataType) {
+        var task = getCurrentTask(this);
 
-            agentStubMap.each(function (stub) {
-              stub.perform(performArgs_1);
-            });
+        if (task) {
+          var data = task.context.data;
+          return dataType == null ? data : data.getLinkedData(dataType);
+        } else {
+          // When series is not alive (that may happen when click toolbox
+          // 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$1(this).data;
+        }
+      };
 
-            if (overallTask.perform(performArgs_1)) {
-              unfinished = true;
-            }
-          } else if (seriesTaskMap) {
-            seriesTaskMap.each(function (task, pipelineId) {
-              if (needSetDirty(opt, task)) {
-                task.dirty();
-              }
+      SeriesModel.prototype.getAllData = function () {
+        var mainData = this.getData();
+        return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{
+          data: mainData
+        }];
+      };
 
-              var performArgs = scheduler.getPerformArgs(task, opt.block); // FIXME
-              // if intending to decalare `performRawSeries` in handlers, only
-              // stream-independent (specifically, data item independent) operations can be
-              // performed. Because is a series is filtered, most of the tasks will not
-              // be performed. A stream-dependent operation probably cause wrong biz logic.
-              // Perhaps we should not provide a separate callback for this case instead
-              // of providing the config `performRawSeries`. The stream-dependent operaions
-              // and stream-independent operations should better not be mixed.
+      SeriesModel.prototype.setData = function (data) {
+        var task = getCurrentTask(this);
 
-              performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model);
-              scheduler.updatePayload(task, payload);
+        if (task) {
+          var context = task.context; // Consider case: filter, data sample.
+          // FIXME:TS never used, so comment it
+          // if (context.data !== data && task.modifyOutputEnd) {
+          //     task.setOutputEnd(data.count());
+          // }
 
-              if (task.perform(performArgs)) {
-                unfinished = true;
-              }
-            });
+          context.outputData = data; // Caution: setData should update context.data,
+          // Because getData may be called multiply in a
+          // single stage and expect to get the data just
+          // set. (For example, AxisProxy, x y both call
+          // getData and setDate sequentially).
+          // So the context.data should be fetched from
+          // upstream each time when a stage starts to be
+          // performed.
+
+          if (task !== this.dataTask) {
+            context.data = data;
           }
-        });
+        }
 
-        function needSetDirty(opt, task) {
-          return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));
+        inner$1(this).data = data;
+      };
+
+      SeriesModel.prototype.getEncode = function () {
+        var encode = this.get('encode', true);
+
+        if (encode) {
+          return createHashMap(encode);
         }
+      };
 
-        this.unfinished = unfinished || this.unfinished;
+      SeriesModel.prototype.getSourceManager = function () {
+        return inner$1(this).sourceManager;
       };
 
-      Scheduler.prototype.performSeriesTasks = function (ecModel) {
-        var unfinished;
-        ecModel.eachSeries(function (seriesModel) {
-          // Progress to the end for dataInit and dataRestore.
-          unfinished = seriesModel.dataTask.perform() || unfinished;
-        });
-        this.unfinished = unfinished || this.unfinished;
+      SeriesModel.prototype.getSource = function () {
+        return this.getSourceManager().getSource();
       };
+      /**
+       * Get data before processed
+       */
 
-      Scheduler.prototype.plan = function () {
-        // Travel pipelines, check block.
-        this._pipelineMap.each(function (pipeline) {
-          var task = pipeline.tail;
 
-          do {
-            if (task.__block) {
-              pipeline.blockIndex = task.__idxInPipeline;
-              break;
-            }
+      SeriesModel.prototype.getRawData = function () {
+        return inner$1(this).dataBeforeProcessed;
+      };
 
-            task = task.getUpstream();
-          } while (task);
-        });
+      SeriesModel.prototype.getColorBy = function () {
+        var colorBy = this.get('colorBy');
+        return colorBy || 'series';
       };
 
-      Scheduler.prototype.updatePayload = function (task, payload) {
-        payload !== 'remain' && (task.context.payload = payload);
+      SeriesModel.prototype.isColorBySeries = function () {
+        return this.getColorBy() === 'series';
       };
+      /**
+       * Get base axis if has coordinate system and has axis.
+       * By default use coordSys.getBaseAxis();
+       * Can be overrided for some chart.
+       * @return {type} description
+       */
 
-      Scheduler.prototype._createSeriesStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) {
-        var scheduler = this;
-        var oldSeriesTaskMap = stageHandlerRecord.seriesTaskMap; // The count of stages are totally about only several dozen, so
-        // do not need to reuse the map.
 
-        var newSeriesTaskMap = stageHandlerRecord.seriesTaskMap = createHashMap();
-        var seriesType = stageHandler.seriesType;
-        var getTargetSeries = stageHandler.getTargetSeries; // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,
-        // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,
-        // it works but it may cause other irrelevant charts blocked.
+      SeriesModel.prototype.getBaseAxis = function () {
+        var coordSys = this.coordinateSystem; // @ts-ignore
 
-        if (stageHandler.createOnAllSeries) {
-          ecModel.eachRawSeries(create);
-        } else if (seriesType) {
-          ecModel.eachRawSeriesByType(seriesType, create);
-        } else if (getTargetSeries) {
-          getTargetSeries(ecModel, api).each(create);
-        }
+        return coordSys && coordSys.getBaseAxis && coordSys.getBaseAxis();
+      };
+      /**
+       * Default tooltip formatter
+       *
+       * @param dataIndex
+       * @param multipleSeries
+       * @param dataType
+       * @param renderMode valid values: 'html'(by default) and 'richText'.
+       *        'html' is used for rendering tooltip in extra DOM form, and the result
+       *        string is used as DOM HTML content.
+       *        'richText' is used for rendering tooltip in rich text form, for those where
+       *        DOM operation is not supported.
+       * @return formatted tooltip with `html` and `markers`
+       *        Notice: The override method can also return string
+       */
 
-        function create(seriesModel) {
-          var pipelineId = seriesModel.uid; // Init tasks for each seriesModel only once.
-          // Reuse original task instance.
 
-          var task = newSeriesTaskMap.set(pipelineId, oldSeriesTaskMap && oldSeriesTaskMap.get(pipelineId) || createTask({
-            plan: seriesTaskPlan,
-            reset: seriesTaskReset,
-            count: seriesTaskCount
-          }));
-          task.context = {
-            model: seriesModel,
-            ecModel: ecModel,
-            api: api,
-            // PENDING: `useClearVisual` not used?
-            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,
-            plan: stageHandler.plan,
-            reset: stageHandler.reset,
-            scheduler: scheduler
-          };
+      SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) {
+        return defaultSeriesFormatTooltip({
+          series: this,
+          dataIndex: dataIndex,
+          multipleSeries: multipleSeries
+        });
+      };
 
-          scheduler._pipe(seriesModel, task);
+      SeriesModel.prototype.isAnimationEnabled = function () {
+        if (env.node) {
+          return false;
         }
+
+        var animationEnabled = this.getShallow('animation');
+
+        if (animationEnabled) {
+          if (this.getData().count() > this.getShallow('animationThreshold')) {
+            animationEnabled = false;
+          }
+        }
+
+        return !!animationEnabled;
       };
 
-      Scheduler.prototype._createOverallStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) {
-        var scheduler = this;
-        var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask // For overall task, the function only be called on reset stage.
-        || createTask({
-          reset: overallTaskReset
-        });
-        overallTask.context = {
-          ecModel: ecModel,
-          api: api,
-          overallReset: stageHandler.overallReset,
-          scheduler: scheduler
-        };
-        var oldAgentStubMap = overallTask.agentStubMap; // The count of stages are totally about only several dozen, so
-        // do not need to reuse the map.
+      SeriesModel.prototype.restoreData = function () {
+        this.dataTask.dirty();
+      };
 
-        var newAgentStubMap = overallTask.agentStubMap = createHashMap();
-        var seriesType = stageHandler.seriesType;
-        var getTargetSeries = stageHandler.getTargetSeries;
-        var overallProgress = true;
-        var shouldOverallTaskDirty = false; // FIXME:TS never used, so comment it
-        // let modifyOutputEnd = stageHandler.modifyOutputEnd;
-        // An overall task with seriesType detected or has `getTargetSeries`, we add
-        // stub in each pipelines, it will set the overall task dirty when the pipeline
-        // progress. Moreover, to avoid call the overall task each frame (too frequent),
-        // we set the pipeline block.
+      SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) {
+        var ecModel = this.ecModel; // PENDING
 
-        var errMsg = '';
+        var color = PaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum);
 
-        if ("development" !== 'production') {
-          errMsg = '"createOnAllSeries" do not supported for "overallReset", ' + 'becuase it will block all streams.';
+        if (!color) {
+          color = ecModel.getColorFromPalette(name, scope, requestColorNum);
         }
 
-        assert(!stageHandler.createOnAllSeries, errMsg);
+        return color;
+      };
+      /**
+       * Use `data.mapDimensionsAll(coordDim)` instead.
+       * @deprecated
+       */
 
-        if (seriesType) {
-          ecModel.eachRawSeriesByType(seriesType, createStub);
-        } else if (getTargetSeries) {
-          getTargetSeries(ecModel, api).each(createStub);
-        } // Otherwise, (usually it is legancy case), the overall task will only be
-        // executed when upstream dirty. Otherwise the progressive rendering of all
-        // pipelines will be disabled unexpectedly. But it still needs stubs to receive
-        // dirty info from upsteam.
-        else {
-            overallProgress = false;
-            each(ecModel.getSeries(), createStub);
-          }
 
-        function createStub(seriesModel) {
-          var pipelineId = seriesModel.uid;
-          var stub = newAgentStubMap.set(pipelineId, oldAgentStubMap && oldAgentStubMap.get(pipelineId) || ( // When the result of `getTargetSeries` changed, the overallTask
-          // should be set as dirty and re-performed.
-          shouldOverallTaskDirty = true, createTask({
-            reset: stubReset,
-            onDirty: stubOnDirty
-          })));
-          stub.context = {
-            model: seriesModel,
-            overallProgress: overallProgress // FIXME:TS never used, so comment it
-            // modifyOutputEnd: modifyOutputEnd
+      SeriesModel.prototype.coordDimToDataDim = function (coordDim) {
+        return this.getRawData().mapDimensionsAll(coordDim);
+      };
+      /**
+       * Get progressive rendering count each step
+       */
 
-          };
-          stub.agent = overallTask;
-          stub.__block = overallProgress;
 
-          scheduler._pipe(seriesModel, stub);
+      SeriesModel.prototype.getProgressive = function () {
+        return this.get('progressive');
+      };
+      /**
+       * Get progressive rendering count each step
+       */
+
+
+      SeriesModel.prototype.getProgressiveThreshold = function () {
+        return this.get('progressiveThreshold');
+      }; // PENGING If selectedMode is null ?
+
+
+      SeriesModel.prototype.select = function (innerDataIndices, dataType) {
+        this._innerSelect(this.getData(dataType), innerDataIndices);
+      };
+
+      SeriesModel.prototype.unselect = function (innerDataIndices, dataType) {
+        var selectedMap = this.option.selectedMap;
+
+        if (!selectedMap) {
+          return;
         }
 
-        if (shouldOverallTaskDirty) {
-          overallTask.dirty();
+        var data = this.getData(dataType);
+
+        for (var i = 0; i < innerDataIndices.length; i++) {
+          var dataIndex = innerDataIndices[i];
+          var nameOrId = getSelectionKey(data, dataIndex);
+          selectedMap[nameOrId] = false;
+          this._selectedDataIndicesMap[nameOrId] = -1;
         }
       };
 
-      Scheduler.prototype._pipe = function (seriesModel, task) {
-        var pipelineId = seriesModel.uid;
+      SeriesModel.prototype.toggleSelect = function (innerDataIndices, dataType) {
+        var tmpArr = [];
 
-        var pipeline = this._pipelineMap.get(pipelineId);
+        for (var i = 0; i < innerDataIndices.length; i++) {
+          tmpArr[0] = innerDataIndices[i];
+          this.isSelected(innerDataIndices[i], dataType) ? this.unselect(tmpArr, dataType) : this.select(tmpArr, dataType);
+        }
+      };
 
-        !pipeline.head && (pipeline.head = task);
-        pipeline.tail && pipeline.tail.pipe(task);
-        pipeline.tail = task;
-        task.__idxInPipeline = pipeline.count++;
-        task.__pipeline = pipeline;
+      SeriesModel.prototype.getSelectedDataIndices = function () {
+        var selectedDataIndicesMap = this._selectedDataIndicesMap;
+        var nameOrIds = keys(selectedDataIndicesMap);
+        var dataIndices = [];
+
+        for (var i = 0; i < nameOrIds.length; i++) {
+          var dataIndex = selectedDataIndicesMap[nameOrIds[i]];
+
+          if (dataIndex >= 0) {
+            dataIndices.push(dataIndex);
+          }
+        }
+
+        return dataIndices;
       };
 
-      Scheduler.wrapStageHandler = function (stageHandler, visualType) {
-        if (isFunction(stageHandler)) {
-          stageHandler = {
-            overallReset: stageHandler,
-            seriesType: detectSeriseType(stageHandler)
-          };
+      SeriesModel.prototype.isSelected = function (dataIndex, dataType) {
+        var selectedMap = this.option.selectedMap;
+
+        if (!selectedMap) {
+          return false;
         }
 
-        stageHandler.uid = getUID('stageHandler');
-        visualType && (stageHandler.visualType = visualType);
-        return stageHandler;
+        var data = this.getData(dataType);
+        var nameOrId = getSelectionKey(data, dataIndex);
+        return selectedMap[nameOrId] || false;
       };
-      return Scheduler;
-    }();
 
-    function overallTaskReset(context) {
-      context.overallReset(context.ecModel, context.api, context.payload);
-    }
+      SeriesModel.prototype.isUniversalTransitionEnabled = function () {
+        if (this[SERIES_UNIVERSAL_TRANSITION_PROP]) {
+          return true;
+        }
 
-    function stubReset(context) {
-      return context.overallProgress && stubProgress;
-    }
+        var universalTransitionOpt = this.option.universalTransition; // Quick reject
 
-    function stubProgress() {
-      this.agent.dirty();
-      this.getDownstream().dirty();
-    }
+        if (!universalTransitionOpt) {
+          return false;
+        }
 
-    function stubOnDirty() {
-      this.agent && this.agent.dirty();
-    }
+        if (universalTransitionOpt === true) {
+          return true;
+        } // Can be simply 'universalTransition: true'
 
-    function seriesTaskPlan(context) {
-      return context.plan ? context.plan(context.model, context.ecModel, context.api, context.payload) : null;
-    }
 
-    function seriesTaskReset(context) {
-      if (context.useClearVisual) {
-        context.data.clearAllVisual();
-      }
+        return universalTransitionOpt && universalTransitionOpt.enabled;
+      };
 
-      var resetDefines = context.resetDefines = normalizeToArray(context.reset(context.model, context.ecModel, context.api, context.payload));
-      return resetDefines.length > 1 ? map(resetDefines, function (v, idx) {
-        return makeSeriesTaskProgress(idx);
-      }) : singleSeriesTaskProgress;
-    }
+      SeriesModel.prototype._innerSelect = function (data, innerDataIndices) {
+        var _a, _b;
 
-    var singleSeriesTaskProgress = makeSeriesTaskProgress(0);
+        var selectedMode = this.option.selectedMode;
+        var len = innerDataIndices.length;
 
-    function makeSeriesTaskProgress(resetDefineIdx) {
-      return function (params, context) {
-        var data = context.data;
-        var resetDefine = context.resetDefines[resetDefineIdx];
+        if (!selectedMode || !len) {
+          return;
+        }
 
-        if (resetDefine && resetDefine.dataEach) {
-          for (var i = params.start; i < params.end; i++) {
-            resetDefine.dataEach(data, i);
+        if (selectedMode === 'multiple') {
+          var selectedMap = this.option.selectedMap || (this.option.selectedMap = {});
+
+          for (var i = 0; i < len; i++) {
+            var dataIndex = innerDataIndices[i]; // TODO diffrent types of data share same object.
+
+            var nameOrId = getSelectionKey(data, dataIndex);
+            selectedMap[nameOrId] = true;
+            this._selectedDataIndicesMap[nameOrId] = data.getRawIndex(dataIndex);
           }
-        } else if (resetDefine && resetDefine.progress) {
-          resetDefine.progress(params, data);
+        } else if (selectedMode === 'single' || selectedMode === true) {
+          var lastDataIndex = innerDataIndices[len - 1];
+          var nameOrId = getSelectionKey(data, lastDataIndex);
+          this.option.selectedMap = (_a = {}, _a[nameOrId] = true, _a);
+          this._selectedDataIndicesMap = (_b = {}, _b[nameOrId] = data.getRawIndex(lastDataIndex), _b);
         }
       };
-    }
 
-    function seriesTaskCount(context) {
-      return context.data.count();
-    }
-    /**
-     * Only some legacy stage handlers (usually in echarts extensions) are pure function.
-     * To ensure that they can work normally, they should work in block mode, that is,
-     * they should not be started util the previous tasks finished. So they cause the
-     * progressive rendering disabled. We try to detect the series type, to narrow down
-     * the block range to only the series type they concern, but not all series.
-     */
+      SeriesModel.prototype._initSelectedMapFromData = function (data) {
+        // Ignore select info in data if selectedMap exists.
+        // NOTE It's only for legacy usage. edge data is not supported.
+        if (this.option.selectedMap) {
+          return;
+        }
 
+        var dataIndices = [];
 
-    function detectSeriseType(legacyFunc) {
-      seriesType = null;
+        if (data.hasItemOption) {
+          data.each(function (idx) {
+            var rawItem = data.getRawDataItem(idx);
 
-      try {
-        // Assume there is no async when calling `eachSeriesByType`.
-        legacyFunc(ecModelMock, apiMock);
-      } catch (e) {}
+            if (rawItem && rawItem.selected) {
+              dataIndices.push(idx);
+            }
+          });
+        }
 
-      return seriesType;
-    }
+        if (dataIndices.length > 0) {
+          this._innerSelect(data, dataIndices);
+        }
+      }; // /**
+      //  * @see {module:echarts/stream/Scheduler}
+      //  */
+      // abstract pipeTask: null
 
-    var ecModelMock = {};
-    var apiMock = {};
-    var seriesType;
-    mockMethods(ecModelMock, GlobalModel);
-    mockMethods(apiMock, ExtensionAPI);
 
-    ecModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {
-      seriesType = type;
-    };
+      SeriesModel.registerClass = function (clz) {
+        return ComponentModel.registerClass(clz);
+      };
 
-    ecModelMock.eachComponent = function (cond) {
-      if (cond.mainType === 'series' && cond.subType) {
-        seriesType = cond.subType;
-      }
-    };
+      SeriesModel.protoInitialize = function () {
+        var proto = SeriesModel.prototype;
+        proto.type = 'series.__base__';
+        proto.seriesIndex = 0;
+        proto.ignoreStyleOnData = false;
+        proto.hasSymbolVisual = false;
+        proto.defaultSymbol = 'circle'; // Make sure the values can be accessed!
 
-    function mockMethods(target, Clz) {
-      /* eslint-disable */
-      for (var name_1 in Clz.prototype) {
-        // Do not use hasOwnProperty
-        target[name_1] = noop;
+        proto.visualStyleAccessPath = 'itemStyle';
+        proto.visualDrawType = 'fill';
+      }();
+
+      return SeriesModel;
+    }(ComponentModel);
+
+    mixin(SeriesModel, DataFormatMixin);
+    mixin(SeriesModel, PaletteMixin);
+    mountExtend(SeriesModel, ComponentModel);
+    /**
+     * MUST be called after `prepareSource` called
+     * Here we need to make auto series, especially for auto legend. But we
+     * do not modify series.name in option to avoid side effects.
+     */
+
+    function autoSeriesName(seriesModel) {
+      // User specified name has higher priority, otherwise it may cause
+      // series can not be queried unexpectedly.
+      var name = seriesModel.name;
+
+      if (!isNameSpecified(seriesModel)) {
+        seriesModel.name = getSeriesAutoName(seriesModel) || name;
       }
-      /* eslint-enable */
+    }
 
+    function getSeriesAutoName(seriesModel) {
+      var data = seriesModel.getRawData();
+      var dataDims = data.mapDimensionsAll('seriesName');
+      var nameArr = [];
+      each(dataDims, function (dataDim) {
+        var dimInfo = data.getDimensionInfo(dataDim);
+        dimInfo.displayName && nameArr.push(dimInfo.displayName);
+      });
+      return nameArr.join(' ');
     }
 
-    /*
-    * Licensed to the Apache Software Foundation (ASF) under one
-    * or more contributor license agreements.  See the NOTICE file
-    * distributed with this work for additional information
-    * regarding copyright ownership.  The ASF licenses this file
-    * to you under the Apache License, Version 2.0 (the
-    * "License"); you may not use this file except in compliance
-    * with the License.  You may obtain a copy of the License at
-    *
-    *   http://www.apache.org/licenses/LICENSE-2.0
-    *
-    * Unless required by applicable law or agreed to in writing,
-    * software distributed under the License is distributed on an
-    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    * KIND, either express or implied.  See the License for the
-    * specific language governing permissions and limitations
-    * under the License.
-    */
+    function dataTaskCount(context) {
+      return context.model.getRawData().count();
+    }
 
+    function dataTaskReset(context) {
+      var seriesModel = context.model;
+      seriesModel.setData(seriesModel.getRawData().cloneShallow());
+      return dataTaskProgress;
+    }
 
-    /**
-     * AUTO-GENERATED FILE. DO NOT MODIFY.
-     */
+    function dataTaskProgress(param, context) {
+      // Avoid repead cloneShallow when data just created in reset.
+      if (context.outputData && param.end > context.outputData.count()) {
+        context.model.getRawData().cloneShallow(context.outputData);
+      }
+    } // TODO refactor
 
-    /*
-    * Licensed to the Apache Software Foundation (ASF) under one
-    * or more contributor license agreements.  See the NOTICE file
-    * distributed with this work for additional information
-    * regarding copyright ownership.  The ASF licenses this file
-    * to you under the Apache License, Version 2.0 (the
-    * "License"); you may not use this file except in compliance
-    * with the License.  You may obtain a copy of the License at
-    *
-    *   http://www.apache.org/licenses/LICENSE-2.0
-    *
-    * Unless required by applicable law or agreed to in writing,
-    * software distributed under the License is distributed on an
-    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    * KIND, either express or implied.  See the License for the
-    * specific language governing permissions and limitations
-    * under the License.
-    */
-    var colorAll = ['#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'];
-    var lightTheme = {
-      color: colorAll,
-      colorLayer: [['#37A2DA', '#ffd85c', '#fd7b5f'], ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'], ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'], colorAll]
-    };
 
-    /*
-    * Licensed to the Apache Software Foundation (ASF) under one
-    * or more contributor license agreements.  See the NOTICE file
-    * distributed with this work for additional information
-    * regarding copyright ownership.  The ASF licenses this file
-    * to you under the Apache License, Version 2.0 (the
-    * "License"); you may not use this file except in compliance
-    * with the License.  You may obtain a copy of the License at
-    *
-    *   http://www.apache.org/licenses/LICENSE-2.0
-    *
-    * Unless required by applicable law or agreed to in writing,
-    * software distributed under the License is distributed on an
-    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    * KIND, either express or implied.  See the License for the
-    * specific language governing permissions and limitations
-    * under the License.
-    */
+    function wrapData(data, seriesModel) {
+      each(concatArray(data.CHANGABLE_METHODS, data.DOWNSAMPLE_METHODS), function (methodName) {
+        data.wrapMethod(methodName, curry(onDataChange, seriesModel));
+      });
+    }
 
+    function onDataChange(seriesModel, newList) {
+      var task = getCurrentTask(seriesModel);
 
-    /**
-     * AUTO-GENERATED FILE. DO NOT MODIFY.
-     */
+      if (task) {
+        // Consider case: filter, selectRange
+        task.setOutputEnd((newList || this).count());
+      }
 
-    /*
-    * Licensed to the Apache Software Foundation (ASF) under one
-    * or more contributor license agreements.  See the NOTICE file
-    * distributed with this work for additional information
-    * regarding copyright ownership.  The ASF licenses this file
-    * to you under the Apache License, Version 2.0 (the
-    * "License"); you may not use this file except in compliance
-    * with the License.  You may obtain a copy of the License at
-    *
-    *   http://www.apache.org/licenses/LICENSE-2.0
-    *
-    * Unless required by applicable law or agreed to in writing,
-    * software distributed under the License is distributed on an
-    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-    * KIND, either express or implied.  See the License for the
-    * specific language governing permissions and limitations
-    * under the License.
-    */
-    var contrastColor = '#B9B8CE';
-    var backgroundColor = '#100C2A';
+      return newList;
+    }
 
-    var axisCommon = function () {
-      return {
-        axisLine: {
-          lineStyle: {
-            color: contrastColor
-          }
-        },
-        splitLine: {
-          lineStyle: {
-            color: '#484753'
-          }
-        },
-        splitArea: {
-          areaStyle: {
-            color: ['rgba(255,255,255,0.02)', 'rgba(255,255,255,0.05)']
-          }
-        },
-        minorSplitLine: {
-          lineStyle: {
-            color: '#20203B'
-          }
-        }
-      };
-    };
+    function getCurrentTask(seriesModel) {
+      var scheduler = (seriesModel.ecModel || {}).scheduler;
+      var pipeline = scheduler && scheduler.getPipeline(seriesModel.uid);
 
-    var colorPalette = ['#4992ff', '#7cffb2', '#fddd60', '#ff6e76', '#58d9f9', '#05c091', '#ff8a45', '#8d48e3', '#dd79ff'];
-    var theme = {
-      darkMode: true,
-      color: colorPalette,
-      backgroundColor: backgroundColor,
-      axisPointer: {
-        lineStyle: {
-          color: '#817f91'
-        },
-        crossStyle: {
-          color: '#817f91'
-        },
-        label: {
-          // TODO Contrast of label backgorundColor
-          color: '#fff'
-        }
-      },
-      legend: {
-        textStyle: {
-          color: contrastColor
-        }
-      },
-      textStyle: {
-        color: contrastColor
-      },
-      title: {
-        textStyle: {
-          color: '#EEF1FA'
-        },
-        subtextStyle: {
-          color: '#B9B8CE'
-        }
-      },
-      toolbox: {
-        iconStyle: {
-          borderColor: contrastColor
-        }
-      },
-      dataZoom: {
-        borderColor: '#71708A',
-        textStyle: {
-          color: contrastColor
-        },
-        brushStyle: {
-          color: 'rgba(135,163,206,0.3)'
-        },
-        handleStyle: {
-          color: '#353450',
-          borderColor: '#C5CBE3'
-        },
-        moveHandleStyle: {
-          color: '#B0B6C3',
-          opacity: 0.3
-        },
-        fillerColor: 'rgba(135,163,206,0.2)',
-        emphasis: {
-          handleStyle: {
-            borderColor: '#91B7F2',
-            color: '#4D587D'
-          },
-          moveHandleStyle: {
-            color: '#636D9A',
-            opacity: 0.7
-          }
-        },
-        dataBackground: {
-          lineStyle: {
-            color: '#71708A',
-            width: 1
-          },
-          areaStyle: {
-            color: '#71708A'
-          }
-        },
-        selectedDataBackground: {
-          lineStyle: {
-            color: '#87A3CE'
-          },
-          areaStyle: {
-            color: '#87A3CE'
-          }
-        }
-      },
-      visualMap: {
-        textStyle: {
-          color: contrastColor
-        }
-      },
-      timeline: {
-        lineStyle: {
-          color: contrastColor
-        },
-        label: {
-          color: contrastColor
-        },
-        controlStyle: {
-          color: contrastColor,
-          borderColor: contrastColor
-        }
-      },
-      calendar: {
-        itemStyle: {
-          color: backgroundColor
-        },
-        dayLabel: {
-          color: contrastColor
-        },
-        monthLabel: {
-          color: contrastColor
-        },
-        yearLabel: {
-          color: contrastColor
-        }
-      },
-      timeAxis: axisCommon(),
-      logAxis: axisCommon(),
-      valueAxis: axisCommon(),
-      categoryAxis: axisCommon(),
-      line: {
-        symbol: 'circle'
-      },
-      graph: {
-        color: colorPalette
-      },
-      gauge: {
-        title: {
-          color: contrastColor
-        },
-        axisLine: {
-          lineStyle: {
-            color: [[1, 'rgba(207,212,219,0.2)']]
+      if (pipeline) {
+        // When pipline finished, the currrentTask keep the last
+        // task (renderTask).
+        var task = pipeline.currentTask;
+
+        if (task) {
+          var agentStubMap = task.agentStubMap;
+
+          if (agentStubMap) {
+            task = agentStubMap.get(seriesModel.uid);
           }
-        },
-        axisLabel: {
-          color: contrastColor
-        },
-        detail: {
-          color: '#EEF1FA'
         }
-      },
-      candlestick: {
-        itemStyle: {
-          color: '#f64e56',
-          color0: '#54ea92',
-          borderColor: '#f64e56',
-          borderColor0: '#54ea92' // borderColor: '#ca2824',
-          // borderColor0: '#09a443'
 
-        }
+        return task;
       }
-    };
-    theme.categoryAxis.splitLine.show = false;
-
-    /**
-     * Usage of query:
-     * `chart.on('click', query, handler);`
-     * The `query` can be:
-     * + The component type query string, only `mainType` or `mainType.subType`,
-     *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.
-     * + The component query object, like:
-     *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,
-     *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.
-     * + The data query object, like:
-     *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.
-     * + The other query object (cmponent customized query), like:
-     *   `{element: 'some'}` (only available in custom series).
-     *
-     * Caveat: If a prop in the `query` object is `null/undefined`, it is the
-     * same as there is no such prop in the `query` object.
-     */
+    }
 
-    var ECEventProcessor =
+    var ComponentView =
     /** @class */
     function () {
-      function ECEventProcessor() {}
+      function ComponentView() {
+        this.group = new Group();
+        this.uid = getUID('viewComponent');
+      }
 
-      ECEventProcessor.prototype.normalizeQuery = function (query) {
-        var cptQuery = {};
-        var dataQuery = {};
-        var otherQuery = {}; // `query` is `mainType` or `mainType.subType` of component.
+      ComponentView.prototype.init = function (ecModel, api) {};
 
-        if (isString(query)) {
-          var condCptType = parseClassType(query); // `.main` and `.sub` may be ''.
+      ComponentView.prototype.render = function (model, ecModel, api, payload) {};
 
-          cptQuery.mainType = condCptType.main || null;
-          cptQuery.subType = condCptType.sub || null;
-        } // `query` is an object, convert to {mainType, index, name, id}.
-        else {
-            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,
-            // can not be used in `compomentModel.filterForExposedEvent`.
-            var suffixes_1 = ['Index', 'Name', 'Id'];
-            var dataKeys_1 = {
-              name: 1,
-              dataIndex: 1,
-              dataType: 1
-            };
-            each(query, function (val, key) {
-              var reserved = false;
+      ComponentView.prototype.dispose = function (ecModel, api) {};
 
-              for (var i = 0; i < suffixes_1.length; i++) {
-                var propSuffix = suffixes_1[i];
-                var suffixPos = key.lastIndexOf(propSuffix);
+      ComponentView.prototype.updateView = function (model, ecModel, api, payload) {// Do nothing;
+      };
 
-                if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {
-                  var mainType = key.slice(0, suffixPos); // Consider `dataIndex`.
+      ComponentView.prototype.updateLayout = function (model, ecModel, api, payload) {// Do nothing;
+      };
 
-                  if (mainType !== 'data') {
-                    cptQuery.mainType = mainType;
-                    cptQuery[propSuffix.toLowerCase()] = val;
-                    reserved = true;
-                  }
-                }
-              }
+      ComponentView.prototype.updateVisual = function (model, ecModel, api, payload) {// Do nothing;
+      };
+      /**
+       * Hook for blur target series.
+       * Can be used in marker for blur the markers
+       */
 
-              if (dataKeys_1.hasOwnProperty(key)) {
-                dataQuery[key] = val;
-                reserved = true;
-              }
 
-              if (!reserved) {
-                otherQuery[key] = val;
-              }
-            });
-          }
+      ComponentView.prototype.blurSeries = function (seriesModels, ecModel) {// Do nothing;
+      };
 
-        return {
-          cptQuery: cptQuery,
-          dataQuery: dataQuery,
-          otherQuery: otherQuery
-        };
+      return ComponentView;
+    }();
+    enableClassExtend(ComponentView);
+    enableClassManagement(ComponentView);
+
+    /**
+     * @return {string} If large mode changed, return string 'reset';
+     */
+
+    function createRenderPlanner() {
+      var inner = makeInner();
+      return function (seriesModel) {
+        var fields = inner(seriesModel);
+        var pipelineContext = seriesModel.pipelineContext;
+        var originalLarge = !!fields.large;
+        var originalProgressive = !!fields.progressiveRender; // FIXME: if the planner works on a filtered series, `pipelineContext` does not
+        // exists. See #11611 . Probably we need to modify this structure, see the comment
+        // on `performRawSeries` in `Schedular.js`.
+
+        var large = fields.large = !!(pipelineContext && pipelineContext.large);
+        var progressive = fields.progressiveRender = !!(pipelineContext && pipelineContext.progressiveRender);
+        return !!(originalLarge !== large || originalProgressive !== progressive) && 'reset';
       };
+    }
 
-      ECEventProcessor.prototype.filter = function (eventType, query) {
-        // They should be assigned before each trigger call.
-        var eventInfo = this.eventInfo;
+    var inner$2 = makeInner();
+    var renderPlanner = createRenderPlanner();
 
-        if (!eventInfo) {
-          return true;
-        }
+    var ChartView =
+    /** @class */
+    function () {
+      function ChartView() {
+        this.group = new Group();
+        this.uid = getUID('viewChart');
+        this.renderTask = createTask({
+          plan: renderTaskPlan,
+          reset: renderTaskReset
+        });
+        this.renderTask.context = {
+          view: this
+        };
+      }
 
-        var targetEl = eventInfo.targetEl;
-        var packedEvent = eventInfo.packedEvent;
-        var model = eventInfo.model;
-        var view = eventInfo.view; // For event like 'globalout'.
+      ChartView.prototype.init = function (ecModel, api) {};
 
-        if (!model || !view) {
-          return true;
-        }
+      ChartView.prototype.render = function (seriesModel, ecModel, api, payload) {};
+      /**
+       * Highlight series or specified data item.
+       */
 
-        var cptQuery = query.cptQuery;
-        var dataQuery = query.dataQuery;
-        return check(cptQuery, model, 'mainType') && check(cptQuery, model, 'subType') && check(cptQuery, model, 'index', 'componentIndex') && check(cptQuery, model, 'name') && check(cptQuery, model, 'id') && check(dataQuery, packedEvent, 'name') && check(dataQuery, packedEvent, 'dataIndex') && check(dataQuery, packedEvent, 'dataType') && (!view.filterForExposedEvent || view.filterForExposedEvent(eventType, query.otherQuery, targetEl, packedEvent));
 
-        function check(query, host, prop, propOnHost) {
-          return query[prop] == null || host[propOnHost || prop] === query[prop];
-        }
+      ChartView.prototype.highlight = function (seriesModel, ecModel, api, payload) {
+        toggleHighlight(seriesModel.getData(), payload, 'emphasis');
       };
+      /**
+       * Downplay series or specified data item.
+       */
 
-      ECEventProcessor.prototype.afterTrigger = function () {
-        // Make sure the eventInfo wont be used in next trigger.
-        this.eventInfo = null;
+
+      ChartView.prototype.downplay = function (seriesModel, ecModel, api, payload) {
+        toggleHighlight(seriesModel.getData(), payload, 'normal');
       };
+      /**
+       * Remove self.
+       */
+
+
+      ChartView.prototype.remove = function (ecModel, api) {
+        this.group.removeAll();
+      };
+      /**
+       * Dispose self.
+       */
+
+
+      ChartView.prototype.dispose = function (ecModel, api) {};
 
-      return ECEventProcessor;
-    }();
+      ChartView.prototype.updateView = function (seriesModel, ecModel, api, payload) {
+        this.render(seriesModel, ecModel, api, payload);
+      }; // FIXME never used?
 
-    var seriesSymbolTask = {
-      createOnAllSeries: true,
-      // For legend.
-      performRawSeries: true,
-      reset: function (seriesModel, ecModel) {
-        var data = seriesModel.getData();
 
-        if (seriesModel.legendIcon) {
-          data.setVisual('legendIcon', seriesModel.legendIcon);
-        }
+      ChartView.prototype.updateLayout = function (seriesModel, ecModel, api, payload) {
+        this.render(seriesModel, ecModel, api, payload);
+      }; // FIXME never used?
 
-        if (!seriesModel.hasSymbolVisual) {
-          return;
-        }
 
-        var symbolType = seriesModel.get('symbol');
-        var symbolSize = seriesModel.get('symbolSize');
-        var keepAspect = seriesModel.get('symbolKeepAspect');
-        var symbolRotate = seriesModel.get('symbolRotate');
-        var symbolOffset = seriesModel.get('symbolOffset');
-        var hasSymbolTypeCallback = isFunction(symbolType);
-        var hasSymbolSizeCallback = isFunction(symbolSize);
-        var hasSymbolRotateCallback = isFunction(symbolRotate);
-        var hasSymbolOffsetCallback = isFunction(symbolOffset);
-        var hasCallback = hasSymbolTypeCallback || hasSymbolSizeCallback || hasSymbolRotateCallback || hasSymbolOffsetCallback;
-        var seriesSymbol = !hasSymbolTypeCallback && symbolType ? symbolType : seriesModel.defaultSymbol;
-        var seriesSymbolSize = !hasSymbolSizeCallback ? symbolSize : null;
-        var seriesSymbolRotate = !hasSymbolRotateCallback ? symbolRotate : null;
-        var seriesSymbolOffset = !hasSymbolOffsetCallback ? symbolOffset : null;
-        data.setVisual({
-          legendIcon: seriesModel.legendIcon || seriesSymbol,
-          // If seting callback functions on `symbol` or `symbolSize`, for simplicity and avoiding
-          // to bring trouble, we do not pick a reuslt from one of its calling on data item here,
-          // but just use the default value. Callback on `symbol` or `symbolSize` is convenient in
-          // some cases but generally it is not recommanded.
-          symbol: seriesSymbol,
-          symbolSize: seriesSymbolSize,
-          symbolKeepAspect: keepAspect,
-          symbolRotate: seriesSymbolRotate,
-          symbolOffset: seriesSymbolOffset
-        }); // Only visible series has each data be visual encoded
+      ChartView.prototype.updateVisual = function (seriesModel, ecModel, api, payload) {
+        this.render(seriesModel, ecModel, api, payload);
+      };
 
-        if (ecModel.isSeriesFiltered(seriesModel)) {
-          return;
-        }
+      ChartView.markUpdateMethod = function (payload, methodName) {
+        inner$2(payload).updateMethod = methodName;
+      };
 
-        function dataEach(data, idx) {
-          var rawValue = seriesModel.getRawValue(idx);
-          var params = seriesModel.getDataParams(idx);
-          hasSymbolTypeCallback && data.setItemVisual(idx, 'symbol', symbolType(rawValue, params));
-          hasSymbolSizeCallback && data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));
-          hasSymbolRotateCallback && data.setItemVisual(idx, 'symbolRotate', symbolRotate(rawValue, params));
-          hasSymbolOffsetCallback && data.setItemVisual(idx, 'symbolOffset', symbolOffset(rawValue, params));
-        }
+      ChartView.protoInitialize = function () {
+        var proto = ChartView.prototype;
+        proto.type = 'chart';
+      }();
 
-        return {
-          dataEach: hasCallback ? dataEach : null
-        };
+      return ChartView;
+    }();
+    /**
+     * Set state of single element
+     */
+
+    function elSetState(el, state, highlightDigit) {
+      if (el) {
+        (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit);
       }
-    };
-    var dataSymbolTask = {
-      createOnAllSeries: true,
-      // For legend.
-      performRawSeries: true,
-      reset: function (seriesModel, ecModel) {
-        if (!seriesModel.hasSymbolVisual) {
-          return;
-        } // Only visible series has each data be visual encoded
+    }
 
+    function toggleHighlight(data, payload, state) {
+      var dataIndex = queryDataIndex(data, payload);
+      var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null;
 
-        if (ecModel.isSeriesFiltered(seriesModel)) {
-          return;
-        }
+      if (dataIndex != null) {
+        each(normalizeToArray(dataIndex), function (dataIdx) {
+          elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit);
+        });
+      } else {
+        data.eachItemGraphicEl(function (el) {
+          elSetState(el, state, highlightDigit);
+        });
+      }
+    }
 
-        var data = seriesModel.getData();
+    enableClassExtend(ChartView, ['dispose']);
+    enableClassManagement(ChartView);
 
-        function dataEach(data, idx) {
-          var itemModel = data.getItemModel(idx);
-          var itemSymbolType = itemModel.getShallow('symbol', true);
-          var itemSymbolSize = itemModel.getShallow('symbolSize', true);
-          var itemSymbolRotate = itemModel.getShallow('symbolRotate', true);
-          var itemSymbolOffset = itemModel.getShallow('symbolOffset', true);
-          var itemSymbolKeepAspect = itemModel.getShallow('symbolKeepAspect', true); // If has item symbol
+    function renderTaskPlan(context) {
+      return renderPlanner(context.model);
+    }
 
-          if (itemSymbolType != null) {
-            data.setItemVisual(idx, 'symbol', itemSymbolType);
-          }
+    function renderTaskReset(context) {
+      var seriesModel = context.model;
+      var ecModel = context.ecModel;
+      var api = context.api;
+      var payload = context.payload; // FIXME: remove updateView updateVisual
 
-          if (itemSymbolSize != null) {
-            // PENDING Transform symbolSize ?
-            data.setItemVisual(idx, 'symbolSize', itemSymbolSize);
-          }
+      var progressiveRender = seriesModel.pipelineContext.progressiveRender;
+      var view = context.view;
+      var updateMethod = payload && inner$2(payload).updateMethod;
+      var methodName = progressiveRender ? 'incrementalPrepareRender' : updateMethod && view[updateMethod] ? updateMethod // `appendData` is also supported when data amount
+      // is less than progressive threshold.
+      : 'render';
 
-          if (itemSymbolRotate != null) {
-            data.setItemVisual(idx, 'symbolRotate', itemSymbolRotate);
-          }
+      if (methodName !== 'render') {
+        view[methodName](seriesModel, ecModel, api, payload);
+      }
 
-          if (itemSymbolOffset != null) {
-            data.setItemVisual(idx, 'symbolOffset', itemSymbolOffset);
-          }
+      return progressMethodMap[methodName];
+    }
 
-          if (itemSymbolKeepAspect != null) {
-            data.setItemVisual(idx, 'symbolKeepAspect', itemSymbolKeepAspect);
-          }
+    var progressMethodMap = {
+      incrementalPrepareRender: {
+        progress: function (params, context) {
+          context.view.incrementalRender(params, context.model, context.ecModel, context.api, context.payload);
+        }
+      },
+      render: {
+        // Put view.render in `progress` to support appendData. But in this case
+        // view.render should not be called in reset, otherwise it will be called
+        // twise. Use `forceFirstProgress` to make sure that view.render is called
+        // in any cases.
+        forceFirstProgress: true,
+        progress: function (params, context) {
+          context.view.render(context.model, context.ecModel, context.api, context.payload);
         }
-
-        return {
-          dataEach: data.hasItemOption ? dataEach : null
-        };
       }
     };
 
@@ -24473,1361 +24300,1540 @@
     * specific language governing permissions and limitations
     * under the License.
     */
-    function getItemVisualFromData(data, dataIndex, key) {
-      switch (key) {
-        case 'color':
-          var style = data.getItemVisual(dataIndex, 'style');
-          return style[data.getVisual('drawType')];
-
-        case 'opacity':
-          return data.getItemVisual(dataIndex, 'style').opacity;
-
-        case 'symbol':
-        case 'symbolSize':
-        case 'liftZ':
-          return data.getItemVisual(dataIndex, key);
+    var ORIGIN_METHOD = '\0__throttleOriginMethod';
+    var RATE = '\0__throttleRate';
+    var THROTTLE_TYPE = '\0__throttleType';
+    /**
+     * @public
+     * @param {(Function)} fn
+     * @param {number} [delay=0] Unit: ms.
+     * @param {boolean} [debounce=false]
+     *        true: If call interval less than `delay`, only the last call works.
+     *        false: If call interval less than `delay, call works on fixed rate.
+     * @return {(Function)} throttled fn.
+     */
 
-        default:
-          if ("development" !== 'production') {
-            console.warn("Unknown visual type " + key);
-          }
+    function throttle(fn, delay, debounce) {
+      var currCall;
+      var lastCall = 0;
+      var lastExec = 0;
+      var timer = null;
+      var diff;
+      var scope;
+      var args;
+      var debounceNextCall;
+      delay = delay || 0;
 
+      function exec() {
+        lastExec = new Date().getTime();
+        timer = null;
+        fn.apply(scope, args || []);
       }
-    }
-    function getVisualFromData(data, key) {
-      switch (key) {
-        case 'color':
-          var style = data.getVisual('style');
-          return style[data.getVisual('drawType')];
 
-        case 'opacity':
-          return data.getVisual('style').opacity;
+      var cb = function () {
+        var cbArgs = [];
 
-        case 'symbol':
-        case 'symbolSize':
-        case 'liftZ':
-          return data.getVisual(key);
+        for (var _i = 0; _i < arguments.length; _i++) {
+          cbArgs[_i] = arguments[_i];
+        }
 
-        default:
-          if ("development" !== 'production') {
-            console.warn("Unknown visual type " + key);
+        currCall = new Date().getTime();
+        scope = this;
+        args = cbArgs;
+        var thisDelay = debounceNextCall || delay;
+        var thisDebounce = debounceNextCall || debounce;
+        debounceNextCall = null;
+        diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;
+        clearTimeout(timer); // Here we should make sure that: the `exec` SHOULD NOT be called later
+        // than a new call of `cb`, that is, preserving the command order. Consider
+        // calculating "scale rate" when roaming as an example. When a call of `cb`
+        // happens, either the `exec` is called dierectly, or the call is delayed.
+        // But the delayed call should never be later than next call of `cb`. Under
+        // this assurance, we can simply update view state each time `dispatchAction`
+        // triggered by user roaming, but not need to add extra code to avoid the
+        // state being "rolled-back".
+
+        if (thisDebounce) {
+          timer = setTimeout(exec, thisDelay);
+        } else {
+          if (diff >= 0) {
+            exec();
+          } else {
+            timer = setTimeout(exec, -diff);
           }
+        }
 
-      }
-    }
+        lastCall = currCall;
+      };
+      /**
+       * Clear throttle.
+       * @public
+       */
 
-    var PI2$6 = Math.PI * 2;
-    var CMD$3 = PathProxy.CMD;
-    var DEFAULT_SEARCH_SPACE = ['top', 'right', 'bottom', 'left'];
 
-    function getCandidateAnchor(pos, distance, rect, outPt, outDir) {
-      var width = rect.width;
-      var height = rect.height;
+      cb.clear = function () {
+        if (timer) {
+          clearTimeout(timer);
+          timer = null;
+        }
+      };
+      /**
+       * Enable debounce once.
+       */
 
-      switch (pos) {
-        case 'top':
-          outPt.set(rect.x + width / 2, rect.y - distance);
-          outDir.set(0, -1);
-          break;
 
-        case 'bottom':
-          outPt.set(rect.x + width / 2, rect.y + height + distance);
-          outDir.set(0, 1);
-          break;
+      cb.debounceNextCall = function (debounceDelay) {
+        debounceNextCall = debounceDelay;
+      };
 
-        case 'left':
-          outPt.set(rect.x - distance, rect.y + height / 2);
-          outDir.set(-1, 0);
-          break;
+      return cb;
+    }
+    /**
+     * Create throttle method or update throttle rate.
+     *
+     * @example
+     * ComponentView.prototype.render = function () {
+     *     ...
+     *     throttle.createOrUpdate(
+     *         this,
+     *         '_dispatchAction',
+     *         this.model.get('throttle'),
+     *         'fixRate'
+     *     );
+     * };
+     * ComponentView.prototype.remove = function () {
+     *     throttle.clear(this, '_dispatchAction');
+     * };
+     * ComponentView.prototype.dispose = function () {
+     *     throttle.clear(this, '_dispatchAction');
+     * };
+     *
+     */
 
-        case 'right':
-          outPt.set(rect.x + width + distance, rect.y + height / 2);
-          outDir.set(1, 0);
-          break;
+    function createOrUpdate(obj, fnAttr, rate, throttleType) {
+      var fn = obj[fnAttr];
+
+      if (!fn) {
+        return;
       }
-    }
 
-    function projectPointToArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y, out) {
-      x -= cx;
-      y -= cy;
-      var d = Math.sqrt(x * x + y * y);
-      x /= d;
-      y /= d; // Intersect point.
+      var originFn = fn[ORIGIN_METHOD] || fn;
+      var lastThrottleType = fn[THROTTLE_TYPE];
+      var lastRate = fn[RATE];
 
-      var ox = x * r + cx;
-      var oy = y * r + cy;
+      if (lastRate !== rate || lastThrottleType !== throttleType) {
+        if (rate == null || !throttleType) {
+          return obj[fnAttr] = originFn;
+        }
 
-      if (Math.abs(startAngle - endAngle) % PI2$6 < 1e-4) {
-        // Is a circle
-        out[0] = ox;
-        out[1] = oy;
-        return d - r;
+        fn = obj[fnAttr] = throttle(originFn, rate, throttleType === 'debounce');
+        fn[ORIGIN_METHOD] = originFn;
+        fn[THROTTLE_TYPE] = throttleType;
+        fn[RATE] = rate;
       }
 
-      if (anticlockwise) {
-        var tmp = startAngle;
-        startAngle = normalizeRadian(endAngle);
-        endAngle = normalizeRadian(tmp);
-      } else {
-        startAngle = normalizeRadian(startAngle);
-        endAngle = normalizeRadian(endAngle);
-      }
+      return fn;
+    }
+    /**
+     * Clear throttle. Example see throttle.createOrUpdate.
+     */
+
+    function clear(obj, fnAttr) {
+      var fn = obj[fnAttr];
 
-      if (startAngle > endAngle) {
-        endAngle += PI2$6;
+      if (fn && fn[ORIGIN_METHOD]) {
+        obj[fnAttr] = fn[ORIGIN_METHOD];
       }
+    }
 
-      var angle = Math.atan2(y, x);
+    var inner$3 = makeInner();
+    var defaultStyleMappers = {
+      itemStyle: makeStyleMapper(ITEM_STYLE_KEY_MAP, true),
+      lineStyle: makeStyleMapper(LINE_STYLE_KEY_MAP, true)
+    };
+    var defaultColorKey = {
+      lineStyle: 'stroke',
+      itemStyle: 'fill'
+    };
 
-      if (angle < 0) {
-        angle += PI2$6;
-      }
+    function getStyleMapper(seriesModel, stylePath) {
+      var styleMapper = seriesModel.visualStyleMapper || defaultStyleMappers[stylePath];
 
-      if (angle >= startAngle && angle <= endAngle || angle + PI2$6 >= startAngle && angle + PI2$6 <= endAngle) {
-        // Project point is on the arc.
-        out[0] = ox;
-        out[1] = oy;
-        return d - r;
+      if (!styleMapper) {
+        console.warn("Unkown style type '" + stylePath + "'.");
+        return defaultStyleMappers.itemStyle;
       }
 
-      var x1 = r * Math.cos(startAngle) + cx;
-      var y1 = r * Math.sin(startAngle) + cy;
-      var x2 = r * Math.cos(endAngle) + cx;
-      var y2 = r * Math.sin(endAngle) + cy;
-      var d1 = (x1 - x) * (x1 - x) + (y1 - y) * (y1 - y);
-      var d2 = (x2 - x) * (x2 - x) + (y2 - y) * (y2 - y);
+      return styleMapper;
+    }
 
-      if (d1 < d2) {
-        out[0] = x1;
-        out[1] = y1;
-        return Math.sqrt(d1);
-      } else {
-        out[0] = x2;
-        out[1] = y2;
-        return Math.sqrt(d2);
+    function getDefaultColorKey(seriesModel, stylePath) {
+      // return defaultColorKey[stylePath] ||
+      var colorKey = seriesModel.visualDrawType || defaultColorKey[stylePath];
+
+      if (!colorKey) {
+        console.warn("Unkown style type '" + stylePath + "'.");
+        return 'fill';
       }
+
+      return colorKey;
     }
 
-    function projectPointToLine(x1, y1, x2, y2, x, y, out, limitToEnds) {
-      var dx = x - x1;
-      var dy = y - y1;
-      var dx1 = x2 - x1;
-      var dy1 = y2 - y1;
-      var lineLen = Math.sqrt(dx1 * dx1 + dy1 * dy1);
-      dx1 /= lineLen;
-      dy1 /= lineLen; // dot product
+    var seriesStyleTask = {
+      createOnAllSeries: true,
+      performRawSeries: true,
+      reset: function (seriesModel, ecModel) {
+        var data = seriesModel.getData();
+        var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle
 
-      var projectedLen = dx * dx1 + dy * dy1;
-      var t = projectedLen / lineLen;
+        var styleModel = seriesModel.getModel(stylePath);
+        var getStyle = getStyleMapper(seriesModel, stylePath);
+        var globalStyle = getStyle(styleModel);
+        var decalOption = styleModel.getShallow('decal');
 
-      if (limitToEnds) {
-        t = Math.min(Math.max(t, 0), 1);
-      }
+        if (decalOption) {
+          data.setVisual('decal', decalOption);
+          decalOption.dirty = true;
+        } // TODO
 
-      t *= lineLen;
-      var ox = out[0] = x1 + t * dx1;
-      var oy = out[1] = y1 + t * dy1;
-      return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y));
-    }
 
-    function projectPointToRect(x1, y1, width, height, x, y, out) {
-      if (width < 0) {
-        x1 = x1 + width;
-        width = -width;
-      }
+        var colorKey = getDefaultColorKey(seriesModel, stylePath);
+        var color = globalStyle[colorKey]; // TODO style callback
+
+        var colorCallback = isFunction(color) ? color : null;
+        var hasAutoColor = globalStyle.fill === 'auto' || globalStyle.stroke === 'auto'; // Get from color palette by default.
+
+        if (!globalStyle[colorKey] || colorCallback || hasAutoColor) {
+          // Note: if some series has color specified (e.g., by itemStyle.color), we DO NOT
+          // make it effect palette. Bacause some scenarios users need to make some series
+          // transparent or as background, which should better not effect the palette.
+          var colorPalette = seriesModel.getColorFromPalette( // TODO series count changed.
+          seriesModel.name, null, ecModel.getSeriesCount());
+
+          if (!globalStyle[colorKey]) {
+            globalStyle[colorKey] = colorPalette;
+            data.setVisual('colorFromPalette', true);
+          }
+
+          globalStyle.fill = globalStyle.fill === 'auto' || typeof globalStyle.fill === 'function' ? colorPalette : globalStyle.fill;
+          globalStyle.stroke = globalStyle.stroke === 'auto' || typeof globalStyle.stroke === 'function' ? colorPalette : globalStyle.stroke;
+        }
+
+        data.setVisual('style', globalStyle);
+        data.setVisual('drawType', colorKey); // Only visible series has each data be visual encoded
 
-      if (height < 0) {
-        y1 = y1 + height;
-        height = -height;
+        if (!ecModel.isSeriesFiltered(seriesModel) && colorCallback) {
+          data.setVisual('colorFromPalette', false);
+          return {
+            dataEach: function (data, idx) {
+              var dataParams = seriesModel.getDataParams(idx);
+              var itemStyle = extend({}, globalStyle);
+              itemStyle[colorKey] = colorCallback(dataParams);
+              data.setItemVisual(idx, 'style', itemStyle);
+            }
+          };
+        }
       }
+    };
+    var sharedModel = new Model();
+    var dataStyleTask = {
+      createOnAllSeries: true,
+      performRawSeries: true,
+      reset: function (seriesModel, ecModel) {
+        if (seriesModel.ignoreStyleOnData || ecModel.isSeriesFiltered(seriesModel)) {
+          return;
+        }
 
-      var x2 = x1 + width;
-      var y2 = y1 + height;
-      var ox = out[0] = Math.min(Math.max(x, x1), x2);
-      var oy = out[1] = Math.min(Math.max(y, y1), y2);
-      return Math.sqrt((ox - x) * (ox - x) + (oy - y) * (oy - y));
-    }
+        var data = seriesModel.getData();
+        var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle
 
-    var tmpPt = [];
+        var getStyle = getStyleMapper(seriesModel, stylePath);
+        var colorKey = data.getVisual('drawType');
+        return {
+          dataEach: data.hasItemOption ? function (data, idx) {
+            // Not use getItemModel for performance considuration
+            var rawItem = data.getRawDataItem(idx);
 
-    function nearestPointOnRect(pt, rect, out) {
-      var dist = projectPointToRect(rect.x, rect.y, rect.width, rect.height, pt.x, pt.y, tmpPt);
-      out.set(tmpPt[0], tmpPt[1]);
-      return dist;
-    }
-    /**
-     * Calculate min distance corresponding point.
-     * This method won't evaluate if point is in the path.
-     */
-
-
-    function nearestPointOnPath(pt, path, out) {
-      var xi = 0;
-      var yi = 0;
-      var x0 = 0;
-      var y0 = 0;
-      var x1;
-      var y1;
-      var minDist = Infinity;
-      var data = path.data;
-      var x = pt.x;
-      var y = pt.y;
-
-      for (var i = 0; i < data.length;) {
-        var cmd = data[i++];
-
-        if (i === 1) {
-          xi = data[i];
-          yi = data[i + 1];
-          x0 = xi;
-          y0 = yi;
-        }
-
-        var d = minDist;
-
-        switch (cmd) {
-          case CMD$3.M:
-            // moveTo 命令重新创建一个新的 subpath, 并且更新新的起点
-            // 在 closePath 的时候使用
-            x0 = data[i++];
-            y0 = data[i++];
-            xi = x0;
-            yi = y0;
-            break;
+            if (rawItem && rawItem[stylePath]) {
+              sharedModel.option = rawItem[stylePath];
+              var style = getStyle(sharedModel);
+              var existsStyle = data.ensureUniqueItemVisual(idx, 'style');
+              extend(existsStyle, style);
 
-          case CMD$3.L:
-            d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true);
-            xi = data[i++];
-            yi = data[i++];
-            break;
+              if (sharedModel.option.decal) {
+                data.setItemVisual(idx, 'decal', sharedModel.option.decal);
+                sharedModel.option.decal.dirty = true;
+              }
 
-          case CMD$3.C:
-            d = cubicProjectPoint(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt);
-            xi = data[i++];
-            yi = data[i++];
-            break;
+              if (colorKey in style) {
+                data.setItemVisual(idx, 'colorFromPalette', false);
+              }
+            }
+          } : null
+        };
+      }
+    }; // Pick color from palette for the data which has not been set with color yet.
+    // Note: do not support stream rendering. No such cases yet.
 
-          case CMD$3.Q:
-            d = quadraticProjectPoint(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y, tmpPt);
-            xi = data[i++];
-            yi = data[i++];
-            break;
+    var dataColorPaletteTask = {
+      performRawSeries: true,
+      overallReset: function (ecModel) {
+        // Each type of series use one scope.
+        // Pie and funnel are using diferrent scopes
+        var paletteScopeGroupByType = createHashMap();
+        ecModel.eachSeries(function (seriesModel) {
+          var colorBy = seriesModel.getColorBy();
+
+          if (seriesModel.isColorBySeries()) {
+            return;
+          }
 
-          case CMD$3.A:
-            // TODO Arc 判断的开销比较大
-            var cx = data[i++];
-            var cy = data[i++];
-            var rx = data[i++];
-            var ry = data[i++];
-            var theta = data[i++];
-            var dTheta = data[i++]; // TODO Arc 旋转
+          var key = seriesModel.type + '-' + colorBy;
+          var colorScope = paletteScopeGroupByType.get(key);
+
+          if (!colorScope) {
+            colorScope = {};
+            paletteScopeGroupByType.set(key, colorScope);
+          }
+
+          inner$3(seriesModel).scope = colorScope;
+        });
+        ecModel.eachSeries(function (seriesModel) {
+          if (seriesModel.isColorBySeries() || ecModel.isSeriesFiltered(seriesModel)) {
+            return;
+          }
 
-            i += 1;
-            var anticlockwise = !!(1 - data[i++]);
-            x1 = Math.cos(theta) * rx + cx;
-            y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令
+          var dataAll = seriesModel.getRawData();
+          var idxMap = {};
+          var data = seriesModel.getData();
+          var colorScope = inner$3(seriesModel).scope;
+          var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle';
+          var colorKey = getDefaultColorKey(seriesModel, stylePath);
+          data.each(function (idx) {
+            var rawIdx = data.getRawIndex(idx);
+            idxMap[rawIdx] = idx;
+          }); // Iterate on data before filtered. To make sure color from palette can be
+          // Consistent when toggling legend.
 
-            if (i <= 1) {
-              // 第一个命令起点还未定义
-              x0 = x1;
-              y0 = y1;
-            } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放
+          dataAll.each(function (rawIdx) {
+            var idx = idxMap[rawIdx];
+            var fromPalette = data.getItemVisual(idx, 'colorFromPalette'); // Get color from palette for each data only when the color is inherited from series color, which is
+            // also picked from color palette. So following situation is not in the case:
+            // 1. series.itemStyle.color is set
+            // 2. color is encoded by visualMap
 
+            if (fromPalette) {
+              var itemStyle = data.ensureUniqueItemVisual(idx, 'style');
+              var name_1 = dataAll.getName(rawIdx) || rawIdx + '';
+              var dataCount = dataAll.count();
+              itemStyle[colorKey] = seriesModel.getColorFromPalette(name_1, colorScope, dataCount);
+            }
+          });
+        });
+      }
+    };
 
-            var _x = (x - cx) * ry / rx + cx;
+    var PI$3 = Math.PI;
+    /**
+     * @param {module:echarts/ExtensionAPI} api
+     * @param {Object} [opts]
+     * @param {string} [opts.text]
+     * @param {string} [opts.color]
+     * @param {string} [opts.textColor]
+     * @return {module:zrender/Element}
+     */
 
-            d = projectPointToArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y, tmpPt);
-            xi = Math.cos(theta + dTheta) * rx + cx;
-            yi = Math.sin(theta + dTheta) * ry + cy;
-            break;
+    function defaultLoading(api, opts) {
+      opts = opts || {};
+      defaults(opts, {
+        text: 'loading',
+        textColor: '#000',
+        fontSize: 12,
+        fontWeight: 'normal',
+        fontStyle: 'normal',
+        fontFamily: 'sans-serif',
+        maskColor: 'rgba(255, 255, 255, 0.8)',
+        showSpinner: true,
+        color: '#5470c6',
+        spinnerRadius: 10,
+        lineWidth: 5,
+        zlevel: 0
+      });
+      var group = new Group();
+      var mask = new Rect({
+        style: {
+          fill: opts.maskColor
+        },
+        zlevel: opts.zlevel,
+        z: 10000
+      });
+      group.add(mask);
+      var textContent = new ZRText({
+        style: {
+          text: opts.text,
+          fill: opts.textColor,
+          fontSize: opts.fontSize,
+          fontWeight: opts.fontWeight,
+          fontStyle: opts.fontStyle,
+          fontFamily: opts.fontFamily
+        },
+        zlevel: opts.zlevel,
+        z: 10001
+      });
+      var labelRect = new Rect({
+        style: {
+          fill: 'none'
+        },
+        textContent: textContent,
+        textConfig: {
+          position: 'right',
+          distance: 10
+        },
+        zlevel: opts.zlevel,
+        z: 10001
+      });
+      group.add(labelRect);
+      var arc;
 
-          case CMD$3.R:
-            x0 = xi = data[i++];
-            y0 = yi = data[i++];
-            var width = data[i++];
-            var height = data[i++];
-            d = projectPointToRect(x0, y0, width, height, x, y, tmpPt);
-            break;
+      if (opts.showSpinner) {
+        arc = new Arc({
+          shape: {
+            startAngle: -PI$3 / 2,
+            endAngle: -PI$3 / 2 + 0.1,
+            r: opts.spinnerRadius
+          },
+          style: {
+            stroke: opts.color,
+            lineCap: 'round',
+            lineWidth: opts.lineWidth
+          },
+          zlevel: opts.zlevel,
+          z: 10001
+        });
+        arc.animateShape(true).when(1000, {
+          endAngle: PI$3 * 3 / 2
+        }).start('circularInOut');
+        arc.animateShape(true).when(1000, {
+          startAngle: PI$3 * 3 / 2
+        }).delay(300).start('circularInOut');
+        group.add(arc);
+      } // Inject resize
 
-          case CMD$3.Z:
-            d = projectPointToLine(xi, yi, x0, y0, x, y, tmpPt, true);
-            xi = x0;
-            yi = y0;
-            break;
-        }
 
-        if (d < minDist) {
-          minDist = d;
-          out.set(tmpPt[0], tmpPt[1]);
-        }
-      }
+      group.resize = function () {
+        var textWidth = textContent.getBoundingRect().width;
+        var r = opts.showSpinner ? opts.spinnerRadius : 0; // cx = (containerWidth - arcDiameter - textDistance - textWidth) / 2
+        // textDistance needs to be calculated when both animation and text exist
 
-      return minDist;
-    } // Temporal varible for intermediate usage.
+        var cx = (api.getWidth() - r * 2 - (opts.showSpinner && textWidth ? 10 : 0) - textWidth) / 2 - (opts.showSpinner && textWidth ? 0 : 5 + textWidth / 2) // only show the text
+        + (opts.showSpinner ? 0 : textWidth / 2) // only show the spinner
+        + (textWidth ? 0 : r);
+        var cy = api.getHeight() / 2;
+        opts.showSpinner && arc.setShape({
+          cx: cx,
+          cy: cy
+        });
+        labelRect.setShape({
+          x: cx - r,
+          y: cy - r,
+          width: r * 2,
+          height: r * 2
+        });
+        mask.setShape({
+          x: 0,
+          y: 0,
+          width: api.getWidth(),
+          height: api.getHeight()
+        });
+      };
 
+      group.resize();
+      return group;
+    }
 
-    var pt0 = new Point();
-    var pt1 = new Point();
-    var pt2 = new Point();
-    var dir = new Point();
-    var dir2 = new Point();
-    /**
-     * Calculate a proper guide line based on the label position and graphic element definition
-     * @param label
-     * @param labelRect
-     * @param target
-     * @param targetRect
-     */
+    var Scheduler =
+    /** @class */
+    function () {
+      function Scheduler(ecInstance, api, dataProcessorHandlers, visualHandlers) {
+        // key: handlerUID
+        this._stageTaskMap = createHashMap();
+        this.ecInstance = ecInstance;
+        this.api = api; // Fix current processors in case that in some rear cases that
+        // processors might be registered after echarts instance created.
+        // Register processors incrementally for a echarts instance is
+        // not supported by this stream architecture.
 
-    function updateLabelLinePoints(target, labelLineModel) {
-      if (!target) {
-        return;
+        dataProcessorHandlers = this._dataProcessorHandlers = dataProcessorHandlers.slice();
+        visualHandlers = this._visualHandlers = visualHandlers.slice();
+        this._allHandlers = dataProcessorHandlers.concat(visualHandlers);
       }
 
-      var labelLine = target.getTextGuideLine();
-      var label = target.getTextContent(); // Needs to create text guide in each charts.
+      Scheduler.prototype.restoreData = function (ecModel, payload) {
+        // TODO: Only restore needed series and components, but not all components.
+        // Currently `restoreData` of all of the series and component will be called.
+        // But some independent components like `title`, `legend`, `graphic`, `toolbox`,
+        // `tooltip`, `axisPointer`, etc, do not need series refresh when `setOption`,
+        // and some components like coordinate system, axes, dataZoom, visualMap only
+        // need their target series refresh.
+        // (1) If we are implementing this feature some day, we should consider these cases:
+        // if a data processor depends on a component (e.g., dataZoomProcessor depends
+        // on the settings of `dataZoom`), it should be re-performed if the component
+        // is modified by `setOption`.
+        // (2) If a processor depends on sevral series, speicified by its `getTargetSeries`,
+        // it should be re-performed when the result array of `getTargetSeries` changed.
+        // We use `dependencies` to cover these issues.
+        // (3) How to update target series when coordinate system related components modified.
+        // TODO: simply the dirty mechanism? Check whether only the case here can set tasks dirty,
+        // and this case all of the tasks will be set as dirty.
+        ecModel.restoreData(payload); // Theoretically an overall task not only depends on each of its target series, but also
+        // depends on all of the series.
+        // The overall task is not in pipeline, and `ecModel.restoreData` only set pipeline tasks
+        // dirty. If `getTargetSeries` of an overall task returns nothing, we should also ensure
+        // that the overall task is set as dirty and to be performed, otherwise it probably cause
+        // state chaos. So we have to set dirty of all of the overall tasks manually, otherwise it
+        // probably cause state chaos (consider `dataZoomProcessor`).
 
-      if (!(label && labelLine)) {
-        return;
-      }
+        this._stageTaskMap.each(function (taskRecord) {
+          var overallTask = taskRecord.overallTask;
+          overallTask && overallTask.dirty();
+        });
+      }; // If seriesModel provided, incremental threshold is check by series data.
 
-      var labelGuideConfig = target.textGuideLineConfig || {};
-      var points = [[0, 0], [0, 0], [0, 0]];
-      var searchSpace = labelGuideConfig.candidates || DEFAULT_SEARCH_SPACE;
-      var labelRect = label.getBoundingRect().clone();
-      labelRect.applyTransform(label.getComputedTransform());
-      var minDist = Infinity;
-      var anchorPoint = labelGuideConfig.anchor;
-      var targetTransform = target.getComputedTransform();
-      var targetInversedTransform = targetTransform && invert([], targetTransform);
-      var len = labelLineModel.get('length2') || 0;
 
-      if (anchorPoint) {
-        pt2.copy(anchorPoint);
-      }
+      Scheduler.prototype.getPerformArgs = function (task, isBlock) {
+        // For overall task
+        if (!task.__pipeline) {
+          return;
+        }
 
-      for (var i = 0; i < searchSpace.length; i++) {
-        var candidate = searchSpace[i];
-        getCandidateAnchor(candidate, 0, labelRect, pt0, dir);
-        Point.scaleAndAdd(pt1, pt0, dir, len); // Transform to target coord space.
+        var pipeline = this._pipelineMap.get(task.__pipeline.id);
 
-        pt1.transform(targetInversedTransform); // Note: getBoundingRect will ensure the `path` being created.
+        var pCtx = pipeline.context;
+        var incremental = !isBlock && pipeline.progressiveEnabled && (!pCtx || pCtx.progressiveRender) && task.__idxInPipeline > pipeline.blockIndex;
+        var step = incremental ? pipeline.step : null;
+        var modDataCount = pCtx && pCtx.modDataCount;
+        var modBy = modDataCount != null ? Math.ceil(modDataCount / step) : null;
+        return {
+          step: step,
+          modBy: modBy,
+          modDataCount: modDataCount
+        };
+      };
 
-        var boundingRect = target.getBoundingRect();
-        var dist = anchorPoint ? anchorPoint.distance(pt1) : target instanceof Path ? nearestPointOnPath(pt1, target.path, pt2) : nearestPointOnRect(pt1, boundingRect, pt2); // TODO pt2 is in the path
+      Scheduler.prototype.getPipeline = function (pipelineId) {
+        return this._pipelineMap.get(pipelineId);
+      };
+      /**
+       * Current, progressive rendering starts from visual and layout.
+       * Always detect render mode in the same stage, avoiding that incorrect
+       * detection caused by data filtering.
+       * Caution:
+       * `updateStreamModes` use `seriesModel.getData()`.
+       */
 
-        if (dist < minDist) {
-          minDist = dist; // Transform back to global space.
 
-          pt1.transform(targetTransform);
-          pt2.transform(targetTransform);
-          pt2.toArray(points[0]);
-          pt1.toArray(points[1]);
-          pt0.toArray(points[2]);
-        }
-      }
+      Scheduler.prototype.updateStreamModes = function (seriesModel, view) {
+        var pipeline = this._pipelineMap.get(seriesModel.uid);
 
-      limitTurnAngle(points, labelLineModel.get('minTurnAngle'));
-      labelLine.setShape({
-        points: points
-      });
-    } // Temporal variable for the limitTurnAngle function
+        var data = seriesModel.getData();
+        var dataLen = data.count(); // `progressiveRender` means that can render progressively in each
+        // animation frame. Note that some types of series do not provide
+        // `view.incrementalPrepareRender` but support `chart.appendData`. We
+        // use the term `incremental` but not `progressive` to describe the
+        // case that `chart.appendData`.
 
-    var tmpArr = [];
-    var tmpProjPoint = new Point();
-    /**
-     * Reduce the line segment attached to the label to limit the turn angle between two segments.
-     * @param linePoints
-     * @param minTurnAngle Radian of minimum turn angle. 0 - 180
-     */
+        var progressiveRender = pipeline.progressiveEnabled && view.incrementalPrepareRender && dataLen >= pipeline.threshold;
+        var large = seriesModel.get('large') && dataLen >= seriesModel.get('largeThreshold'); // TODO: modDataCount should not updated if `appendData`, otherwise cause whole repaint.
+        // see `test/candlestick-large3.html`
 
-    function limitTurnAngle(linePoints, minTurnAngle) {
-      if (!(minTurnAngle <= 180 && minTurnAngle > 0)) {
-        return;
-      }
+        var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;
+        seriesModel.pipelineContext = pipeline.context = {
+          progressiveRender: progressiveRender,
+          modDataCount: modDataCount,
+          large: large
+        };
+      };
 
-      minTurnAngle = minTurnAngle / 180 * Math.PI; // The line points can be
-      //      /pt1----pt2 (label)
-      //     /
-      // pt0/
+      Scheduler.prototype.restorePipelines = function (ecModel) {
+        var scheduler = this;
+        var pipelineMap = scheduler._pipelineMap = createHashMap();
+        ecModel.eachSeries(function (seriesModel) {
+          var progressive = seriesModel.getProgressive();
+          var pipelineId = seriesModel.uid;
+          pipelineMap.set(pipelineId, {
+            id: pipelineId,
+            head: null,
+            tail: null,
+            threshold: seriesModel.getProgressiveThreshold(),
+            progressiveEnabled: progressive && !(seriesModel.preventIncremental && seriesModel.preventIncremental()),
+            blockIndex: -1,
+            step: Math.round(progressive || 700),
+            count: 0
+          });
 
-      pt0.fromArray(linePoints[0]);
-      pt1.fromArray(linePoints[1]);
-      pt2.fromArray(linePoints[2]);
-      Point.sub(dir, pt0, pt1);
-      Point.sub(dir2, pt2, pt1);
-      var len1 = dir.len();
-      var len2 = dir2.len();
+          scheduler._pipe(seriesModel, seriesModel.dataTask);
+        });
+      };
 
-      if (len1 < 1e-3 || len2 < 1e-3) {
-        return;
-      }
+      Scheduler.prototype.prepareStageTasks = function () {
+        var stageTaskMap = this._stageTaskMap;
+        var ecModel = this.api.getModel();
+        var api = this.api;
+        each(this._allHandlers, function (handler) {
+          var record = stageTaskMap.get(handler.uid) || stageTaskMap.set(handler.uid, {});
+          var errMsg = '';
 
-      dir.scale(1 / len1);
-      dir2.scale(1 / len2);
-      var angleCos = dir.dot(dir2);
-      var minTurnAngleCos = Math.cos(minTurnAngle);
+          if ("development" !== 'production') {
+            // Currently do not need to support to sepecify them both.
+            errMsg = '"reset" and "overallReset" must not be both specified.';
+          }
 
-      if (minTurnAngleCos < angleCos) {
-        // Smaller than minTurnAngle
-        // Calculate project point of pt0 on pt1-pt2
-        var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false);
-        tmpProjPoint.fromArray(tmpArr); // Calculate new projected length with limited minTurnAngle and get the new connect point
+          assert(!(handler.reset && handler.overallReset), errMsg);
+          handler.reset && this._createSeriesStageTask(handler, record, ecModel, api);
+          handler.overallReset && this._createOverallStageTask(handler, record, ecModel, api);
+        }, this);
+      };
 
-        tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI - minTurnAngle)); // Limit the new calculated connect point between pt1 and pt2.
+      Scheduler.prototype.prepareView = function (view, model, ecModel, api) {
+        var renderTask = view.renderTask;
+        var context = renderTask.context;
+        context.model = model;
+        context.ecModel = ecModel;
+        context.api = api;
+        renderTask.__block = !view.incrementalPrepareRender;
 
-        var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y);
+        this._pipe(model, renderTask);
+      };
 
-        if (isNaN(t)) {
-          return;
-        }
+      Scheduler.prototype.performDataProcessorTasks = function (ecModel, payload) {
+        // If we do not use `block` here, it should be considered when to update modes.
+        this._performStageTasks(this._dataProcessorHandlers, ecModel, payload, {
+          block: true
+        });
+      };
 
-        if (t < 0) {
-          Point.copy(tmpProjPoint, pt1);
-        } else if (t > 1) {
-          Point.copy(tmpProjPoint, pt2);
-        }
+      Scheduler.prototype.performVisualTasks = function (ecModel, payload, opt) {
+        this._performStageTasks(this._visualHandlers, ecModel, payload, opt);
+      };
 
-        tmpProjPoint.toArray(linePoints[1]);
-      }
-    }
-    /**
-     * Limit the angle of line and the surface
-     * @param maxSurfaceAngle Radian of minimum turn angle. 0 - 180. 0 is same direction to normal. 180 is opposite
-     */
+      Scheduler.prototype._performStageTasks = function (stageHandlers, ecModel, payload, opt) {
+        opt = opt || {};
+        var unfinished = false;
+        var scheduler = this;
+        each(stageHandlers, function (stageHandler, idx) {
+          if (opt.visualType && opt.visualType !== stageHandler.visualType) {
+            return;
+          }
 
-    function limitSurfaceAngle(linePoints, surfaceNormal, maxSurfaceAngle) {
-      if (!(maxSurfaceAngle <= 180 && maxSurfaceAngle > 0)) {
-        return;
-      }
+          var stageHandlerRecord = scheduler._stageTaskMap.get(stageHandler.uid);
 
-      maxSurfaceAngle = maxSurfaceAngle / 180 * Math.PI;
-      pt0.fromArray(linePoints[0]);
-      pt1.fromArray(linePoints[1]);
-      pt2.fromArray(linePoints[2]);
-      Point.sub(dir, pt1, pt0);
-      Point.sub(dir2, pt2, pt1);
-      var len1 = dir.len();
-      var len2 = dir2.len();
+          var seriesTaskMap = stageHandlerRecord.seriesTaskMap;
+          var overallTask = stageHandlerRecord.overallTask;
 
-      if (len1 < 1e-3 || len2 < 1e-3) {
-        return;
-      }
+          if (overallTask) {
+            var overallNeedDirty_1;
+            var agentStubMap = overallTask.agentStubMap;
+            agentStubMap.each(function (stub) {
+              if (needSetDirty(opt, stub)) {
+                stub.dirty();
+                overallNeedDirty_1 = true;
+              }
+            });
+            overallNeedDirty_1 && overallTask.dirty();
+            scheduler.updatePayload(overallTask, payload);
+            var performArgs_1 = scheduler.getPerformArgs(overallTask, opt.block); // Execute stubs firstly, which may set the overall task dirty,
+            // then execute the overall task. And stub will call seriesModel.setData,
+            // which ensures that in the overallTask seriesModel.getData() will not
+            // return incorrect data.
 
-      dir.scale(1 / len1);
-      dir2.scale(1 / len2);
-      var angleCos = dir.dot(surfaceNormal);
-      var maxSurfaceAngleCos = Math.cos(maxSurfaceAngle);
+            agentStubMap.each(function (stub) {
+              stub.perform(performArgs_1);
+            });
 
-      if (angleCos < maxSurfaceAngleCos) {
-        // Calculate project point of pt0 on pt1-pt2
-        var d = projectPointToLine(pt1.x, pt1.y, pt2.x, pt2.y, pt0.x, pt0.y, tmpArr, false);
-        tmpProjPoint.fromArray(tmpArr);
-        var HALF_PI = Math.PI / 2;
-        var angle2 = Math.acos(dir2.dot(surfaceNormal));
-        var newAngle = HALF_PI + angle2 - maxSurfaceAngle;
+            if (overallTask.perform(performArgs_1)) {
+              unfinished = true;
+            }
+          } else if (seriesTaskMap) {
+            seriesTaskMap.each(function (task, pipelineId) {
+              if (needSetDirty(opt, task)) {
+                task.dirty();
+              }
 
-        if (newAngle >= HALF_PI) {
-          // parallel
-          Point.copy(tmpProjPoint, pt2);
-        } else {
-          // Calculate new projected length with limited minTurnAngle and get the new connect point
-          tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI / 2 - newAngle)); // Limit the new calculated connect point between pt1 and pt2.
+              var performArgs = scheduler.getPerformArgs(task, opt.block); // FIXME
+              // if intending to decalare `performRawSeries` in handlers, only
+              // stream-independent (specifically, data item independent) operations can be
+              // performed. Because is a series is filtered, most of the tasks will not
+              // be performed. A stream-dependent operation probably cause wrong biz logic.
+              // Perhaps we should not provide a separate callback for this case instead
+              // of providing the config `performRawSeries`. The stream-dependent operaions
+              // and stream-independent operations should better not be mixed.
 
-          var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y);
+              performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model);
+              scheduler.updatePayload(task, payload);
 
-          if (isNaN(t)) {
-            return;
+              if (task.perform(performArgs)) {
+                unfinished = true;
+              }
+            });
           }
+        });
 
-          if (t < 0) {
-            Point.copy(tmpProjPoint, pt1);
-          } else if (t > 1) {
-            Point.copy(tmpProjPoint, pt2);
-          }
+        function needSetDirty(opt, task) {
+          return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));
         }
 
-        tmpProjPoint.toArray(linePoints[1]);
-      }
-    }
-
-    function setLabelLineState(labelLine, ignore, stateName, stateModel) {
-      var isNormal = stateName === 'normal';
-      var stateObj = isNormal ? labelLine : labelLine.ensureState(stateName); // Make sure display.
+        this.unfinished = unfinished || this.unfinished;
+      };
 
-      stateObj.ignore = ignore; // Set smooth
+      Scheduler.prototype.performSeriesTasks = function (ecModel) {
+        var unfinished;
+        ecModel.eachSeries(function (seriesModel) {
+          // Progress to the end for dataInit and dataRestore.
+          unfinished = seriesModel.dataTask.perform() || unfinished;
+        });
+        this.unfinished = unfinished || this.unfinished;
+      };
 
-      var smooth = stateModel.get('smooth');
+      Scheduler.prototype.plan = function () {
+        // Travel pipelines, check block.
+        this._pipelineMap.each(function (pipeline) {
+          var task = pipeline.tail;
 
-      if (smooth && smooth === true) {
-        smooth = 0.3;
-      }
+          do {
+            if (task.__block) {
+              pipeline.blockIndex = task.__idxInPipeline;
+              break;
+            }
 
-      stateObj.shape = stateObj.shape || {};
+            task = task.getUpstream();
+          } while (task);
+        });
+      };
 
-      if (smooth > 0) {
-        stateObj.shape.smooth = smooth;
-      }
+      Scheduler.prototype.updatePayload = function (task, payload) {
+        payload !== 'remain' && (task.context.payload = payload);
+      };
 
-      var styleObj = stateModel.getModel('lineStyle').getLineStyle();
-      isNormal ? labelLine.useStyle(styleObj) : stateObj.style = styleObj;
-    }
+      Scheduler.prototype._createSeriesStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) {
+        var scheduler = this;
+        var oldSeriesTaskMap = stageHandlerRecord.seriesTaskMap; // The count of stages are totally about only several dozen, so
+        // do not need to reuse the map.
 
-    function buildLabelLinePath(path, shape) {
-      var smooth = shape.smooth;
-      var points = shape.points;
+        var newSeriesTaskMap = stageHandlerRecord.seriesTaskMap = createHashMap();
+        var seriesType = stageHandler.seriesType;
+        var getTargetSeries = stageHandler.getTargetSeries; // If a stageHandler should cover all series, `createOnAllSeries` should be declared mandatorily,
+        // to avoid some typo or abuse. Otherwise if an extension do not specify a `seriesType`,
+        // it works but it may cause other irrelevant charts blocked.
 
-      if (!points) {
-        return;
-      }
+        if (stageHandler.createOnAllSeries) {
+          ecModel.eachRawSeries(create);
+        } else if (seriesType) {
+          ecModel.eachRawSeriesByType(seriesType, create);
+        } else if (getTargetSeries) {
+          getTargetSeries(ecModel, api).each(create);
+        }
 
-      path.moveTo(points[0][0], points[0][1]);
+        function create(seriesModel) {
+          var pipelineId = seriesModel.uid; // Init tasks for each seriesModel only once.
+          // Reuse original task instance.
 
-      if (smooth > 0 && points.length >= 3) {
-        var len1 = dist(points[0], points[1]);
-        var len2 = dist(points[1], points[2]);
+          var task = newSeriesTaskMap.set(pipelineId, oldSeriesTaskMap && oldSeriesTaskMap.get(pipelineId) || createTask({
+            plan: seriesTaskPlan,
+            reset: seriesTaskReset,
+            count: seriesTaskCount
+          }));
+          task.context = {
+            model: seriesModel,
+            ecModel: ecModel,
+            api: api,
+            // PENDING: `useClearVisual` not used?
+            useClearVisual: stageHandler.isVisual && !stageHandler.isLayout,
+            plan: stageHandler.plan,
+            reset: stageHandler.reset,
+            scheduler: scheduler
+          };
 
-        if (!len1 || !len2) {
-          path.lineTo(points[1][0], points[1][1]);
-          path.lineTo(points[2][0], points[2][1]);
-          return;
+          scheduler._pipe(seriesModel, task);
         }
+      };
 
-        var moveLen = Math.min(len1, len2) * smooth;
-        var midPoint0 = lerp([], points[1], points[0], moveLen / len1);
-        var midPoint2 = lerp([], points[1], points[2], moveLen / len2);
-        var midPoint1 = lerp([], midPoint0, midPoint2, 0.5);
-        path.bezierCurveTo(midPoint0[0], midPoint0[1], midPoint0[0], midPoint0[1], midPoint1[0], midPoint1[1]);
-        path.bezierCurveTo(midPoint2[0], midPoint2[1], midPoint2[0], midPoint2[1], points[2][0], points[2][1]);
-      } else {
-        for (var i = 1; i < points.length; i++) {
-          path.lineTo(points[i][0], points[i][1]);
-        }
-      }
-    }
-    /**
-     * Create a label line if necessary and set it's style.
-     */
+      Scheduler.prototype._createOverallStageTask = function (stageHandler, stageHandlerRecord, ecModel, api) {
+        var scheduler = this;
+        var overallTask = stageHandlerRecord.overallTask = stageHandlerRecord.overallTask // For overall task, the function only be called on reset stage.
+        || createTask({
+          reset: overallTaskReset
+        });
+        overallTask.context = {
+          ecModel: ecModel,
+          api: api,
+          overallReset: stageHandler.overallReset,
+          scheduler: scheduler
+        };
+        var oldAgentStubMap = overallTask.agentStubMap; // The count of stages are totally about only several dozen, so
+        // do not need to reuse the map.
 
+        var newAgentStubMap = overallTask.agentStubMap = createHashMap();
+        var seriesType = stageHandler.seriesType;
+        var getTargetSeries = stageHandler.getTargetSeries;
+        var overallProgress = true;
+        var shouldOverallTaskDirty = false; // FIXME:TS never used, so comment it
+        // let modifyOutputEnd = stageHandler.modifyOutputEnd;
+        // An overall task with seriesType detected or has `getTargetSeries`, we add
+        // stub in each pipelines, it will set the overall task dirty when the pipeline
+        // progress. Moreover, to avoid call the overall task each frame (too frequent),
+        // we set the pipeline block.
 
-    function setLabelLineStyle(targetEl, statesModels, defaultStyle) {
-      var labelLine = targetEl.getTextGuideLine();
-      var label = targetEl.getTextContent();
+        var errMsg = '';
 
-      if (!label) {
-        // Not show label line if there is no label.
-        if (labelLine) {
-          targetEl.removeTextGuideLine();
+        if ("development" !== 'production') {
+          errMsg = '"createOnAllSeries" do not supported for "overallReset", ' + 'becuase it will block all streams.';
         }
 
-        return;
-      }
+        assert(!stageHandler.createOnAllSeries, errMsg);
 
-      var normalModel = statesModels.normal;
-      var showNormal = normalModel.get('show');
-      var labelIgnoreNormal = label.ignore;
+        if (seriesType) {
+          ecModel.eachRawSeriesByType(seriesType, createStub);
+        } else if (getTargetSeries) {
+          getTargetSeries(ecModel, api).each(createStub);
+        } // Otherwise, (usually it is legancy case), the overall task will only be
+        // executed when upstream dirty. Otherwise the progressive rendering of all
+        // pipelines will be disabled unexpectedly. But it still needs stubs to receive
+        // dirty info from upsteam.
+        else {
+            overallProgress = false;
+            each(ecModel.getSeries(), createStub);
+          }
 
-      for (var i = 0; i < DISPLAY_STATES.length; i++) {
-        var stateName = DISPLAY_STATES[i];
-        var stateModel = statesModels[stateName];
-        var isNormal = stateName === 'normal';
+        function createStub(seriesModel) {
+          var pipelineId = seriesModel.uid;
+          var stub = newAgentStubMap.set(pipelineId, oldAgentStubMap && oldAgentStubMap.get(pipelineId) || ( // When the result of `getTargetSeries` changed, the overallTask
+          // should be set as dirty and re-performed.
+          shouldOverallTaskDirty = true, createTask({
+            reset: stubReset,
+            onDirty: stubOnDirty
+          })));
+          stub.context = {
+            model: seriesModel,
+            overallProgress: overallProgress // FIXME:TS never used, so comment it
+            // modifyOutputEnd: modifyOutputEnd
 
-        if (stateModel) {
-          var stateShow = stateModel.get('show');
-          var isLabelIgnored = isNormal ? labelIgnoreNormal : retrieve2(label.states[stateName] && label.states[stateName].ignore, labelIgnoreNormal);
+          };
+          stub.agent = overallTask;
+          stub.__block = overallProgress;
 
-          if (isLabelIgnored // Not show when label is not shown in this state.
-          || !retrieve2(stateShow, showNormal) // Use normal state by default if not set.
-          ) {
-              var stateObj = isNormal ? labelLine : labelLine && labelLine.states.normal;
+          scheduler._pipe(seriesModel, stub);
+        }
 
-              if (stateObj) {
-                stateObj.ignore = true;
-              }
+        if (shouldOverallTaskDirty) {
+          overallTask.dirty();
+        }
+      };
 
-              continue;
-            } // Create labelLine if not exists
+      Scheduler.prototype._pipe = function (seriesModel, task) {
+        var pipelineId = seriesModel.uid;
 
+        var pipeline = this._pipelineMap.get(pipelineId);
 
-          if (!labelLine) {
-            labelLine = new Polyline();
-            targetEl.setTextGuideLine(labelLine); // Reset state of normal because it's new created.
-            // NOTE: NORMAL should always been the first!
+        !pipeline.head && (pipeline.head = task);
+        pipeline.tail && pipeline.tail.pipe(task);
+        pipeline.tail = task;
+        task.__idxInPipeline = pipeline.count++;
+        task.__pipeline = pipeline;
+      };
 
-            if (!isNormal && (labelIgnoreNormal || !showNormal)) {
-              setLabelLineState(labelLine, true, 'normal', statesModels.normal);
-            } // Use same state proxy.
+      Scheduler.wrapStageHandler = function (stageHandler, visualType) {
+        if (isFunction(stageHandler)) {
+          stageHandler = {
+            overallReset: stageHandler,
+            seriesType: detectSeriseType(stageHandler)
+          };
+        }
 
+        stageHandler.uid = getUID('stageHandler');
+        visualType && (stageHandler.visualType = visualType);
+        return stageHandler;
+      };
+      return Scheduler;
+    }();
 
-            if (targetEl.stateProxy) {
-              labelLine.stateProxy = targetEl.stateProxy;
-            }
-          }
+    function overallTaskReset(context) {
+      context.overallReset(context.ecModel, context.api, context.payload);
+    }
 
-          setLabelLineState(labelLine, false, stateName, stateModel);
-        }
-      }
+    function stubReset(context) {
+      return context.overallProgress && stubProgress;
+    }
 
-      if (labelLine) {
-        defaults(labelLine.style, defaultStyle); // Not fill.
+    function stubProgress() {
+      this.agent.dirty();
+      this.getDownstream().dirty();
+    }
 
-        labelLine.style.fill = null;
-        var showAbove = normalModel.get('showAbove');
-        var labelLineConfig = targetEl.textGuideLineConfig = targetEl.textGuideLineConfig || {};
-        labelLineConfig.showAbove = showAbove || false; // Custom the buildPath.
+    function stubOnDirty() {
+      this.agent && this.agent.dirty();
+    }
 
-        labelLine.buildPath = buildLabelLinePath;
-      }
+    function seriesTaskPlan(context) {
+      return context.plan ? context.plan(context.model, context.ecModel, context.api, context.payload) : null;
     }
-    function getLabelLineStatesModels(itemModel, labelLineName) {
-      labelLineName = labelLineName || 'labelLine';
-      var statesModels = {
-        normal: itemModel.getModel(labelLineName)
-      };
 
-      for (var i = 0; i < SPECIAL_STATES.length; i++) {
-        var stateName = SPECIAL_STATES[i];
-        statesModels[stateName] = itemModel.getModel([stateName, labelLineName]);
+    function seriesTaskReset(context) {
+      if (context.useClearVisual) {
+        context.data.clearAllVisual();
       }
 
-      return statesModels;
+      var resetDefines = context.resetDefines = normalizeToArray(context.reset(context.model, context.ecModel, context.api, context.payload));
+      return resetDefines.length > 1 ? map(resetDefines, function (v, idx) {
+        return makeSeriesTaskProgress(idx);
+      }) : singleSeriesTaskProgress;
     }
 
-    function prepareLayoutList(input) {
-      var list = [];
+    var singleSeriesTaskProgress = makeSeriesTaskProgress(0);
 
-      for (var i = 0; i < input.length; i++) {
-        var rawItem = input[i];
+    function makeSeriesTaskProgress(resetDefineIdx) {
+      return function (params, context) {
+        var data = context.data;
+        var resetDefine = context.resetDefines[resetDefineIdx];
 
-        if (rawItem.defaultAttr.ignore) {
-          continue;
+        if (resetDefine && resetDefine.dataEach) {
+          for (var i = params.start; i < params.end; i++) {
+            resetDefine.dataEach(data, i);
+          }
+        } else if (resetDefine && resetDefine.progress) {
+          resetDefine.progress(params, data);
         }
+      };
+    }
 
-        var label = rawItem.label;
-        var transform = label.getComputedTransform(); // NOTE: Get bounding rect after getComputedTransform, or label may not been updated by the host el.
-
-        var localRect = label.getBoundingRect();
-        var isAxisAligned = !transform || transform[1] < 1e-5 && transform[2] < 1e-5;
-        var minMargin = label.style.margin || 0;
-        var globalRect = localRect.clone();
-        globalRect.applyTransform(transform);
-        globalRect.x -= minMargin / 2;
-        globalRect.y -= minMargin / 2;
-        globalRect.width += minMargin;
-        globalRect.height += minMargin;
-        var obb = isAxisAligned ? new OrientedBoundingRect(localRect, transform) : null;
-        list.push({
-          label: label,
-          labelLine: rawItem.labelLine,
-          rect: globalRect,
-          localRect: localRect,
-          obb: obb,
-          priority: rawItem.priority,
-          defaultAttr: rawItem.defaultAttr,
-          layoutOption: rawItem.computedLayoutOption,
-          axisAligned: isAxisAligned,
-          transform: transform
-        });
-      }
-
-      return list;
+    function seriesTaskCount(context) {
+      return context.data.count();
     }
+    /**
+     * Only some legacy stage handlers (usually in echarts extensions) are pure function.
+     * To ensure that they can work normally, they should work in block mode, that is,
+     * they should not be started util the previous tasks finished. So they cause the
+     * progressive rendering disabled. We try to detect the series type, to narrow down
+     * the block range to only the series type they concern, but not all series.
+     */
 
-    function shiftLayout(list, xyDim, sizeDim, minBound, maxBound, balanceShift) {
-      var len = list.length;
 
-      if (len < 2) {
-        return;
-      }
+    function detectSeriseType(legacyFunc) {
+      seriesType = null;
 
-      list.sort(function (a, b) {
-        return a.rect[xyDim] - b.rect[xyDim];
-      });
-      var lastPos = 0;
-      var delta;
-      var adjusted = false;
-      var totalShifts = 0;
+      try {
+        // Assume there is no async when calling `eachSeriesByType`.
+        legacyFunc(ecModelMock, apiMock);
+      } catch (e) {}
 
-      for (var i = 0; i < len; i++) {
-        var item = list[i];
-        var rect = item.rect;
-        delta = rect[xyDim] - lastPos;
+      return seriesType;
+    }
 
-        if (delta < 0) {
-          // shiftForward(i, len, -delta);
-          rect[xyDim] -= delta;
-          item.label[xyDim] -= delta;
-          adjusted = true;
-        }
+    var ecModelMock = {};
+    var apiMock = {};
+    var seriesType;
+    mockMethods(ecModelMock, GlobalModel);
+    mockMethods(apiMock, ExtensionAPI);
 
-        var shift = Math.max(-delta, 0);
-        totalShifts += shift;
-        lastPos = rect[xyDim] + rect[sizeDim];
+    ecModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {
+      seriesType = type;
+    };
+
+    ecModelMock.eachComponent = function (cond) {
+      if (cond.mainType === 'series' && cond.subType) {
+        seriesType = cond.subType;
       }
+    };
 
-      if (totalShifts > 0 && balanceShift) {
-        // Shift back to make the distribution more equally.
-        shiftList(-totalShifts / len, 0, len);
-      } // TODO bleedMargin?
+    function mockMethods(target, Clz) {
+      /* eslint-disable */
+      for (var name_1 in Clz.prototype) {
+        // Do not use hasOwnProperty
+        target[name_1] = noop;
+      }
+      /* eslint-enable */
 
+    }
 
-      var first = list[0];
-      var last = list[len - 1];
-      var minGap;
-      var maxGap;
-      updateMinMaxGap(); // If ends exceed two bounds, squeeze at most 80%, then take the gap of two bounds.
+    /*
+    * Licensed to the Apache Software Foundation (ASF) under one
+    * or more contributor license agreements.  See the NOTICE file
+    * distributed with this work for additional information
+    * regarding copyright ownership.  The ASF licenses this file
+    * to you under the Apache License, Version 2.0 (the
+    * "License"); you may not use this file except in compliance
+    * with the License.  You may obtain a copy of the License at
+    *
+    *   http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing,
+    * software distributed under the License is distributed on an
+    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    * KIND, either express or implied.  See the License for the
+    * specific language governing permissions and limitations
+    * under the License.
+    */
 
-      minGap < 0 && squeezeGaps(-minGap, 0.8);
-      maxGap < 0 && squeezeGaps(maxGap, 0.8);
-      updateMinMaxGap();
-      takeBoundsGap(minGap, maxGap, 1);
-      takeBoundsGap(maxGap, minGap, -1); // Handle bailout when there is not enough space.
 
-      updateMinMaxGap();
+    /**
+     * AUTO-GENERATED FILE. DO NOT MODIFY.
+     */
 
-      if (minGap < 0) {
-        squeezeWhenBailout(-minGap);
-      }
+    /*
+    * Licensed to the Apache Software Foundation (ASF) under one
+    * or more contributor license agreements.  See the NOTICE file
+    * distributed with this work for additional information
+    * regarding copyright ownership.  The ASF licenses this file
+    * to you under the Apache License, Version 2.0 (the
+    * "License"); you may not use this file except in compliance
+    * with the License.  You may obtain a copy of the License at
+    *
+    *   http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing,
+    * software distributed under the License is distributed on an
+    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    * KIND, either express or implied.  See the License for the
+    * specific language governing permissions and limitations
+    * under the License.
+    */
+    var colorAll = ['#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'];
+    var lightTheme = {
+      color: colorAll,
+      colorLayer: [['#37A2DA', '#ffd85c', '#fd7b5f'], ['#37A2DA', '#67E0E3', '#FFDB5C', '#ff9f7f', '#E062AE', '#9d96f5'], ['#37A2DA', '#32C5E9', '#9FE6B8', '#FFDB5C', '#ff9f7f', '#fb7293', '#e7bcf3', '#8378EA', '#96BFFF'], colorAll]
+    };
 
-      if (maxGap < 0) {
-        squeezeWhenBailout(maxGap);
-      }
+    /*
+    * Licensed to the Apache Software Foundation (ASF) under one
+    * or more contributor license agreements.  See the NOTICE file
+    * distributed with this work for additional information
+    * regarding copyright ownership.  The ASF licenses this file
+    * to you under the Apache License, Version 2.0 (the
+    * "License"); you may not use this file except in compliance
+    * with the License.  You may obtain a copy of the License at
+    *
+    *   http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing,
+    * software distributed under the License is distributed on an
+    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    * KIND, either express or implied.  See the License for the
+    * specific language governing permissions and limitations
+    * under the License.
+    */
 
-      function updateMinMaxGap() {
-        minGap = first.rect[xyDim] - minBound;
-        maxGap = maxBound - last.rect[xyDim] - last.rect[sizeDim];
-      }
 
-      function takeBoundsGap(gapThisBound, gapOtherBound, moveDir) {
-        if (gapThisBound < 0) {
-          // Move from other gap if can.
-          var moveFromMaxGap = Math.min(gapOtherBound, -gapThisBound);
+    /**
+     * AUTO-GENERATED FILE. DO NOT MODIFY.
+     */
 
-          if (moveFromMaxGap > 0) {
-            shiftList(moveFromMaxGap * moveDir, 0, len);
-            var remained = moveFromMaxGap + gapThisBound;
+    /*
+    * Licensed to the Apache Software Foundation (ASF) under one
+    * or more contributor license agreements.  See the NOTICE file
+    * distributed with this work for additional information
+    * regarding copyright ownership.  The ASF licenses this file
+    * to you under the Apache License, Version 2.0 (the
+    * "License"); you may not use this file except in compliance
+    * with the License.  You may obtain a copy of the License at
+    *
+    *   http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing,
+    * software distributed under the License is distributed on an
+    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    * KIND, either express or implied.  See the License for the
+    * specific language governing permissions and limitations
+    * under the License.
+    */
+    var contrastColor = '#B9B8CE';
+    var backgroundColor = '#100C2A';
 
-            if (remained < 0) {
-              squeezeGaps(-remained * moveDir, 1);
-            }
-          } else {
-            squeezeGaps(-gapThisBound * moveDir, 1);
+    var axisCommon = function () {
+      return {
+        axisLine: {
+          lineStyle: {
+            color: contrastColor
+          }
+        },
+        splitLine: {
+          lineStyle: {
+            color: '#484753'
+          }
+        },
+        splitArea: {
+          areaStyle: {
+            color: ['rgba(255,255,255,0.02)', 'rgba(255,255,255,0.05)']
+          }
+        },
+        minorSplitLine: {
+          lineStyle: {
+            color: '#20203B'
           }
         }
-      }
+      };
+    };
 
-      function shiftList(delta, start, end) {
-        if (delta !== 0) {
-          adjusted = true;
+    var colorPalette = ['#4992ff', '#7cffb2', '#fddd60', '#ff6e76', '#58d9f9', '#05c091', '#ff8a45', '#8d48e3', '#dd79ff'];
+    var theme = {
+      darkMode: true,
+      color: colorPalette,
+      backgroundColor: backgroundColor,
+      axisPointer: {
+        lineStyle: {
+          color: '#817f91'
+        },
+        crossStyle: {
+          color: '#817f91'
+        },
+        label: {
+          // TODO Contrast of label backgorundColor
+          color: '#fff'
         }
-
-        for (var i = start; i < end; i++) {
-          var item = list[i];
-          var rect = item.rect;
-          rect[xyDim] += delta;
-          item.label[xyDim] += delta;
+      },
+      legend: {
+        textStyle: {
+          color: contrastColor
+        }
+      },
+      textStyle: {
+        color: contrastColor
+      },
+      title: {
+        textStyle: {
+          color: '#EEF1FA'
+        },
+        subtextStyle: {
+          color: '#B9B8CE'
+        }
+      },
+      toolbox: {
+        iconStyle: {
+          borderColor: contrastColor
+        }
+      },
+      dataZoom: {
+        borderColor: '#71708A',
+        textStyle: {
+          color: contrastColor
+        },
+        brushStyle: {
+          color: 'rgba(135,163,206,0.3)'
+        },
+        handleStyle: {
+          color: '#353450',
+          borderColor: '#C5CBE3'
+        },
+        moveHandleStyle: {
+          color: '#B0B6C3',
+          opacity: 0.3
+        },
+        fillerColor: 'rgba(135,163,206,0.2)',
+        emphasis: {
+          handleStyle: {
+            borderColor: '#91B7F2',
+            color: '#4D587D'
+          },
+          moveHandleStyle: {
+            color: '#636D9A',
+            opacity: 0.7
+          }
+        },
+        dataBackground: {
+          lineStyle: {
+            color: '#71708A',
+            width: 1
+          },
+          areaStyle: {
+            color: '#71708A'
+          }
+        },
+        selectedDataBackground: {
+          lineStyle: {
+            color: '#87A3CE'
+          },
+          areaStyle: {
+            color: '#87A3CE'
+          }
+        }
+      },
+      visualMap: {
+        textStyle: {
+          color: contrastColor
         }
-      } // Squeeze gaps if the labels exceed margin.
-
-
-      function squeezeGaps(delta, maxSqeezePercent) {
-        var gaps = [];
-        var totalGaps = 0;
-
-        for (var i = 1; i < len; i++) {
-          var prevItemRect = list[i - 1].rect;
-          var gap = Math.max(list[i].rect[xyDim] - prevItemRect[xyDim] - prevItemRect[sizeDim], 0);
-          gaps.push(gap);
-          totalGaps += gap;
+      },
+      timeline: {
+        lineStyle: {
+          color: contrastColor
+        },
+        label: {
+          color: contrastColor
+        },
+        controlStyle: {
+          color: contrastColor,
+          borderColor: contrastColor
         }
-
-        if (!totalGaps) {
-          return;
+      },
+      calendar: {
+        itemStyle: {
+          color: backgroundColor
+        },
+        dayLabel: {
+          color: contrastColor
+        },
+        monthLabel: {
+          color: contrastColor
+        },
+        yearLabel: {
+          color: contrastColor
         }
-
-        var squeezePercent = Math.min(Math.abs(delta) / totalGaps, maxSqeezePercent);
-
-        if (delta > 0) {
-          for (var i = 0; i < len - 1; i++) {
-            // Distribute the shift delta to all gaps.
-            var movement = gaps[i] * squeezePercent; // Forward
-
-            shiftList(movement, 0, i + 1);
-          }
-        } else {
-          // Backward
-          for (var i = len - 1; i > 0; i--) {
-            // Distribute the shift delta to all gaps.
-            var movement = gaps[i - 1] * squeezePercent;
-            shiftList(-movement, i, len);
+      },
+      timeAxis: axisCommon(),
+      logAxis: axisCommon(),
+      valueAxis: axisCommon(),
+      categoryAxis: axisCommon(),
+      line: {
+        symbol: 'circle'
+      },
+      graph: {
+        color: colorPalette
+      },
+      gauge: {
+        title: {
+          color: contrastColor
+        },
+        axisLine: {
+          lineStyle: {
+            color: [[1, 'rgba(207,212,219,0.2)']]
           }
+        },
+        axisLabel: {
+          color: contrastColor
+        },
+        detail: {
+          color: '#EEF1FA'
         }
-      }
-      /**
-       * Squeeze to allow overlap if there is no more space available.
-       * Let other overlapping strategy like hideOverlap do the job instead of keep exceeding the bounds.
-       */
-
-
-      function squeezeWhenBailout(delta) {
-        var dir = delta < 0 ? -1 : 1;
-        delta = Math.abs(delta);
-        var moveForEachLabel = Math.ceil(delta / (len - 1));
-
-        for (var i = 0; i < len - 1; i++) {
-          if (dir > 0) {
-            // Forward
-            shiftList(moveForEachLabel, 0, i + 1);
-          } else {
-            // Backward
-            shiftList(-moveForEachLabel, len - i - 1, len);
-          }
-
-          delta -= moveForEachLabel;
+      },
+      candlestick: {
+        itemStyle: {
+          color: '#f64e56',
+          color0: '#54ea92',
+          borderColor: '#f64e56',
+          borderColor0: '#54ea92' // borderColor: '#ca2824',
+          // borderColor0: '#09a443'
 
-          if (delta <= 0) {
-            return;
-          }
         }
       }
+    };
+    theme.categoryAxis.splitLine.show = false;
 
-      return adjusted;
-    }
-    /**
-     * Adjust labels on x direction to avoid overlap.
-     */
-
-
-    function shiftLayoutOnX(list, leftBound, rightBound, // If average the shifts on all labels and add them to 0
-    // TODO: Not sure if should enable it.
-    // Pros: The angle of lines will distribute more equally
-    // Cons: In some layout. It may not what user wanted. like in pie. the label of last sector is usually changed unexpectedly.
-    balanceShift) {
-      return shiftLayout(list, 'x', 'width', leftBound, rightBound, balanceShift);
-    }
     /**
-     * Adjust labels on y direction to avoid overlap.
+     * Usage of query:
+     * `chart.on('click', query, handler);`
+     * The `query` can be:
+     * + The component type query string, only `mainType` or `mainType.subType`,
+     *   like: 'xAxis', 'series', 'xAxis.category' or 'series.line'.
+     * + The component query object, like:
+     *   `{seriesIndex: 2}`, `{seriesName: 'xx'}`, `{seriesId: 'some'}`,
+     *   `{xAxisIndex: 2}`, `{xAxisName: 'xx'}`, `{xAxisId: 'some'}`.
+     * + The data query object, like:
+     *   `{dataIndex: 123}`, `{dataType: 'link'}`, `{name: 'some'}`.
+     * + The other query object (cmponent customized query), like:
+     *   `{element: 'some'}` (only available in custom series).
+     *
+     * Caveat: If a prop in the `query` object is `null/undefined`, it is the
+     * same as there is no such prop in the `query` object.
      */
 
-    function shiftLayoutOnY(list, topBound, bottomBound, // If average the shifts on all labels and add them to 0
-    balanceShift) {
-      return shiftLayout(list, 'y', 'height', topBound, bottomBound, balanceShift);
-    }
-    function hideOverlap(labelList) {
-      var displayedLabels = []; // TODO, render overflow visible first, put in the displayedLabels.
-
-      labelList.sort(function (a, b) {
-        return b.priority - a.priority;
-      });
-      var globalRect = new BoundingRect(0, 0, 0, 0);
-
-      function hideEl(el) {
-        if (!el.ignore) {
-          // Show on emphasis.
-          var emphasisState = el.ensureState('emphasis');
-
-          if (emphasisState.ignore == null) {
-            emphasisState.ignore = false;
-          }
-        }
+    var ECEventProcessor =
+    /** @class */
+    function () {
+      function ECEventProcessor() {}
 
-        el.ignore = true;
-      }
+      ECEventProcessor.prototype.normalizeQuery = function (query) {
+        var cptQuery = {};
+        var dataQuery = {};
+        var otherQuery = {}; // `query` is `mainType` or `mainType.subType` of component.
 
-      for (var i = 0; i < labelList.length; i++) {
-        var labelItem = labelList[i];
-        var isAxisAligned = labelItem.axisAligned;
-        var localRect = labelItem.localRect;
-        var transform = labelItem.transform;
-        var label = labelItem.label;
-        var labelLine = labelItem.labelLine;
-        globalRect.copy(labelItem.rect); // Add a threshold because layout may be aligned precisely.
+        if (isString(query)) {
+          var condCptType = parseClassType(query); // `.main` and `.sub` may be ''.
 
-        globalRect.width -= 0.1;
-        globalRect.height -= 0.1;
-        globalRect.x += 0.05;
-        globalRect.y += 0.05;
-        var obb = labelItem.obb;
-        var overlapped = false;
+          cptQuery.mainType = condCptType.main || null;
+          cptQuery.subType = condCptType.sub || null;
+        } // `query` is an object, convert to {mainType, index, name, id}.
+        else {
+            // `xxxIndex`, `xxxName`, `xxxId`, `name`, `dataIndex`, `dataType` is reserved,
+            // can not be used in `compomentModel.filterForExposedEvent`.
+            var suffixes_1 = ['Index', 'Name', 'Id'];
+            var dataKeys_1 = {
+              name: 1,
+              dataIndex: 1,
+              dataType: 1
+            };
+            each(query, function (val, key) {
+              var reserved = false;
 
-        for (var j = 0; j < displayedLabels.length; j++) {
-          var existsTextCfg = displayedLabels[j]; // Fast rejection.
+              for (var i = 0; i < suffixes_1.length; i++) {
+                var propSuffix = suffixes_1[i];
+                var suffixPos = key.lastIndexOf(propSuffix);
 
-          if (!globalRect.intersect(existsTextCfg.rect)) {
-            continue;
-          }
+                if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {
+                  var mainType = key.slice(0, suffixPos); // Consider `dataIndex`.
 
-          if (isAxisAligned && existsTextCfg.axisAligned) {
-            // Is overlapped
-            overlapped = true;
-            break;
-          }
+                  if (mainType !== 'data') {
+                    cptQuery.mainType = mainType;
+                    cptQuery[propSuffix.toLowerCase()] = val;
+                    reserved = true;
+                  }
+                }
+              }
 
-          if (!existsTextCfg.obb) {
-            // If self is not axis aligned. But other is.
-            existsTextCfg.obb = new OrientedBoundingRect(existsTextCfg.localRect, existsTextCfg.transform);
-          }
+              if (dataKeys_1.hasOwnProperty(key)) {
+                dataQuery[key] = val;
+                reserved = true;
+              }
 
-          if (!obb) {
-            // If self is axis aligned. But other is not.
-            obb = new OrientedBoundingRect(localRect, transform);
+              if (!reserved) {
+                otherQuery[key] = val;
+              }
+            });
           }
 
-          if (obb.intersect(existsTextCfg.obb)) {
-            overlapped = true;
-            break;
-          }
-        } // TODO Callback to determine if this overlap should be handled?
+        return {
+          cptQuery: cptQuery,
+          dataQuery: dataQuery,
+          otherQuery: otherQuery
+        };
+      };
 
+      ECEventProcessor.prototype.filter = function (eventType, query) {
+        // They should be assigned before each trigger call.
+        var eventInfo = this.eventInfo;
 
-        if (overlapped) {
-          hideEl(label);
-          labelLine && hideEl(labelLine);
-        } else {
-          label.attr('ignore', labelItem.defaultAttr.ignore);
-          labelLine && labelLine.attr('ignore', labelItem.defaultAttr.labelGuideIgnore);
-          displayedLabels.push(labelItem);
+        if (!eventInfo) {
+          return true;
         }
-      }
-    }
 
-    function cloneArr(points) {
-      if (points) {
-        var newPoints = [];
+        var targetEl = eventInfo.targetEl;
+        var packedEvent = eventInfo.packedEvent;
+        var model = eventInfo.model;
+        var view = eventInfo.view; // For event like 'globalout'.
 
-        for (var i = 0; i < points.length; i++) {
-          newPoints.push(points[i].slice());
+        if (!model || !view) {
+          return true;
         }
 
-        return newPoints;
-      }
-    }
-
-    function prepareLayoutCallbackParams(labelItem, hostEl) {
-      var label = labelItem.label;
-      var labelLine = hostEl && hostEl.getTextGuideLine();
-      return {
-        dataIndex: labelItem.dataIndex,
-        dataType: labelItem.dataType,
-        seriesIndex: labelItem.seriesModel.seriesIndex,
-        text: labelItem.label.style.text,
-        rect: labelItem.hostRect,
-        labelRect: labelItem.rect,
-        // x: labelAttr.x,
-        // y: labelAttr.y,
-        align: label.style.align,
-        verticalAlign: label.style.verticalAlign,
-        labelLinePoints: cloneArr(labelLine && labelLine.shape.points)
-      };
-    }
-
-    var LABEL_OPTION_TO_STYLE_KEYS = ['align', 'verticalAlign', 'width', 'height', 'fontSize'];
-    var dummyTransformable = new Transformable();
-    var labelLayoutInnerStore = makeInner();
-    var labelLineAnimationStore = makeInner();
-
-    function extendWithKeys(target, source, keys) {
-      for (var i = 0; i < keys.length; i++) {
-        var key = keys[i];
+        var cptQuery = query.cptQuery;
+        var dataQuery = query.dataQuery;
+        return check(cptQuery, model, 'mainType') && check(cptQuery, model, 'subType') && check(cptQuery, model, 'index', 'componentIndex') && check(cptQuery, model, 'name') && check(cptQuery, model, 'id') && check(dataQuery, packedEvent, 'name') && check(dataQuery, packedEvent, 'dataIndex') && check(dataQuery, packedEvent, 'dataType') && (!view.filterForExposedEvent || view.filterForExposedEvent(eventType, query.otherQuery, targetEl, packedEvent));
 
-        if (source[key] != null) {
-          target[key] = source[key];
+        function check(query, host, prop, propOnHost) {
+          return query[prop] == null || host[propOnHost || prop] === query[prop];
         }
-      }
-    }
-
-    var LABEL_LAYOUT_PROPS = ['x', 'y', 'rotation'];
-
-    var LabelManager =
-    /** @class */
-    function () {
-      function LabelManager() {
-        this._labelList = [];
-        this._chartViewList = [];
-      }
-
-      LabelManager.prototype.clearLabels = function () {
-        this._labelList = [];
-        this._chartViewList = [];
       };
-      /**
-       * Add label to manager
-       */
 
+      ECEventProcessor.prototype.afterTrigger = function () {
+        // Make sure the eventInfo wont be used in next trigger.
+        this.eventInfo = null;
+      };
 
-      LabelManager.prototype._addLabel = function (dataIndex, dataType, seriesModel, label, layoutOption) {
-        var labelStyle = label.style;
-        var hostEl = label.__hostTarget;
-        var textConfig = hostEl.textConfig || {}; // TODO: If label is in other state.
+      return ECEventProcessor;
+    }();
 
-        var labelTransform = label.getComputedTransform();
-        var labelRect = label.getBoundingRect().plain();
-        BoundingRect.applyTransform(labelRect, labelRect, labelTransform);
+    var seriesSymbolTask = {
+      createOnAllSeries: true,
+      // For legend.
+      performRawSeries: true,
+      reset: function (seriesModel, ecModel) {
+        var data = seriesModel.getData();
 
-        if (labelTransform) {
-          dummyTransformable.setLocalTransform(labelTransform);
-        } else {
-          // Identity transform.
-          dummyTransformable.x = dummyTransformable.y = dummyTransformable.rotation = dummyTransformable.originX = dummyTransformable.originY = 0;
-          dummyTransformable.scaleX = dummyTransformable.scaleY = 1;
+        if (seriesModel.legendIcon) {
+          data.setVisual('legendIcon', seriesModel.legendIcon);
         }
 
-        var host = label.__hostTarget;
-        var hostRect;
-
-        if (host) {
-          hostRect = host.getBoundingRect().plain();
-          var transform = host.getComputedTransform();
-          BoundingRect.applyTransform(hostRect, hostRect, transform);
+        if (!seriesModel.hasSymbolVisual) {
+          return;
         }
 
-        var labelGuide = hostRect && host.getTextGuideLine();
-
-        this._labelList.push({
-          label: label,
-          labelLine: labelGuide,
-          seriesModel: seriesModel,
-          dataIndex: dataIndex,
-          dataType: dataType,
-          layoutOption: layoutOption,
-          computedLayoutOption: null,
-          rect: labelRect,
-          hostRect: hostRect,
-          // Label with lower priority will be hidden when overlapped
-          // Use rect size as default priority
-          priority: hostRect ? hostRect.width * hostRect.height : 0,
-          // Save default label attributes.
-          // For restore if developers want get back to default value in callback.
-          defaultAttr: {
-            ignore: label.ignore,
-            labelGuideIgnore: labelGuide && labelGuide.ignore,
-            x: dummyTransformable.x,
-            y: dummyTransformable.y,
-            scaleX: dummyTransformable.scaleX,
-            scaleY: dummyTransformable.scaleY,
-            rotation: dummyTransformable.rotation,
-            style: {
-              x: labelStyle.x,
-              y: labelStyle.y,
-              align: labelStyle.align,
-              verticalAlign: labelStyle.verticalAlign,
-              width: labelStyle.width,
-              height: labelStyle.height,
-              fontSize: labelStyle.fontSize
-            },
-            cursor: label.cursor,
-            attachedPos: textConfig.position,
-            attachedRot: textConfig.rotation
-          }
-        });
-      };
-
-      LabelManager.prototype.addLabelsOfSeries = function (chartView) {
-        var _this = this;
-
-        this._chartViewList.push(chartView);
-
-        var seriesModel = chartView.__model;
-        var layoutOption = seriesModel.get('labelLayout');
-        /**
-         * Ignore layouting if it's not specified anything.
-         */
+        var symbolType = seriesModel.get('symbol');
+        var symbolSize = seriesModel.get('symbolSize');
+        var keepAspect = seriesModel.get('symbolKeepAspect');
+        var symbolRotate = seriesModel.get('symbolRotate');
+        var symbolOffset = seriesModel.get('symbolOffset');
+        var hasSymbolTypeCallback = isFunction(symbolType);
+        var hasSymbolSizeCallback = isFunction(symbolSize);
+        var hasSymbolRotateCallback = isFunction(symbolRotate);
+        var hasSymbolOffsetCallback = isFunction(symbolOffset);
+        var hasCallback = hasSymbolTypeCallback || hasSymbolSizeCallback || hasSymbolRotateCallback || hasSymbolOffsetCallback;
+        var seriesSymbol = !hasSymbolTypeCallback && symbolType ? symbolType : seriesModel.defaultSymbol;
+        var seriesSymbolSize = !hasSymbolSizeCallback ? symbolSize : null;
+        var seriesSymbolRotate = !hasSymbolRotateCallback ? symbolRotate : null;
+        var seriesSymbolOffset = !hasSymbolOffsetCallback ? symbolOffset : null;
+        data.setVisual({
+          legendIcon: seriesModel.legendIcon || seriesSymbol,
+          // If seting callback functions on `symbol` or `symbolSize`, for simplicity and avoiding
+          // to bring trouble, we do not pick a reuslt from one of its calling on data item here,
+          // but just use the default value. Callback on `symbol` or `symbolSize` is convenient in
+          // some cases but generally it is not recommanded.
+          symbol: seriesSymbol,
+          symbolSize: seriesSymbolSize,
+          symbolKeepAspect: keepAspect,
+          symbolRotate: seriesSymbolRotate,
+          symbolOffset: seriesSymbolOffset
+        }); // Only visible series has each data be visual encoded
 
-        if (!(isFunction(layoutOption) || keys(layoutOption).length)) {
+        if (ecModel.isSeriesFiltered(seriesModel)) {
           return;
         }
 
-        chartView.group.traverse(function (child) {
-          if (child.ignore) {
-            return true; // Stop traverse descendants.
-          } // Only support label being hosted on graphic elements.
-
-
-          var textEl = child.getTextContent();
-          var ecData = getECData(child); // Can only attach the text on the element with dataIndex
+        function dataEach(data, idx) {
+          var rawValue = seriesModel.getRawValue(idx);
+          var params = seriesModel.getDataParams(idx);
+          hasSymbolTypeCallback && data.setItemVisual(idx, 'symbol', symbolType(rawValue, params));
+          hasSymbolSizeCallback && data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));
+          hasSymbolRotateCallback && data.setItemVisual(idx, 'symbolRotate', symbolRotate(rawValue, params));
+          hasSymbolOffsetCallback && data.setItemVisual(idx, 'symbolOffset', symbolOffset(rawValue, params));
+        }
 
-          if (textEl && !textEl.disableLabelLayout) {
-            _this._addLabel(ecData.dataIndex, ecData.dataType, seriesModel, textEl, layoutOption);
-          }
-        });
-      };
+        return {
+          dataEach: hasCallback ? dataEach : null
+        };
+      }
+    };
+    var dataSymbolTask = {
+      createOnAllSeries: true,
+      // For legend.
+      performRawSeries: true,
+      reset: function (seriesModel, ecModel) {
+        if (!seriesModel.hasSymbolVisual) {
+          return;
+        } // Only visible series has each data be visual encoded
 
-      LabelManager.prototype.updateLayoutConfig = function (api) {
-        var width = api.getWidth();
-        var height = api.getHeight();
 
-        function createDragHandler(el, labelLineModel) {
-          return function () {
-            updateLabelLinePoints(el, labelLineModel);
-          };
+        if (ecModel.isSeriesFiltered(seriesModel)) {
+          return;
         }
 
-        for (var i = 0; i < this._labelList.length; i++) {
-          var labelItem = this._labelList[i];
-          var label = labelItem.label;
-          var hostEl = label.__hostTarget;
-          var defaultLabelAttr = labelItem.defaultAttr;
-          var layoutOption = void 0; // TODO A global layout option?
-
-          if (typeof labelItem.layoutOption === 'function') {
-            layoutOption = labelItem.layoutOption(prepareLayoutCallbackParams(labelItem, hostEl));
-          } else {
-            layoutOption = labelItem.layoutOption;
-          }
-
-          layoutOption = layoutOption || {};
-          labelItem.computedLayoutOption = layoutOption;
-          var degreeToRadian = Math.PI / 180; // TODO hostEl should always exists.
-          // Or label should not have parent because the x, y is all in global space.
-
-          if (hostEl) {
-            hostEl.setTextConfig({
-              // Force to set local false.
-              local: false,
-              // Ignore position and rotation config on the host el if x or y is changed.
-              position: layoutOption.x != null || layoutOption.y != null ? null : defaultLabelAttr.attachedPos,
-              // Ignore rotation config on the host el if rotation is changed.
-              rotation: layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.attachedRot,
-              offset: [layoutOption.dx || 0, layoutOption.dy || 0]
-            });
-          }
-
-          var needsUpdateLabelLine = false;
+        var data = seriesModel.getData();
 
-          if (layoutOption.x != null) {
-            // TODO width of chart view.
-            label.x = parsePercent$1(layoutOption.x, width);
-            label.setStyle('x', 0); // Ignore movement in style. TODO: origin.
+        function dataEach(data, idx) {
+          var itemModel = data.getItemModel(idx);
+          var itemSymbolType = itemModel.getShallow('symbol', true);
+          var itemSymbolSize = itemModel.getShallow('symbolSize', true);
+          var itemSymbolRotate = itemModel.getShallow('symbolRotate', true);
+          var itemSymbolOffset = itemModel.getShallow('symbolOffset', true);
+          var itemSymbolKeepAspect = itemModel.getShallow('symbolKeepAspect', true); // If has item symbol
 
-            needsUpdateLabelLine = true;
-          } else {
-            label.x = defaultLabelAttr.x;
-            label.setStyle('x', defaultLabelAttr.style.x);
+          if (itemSymbolType != null) {
+            data.setItemVisual(idx, 'symbol', itemSymbolType);
           }
 
-          if (layoutOption.y != null) {
-            // TODO height of chart view.
-            label.y = parsePercent$1(layoutOption.y, height);
-            label.setStyle('y', 0); // Ignore movement in style.
-
-            needsUpdateLabelLine = true;
-          } else {
-            label.y = defaultLabelAttr.y;
-            label.setStyle('y', defaultLabelAttr.style.y);
+          if (itemSymbolSize != null) {
+            // PENDING Transform symbolSize ?
+            data.setItemVisual(idx, 'symbolSize', itemSymbolSize);
           }
 
-          if (layoutOption.labelLinePoints) {
-            var guideLine = hostEl.getTextGuideLine();
-
-            if (guideLine) {
-              guideLine.setShape({
-                points: layoutOption.labelLinePoints
-              }); // Not update
-
-              needsUpdateLabelLine = false;
-            }
+          if (itemSymbolRotate != null) {
+            data.setItemVisual(idx, 'symbolRotate', itemSymbolRotate);
           }
 
-          var labelLayoutStore = labelLayoutInnerStore(label);
-          labelLayoutStore.needsUpdateLabelLine = needsUpdateLabelLine;
-          label.rotation = layoutOption.rotate != null ? layoutOption.rotate * degreeToRadian : defaultLabelAttr.rotation;
-          label.scaleX = defaultLabelAttr.scaleX;
-          label.scaleY = defaultLabelAttr.scaleY;
-
-          for (var k = 0; k < LABEL_OPTION_TO_STYLE_KEYS.length; k++) {
-            var key = LABEL_OPTION_TO_STYLE_KEYS[k];
-            label.setStyle(key, layoutOption[key] != null ? layoutOption[key] : defaultLabelAttr.style[key]);
+          if (itemSymbolOffset != null) {
+            data.setItemVisual(idx, 'symbolOffset', itemSymbolOffset);
           }
 
-          if (layoutOption.draggable) {
-            label.draggable = true;
-            label.cursor = 'move';
-
-            if (hostEl) {
-              var hostModel = labelItem.seriesModel;
-
-              if (labelItem.dataIndex != null) {
-                var data = labelItem.seriesModel.getData(labelItem.dataType);
-                hostModel = data.getItemModel(labelItem.dataIndex);
-              }
-
-              label.on('drag', createDragHandler(hostEl, hostModel.getModel('labelLine')));
-            }
-          } else {
-            // TODO Other drag functions?
-            label.off('drag');
-            label.cursor = defaultLabelAttr.cursor;
+          if (itemSymbolKeepAspect != null) {
+            data.setItemVisual(idx, 'symbolKeepAspect', itemSymbolKeepAspect);
           }
         }
-      };
-
-      LabelManager.prototype.layout = function (api) {
-        var width = api.getWidth();
-        var height = api.getHeight();
-        var labelList = prepareLayoutList(this._labelList);
-        var labelsNeedsAdjustOnX = filter(labelList, function (item) {
-          return item.layoutOption.moveOverlap === 'shiftX';
-        });
-        var labelsNeedsAdjustOnY = filter(labelList, function (item) {
-          return item.layoutOption.moveOverlap === 'shiftY';
-        });
-        shiftLayoutOnX(labelsNeedsAdjustOnX, 0, width);
-        shiftLayoutOnY(labelsNeedsAdjustOnY, 0, height);
-        var labelsNeedsHideOverlap = filter(labelList, function (item) {
-          return item.layoutOption.hideOverlap;
-        });
-        hideOverlap(labelsNeedsHideOverlap);
-      };
-      /**
-       * Process all labels. Not only labels with layoutOption.
-       */
-
-
-      LabelManager.prototype.processLabelsOverall = function () {
-        var _this = this;
-
-        each(this._chartViewList, function (chartView) {
-          var seriesModel = chartView.__model;
-          var ignoreLabelLineUpdate = chartView.ignoreLabelLineUpdate;
-          var animationEnabled = seriesModel.isAnimationEnabled();
-          chartView.group.traverse(function (child) {
-            if (child.ignore) {
-              return true; // Stop traverse descendants.
-            }
-
-            var needsUpdateLabelLine = !ignoreLabelLineUpdate;
-            var label = child.getTextContent();
 
-            if (!needsUpdateLabelLine && label) {
-              needsUpdateLabelLine = labelLayoutInnerStore(label).needsUpdateLabelLine;
-            }
-
-            if (needsUpdateLabelLine) {
-              _this._updateLabelLine(child, seriesModel);
-            }
-
-            if (animationEnabled) {
-              _this._animateLabels(child, seriesModel);
-            }
-          });
-        });
-      };
-
-      LabelManager.prototype._updateLabelLine = function (el, seriesModel) {
-        // Only support label being hosted on graphic elements.
-        var textEl = el.getTextContent(); // Update label line style.
-
-        var ecData = getECData(el);
-        var dataIndex = ecData.dataIndex; // Only support labelLine on the labels represent data.
-
-        if (textEl && dataIndex != null) {
-          var data = seriesModel.getData(ecData.dataType);
-          var itemModel = data.getItemModel(dataIndex);
-          var defaultStyle = {};
-          var visualStyle = data.getItemVisual(dataIndex, 'style');
-          var visualType = data.getVisual('drawType'); // Default to be same with main color
-
-          defaultStyle.stroke = visualStyle[visualType];
-          var labelLineModel = itemModel.getModel('labelLine');
-          setLabelLineStyle(el, getLabelLineStatesModels(itemModel), defaultStyle);
-          updateLabelLinePoints(el, labelLineModel);
-        }
-      };
-
-      LabelManager.prototype._animateLabels = function (el, seriesModel) {
-        var textEl = el.getTextContent();
-        var guideLine = el.getTextGuideLine(); // Animate
-
-        if (textEl && !textEl.ignore && !textEl.invisible && !el.disableLabelAnimation && !isElementRemoved(el)) {
-          var layoutStore = labelLayoutInnerStore(textEl);
-          var oldLayout = layoutStore.oldLayout;
-          var ecData = getECData(el);
-          var dataIndex = ecData.dataIndex;
-          var newProps = {
-            x: textEl.x,
-            y: textEl.y,
-            rotation: textEl.rotation
-          };
-          var data = seriesModel.getData(ecData.dataType);
-
-          if (!oldLayout) {
-            textEl.attr(newProps); // Disable fade in animation if value animation is enabled.
-
-            if (!labelInner(textEl).valueAnimation) {
-              var oldOpacity = retrieve2(textEl.style.opacity, 1); // Fade in animation
+        return {
+          dataEach: data.hasItemOption ? dataEach : null
+        };
+      }
+    };
 
-              textEl.style.opacity = 0;
-              initProps(textEl, {
-                style: {
-                  opacity: oldOpacity
-                }
-              }, seriesModel, dataIndex);
-            }
-          } else {
-            textEl.attr(oldLayout); // Make sure the animation from is in the right status.
+    /*
+    * Licensed to the Apache Software Foundation (ASF) under one
+    * or more contributor license agreements.  See the NOTICE file
+    * distributed with this work for additional information
+    * regarding copyright ownership.  The ASF licenses this file
+    * to you under the Apache License, Version 2.0 (the
+    * "License"); you may not use this file except in compliance
+    * with the License.  You may obtain a copy of the License at
+    *
+    *   http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing,
+    * software distributed under the License is distributed on an
+    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    * KIND, either express or implied.  See the License for the
+    * specific language governing permissions and limitations
+    * under the License.
+    */
 
-            var prevStates = el.prevStates;
 
-            if (prevStates) {
-              if (indexOf(prevStates, 'select') >= 0) {
-                textEl.attr(layoutStore.oldLayoutSelect);
-              }
+    /**
+     * AUTO-GENERATED FILE. DO NOT MODIFY.
+     */
 
-              if (indexOf(prevStates, 'emphasis') >= 0) {
-                textEl.attr(layoutStore.oldLayoutEmphasis);
-              }
-            }
+    /*
+    * Licensed to the Apache Software Foundation (ASF) under one
+    * or more contributor license agreements.  See the NOTICE file
+    * distributed with this work for additional information
+    * regarding copyright ownership.  The ASF licenses this file
+    * to you under the Apache License, Version 2.0 (the
+    * "License"); you may not use this file except in compliance
+    * with the License.  You may obtain a copy of the License at
+    *
+    *   http://www.apache.org/licenses/LICENSE-2.0
+    *
+    * Unless required by applicable law or agreed to in writing,
+    * software distributed under the License is distributed on an
+    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    * KIND, either express or implied.  See the License for the
+    * specific language governing permissions and limitations
+    * under the License.
+    */
+    function getItemVisualFromData(data, dataIndex, key) {
+      switch (key) {
+        case 'color':
+          var style = data.getItemVisual(dataIndex, 'style');
+          return style[data.getVisual('drawType')];
 
-            updateProps(textEl, newProps, seriesModel, dataIndex);
-          }
+        case 'opacity':
+          return data.getItemVisual(dataIndex, 'style').opacity;
 
-          layoutStore.oldLayout = newProps;
+        case 'symbol':
+        case 'symbolSize':
+        case 'liftZ':
+          return data.getItemVisual(dataIndex, key);
 
-          if (textEl.states.select) {
-            var layoutSelect = layoutStore.oldLayoutSelect = {};
-            extendWithKeys(layoutSelect, newProps, LABEL_LAYOUT_PROPS);
-            extendWithKeys(layoutSelect, textEl.states.select, LABEL_LAYOUT_PROPS);
+        default:
+          if ("development" !== 'production') {
+            console.warn("Unknown visual type " + key);
           }
 
-          if (textEl.states.emphasis) {
-            var layoutEmphasis = layoutStore.oldLayoutEmphasis = {};
-            extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS);
-            extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS);
-          }
+      }
+    }
+    function getVisualFromData(data, key) {
+      switch (key) {
+        case 'color':
+          var style = data.getVisual('style');
+          return style[data.getVisual('drawType')];
 
-          animateLabelValue(textEl, dataIndex, data, seriesModel, seriesModel);
-        }
+        case 'opacity':
+          return data.getVisual('style').opacity;
 
-        if (guideLine && !guideLine.ignore && !guideLine.invisible) {
-          var layoutStore = labelLineAnimationStore(guideLine);
-          var oldLayout = layoutStore.oldLayout;
-          var newLayout = {
-            points: guideLine.shape.points
-          };
+        case 'symbol':
+        case 'symbolSize':
+        case 'liftZ':
+          return data.getVisual(key);
 
-          if (!oldLayout) {
-            guideLine.setShape(newLayout);
-            guideLine.style.strokePercent = 0;
-            initProps(guideLine, {
-              style: {
-                strokePercent: 1
-              }
-            }, seriesModel);
-          } else {
-            guideLine.attr({
-              shape: oldLayout
-            });
-            updateProps(guideLine, {
-              shape: newLayout
-            }, seriesModel);
+        default:
+          if ("development" !== 'production') {
+            console.warn("Unknown visual type " + key);
           }
 
-          layoutStore.oldLayout = newLayout;
-        }
-      };
-
-      return LabelManager;
-    }();
+      }
+    }
 
     // Inlucdes: pieSelect, pieUnSelect, pieToggleSelect, mapSelect, mapUnSelect, mapToggleSelect
 
@@ -25969,6 +25975,7 @@
     }
 
     var wmUniqueIndex = Math.round(Math.random() * 9);
+    var supportDefineProperty = typeof Object.defineProperty === 'function';
     var WeakMap = (function () {
         function WeakMap() {
             this._id = '__ec_inner_' + wmUniqueIndex++;
@@ -25978,7 +25985,7 @@
         };
         WeakMap.prototype.set = function (key, value) {
             var target = this._guard(key);
-            if (typeof Object.defineProperty === 'function') {
+            if (supportDefineProperty) {
                 Object.defineProperty(target, this._id, {
                     value: value,
                     enumerable: false,
@@ -26298,6 +26305,24 @@
 
       return symbolPath;
     }
+    function normalizeSymbolSize(symbolSize) {
+      if (!isArray(symbolSize)) {
+        symbolSize = [+symbolSize, +symbolSize];
+      }
+
+      return [symbolSize[0] || 0, symbolSize[1] || 0];
+    }
+    function normalizeSymbolOffset(symbolOffset, symbolSize) {
+      if (symbolOffset == null) {
+        return;
+      }
+
+      if (!isArray(symbolOffset)) {
+        symbolOffset = [symbolOffset, symbolOffset];
+      }
+
+      return [parsePercent$1(symbolOffset[0], symbolSize[0]) || 0, parsePercent$1(retrieve2(symbolOffset[1], symbolOffset[0]), symbolSize[1]) || 0];
+    }
 
     function createLinearGradient(ctx, obj, rect) {
         var x = obj.x == null ? 0 : obj.x;
@@ -26375,6 +26400,9 @@
         var stroke = style.stroke;
         return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0));
     }
+    function isValidStrokeFillStyle(strokeOrFill) {
+        return typeof strokeOrFill === 'string' && strokeOrFill !== 'none';
+    }
     function styleHasFill(style) {
         var fill = style.fill;
         return fill != null && fill !== 'none';
@@ -26692,14 +26720,14 @@
                 flushPathDrawn(ctx, scope);
                 styleChanged = true;
             }
-            ctx.fillStyle = style.fill;
+            isValidStrokeFillStyle(style.fill) && (ctx.fillStyle = style.fill);
         }
         if (forceSetAll || style.stroke !== prevStyle.stroke) {
             if (!styleChanged) {
                 flushPathDrawn(ctx, scope);
                 styleChanged = true;
             }
-            ctx.strokeStyle = style.stroke;
+            isValidStrokeFillStyle(style.stroke) && (ctx.strokeStyle = style.stroke);
         }
         if (forceSetAll || style.opacity !== prevStyle.opacity) {
             if (!styleChanged) {
@@ -29070,15 +29098,12 @@
       }
     };
 
-    var assert$1 = assert;
-    var each$3 = each;
-    var isFunction$1 = isFunction;
-    var isObject$2 = isObject;
-    var indexOf$1 = indexOf;
+    var lifecycle = new Eventful();
+
     var hasWindow = typeof window !== 'undefined';
-    var version$1 = '5.1.2';
+    var version$1 = '5.2.0';
     var dependencies = {
-      zrender: '5.1.1'
+      zrender: '5.2.0'
     };
     var TEST_FRAME_REMAIN_TIME = 1;
     var PRIORITY_PROCESSOR_SERIES_FILTER = 800; // Some data processors depends on the stack result dimension (to calculate data extent).
@@ -29130,7 +29155,7 @@
     // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).
 
     var IN_MAIN_PROCESS_KEY = '__flagInMainProcess';
-    var OPTION_UPDATED_KEY = '__optionUpdated';
+    var PENDING_UPDATE = '__pendingUpdate';
     var STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus';
     var ACTION_REG = /^[a-zA-Z0-9_]+$/;
     var CONNECT_STATUS_KEY = '__connectUpdateStatus';
@@ -29206,10 +29231,8 @@
     var render;
     var renderComponents;
     var renderSeries;
-    var performPostUpdateFuncs;
     var createExtensionAPI;
     var enableConnect;
-    var setTransitionOpt;
     var markStatusToUpdate;
     var applyChangedStates;
 
@@ -29270,8 +29293,7 @@
         sort(visualFuncs, prioritySortFunc);
         sort(dataProcessorFuncs, prioritySortFunc);
         _this._scheduler = new Scheduler(_this, api, dataProcessorFuncs, visualFuncs);
-        _this._messageCenter = new MessageCenter();
-        _this._labelManager = new LabelManager(); // Init mouse events
+        _this._messageCenter = new MessageCenter(); // Init mouse events
 
         _this._initEvents(); // In case some people write `window.onresize = chart.resize`
 
@@ -29293,11 +29315,11 @@
         applyChangedStates(this);
         var scheduler = this._scheduler; // Lazy update
 
-        if (this[OPTION_UPDATED_KEY]) {
-          var silent = this[OPTION_UPDATED_KEY].silent;
+        if (this[PENDING_UPDATE]) {
+          var silent = this[PENDING_UPDATE].silent;
           this[IN_MAIN_PROCESS_KEY] = true;
           prepare(this);
-          updateMethods.update.call(this); // At present, in each frame, zrender performs:
+          updateMethods.update.call(this, null, this[PENDING_UPDATE].updateParams); // At present, in each frame, zrender performs:
           //   (1) animation step forward.
           //   (2) trigger('frame') (where this `_onframe` is called)
           //   (3) zrender flush (render).
@@ -29307,7 +29329,7 @@
           this._zr.flush();
 
           this[IN_MAIN_PROCESS_KEY] = false;
-          this[OPTION_UPDATED_KEY] = false;
+          this[PENDING_UPDATE] = null;
           flushPendingActions.call(this, silent);
           triggerUpdatedEvent.call(this, silent);
         } // Avoid do both lazy update and progress in one frame.
@@ -29331,7 +29353,7 @@
               // console.log('--- ec frame visual ---', remainTime);
 
               scheduler.performVisualTasks(ecModel);
-              renderSeries(this, this._model, api, 'remain');
+              renderSeries(this, this._model, api, 'remain', {});
               remainTime -= +new Date() - startTime;
             } while (remainTime > 0 && scheduler.unfinished); // Call flush explicitly for trigger finished event.
 
@@ -29360,7 +29382,7 @@
 
       ECharts.prototype.setOption = function (option, notMerge, lazyUpdate) {
         if ("development" !== 'production') {
-          assert$1(!this[IN_MAIN_PROCESS_KEY], '`setOption` should not be called during main process.');
+          assert(!this[IN_MAIN_PROCESS_KEY], '`setOption` should not be called during main process.');
         }
 
         if (this._disposed) {
@@ -29372,7 +29394,7 @@
         var replaceMerge;
         var transitionOpt;
 
-        if (isObject$2(notMerge)) {
+        if (isObject(notMerge)) {
           lazyUpdate = notMerge.lazyUpdate;
           silent = notMerge.silent;
           replaceMerge = notMerge.replaceMerge;
@@ -29394,11 +29416,15 @@
           replaceMerge: replaceMerge
         }, optionPreprocessorFuncs);
 
-        setTransitionOpt(this, transitionOpt);
+        var updateParams = {
+          seriesTransition: transitionOpt,
+          optionChanged: true
+        };
 
         if (lazyUpdate) {
-          this[OPTION_UPDATED_KEY] = {
-            silent: silent
+          this[PENDING_UPDATE] = {
+            silent: silent,
+            updateParams: updateParams
           };
           this[IN_MAIN_PROCESS_KEY] = false; // `setOption(option, {lazyMode: true})` may be called when zrender has been slept.
           // It should wake it up to make sure zrender start to render at the next frame.
@@ -29406,12 +29432,12 @@
           this.getZr().wakeUp();
         } else {
           prepare(this);
-          updateMethods.update.call(this); // Ensure zr refresh sychronously, and then pixel in canvas can be
+          updateMethods.update.call(this, null, updateParams); // Ensure zr refresh sychronously, and then pixel in canvas can be
           // fetched after `setOption`.
 
           this._zr.flush();
 
-          this[OPTION_UPDATED_KEY] = false;
+          this[PENDING_UPDATE] = null;
           this[IN_MAIN_PROCESS_KEY] = false;
           flushPendingActions.call(this, silent);
           triggerUpdatedEvent.call(this, silent);
@@ -29494,7 +29520,7 @@
         var ecModel = this._model;
         var excludesComponentViews = [];
         var self = this;
-        each$3(excludeComponents, function (componentType) {
+        each(excludeComponents, function (componentType) {
           ecModel.eachComponent({
             mainType: componentType
           }, function (component) {
@@ -29507,7 +29533,7 @@
           });
         });
         var url = this._zr.painter.getType() === 'svg' ? this.getSvgDataURL() : this.getRenderedCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png'));
-        each$3(excludesComponentViews, function (view) {
+        each(excludesComponentViews, function (view) {
           view.group.ignore = false;
         });
         return url;
@@ -29568,7 +29594,7 @@
 
           if (isSvg) {
             var content_1 = '';
-            each$3(canvasList_1, function (item) {
+            each(canvasList_1, function (item) {
               var x = item.left - left_1;
               var y = item.top - top_1;
               content_1 += '<g transform="translate(' + x + ',' + y + ')">' + item.dom + '</g>';
@@ -29597,7 +29623,7 @@
               }));
             }
 
-            each$3(canvasList_1, function (item) {
+            each(canvasList_1, function (item) {
               var img = new ZRImage({
                 style: {
                   x: item.left * dpr_1 - left_1,
@@ -29717,7 +29743,7 @@
       ECharts.prototype._initEvents = function () {
         var _this = this;
 
-        each$3(MOUSE_EVENT_NAMES, function (eveName) {
+        each(MOUSE_EVENT_NAMES, function (eveName) {
           var handler = function (e) {
             var ecModel = _this.getModel();
 
@@ -29797,14 +29823,14 @@
 
           _this._zr.on(eveName, handler, _this);
         });
-        each$3(eventActionMap, function (actionType, eventType) {
+        each(eventActionMap, function (actionType, eventType) {
           _this._messageCenter.on(eventType, function (event) {
             this.trigger(eventType, event);
           }, _this);
         }); // Extra events
         // TODO register?
 
-        each$3(['selectchanged'], function (eventType) {
+        each(['selectchanged'], function (eventType) {
           _this._messageCenter.on(eventType, function (event) {
             this.trigger(eventType, event);
           }, _this);
@@ -29835,18 +29861,22 @@
 
         this._disposed = true;
         setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');
-        var api = this._api;
-        var ecModel = this._model;
-        each$3(this._componentsViews, function (component) {
+        var chart = this;
+        var api = chart._api;
+        var ecModel = chart._model;
+        each(chart._componentsViews, function (component) {
           component.dispose(ecModel, api);
         });
-        each$3(this._chartsViews, function (chart) {
+        each(chart._chartsViews, function (chart) {
           chart.dispose(ecModel, api);
         }); // Dispose after all views disposed
 
-        this._zr.dispose();
+        chart._zr.dispose(); // Set properties to null.
+        // To reduce the memory cost in case the top code still holds this instance unexpectedly.
 
-        delete instances$1[this.id];
+
+        chart._dom = chart._model = chart._chartsMap = chart._componentsMap = chart._chartsViews = chart._componentsViews = chart._scheduler = chart._api = chart._zr = chart._throttledZrFlush = chart._theme = chart._coordSysMgr = chart._messageCenter = null;
+        delete instances$1[chart.id];
       };
       /**
        * Resize the chart
@@ -29855,7 +29885,7 @@
 
       ECharts.prototype.resize = function (opts) {
         if ("development" !== 'production') {
-          assert$1(!this[IN_MAIN_PROCESS_KEY], '`resize` should not be called during main process.');
+          assert(!this[IN_MAIN_PROCESS_KEY], '`resize` should not be called during main process.');
         }
 
         if (this._disposed) {
@@ -29878,13 +29908,13 @@
         // chart.setOption(option, { lazyUpdate: true });
         // chart.resize();
 
-        if (this[OPTION_UPDATED_KEY]) {
+        if (this[PENDING_UPDATE]) {
           if (silent == null) {
-            silent = this[OPTION_UPDATED_KEY].silent;
+            silent = this[PENDING_UPDATE].silent;
           }
 
           needPrepare = true;
-          this[OPTION_UPDATED_KEY] = false;
+          this[PENDING_UPDATE] = null;
         }
 
         this[IN_MAIN_PROCESS_KEY] = true;
@@ -29907,7 +29937,7 @@
           return;
         }
 
-        if (isObject$2(name)) {
+        if (isObject(name)) {
           cfg = name;
           name = '';
         }
@@ -29965,7 +29995,7 @@
           return;
         }
 
-        if (!isObject$2(opt)) {
+        if (!isObject(opt)) {
           opt = {
             silent: !!opt
           };
@@ -30007,10 +30037,11 @@
       };
 
       ECharts.prototype.updateLabelLayout = function () {
-        var labelManager = this._labelManager;
-        labelManager.updateLayoutConfig(this._api);
-        labelManager.layout(this._api);
-        labelManager.processLabelsOverall();
+        lifecycle.trigger('series:layoutlabels', this._model, this._api, {
+          // Not adding series labels.
+          // TODO
+          updatedSeries: []
+        });
       };
 
       ECharts.prototype.appendData = function (params) {
@@ -30024,7 +30055,7 @@
         var seriesModel = ecModel.getSeriesByIndex(seriesIndex);
 
         if ("development" !== 'production') {
-          assert$1(params.data && seriesModel);
+          assert(params.data && seriesModel);
         }
 
         seriesModel.appendData(params); // Note: `appendData` does not support that update extent of coordinate
@@ -30095,7 +30126,7 @@
               ChartView.getClass(classType.sub);
 
               if ("development" !== 'production') {
-                assert$1(Clazz, classType.sub + ' does not exist.');
+                assert(Clazz, classType.sub + ' does not exist.');
               }
 
               view = new Clazz();
@@ -30143,7 +30174,7 @@
             // FIXME
             // Chart will not be update directly here, except set dirty.
             // But there is no such scenario now.
-            each$3([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView);
+            each([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView);
             return;
           }
 
@@ -30162,7 +30193,7 @@
 
           if (excludeSeriesId != null) {
             excludeSeriesIdMap = createHashMap();
-            each$3(normalizeToArray(excludeSeriesId), function (id) {
+            each(normalizeToArray(excludeSeriesId), function (id) {
               var modelId = convertOptionIdName(id, null);
 
               if (modelId != null) {
@@ -30177,42 +30208,52 @@
 
 
           ecModel && ecModel.eachComponent(condition, function (model) {
-            if (!excludeSeriesIdMap || excludeSeriesIdMap.get(model.id) == null) {
-              if (isHighDownPayload(payload)) {
-                if (model instanceof SeriesModel) {
-                  if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur) {
-                    blurSeriesFromHighlightPayload(model, payload, ecIns._api);
-                  }
-                } else {
-                  var _a = findComponentHighDownDispatchers(model.mainType, model.componentIndex, payload.name, ecIns._api),
-                      focusSelf = _a.focusSelf,
-                      dispatchers = _a.dispatchers;
-
-                  if (payload.type === HIGHLIGHT_ACTION_TYPE && focusSelf && !payload.notBlur) {
-                    blurComponent(model.mainType, model.componentIndex, ecIns._api);
-                  } // PENDING:
-                  // Whether to put this "enter emphasis" code in `ComponentView`,
-                  // which will be the same as `ChartView` but might be not necessary
-                  // and will be far from this logic.
+            var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) !== null;
 
+            if (isExcluded) {
+              return;
+            }
 
-                  if (dispatchers) {
-                    each$3(dispatchers, function (dispatcher) {
-                      payload.type === HIGHLIGHT_ACTION_TYPE ? enterEmphasis(dispatcher) : leaveEmphasis(dispatcher);
-                    });
-                  }
+            if (isHighDownPayload(payload)) {
+              if (model instanceof SeriesModel) {
+                if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur) {
+                  blurSeriesFromHighlightPayload(model, payload, ecIns._api);
                 }
-              } else if (isSelectChangePayload(payload)) {
-                // TODO geo
-                if (model instanceof SeriesModel) {
-                  toggleSelectionFromPayload(model, payload, ecIns._api);
-                  updateSeriesElementSelection(model);
-                  markStatusToUpdate(ecIns);
+              } else {
+                var _a = findComponentHighDownDispatchers(model.mainType, model.componentIndex, payload.name, ecIns._api),
+                    focusSelf = _a.focusSelf,
+                    dispatchers = _a.dispatchers;
+
+                if (payload.type === HIGHLIGHT_ACTION_TYPE && focusSelf && !payload.notBlur) {
+                  blurComponent(model.mainType, model.componentIndex, ecIns._api);
+                } // PENDING:
... 108430 lines suppressed ...

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