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:40 UTC

[echarts] 01/01: release 5.2.0

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