From 4b774f04653a89513bc8f847920529c08507f564 Mon Sep 17 00:00:00 2001
From: Tevin <tingquanren@163.com>
Date: Fri, 26 Aug 2022 16:13:55 +0800
Subject: [PATCH] Merge branch 'master' of ssh://dev.zhiheiot.com:29418/mob-components

---
 plugins/echarts/cECharts.scss      |   14 
 common/Tools.js                    |   23 
 layout/loading/CLoading.vue        |    5 
 plugins/echarts/index.js           |   10 
 plugins/echarts/wxCanvas.js        |  111 
 layout/numerical/index.js          |   10 
 layout/numerical/cNumerical.scss   |   26 
 plugins/echarts/echarts.js         | 61116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 layout/numerical/CNumerical.vue    |   74 
 plugins/echarts/CECharts.weapp.vue |  208 
 10 files changed, 61,591 insertions(+), 6 deletions(-)

diff --git a/common/Tools.js b/common/Tools.js
index 6f082fc..b2775cd 100644
--- a/common/Tools.js
+++ b/common/Tools.js
@@ -517,11 +517,28 @@
     }
 
     /**
+     * 转换周数到日期
+     * @param year
+     * @param week
+     * @param weekDay 需要输出星期几对应的日期 (1~7)
+     * @return {Date}
+     */
+    static transWeekIndexToDate(year, week, weekDay) {
+        const yearStart = moment([year, 0, 1]);
+        const dayLong = 24 * 60 * 60 * 1000;
+        const firstWeekLong = (7 - yearStart.day()) * dayLong;
+        const weeksLong = (week - 1) * 7 * dayLong;
+        const weekDayLong = weekDay * dayLong;
+        const dayTimestamp = yearStart.valueOf() + firstWeekLong + weeksLong + weekDayLong;
+        return moment(dayTimestamp).format('YYYY-MM-DD');
+    }
+
+    /**
      * 显示调试面板(仅支持H5)
      * @param cssSelector
      * @param callback
      */
-    static showDevConsole(cssSelector, callback) {
+    static $_showDevConsole(cssSelector, callback) {
         // 只支持 h5 编译
         if (process.env.TARO_ENV !== 'h5') {
             return;
@@ -575,4 +592,6 @@
         const px = (value - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
         console.info(Math.round(px) + 'px');
     };
-}
\ No newline at end of file
+}
+
+global.Tools = Tools;
\ No newline at end of file
diff --git a/layout/loading/CLoading.vue b/layout/loading/CLoading.vue
index 53263da..a77eec2 100644
--- a/layout/loading/CLoading.vue
+++ b/layout/loading/CLoading.vue
@@ -4,10 +4,7 @@
  */
 
 <template>
-    <view
-        class="c-loading"
-        @tap="evt => handleGoTo()"
-    >
+    <view class="c-loading">
         <AtActivityIndicator
             :isOpened="show"
             mode="center"
diff --git a/layout/numerical/CNumerical.vue b/layout/numerical/CNumerical.vue
new file mode 100644
index 0000000..04cdbfd
--- /dev/null
+++ b/layout/numerical/CNumerical.vue
@@ -0,0 +1,74 @@
+/**
+ * CNumerical - 数值显示
+ * @author Tevin
+ */
+
+<template>
+    <view class="c-numerical at-row at-row--wrap">
+        <view
+            class="at-col"
+            v-for="(item,index) in values2"
+            :key="index"
+            :class="'at-col-' + valueFlex[index]"
+        >
+            <view class="c-numerical-value">
+                <text>{{item.integer}}</text>
+                <text
+                    class="c-numerical-decimal"
+                    :class="item.integer.length>6?'small':''"
+                    v-if="item.decimal.length>0"
+                >.{{item.decimal}}</text>
+            </view>
+            <view class="c-numerical-title">{{item.title}}</view>
+        </view>
+    </view>
+</template>
+
+<script>
+import Taro from '@tarojs/taro';
+import {} from 'taro-ui-vue';
+import './cNumerical.scss';
+
+export default {
+    name: 'CNumerical',
+    components: {},
+    props: {
+        values: Array,
+    },
+    computed: {
+        values2() {
+            return (
+                this.values.map(item => ({
+                    ...item,
+                    integer: (item.value + '').split('.')[0] || '',
+                    decimal: (item.value + '').split('.')[1] || '',
+                })) || []
+            );
+        },
+        valueFlex() {
+            return this.values.map((item, index) => {
+                const surplus = this.values.length % 3;
+                if (surplus === 0) {
+                    return 4;
+                } else if (surplus === 1) {
+                    if (index === this.values.length - 1) {
+                        return 12;
+                    } else {
+                        return 4;
+                    }
+                } else if (surplus === 2) {
+                    if (index >= this.values.length - 2) {
+                        return 6;
+                    } else {
+                        return 4;
+                    }
+                }
+            });
+        },
+    },
+    data() {
+        return {};
+    },
+    methods: {},
+};
+</script>
diff --git a/layout/numerical/cNumerical.scss b/layout/numerical/cNumerical.scss
new file mode 100644
index 0000000..f3802e1
--- /dev/null
+++ b/layout/numerical/cNumerical.scss
@@ -0,0 +1,26 @@
+/**
+ * CNumerical - 数值显示
+ * @author Tevin
+ */
+
+@import "../../common/sassMixin";
+
+.c-numerical {
+    text-align: center;
+    .at-col {
+        padding: 10px 0;
+    }
+    .c-numerical-value {
+        font-size: 40px;
+        line-height: 60px;
+        .c-numerical-decimal {
+            &.small {
+                font-size: 30px;
+            }
+        }
+    }
+    .c-numerical-title {
+        font-size: 30px;
+        color: #666;
+    }
+}
\ No newline at end of file
diff --git a/layout/numerical/index.js b/layout/numerical/index.js
new file mode 100644
index 0000000..8ea68e7
--- /dev/null
+++ b/layout/numerical/index.js
@@ -0,0 +1,10 @@
+/**
+ * CNumerical
+ * @author Tevin
+ */
+
+import CNumerical from '@components/layout/numerical/CNumerical.vue';
+
+export {
+    CNumerical,
+}
\ No newline at end of file
diff --git a/plugins/echarts/CECharts.weapp.vue b/plugins/echarts/CECharts.weapp.vue
new file mode 100644
index 0000000..7fc585a
--- /dev/null
+++ b/plugins/echarts/CECharts.weapp.vue
@@ -0,0 +1,208 @@
+/**
+ * CECharts
+ * @author Tevin
+ */
+
+<template>
+    <view class="c-echarts">
+        <canvas
+            class="c-echarts-canvas"
+            type="2d"
+            :id="canvasId"
+            :canvasId="canvasId"
+            @touchstart="evt => disableTouch ? null : touchStart(evt)"
+            @touchmove="evt => disableTouch ? null : touchMove(evt)"
+            @touchend="evt => disableTouch ? null : touchEnd(evt)"
+        ></canvas>
+    </view>
+</template>
+
+<script>
+import WxCanvas from './wxCanvas';
+import * as echarts from './echarts';
+import './cECharts.scss';
+
+let canvasCount = 0;
+const wrapTouch = event => {
+    for (let i = 0; i < event.touches.length; ++i) {
+        const touch = event.touches[i];
+        touch.offsetX = touch.x;
+        touch.offsetY = touch.y;
+    }
+    return event;
+};
+
+export default {
+    name: 'CECharts',
+    components: {},
+    props: {
+        canvasId: {
+            type: String,
+            default: () =>
+                'ec-canvas-' + ++canvasCount + '-' + parseInt(Math.random() * 10000),
+        },
+        disableTouch: {
+            type: Boolean,
+            default: false,
+        },
+        onReady: Function,
+    },
+    data() {
+        return {};
+    },
+    methods: {
+        init(callback) {
+            // 基础库必须 2.9.0 以上,使用 <canvas type="2d"></canvas>,不支持旧版
+            const query = wx.createSelectorQuery();
+            query
+                .select('#' + this.canvasId)
+                .fields({ node: true, size: true })
+                .exec(res => {
+                    const canvasNode = res[0].node;
+                    this.canvasNode = canvasNode;
+                    const canvasDpr = wx.getSystemInfoSync().pixelRatio;
+                    const canvasWidth = res[0].width;
+                    const canvasHeight = res[0].height;
+                    const ctx = canvasNode.getContext('2d');
+                    const canvas = new WxCanvas(ctx, this.canvasId, true, canvasNode);
+                    echarts.setCanvasCreator(() => {
+                        return canvas;
+                    });
+                    if (typeof callback === 'function') {
+                        callback(canvas, canvasWidth, canvasHeight, canvasDpr);
+                    } else {
+                        this.triggerEvent('init', {
+                            canvas: canvas,
+                            width: canvasWidth,
+                            height: canvasHeight,
+                            dpr: canvasDpr,
+                        });
+                    }
+                });
+        },
+        canvasToTempFilePath(opt) {
+            const query = wx.createSelectorQuery().in(this);
+            query
+                .select('#' + this.canvasId)
+                .fields({ node: true, size: true })
+                .exec(res => {
+                    const canvasNode = res[0].node;
+                    opt.canvas = canvasNode;
+                    wx.canvasToTempFilePath(opt);
+                });
+        },
+        touchStart(e) {
+            if (this.chart && e.touches.length > 0) {
+                const touch = e.touches[0];
+                const handler = this.chart.getZr().handler;
+                handler.dispatch('mousedown', {
+                    zrX: touch.x,
+                    zrY: touch.y,
+                    preventDefault: () => {},
+                    stopImmediatePropagation: () => {},
+                    stopPropagation: () => {},
+                });
+                handler.dispatch('mousemove', {
+                    zrX: touch.x,
+                    zrY: touch.y,
+                    preventDefault: () => {},
+                    stopImmediatePropagation: () => {},
+                    stopPropagation: () => {},
+                });
+                handler.processGesture(wrapTouch(e), 'start');
+            }
+        },
+        touchMove(e) {
+            if (this.chart && e.touches.length > 0) {
+                const touch = e.touches[0];
+                const handler = this.chart.getZr().handler;
+                handler.dispatch('mousemove', {
+                    zrX: touch.x,
+                    zrY: touch.y,
+                    preventDefault: () => {},
+                    stopImmediatePropagation: () => {},
+                    stopPropagation: () => {},
+                });
+                handler.processGesture(wrapTouch(e), 'change');
+            }
+        },
+        touchEnd(e) {
+            if (this.chart) {
+                const touch = e.changedTouches ? e.changedTouches[0] : {};
+                const handler = this.chart.getZr().handler;
+                handler.dispatch('mouseup', {
+                    zrX: touch.x,
+                    zrY: touch.y,
+                    preventDefault: () => {},
+                    stopImmediatePropagation: () => {},
+                    stopPropagation: () => {},
+                });
+                handler.dispatch('click', {
+                    zrX: touch.x,
+                    zrY: touch.y,
+                    preventDefault: () => {},
+                    stopImmediatePropagation: () => {},
+                    stopPropagation: () => {},
+                });
+                handler.processGesture(wrapTouch(e), 'end');
+            }
+        },
+    },
+    mounted() {
+        // Disable prograssive because drawImage doesn't support DOM as parameter
+        // See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
+        echarts.registerPreprocessor(option => {
+            if (option && option.series) {
+                if (option.series.length > 0) {
+                    option.series.forEach(series => {
+                        series.progressive = 0;
+                    });
+                } else if (typeof option.series === 'object') {
+                    option.series.progressive = 0;
+                }
+            }
+        });
+        setTimeout(() => {
+            this.init((canvas, width, height, dpr) => {
+                this.chart = echarts.init(canvas, null, {
+                    width: width,
+                    height: height,
+                    devicePixelRatio: dpr, // 像素
+                });
+                canvas.setChart(this.chart);
+                this.onReady && this.onReady(this.chart);
+                this.chart.setOption({
+                    tooltip: {
+                        backgroundColor: 'rgba(50,50,50,0.7)',
+                        textStyle: {
+                            color: '#ffffff',
+                        },
+                        // 重新修正浮窗位置
+                        position: (pos, params, dom, rect, size) => {
+                            const [pX, pY] = pos;
+                            const [contX, contY] = size.contentSize;
+                            const [viewX, viewY] = size.viewSize;
+                            const contentPoint = {};
+                            // 鼠标在左侧时 tooltip 显示到右侧
+                            if (pX < viewX / 2) {
+                                contentPoint.right = Math.max(viewX - pX - contX, 0);
+                            }
+                            // 鼠标在右侧时 tooltip 显示到左侧。
+                            else {
+                                contentPoint.left = Math.max(pX - contX, 0);
+                            }
+                            // 限制不超过底部边界
+                            if (pY + contY <= viewY) {
+                                contentPoint.top = pY;
+                            } else {
+                                contentPoint.top = viewY - contY;
+                            }
+                            return contentPoint;
+                        },
+                    },
+                });
+            });
+        }, 100);
+    },
+};
+</script>
\ No newline at end of file
diff --git a/plugins/echarts/cECharts.scss b/plugins/echarts/cECharts.scss
new file mode 100644
index 0000000..ae5f826
--- /dev/null
+++ b/plugins/echarts/cECharts.scss
@@ -0,0 +1,14 @@
+/**
+ * CECharts
+ * @author Tevin
+ */
+
+@import "../../common/sassMixin";
+
+.c-echarts {
+    .c-echarts-canvas {
+        display: block;
+        width: 100%;
+        height: 100%;
+    }
+}
\ No newline at end of file
diff --git a/plugins/echarts/echarts.js b/plugins/echarts/echarts.js
new file mode 100644
index 0000000..e9158f1
--- /dev/null
+++ b/plugins/echarts/echarts.js
@@ -0,0 +1,61116 @@
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : factory(global.echarts = {});
+})(this, function (exports) {
+  'use strict';
+  /*! *****************************************************************************
+  Copyright (c) Microsoft Corporation.
+  
+  Permission to use, copy, modify, and/or distribute this software for any
+  purpose with or without fee is hereby granted.
+  
+  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+  PERFORMANCE OF THIS SOFTWARE.
+  ***************************************************************************** */
+
+  /* global Reflect, Promise */
+
+  var extendStatics = function (d, b) {
+    extendStatics = Object.setPrototypeOf || {
+      __proto__: []
+    } instanceof Array && function (d, b) {
+      d.__proto__ = b;
+    } || function (d, b) {
+      for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];
+    };
+
+    return extendStatics(d, b);
+  };
+
+  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 __());
+  }
+  /** @deprecated */
+
+  /** @deprecated */
+
+
+  var Browser = function () {
+    function Browser() {
+      this.firefox = false;
+      this.ie = false;
+      this.edge = false;
+      this.newEdge = false;
+      this.weChat = false;
+    }
+
+    return Browser;
+  }();
+
+  var Env = function () {
+    function Env() {
+      this.browser = new Browser();
+      this.node = false;
+      this.wxa = false;
+      this.worker = false;
+      this.svgSupported = false;
+      this.touchEventsSupported = false;
+      this.pointerEventsSupported = false;
+      this.domSupported = false;
+      this.transformSupported = false;
+      this.transform3dSupported = false;
+      this.hasGlobalWindow = typeof window !== 'undefined';
+    }
+
+    return Env;
+  }();
+
+  var env = new Env();
+
+  if (typeof wx === 'object' && typeof wx.getSystemInfoSync === 'function') {
+    env.wxa = true;
+    env.touchEventsSupported = true;
+  } else if (typeof document === 'undefined' && typeof self !== 'undefined') {
+    env.worker = true;
+  } else if (typeof navigator === 'undefined') {
+    env.node = true;
+    env.svgSupported = true;
+  } else {
+    detect(navigator.userAgent, env);
+  }
+
+  function detect(ua, env) {
+    var browser = env.browser;
+    var firefox = ua.match(/Firefox\/([\d.]+)/);
+    var ie = ua.match(/MSIE\s([\d.]+)/) || ua.match(/Trident\/.+?rv:(([\d.]+))/);
+    var edge = ua.match(/Edge?\/([\d.]+)/);
+    var weChat = /micromessenger/i.test(ua);
+
+    if (firefox) {
+      browser.firefox = true;
+      browser.version = firefox[1];
+    }
+
+    if (ie) {
+      browser.ie = true;
+      browser.version = ie[1];
+    }
+
+    if (edge) {
+      browser.edge = true;
+      browser.version = edge[1];
+      browser.newEdge = +edge[1].split('.')[0] > 18;
+    }
+
+    if (weChat) {
+      browser.weChat = true;
+    }
+
+    env.svgSupported = typeof SVGRect !== 'undefined';
+    env.touchEventsSupported = 'ontouchstart' in window && !browser.ie && !browser.edge;
+    env.pointerEventsSupported = 'onpointerdown' in window && (browser.edge || browser.ie && +browser.version >= 11);
+    env.domSupported = typeof document !== 'undefined';
+    var style = document.documentElement.style;
+    env.transform3dSupported = (browser.ie && 'transition' in style || browser.edge || 'WebKitCSSMatrix' in window && 'm11' in new WebKitCSSMatrix() || 'MozPerspective' in style) && !('OTransition' in style);
+    env.transformSupported = env.transform3dSupported || browser.ie && +browser.version >= 9;
+  }
+
+  var DEFAULT_FONT_SIZE = 12;
+  var DEFAULT_FONT_FAMILY = 'sans-serif';
+  var DEFAULT_FONT = DEFAULT_FONT_SIZE + "px " + DEFAULT_FONT_FAMILY;
+  var OFFSET = 20;
+  var SCALE = 100;
+  var defaultWidthMapStr = "007LLmW'55;N0500LLLLLLLLLL00NNNLzWW\\\\WQb\\0FWLg\\bWb\\WQ\\WrWWQ000CL5LLFLL0LL**F*gLLLL5F0LF\\FFF5.5N";
+
+  function getTextWidthMap(mapStr) {
+    var map = {};
+
+    if (typeof JSON === 'undefined') {
+      return map;
+    }
+
+    for (var i = 0; i < mapStr.length; i++) {
+      var char = String.fromCharCode(i + 32);
+      var size = (mapStr.charCodeAt(i) - OFFSET) / SCALE;
+      map[char] = size;
+    }
+
+    return map;
+  }
+
+  var DEFAULT_TEXT_WIDTH_MAP = getTextWidthMap(defaultWidthMapStr);
+  var platformApi = {
+    createCanvas: function () {
+      return typeof document !== 'undefined' && document.createElement('canvas');
+    },
+    measureText: function () {
+      var _ctx;
+
+      var _cachedFont;
+
+      return function (text, font) {
+        if (!_ctx) {
+          var canvas = platformApi.createCanvas();
+          _ctx = canvas && canvas.getContext('2d');
+        }
+
+        if (_ctx) {
+          if (_cachedFont !== font) {
+            _cachedFont = _ctx.font = font || DEFAULT_FONT;
+          }
+
+          return _ctx.measureText(text);
+        } else {
+          text = text || '';
+          font = font || DEFAULT_FONT;
+          var res = /^([0-9]*?)px$/.exec(font);
+          var fontSize = +(res && res[1]) || DEFAULT_FONT_SIZE;
+          var width = 0;
+
+          if (font.indexOf('mono') >= 0) {
+            width = fontSize * text.length;
+          } else {
+            for (var i = 0; i < text.length; i++) {
+              var preCalcWidth = DEFAULT_TEXT_WIDTH_MAP[text[i]];
+              width += preCalcWidth == null ? fontSize : preCalcWidth * fontSize;
+            }
+          }
+
+          return {
+            width: width
+          };
+        }
+      };
+    }(),
+    loadImage: function (src, onload, onerror) {
+      var image = new Image();
+      image.onload = onload;
+      image.onerror = onerror;
+      image.src = src;
+      return image;
+    }
+  };
+
+  function setPlatformAPI(newPlatformApis) {
+    for (var key in platformApi) {
+      if (newPlatformApis[key]) {
+        platformApi[key] = newPlatformApis[key];
+      }
+    }
+  }
+
+  var BUILTIN_OBJECT = reduce(['Function', 'RegExp', 'Date', 'Error', 'CanvasGradient', 'CanvasPattern', 'Image', 'Canvas'], function (obj, val) {
+    obj['[object ' + val + ']'] = true;
+    return obj;
+  }, {});
+  var TYPED_ARRAY = reduce(['Int8', 'Uint8', 'Uint8Clamped', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Float32', 'Float64'], function (obj, val) {
+    obj['[object ' + val + 'Array]'] = true;
+    return obj;
+  }, {});
+  var objToString = Object.prototype.toString;
+  var arrayProto = Array.prototype;
+  var nativeForEach = arrayProto.forEach;
+  var nativeFilter = arrayProto.filter;
+  var nativeSlice = arrayProto.slice;
+  var nativeMap = arrayProto.map;
+
+  var ctorFunction = function () {}.constructor;
+
+  var protoFunction = ctorFunction ? ctorFunction.prototype : null;
+  var protoKey = '__proto__';
+  var idStart = 0x0907;
+
+  function guid() {
+    return idStart++;
+  }
+
+  function logError() {
+    var args = [];
+
+    for (var _i = 0; _i < arguments.length; _i++) {
+      args[_i] = arguments[_i];
+    }
+
+    if (typeof console !== 'undefined') {
+      console.error.apply(console, args);
+    }
+  }
+
+  function clone(source) {
+    if (source == null || typeof source !== 'object') {
+      return source;
+    }
+
+    var result = source;
+    var typeStr = objToString.call(source);
+
+    if (typeStr === '[object Array]') {
+      if (!isPrimitive(source)) {
+        result = [];
+
+        for (var i = 0, len = source.length; i < len; i++) {
+          result[i] = clone(source[i]);
+        }
+      }
+    } else if (TYPED_ARRAY[typeStr]) {
+      if (!isPrimitive(source)) {
+        var Ctor = source.constructor;
+
+        if (Ctor.from) {
+          result = Ctor.from(source);
+        } else {
+          result = new Ctor(source.length);
+
+          for (var i = 0, len = source.length; i < len; i++) {
+            result[i] = source[i];
+          }
+        }
+      }
+    } else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) {
+      result = {};
+
+      for (var key in source) {
+        if (source.hasOwnProperty(key) && key !== protoKey) {
+          result[key] = clone(source[key]);
+        }
+      }
+    }
+
+    return result;
+  }
+
+  function merge(target, source, overwrite) {
+    if (!isObject(source) || !isObject(target)) {
+      return overwrite ? clone(source) : target;
+    }
+
+    for (var key in source) {
+      if (source.hasOwnProperty(key) && key !== protoKey) {
+        var targetProp = target[key];
+        var sourceProp = source[key];
+
+        if (isObject(sourceProp) && isObject(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuiltInObject(sourceProp) && !isBuiltInObject(targetProp) && !isPrimitive(sourceProp) && !isPrimitive(targetProp)) {
+          merge(targetProp, sourceProp, overwrite);
+        } else if (overwrite || !(key in target)) {
+          target[key] = clone(source[key]);
+        }
+      }
+    }
+
+    return target;
+  }
+
+  function mergeAll(targetAndSources, overwrite) {
+    var result = targetAndSources[0];
+
+    for (var i = 1, len = targetAndSources.length; i < len; i++) {
+      result = merge(result, targetAndSources[i], overwrite);
+    }
+
+    return result;
+  }
+
+  function extend(target, source) {
+    if (Object.assign) {
+      Object.assign(target, source);
+    } else {
+      for (var key in source) {
+        if (source.hasOwnProperty(key) && key !== protoKey) {
+          target[key] = source[key];
+        }
+      }
+    }
+
+    return target;
+  }
+
+  function defaults(target, source, overlay) {
+    var keysArr = keys(source);
+
+    for (var i = 0; i < keysArr.length; i++) {
+      var key = keysArr[i];
+
+      if (overlay ? source[key] != null : target[key] == null) {
+        target[key] = source[key];
+      }
+    }
+
+    return target;
+  }
+
+  var createCanvas = platformApi.createCanvas;
+
+  function indexOf(array, value) {
+    if (array) {
+      if (array.indexOf) {
+        return array.indexOf(value);
+      }
+
+      for (var i = 0, len = array.length; i < len; i++) {
+        if (array[i] === value) {
+          return i;
+        }
+      }
+    }
+
+    return -1;
+  }
+
+  function inherits(clazz, baseClazz) {
+    var clazzPrototype = clazz.prototype;
+
+    function F() {}
+
+    F.prototype = baseClazz.prototype;
+    clazz.prototype = new F();
+
+    for (var prop in clazzPrototype) {
+      if (clazzPrototype.hasOwnProperty(prop)) {
+        clazz.prototype[prop] = clazzPrototype[prop];
+      }
+    }
+
+    clazz.prototype.constructor = clazz;
+    clazz.superClass = baseClazz;
+  }
+
+  function mixin(target, source, override) {
+    target = 'prototype' in target ? target.prototype : target;
+    source = 'prototype' in source ? source.prototype : source;
+
+    if (Object.getOwnPropertyNames) {
+      var keyList = Object.getOwnPropertyNames(source);
+
+      for (var i = 0; i < keyList.length; i++) {
+        var key = keyList[i];
+
+        if (key !== 'constructor') {
+          if (override ? source[key] != null : target[key] == null) {
+            target[key] = source[key];
+          }
+        }
+      }
+    } else {
+      defaults(target, source, override);
+    }
+  }
+
+  function isArrayLike(data) {
+    if (!data) {
+      return false;
+    }
+
+    if (typeof data === 'string') {
+      return false;
+    }
+
+    return typeof data.length === 'number';
+  }
+
+  function each(arr, cb, context) {
+    if (!(arr && cb)) {
+      return;
+    }
+
+    if (arr.forEach && arr.forEach === nativeForEach) {
+      arr.forEach(cb, context);
+    } else if (arr.length === +arr.length) {
+      for (var i = 0, len = arr.length; i < len; i++) {
+        cb.call(context, arr[i], i, arr);
+      }
+    } else {
+      for (var key in arr) {
+        if (arr.hasOwnProperty(key)) {
+          cb.call(context, arr[key], key, arr);
+        }
+      }
+    }
+  }
+
+  function map(arr, cb, context) {
+    if (!arr) {
+      return [];
+    }
+
+    if (!cb) {
+      return slice(arr);
+    }
+
+    if (arr.map && arr.map === nativeMap) {
+      return arr.map(cb, context);
+    } else {
+      var result = [];
+
+      for (var i = 0, len = arr.length; i < len; i++) {
+        result.push(cb.call(context, arr[i], i, arr));
+      }
+
+      return result;
+    }
+  }
+
+  function reduce(arr, cb, memo, context) {
+    if (!(arr && cb)) {
+      return;
+    }
+
+    for (var i = 0, len = arr.length; i < len; i++) {
+      memo = cb.call(context, memo, arr[i], i, arr);
+    }
+
+    return memo;
+  }
+
+  function filter(arr, cb, context) {
+    if (!arr) {
+      return [];
+    }
+
+    if (!cb) {
+      return slice(arr);
+    }
+
+    if (arr.filter && arr.filter === nativeFilter) {
+      return arr.filter(cb, context);
+    } else {
+      var result = [];
+
+      for (var i = 0, len = arr.length; i < len; i++) {
+        if (cb.call(context, arr[i], i, arr)) {
+          result.push(arr[i]);
+        }
+      }
+
+      return result;
+    }
+  }
+
+  function find(arr, cb, context) {
+    if (!(arr && cb)) {
+      return;
+    }
+
+    for (var i = 0, len = arr.length; i < len; i++) {
+      if (cb.call(context, arr[i], i, arr)) {
+        return arr[i];
+      }
+    }
+  }
+
+  function keys(obj) {
+    if (!obj) {
+      return [];
+    }
+
+    if (Object.keys) {
+      return Object.keys(obj);
+    }
+
+    var keyList = [];
+
+    for (var key in obj) {
+      if (obj.hasOwnProperty(key)) {
+        keyList.push(key);
+      }
+    }
+
+    return keyList;
+  }
+
+  function bindPolyfill(func, context) {
+    var args = [];
+
+    for (var _i = 2; _i < arguments.length; _i++) {
+      args[_i - 2] = arguments[_i];
+    }
+
+    return function () {
+      return func.apply(context, args.concat(nativeSlice.call(arguments)));
+    };
+  }
+
+  var bind = protoFunction && isFunction(protoFunction.bind) ? protoFunction.call.bind(protoFunction.bind) : bindPolyfill;
+
+  function curry(func) {
+    var args = [];
+
+    for (var _i = 1; _i < arguments.length; _i++) {
+      args[_i - 1] = arguments[_i];
+    }
+
+    return function () {
+      return func.apply(this, args.concat(nativeSlice.call(arguments)));
+    };
+  }
+
+  function isArray(value) {
+    if (Array.isArray) {
+      return Array.isArray(value);
+    }
+
+    return objToString.call(value) === '[object Array]';
+  }
+
+  function isFunction(value) {
+    return typeof value === 'function';
+  }
+
+  function isString(value) {
+    return typeof value === 'string';
+  }
+
+  function isStringSafe(value) {
+    return objToString.call(value) === '[object String]';
+  }
+
+  function isNumber(value) {
+    return typeof value === 'number';
+  }
+
+  function isObject(value) {
+    var type = typeof value;
+    return type === 'function' || !!value && type === 'object';
+  }
+
+  function isBuiltInObject(value) {
+    return !!BUILTIN_OBJECT[objToString.call(value)];
+  }
+
+  function isTypedArray(value) {
+    return !!TYPED_ARRAY[objToString.call(value)];
+  }
+
+  function isDom(value) {
+    return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object';
+  }
+
+  function isGradientObject(value) {
+    return value.colorStops != null;
+  }
+
+  function isImagePatternObject(value) {
+    return value.image != null;
+  }
+
+  function isRegExp(value) {
+    return objToString.call(value) === '[object RegExp]';
+  }
+
+  function eqNaN(value) {
+    return value !== value;
+  }
+
+  function retrieve() {
+    var args = [];
+
+    for (var _i = 0; _i < arguments.length; _i++) {
+      args[_i] = arguments[_i];
+    }
+
+    for (var i = 0, len = args.length; i < len; i++) {
+      if (args[i] != null) {
+        return args[i];
+      }
+    }
+  }
+
+  function retrieve2(value0, value1) {
+    return value0 != null ? value0 : value1;
+  }
+
+  function retrieve3(value0, value1, value2) {
+    return value0 != null ? value0 : value1 != null ? value1 : value2;
+  }
+
+  function slice(arr) {
+    var args = [];
+
+    for (var _i = 1; _i < arguments.length; _i++) {
+      args[_i - 1] = arguments[_i];
+    }
+
+    return nativeSlice.apply(arr, args);
+  }
+
+  function normalizeCssArray(val) {
+    if (typeof val === 'number') {
+      return [val, val, val, val];
+    }
+
+    var len = val.length;
+
+    if (len === 2) {
+      return [val[0], val[1], val[0], val[1]];
+    } else if (len === 3) {
+      return [val[0], val[1], val[2], val[1]];
+    }
+
+    return val;
+  }
+
+  function assert(condition, message) {
+    if (!condition) {
+      throw new Error(message);
+    }
+  }
+
+  function trim(str) {
+    if (str == null) {
+      return null;
+    } else if (typeof str.trim === 'function') {
+      return str.trim();
+    } else {
+      return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+    }
+  }
+
+  var primitiveKey = '__ec_primitive__';
+
+  function setAsPrimitive(obj) {
+    obj[primitiveKey] = true;
+  }
+
+  function isPrimitive(obj) {
+    return obj[primitiveKey];
+  }
+
+  var HashMap = function () {
+    function HashMap(obj) {
+      this.data = {};
+      var isArr = isArray(obj);
+      this.data = {};
+      var thisMap = this;
+      obj instanceof HashMap ? obj.each(visit) : obj && each(obj, visit);
+
+      function visit(value, key) {
+        isArr ? thisMap.set(value, key) : thisMap.set(key, value);
+      }
+    }
+
+    HashMap.prototype.get = function (key) {
+      return this.data.hasOwnProperty(key) ? this.data[key] : null;
+    };
+
+    HashMap.prototype.set = function (key, value) {
+      return this.data[key] = value;
+    };
+
+    HashMap.prototype.each = function (cb, context) {
+      for (var key in this.data) {
+        if (this.data.hasOwnProperty(key)) {
+          cb.call(context, this.data[key], key);
+        }
+      }
+    };
+
+    HashMap.prototype.keys = function () {
+      return keys(this.data);
+    };
+
+    HashMap.prototype.removeKey = function (key) {
+      delete this.data[key];
+    };
+
+    return HashMap;
+  }();
+
+  function createHashMap(obj) {
+    return new HashMap(obj);
+  }
+
+  function concatArray(a, b) {
+    var newArray = new a.constructor(a.length + b.length);
+
+    for (var i = 0; i < a.length; i++) {
+      newArray[i] = a[i];
+    }
+
+    var offset = a.length;
+
+    for (var i = 0; i < b.length; i++) {
+      newArray[i + offset] = b[i];
+    }
+
+    return newArray;
+  }
+
+  function createObject(proto, properties) {
+    var obj;
+
+    if (Object.create) {
+      obj = Object.create(proto);
+    } else {
+      var StyleCtor = function () {};
+
+      StyleCtor.prototype = proto;
+      obj = new StyleCtor();
+    }
+
+    if (properties) {
+      extend(obj, properties);
+    }
+
+    return obj;
+  }
+
+  function disableUserSelect(dom) {
+    var domStyle = dom.style;
+    domStyle.webkitUserSelect = 'none';
+    domStyle.userSelect = 'none';
+    domStyle.webkitTapHighlightColor = 'rgba(0,0,0,0)';
+    domStyle['-webkit-touch-callout'] = 'none';
+  }
+
+  function hasOwn(own, prop) {
+    return own.hasOwnProperty(prop);
+  }
+
+  function noop() {}
+
+  var RADIAN_TO_DEGREE = 180 / Math.PI;
+  var util = (Object.freeze || Object)({
+    guid: guid,
+    logError: logError,
+    clone: clone,
+    merge: merge,
+    mergeAll: mergeAll,
+    extend: extend,
+    defaults: defaults,
+    createCanvas: createCanvas,
+    indexOf: indexOf,
+    inherits: inherits,
+    mixin: mixin,
+    isArrayLike: isArrayLike,
+    each: each,
+    map: map,
+    reduce: reduce,
+    filter: filter,
+    find: find,
+    keys: keys,
+    bind: bind,
+    curry: curry,
+    isArray: isArray,
+    isFunction: isFunction,
+    isString: isString,
+    isStringSafe: isStringSafe,
+    isNumber: isNumber,
+    isObject: isObject,
+    isBuiltInObject: isBuiltInObject,
+    isTypedArray: isTypedArray,
+    isDom: isDom,
+    isGradientObject: isGradientObject,
+    isImagePatternObject: isImagePatternObject,
+    isRegExp: isRegExp,
+    eqNaN: eqNaN,
+    retrieve: retrieve,
+    retrieve2: retrieve2,
+    retrieve3: retrieve3,
+    slice: slice,
+    normalizeCssArray: normalizeCssArray,
+    assert: assert,
+    trim: trim,
+    setAsPrimitive: setAsPrimitive,
+    isPrimitive: isPrimitive,
+    HashMap: HashMap,
+    createHashMap: createHashMap,
+    concatArray: concatArray,
+    createObject: createObject,
+    disableUserSelect: disableUserSelect,
+    hasOwn: hasOwn,
+    noop: noop,
+    RADIAN_TO_DEGREE: RADIAN_TO_DEGREE
+  });
+
+  function create(x, y) {
+    if (x == null) {
+      x = 0;
+    }
+
+    if (y == null) {
+      y = 0;
+    }
+
+    return [x, y];
+  }
+
+  function copy(out, v) {
+    out[0] = v[0];
+    out[1] = v[1];
+    return out;
+  }
+
+  function clone$1(v) {
+    return [v[0], v[1]];
+  }
+
+  function set(out, a, b) {
+    out[0] = a;
+    out[1] = b;
+    return out;
+  }
+
+  function add(out, v1, v2) {
+    out[0] = v1[0] + v2[0];
+    out[1] = v1[1] + v2[1];
+    return out;
+  }
+
+  function scaleAndAdd(out, v1, v2, a) {
+    out[0] = v1[0] + v2[0] * a;
+    out[1] = v1[1] + v2[1] * a;
+    return out;
+  }
+
+  function sub(out, v1, v2) {
+    out[0] = v1[0] - v2[0];
+    out[1] = v1[1] - v2[1];
+    return out;
+  }
+
+  function len(v) {
+    return Math.sqrt(lenSquare(v));
+  }
+
+  var length = len;
+
+  function lenSquare(v) {
+    return v[0] * v[0] + v[1] * v[1];
+  }
+
+  var lengthSquare = lenSquare;
+
+  function mul(out, v1, v2) {
+    out[0] = v1[0] * v2[0];
+    out[1] = v1[1] * v2[1];
+    return out;
+  }
+
+  function div(out, v1, v2) {
+    out[0] = v1[0] / v2[0];
+    out[1] = v1[1] / v2[1];
+    return out;
+  }
+
+  function dot(v1, v2) {
+    return v1[0] * v2[0] + v1[1] * v2[1];
+  }
+
+  function scale(out, v, s) {
+    out[0] = v[0] * s;
+    out[1] = v[1] * s;
+    return out;
+  }
+
+  function normalize(out, v) {
+    var d = len(v);
+
+    if (d === 0) {
+      out[0] = 0;
+      out[1] = 0;
+    } else {
+      out[0] = v[0] / d;
+      out[1] = v[1] / d;
+    }
+
+    return out;
+  }
+
+  function distance(v1, v2) {
+    return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]));
+  }
+
+  var dist = distance;
+
+  function distanceSquare(v1, v2) {
+    return (v1[0] - v2[0]) * (v1[0] - v2[0]) + (v1[1] - v2[1]) * (v1[1] - v2[1]);
+  }
+
+  var distSquare = distanceSquare;
+
+  function negate(out, v) {
+    out[0] = -v[0];
+    out[1] = -v[1];
+    return out;
+  }
+
+  function lerp(out, v1, v2, t) {
+    out[0] = v1[0] + t * (v2[0] - v1[0]);
+    out[1] = v1[1] + t * (v2[1] - v1[1]);
+    return out;
+  }
+
+  function applyTransform(out, v, m) {
+    var x = v[0];
+    var y = v[1];
+    out[0] = m[0] * x + m[2] * y + m[4];
+    out[1] = m[1] * x + m[3] * y + m[5];
+    return out;
+  }
+
+  function min(out, v1, v2) {
+    out[0] = Math.min(v1[0], v2[0]);
+    out[1] = Math.min(v1[1], v2[1]);
+    return out;
+  }
+
+  function max(out, v1, v2) {
+    out[0] = Math.max(v1[0], v2[0]);
+    out[1] = Math.max(v1[1], v2[1]);
+    return out;
+  }
+
+  var vector = (Object.freeze || Object)({
+    create: create,
+    copy: copy,
+    clone: clone$1,
+    set: set,
+    add: add,
+    scaleAndAdd: scaleAndAdd,
+    sub: sub,
+    len: len,
+    length: length,
+    lenSquare: lenSquare,
+    lengthSquare: lengthSquare,
+    mul: mul,
+    div: div,
+    dot: dot,
+    scale: scale,
+    normalize: normalize,
+    distance: distance,
+    dist: dist,
+    distanceSquare: distanceSquare,
+    distSquare: distSquare,
+    negate: negate,
+    lerp: lerp,
+    applyTransform: applyTransform,
+    min: min,
+    max: max
+  });
+
+  var Param = function () {
+    function Param(target, e) {
+      this.target = target;
+      this.topTarget = e && e.topTarget;
+    }
+
+    return Param;
+  }();
+
+  var Draggable = function () {
+    function Draggable(handler) {
+      this.handler = handler;
+      handler.on('mousedown', this._dragStart, this);
+      handler.on('mousemove', this._drag, this);
+      handler.on('mouseup', this._dragEnd, this);
+    }
+
+    Draggable.prototype._dragStart = function (e) {
+      var draggingTarget = e.target;
+
+      while (draggingTarget && !draggingTarget.draggable) {
+        draggingTarget = draggingTarget.parent || draggingTarget.__hostTarget;
+      }
+
+      if (draggingTarget) {
+        this._draggingTarget = draggingTarget;
+        draggingTarget.dragging = true;
+        this._x = e.offsetX;
+        this._y = e.offsetY;
+        this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragstart', e.event);
+      }
+    };
+
+    Draggable.prototype._drag = function (e) {
+      var draggingTarget = this._draggingTarget;
+
+      if (draggingTarget) {
+        var x = e.offsetX;
+        var y = e.offsetY;
+        var dx = x - this._x;
+        var dy = y - this._y;
+        this._x = x;
+        this._y = y;
+        draggingTarget.drift(dx, dy, e);
+        this.handler.dispatchToElement(new Param(draggingTarget, e), 'drag', e.event);
+        var dropTarget = this.handler.findHover(x, y, draggingTarget).target;
+        var lastDropTarget = this._dropTarget;
+        this._dropTarget = dropTarget;
+
+        if (draggingTarget !== dropTarget) {
+          if (lastDropTarget && dropTarget !== lastDropTarget) {
+            this.handler.dispatchToElement(new Param(lastDropTarget, e), 'dragleave', e.event);
+          }
+
+          if (dropTarget && dropTarget !== lastDropTarget) {
+            this.handler.dispatchToElement(new Param(dropTarget, e), 'dragenter', e.event);
+          }
+        }
+      }
+    };
+
+    Draggable.prototype._dragEnd = function (e) {
+      var draggingTarget = this._draggingTarget;
+
+      if (draggingTarget) {
+        draggingTarget.dragging = false;
+      }
+
+      this.handler.dispatchToElement(new Param(draggingTarget, e), 'dragend', e.event);
+
+      if (this._dropTarget) {
+        this.handler.dispatchToElement(new Param(this._dropTarget, e), 'drop', e.event);
+      }
+
+      this._draggingTarget = null;
+      this._dropTarget = null;
+    };
+
+    return Draggable;
+  }();
+
+  var Eventful = function () {
+    function Eventful(eventProcessors) {
+      if (eventProcessors) {
+        this._$eventProcessor = eventProcessors;
+      }
+    }
+
+    Eventful.prototype.on = function (event, query, handler, context) {
+      if (!this._$handlers) {
+        this._$handlers = {};
+      }
+
+      var _h = this._$handlers;
+
+      if (typeof query === 'function') {
+        context = handler;
+        handler = query;
+        query = null;
+      }
+
+      if (!handler || !event) {
+        return this;
+      }
+
+      var eventProcessor = this._$eventProcessor;
+
+      if (query != null && eventProcessor && eventProcessor.normalizeQuery) {
+        query = eventProcessor.normalizeQuery(query);
+      }
+
+      if (!_h[event]) {
+        _h[event] = [];
+      }
+
+      for (var i = 0; i < _h[event].length; i++) {
+        if (_h[event][i].h === handler) {
+          return this;
+        }
+      }
+
+      var wrap = {
+        h: handler,
+        query: query,
+        ctx: context || this,
+        callAtLast: handler.zrEventfulCallAtLast
+      };
+      var lastIndex = _h[event].length - 1;
+      var lastWrap = _h[event][lastIndex];
+      lastWrap && lastWrap.callAtLast ? _h[event].splice(lastIndex, 0, wrap) : _h[event].push(wrap);
+      return this;
+    };
+
+    Eventful.prototype.isSilent = function (eventName) {
+      var _h = this._$handlers;
+      return !_h || !_h[eventName] || !_h[eventName].length;
+    };
+
+    Eventful.prototype.off = function (eventType, handler) {
+      var _h = this._$handlers;
+
+      if (!_h) {
+        return this;
+      }
+
+      if (!eventType) {
+        this._$handlers = {};
+        return this;
+      }
+
+      if (handler) {
+        if (_h[eventType]) {
+          var newList = [];
+
+          for (var i = 0, l = _h[eventType].length; i < l; i++) {
+            if (_h[eventType][i].h !== handler) {
+              newList.push(_h[eventType][i]);
+            }
+          }
+
+          _h[eventType] = newList;
+        }
+
+        if (_h[eventType] && _h[eventType].length === 0) {
+          delete _h[eventType];
+        }
+      } else {
+        delete _h[eventType];
+      }
+
+      return this;
+    };
+
+    Eventful.prototype.trigger = function (eventType) {
+      var args = [];
+
+      for (var _i = 1; _i < arguments.length; _i++) {
+        args[_i - 1] = arguments[_i];
+      }
+
+      if (!this._$handlers) {
+        return this;
+      }
+
+      var _h = this._$handlers[eventType];
+      var eventProcessor = this._$eventProcessor;
+
+      if (_h) {
+        var argLen = args.length;
+        var len = _h.length;
+
+        for (var i = 0; i < len; i++) {
+          var hItem = _h[i];
+
+          if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(eventType, hItem.query)) {
+            continue;
+          }
+
+          switch (argLen) {
+            case 0:
+              hItem.h.call(hItem.ctx);
+              break;
+
+            case 1:
+              hItem.h.call(hItem.ctx, args[0]);
+              break;
+
+            case 2:
+              hItem.h.call(hItem.ctx, args[0], args[1]);
+              break;
+
+            default:
+              hItem.h.apply(hItem.ctx, args);
+              break;
+          }
+        }
+      }
+
+      eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(eventType);
+      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 argLen = args.length;
+        var ctx = args[argLen - 1];
+        var len = _h.length;
+
+        for (var i = 0; i < len; i++) {
+          var hItem = _h[i];
+
+          if (eventProcessor && eventProcessor.filter && hItem.query != null && !eventProcessor.filter(type, hItem.query)) {
+            continue;
+          }
+
+          switch (argLen) {
+            case 0:
+              hItem.h.call(ctx);
+              break;
+
+            case 1:
+              hItem.h.call(ctx, args[0]);
+              break;
+
+            case 2:
+              hItem.h.call(ctx, args[0], args[1]);
+              break;
+
+            default:
+              hItem.h.apply(ctx, args.slice(1, argLen - 1));
+              break;
+          }
+        }
+      }
+
+      eventProcessor && eventProcessor.afterTrigger && eventProcessor.afterTrigger(type);
+      return this;
+    };
+
+    return Eventful;
+  }();
+
+  var LN2 = Math.log(2);
+
+  function determinant(rows, rank, rowStart, rowMask, colMask, detCache) {
+    var cacheKey = rowMask + '-' + colMask;
+    var fullRank = rows.length;
+
+    if (detCache.hasOwnProperty(cacheKey)) {
+      return detCache[cacheKey];
+    }
+
+    if (rank === 1) {
+      var colStart = Math.round(Math.log((1 << fullRank) - 1 & ~colMask) / LN2);
+      return rows[rowStart][colStart];
+    }
+
+    var subRowMask = rowMask | 1 << rowStart;
+    var subRowStart = rowStart + 1;
+
+    while (rowMask & 1 << subRowStart) {
+      subRowStart++;
+    }
+
+    var sum = 0;
+
+    for (var j = 0, colLocalIdx = 0; j < fullRank; j++) {
+      var colTag = 1 << j;
+
+      if (!(colTag & colMask)) {
+        sum += (colLocalIdx % 2 ? -1 : 1) * rows[rowStart][j] * determinant(rows, rank - 1, subRowStart, subRowMask, colMask | colTag, detCache);
+        colLocalIdx++;
+      }
+    }
+
+    detCache[cacheKey] = sum;
+    return sum;
+  }
+
+  function buildTransformer(src, dest) {
+    var mA = [[src[0], src[1], 1, 0, 0, 0, -dest[0] * src[0], -dest[0] * src[1]], [0, 0, 0, src[0], src[1], 1, -dest[1] * src[0], -dest[1] * src[1]], [src[2], src[3], 1, 0, 0, 0, -dest[2] * src[2], -dest[2] * src[3]], [0, 0, 0, src[2], src[3], 1, -dest[3] * src[2], -dest[3] * src[3]], [src[4], src[5], 1, 0, 0, 0, -dest[4] * src[4], -dest[4] * src[5]], [0, 0, 0, src[4], src[5], 1, -dest[5] * src[4], -dest[5] * src[5]], [src[6], src[7], 1, 0, 0, 0, -dest[6] * src[6], -dest[6] * src[7]], [0, 0, 0, src[6], src[7], 1, -dest[7] * src[6], -dest[7] * src[7]]];
+    var detCache = {};
+    var det = determinant(mA, 8, 0, 0, 0, detCache);
+
+    if (det === 0) {
+      return;
+    }
+
+    var vh = [];
+
+    for (var i = 0; i < 8; i++) {
+      for (var j = 0; j < 8; j++) {
+        vh[j] == null && (vh[j] = 0);
+        vh[j] += ((i + j) % 2 ? -1 : 1) * determinant(mA, 7, i === 0 ? 1 : 0, 1 << i, 1 << j, detCache) / det * dest[i];
+      }
+    }
+
+    return function (out, srcPointX, srcPointY) {
+      var pk = srcPointX * vh[6] + srcPointY * vh[7] + 1;
+      out[0] = (srcPointX * vh[0] + srcPointY * vh[1] + vh[2]) / pk;
+      out[1] = (srcPointX * vh[3] + srcPointY * vh[4] + vh[5]) / pk;
+    };
+  }
+
+  var EVENT_SAVED_PROP = '___zrEVENTSAVED';
+  var _calcOut$1 = [];
+
+  function transformLocalCoord(out, elFrom, elTarget, inX, inY) {
+    return transformCoordWithViewport(_calcOut$1, elFrom, inX, inY, true) && transformCoordWithViewport(out, elTarget, _calcOut$1[0], _calcOut$1[1]);
+  }
+
+  function transformCoordWithViewport(out, el, inX, inY, inverse) {
+    if (el.getBoundingClientRect && env.domSupported && !isCanvasEl(el)) {
+      var saved = el[EVENT_SAVED_PROP] || (el[EVENT_SAVED_PROP] = {});
+      var markers = prepareCoordMarkers(el, saved);
+      var transformer = preparePointerTransformer(markers, saved, inverse);
+
+      if (transformer) {
+        transformer(out, inX, inY);
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  function prepareCoordMarkers(el, saved) {
+    var markers = saved.markers;
+
+    if (markers) {
+      return markers;
+    }
+
+    markers = saved.markers = [];
+    var propLR = ['left', 'right'];
+    var propTB = ['top', 'bottom'];
+
+    for (var i = 0; i < 4; i++) {
+      var marker = document.createElement('div');
+      var stl = marker.style;
+      var idxLR = i % 2;
+      var idxTB = (i >> 1) % 2;
+      stl.cssText = ['position: absolute', 'visibility: hidden', 'padding: 0', 'margin: 0', 'border-width: 0', 'user-select: none', 'width:0', 'height:0', propLR[idxLR] + ':0', propTB[idxTB] + ':0', propLR[1 - idxLR] + ':auto', propTB[1 - idxTB] + ':auto', ''].join('!important;');
+      el.appendChild(marker);
+      markers.push(marker);
+    }
+
+    return markers;
+  }
+
+  function preparePointerTransformer(markers, saved, inverse) {
+    var transformerName = inverse ? 'invTrans' : 'trans';
+    var transformer = saved[transformerName];
+    var oldSrcCoords = saved.srcCoords;
+    var srcCoords = [];
+    var destCoords = [];
+    var oldCoordTheSame = true;
+
+    for (var i = 0; i < 4; i++) {
+      var rect = markers[i].getBoundingClientRect();
+      var ii = 2 * i;
+      var x = rect.left;
+      var y = rect.top;
+      srcCoords.push(x, y);
+      oldCoordTheSame = oldCoordTheSame && oldSrcCoords && x === oldSrcCoords[ii] && y === oldSrcCoords[ii + 1];
+      destCoords.push(markers[i].offsetLeft, markers[i].offsetTop);
+    }
+
+    return oldCoordTheSame && transformer ? transformer : (saved.srcCoords = srcCoords, saved[transformerName] = inverse ? buildTransformer(destCoords, srcCoords) : buildTransformer(srcCoords, destCoords));
+  }
+
+  function isCanvasEl(el) {
+    return el.nodeName.toUpperCase() === 'CANVAS';
+  }
+
+  var MOUSE_EVENT_REG = /^(?:mouse|pointer|contextmenu|drag|drop)|click/;
+  var _calcOut = [];
+  var firefoxNotSupportOffsetXY = env.browser.firefox && +env.browser.version.split('.')[0] < 39;
+
+  function clientToLocal(el, e, out, calculate) {
+    out = out || {};
+
+    if (calculate) {
+      calculateZrXY(el, e, out);
+    } else if (firefoxNotSupportOffsetXY && e.layerX != null && e.layerX !== e.offsetX) {
+      out.zrX = e.layerX;
+      out.zrY = e.layerY;
+    } else if (e.offsetX != null) {
+      out.zrX = e.offsetX;
+      out.zrY = e.offsetY;
+    } else {
+      calculateZrXY(el, e, out);
+    }
+
+    return out;
+  }
+
+  function calculateZrXY(el, e, out) {
+    if (env.domSupported && el.getBoundingClientRect) {
+      var ex = e.clientX;
+      var ey = e.clientY;
+
+      if (isCanvasEl(el)) {
+        var box = el.getBoundingClientRect();
+        out.zrX = ex - box.left;
+        out.zrY = ey - box.top;
+        return;
+      } else {
+        if (transformCoordWithViewport(_calcOut, el, ex, ey)) {
+          out.zrX = _calcOut[0];
+          out.zrY = _calcOut[1];
+          return;
+        }
+      }
+    }
+
+    out.zrX = out.zrY = 0;
+  }
+
+  function getNativeEvent(e) {
+    return e || window.event;
+  }
+
+  function normalizeEvent(el, e, calculate) {
+    e = getNativeEvent(e);
+
+    if (e.zrX != null) {
+      return e;
+    }
+
+    var eventType = e.type;
+    var isTouch = eventType && eventType.indexOf('touch') >= 0;
+
+    if (!isTouch) {
+      clientToLocal(el, e, e, calculate);
+      var wheelDelta = getWheelDeltaMayPolyfill(e);
+      e.zrDelta = wheelDelta ? wheelDelta / 120 : -(e.detail || 0) / 3;
+    } else {
+      var touch = eventType !== 'touchend' ? e.targetTouches[0] : e.changedTouches[0];
+      touch && clientToLocal(el, touch, e, calculate);
+    }
+
+    var button = e.button;
+
+    if (e.which == null && button !== undefined && MOUSE_EVENT_REG.test(e.type)) {
+      e.which = button & 1 ? 1 : button & 2 ? 3 : button & 4 ? 2 : 0;
+    }
+
+    return e;
+  }
+
+  function getWheelDeltaMayPolyfill(e) {
+    var rawWheelDelta = e.wheelDelta;
+
+    if (rawWheelDelta) {
+      return rawWheelDelta;
+    }
+
+    var deltaX = e.deltaX;
+    var deltaY = e.deltaY;
+
+    if (deltaX == null || deltaY == null) {
+      return rawWheelDelta;
+    }
+
+    var delta = deltaY !== 0 ? Math.abs(deltaY) : Math.abs(deltaX);
+    var sign = deltaY > 0 ? -1 : deltaY < 0 ? 1 : deltaX > 0 ? -1 : 1;
+    return 3 * delta * sign;
+  }
+
+  function addEventListener(el, name, handler, opt) {
+    el.addEventListener(name, handler, opt);
+  }
+
+  function removeEventListener(el, name, handler, opt) {
+    el.removeEventListener(name, handler, opt);
+  }
+
+  var stop = function (e) {
+    e.preventDefault();
+    e.stopPropagation();
+    e.cancelBubble = true;
+  };
+
+  var GestureMgr = function () {
+    function GestureMgr() {
+      this._track = [];
+    }
+
+    GestureMgr.prototype.recognize = function (event, target, root) {
+      this._doTrack(event, target, root);
+
+      return this._recognize(event);
+    };
+
+    GestureMgr.prototype.clear = function () {
+      this._track.length = 0;
+      return this;
+    };
+
+    GestureMgr.prototype._doTrack = function (event, target, root) {
+      var touches = event.touches;
+
+      if (!touches) {
+        return;
+      }
+
+      var trackItem = {
+        points: [],
+        touches: [],
+        target: target,
+        event: event
+      };
+
+      for (var i = 0, len = touches.length; i < len; i++) {
+        var touch = touches[i];
+        var pos = clientToLocal(root, touch, {});
+        trackItem.points.push([pos.zrX, pos.zrY]);
+        trackItem.touches.push(touch);
+      }
+
+      this._track.push(trackItem);
+    };
+
+    GestureMgr.prototype._recognize = function (event) {
+      for (var eventName in recognizers) {
+        if (recognizers.hasOwnProperty(eventName)) {
+          var gestureInfo = recognizers[eventName](this._track, event);
+
+          if (gestureInfo) {
+            return gestureInfo;
+          }
+        }
+      }
+    };
+
+    return GestureMgr;
+  }();
+
+  function dist$1(pointPair) {
+    var dx = pointPair[1][0] - pointPair[0][0];
+    var dy = pointPair[1][1] - pointPair[0][1];
+    return Math.sqrt(dx * dx + dy * dy);
+  }
+
+  function center(pointPair) {
+    return [(pointPair[0][0] + pointPair[1][0]) / 2, (pointPair[0][1] + pointPair[1][1]) / 2];
+  }
+
+  var recognizers = {
+    pinch: function (tracks, event) {
+      var trackLen = tracks.length;
+
+      if (!trackLen) {
+        return;
+      }
+
+      var pinchEnd = (tracks[trackLen - 1] || {}).points;
+      var pinchPre = (tracks[trackLen - 2] || {}).points || pinchEnd;
+
+      if (pinchPre && pinchPre.length > 1 && pinchEnd && pinchEnd.length > 1) {
+        var pinchScale = dist$1(pinchEnd) / dist$1(pinchPre);
+        !isFinite(pinchScale) && (pinchScale = 1);
+        event.pinchScale = pinchScale;
+        var pinchCenter = center(pinchEnd);
+        event.pinchX = pinchCenter[0];
+        event.pinchY = pinchCenter[1];
+        return {
+          type: 'pinch',
+          target: tracks[0].target,
+          event: event
+        };
+      }
+    }
+  };
+  var SILENT = 'silent';
+
+  function makeEventPacket(eveType, targetInfo, event) {
+    return {
+      type: eveType,
+      event: event,
+      target: targetInfo.target,
+      topTarget: targetInfo.topTarget,
+      cancelBubble: false,
+      offsetX: event.zrX,
+      offsetY: event.zrY,
+      gestureEvent: event.gestureEvent,
+      pinchX: event.pinchX,
+      pinchY: event.pinchY,
+      pinchScale: event.pinchScale,
+      wheelDelta: event.zrDelta,
+      zrByTouch: event.zrByTouch,
+      which: event.which,
+      stop: stopEvent
+    };
+  }
+
+  function stopEvent() {
+    stop(this.event);
+  }
+
+  var EmptyProxy = function (_super) {
+    __extends(EmptyProxy, _super);
+
+    function EmptyProxy() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.handler = null;
+      return _this;
+    }
+
+    EmptyProxy.prototype.dispose = function () {};
+
+    EmptyProxy.prototype.setCursor = function () {};
+
+    return EmptyProxy;
+  }(Eventful);
+
+  var HoveredResult = function () {
+    function HoveredResult(x, y) {
+      this.x = x;
+      this.y = y;
+    }
+
+    return HoveredResult;
+  }();
+
+  var handlerNames = ['click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu'];
+
+  var Handler = function (_super) {
+    __extends(Handler, _super);
+
+    function Handler(storage, painter, proxy, painterRoot) {
+      var _this = _super.call(this) || this;
+
+      _this._hovered = new HoveredResult(0, 0);
+      _this.storage = storage;
+      _this.painter = painter;
+      _this.painterRoot = painterRoot;
+      proxy = proxy || new EmptyProxy();
+      _this.proxy = null;
+
+      _this.setHandlerProxy(proxy);
+
+      _this._draggingMgr = new Draggable(_this);
+      return _this;
+    }
+
+    Handler.prototype.setHandlerProxy = function (proxy) {
+      if (this.proxy) {
+        this.proxy.dispose();
+      }
+
+      if (proxy) {
+        each(handlerNames, function (name) {
+          proxy.on && proxy.on(name, this[name], this);
+        }, this);
+        proxy.handler = this;
+      }
+
+      this.proxy = proxy;
+    };
+
+    Handler.prototype.mousemove = function (event) {
+      var x = event.zrX;
+      var y = event.zrY;
+      var isOutside = isOutsideBoundary(this, x, y);
+      var lastHovered = this._hovered;
+      var lastHoveredTarget = lastHovered.target;
+
+      if (lastHoveredTarget && !lastHoveredTarget.__zr) {
+        lastHovered = this.findHover(lastHovered.x, lastHovered.y);
+        lastHoveredTarget = lastHovered.target;
+      }
+
+      var hovered = this._hovered = isOutside ? new HoveredResult(x, y) : this.findHover(x, y);
+      var hoveredTarget = hovered.target;
+      var proxy = this.proxy;
+      proxy.setCursor && proxy.setCursor(hoveredTarget ? hoveredTarget.cursor : 'default');
+
+      if (lastHoveredTarget && hoveredTarget !== lastHoveredTarget) {
+        this.dispatchToElement(lastHovered, 'mouseout', event);
+      }
+
+      this.dispatchToElement(hovered, 'mousemove', event);
+
+      if (hoveredTarget && hoveredTarget !== lastHoveredTarget) {
+        this.dispatchToElement(hovered, 'mouseover', event);
+      }
+    };
+
+    Handler.prototype.mouseout = function (event) {
+      var eventControl = event.zrEventControl;
+
+      if (eventControl !== 'only_globalout') {
+        this.dispatchToElement(this._hovered, 'mouseout', event);
+      }
+
+      if (eventControl !== 'no_globalout') {
+        this.trigger('globalout', {
+          type: 'globalout',
+          event: event
+        });
+      }
+    };
+
+    Handler.prototype.resize = function () {
+      this._hovered = new HoveredResult(0, 0);
+    };
+
+    Handler.prototype.dispatch = function (eventName, eventArgs) {
+      var handler = this[eventName];
+      handler && handler.call(this, eventArgs);
+    };
+
+    Handler.prototype.dispose = function () {
+      this.proxy.dispose();
+      this.storage = null;
+      this.proxy = null;
+      this.painter = null;
+    };
+
+    Handler.prototype.setCursorStyle = function (cursorStyle) {
+      var proxy = this.proxy;
+      proxy.setCursor && proxy.setCursor(cursorStyle);
+    };
+
+    Handler.prototype.dispatchToElement = function (targetInfo, eventName, event) {
+      targetInfo = targetInfo || {};
+      var el = targetInfo.target;
+
+      if (el && el.silent) {
+        return;
+      }
+
+      var eventKey = 'on' + eventName;
+      var eventPacket = makeEventPacket(eventName, targetInfo, event);
+
+      while (el) {
+        el[eventKey] && (eventPacket.cancelBubble = !!el[eventKey].call(el, eventPacket));
+        el.trigger(eventName, eventPacket);
+        el = el.__hostTarget ? el.__hostTarget : el.parent;
+
+        if (eventPacket.cancelBubble) {
+          break;
+        }
+      }
+
+      if (!eventPacket.cancelBubble) {
+        this.trigger(eventName, eventPacket);
+
+        if (this.painter && this.painter.eachOtherLayer) {
+          this.painter.eachOtherLayer(function (layer) {
+            if (typeof layer[eventKey] === 'function') {
+              layer[eventKey].call(layer, eventPacket);
+            }
+
+            if (layer.trigger) {
+              layer.trigger(eventName, eventPacket);
+            }
+          });
+        }
+      }
+    };
+
+    Handler.prototype.findHover = function (x, y, exclude) {
+      var list = this.storage.getDisplayList();
+      var out = new HoveredResult(x, y);
+
+      for (var i = list.length - 1; i >= 0; i--) {
+        var hoverCheckResult = void 0;
+
+        if (list[i] !== exclude && !list[i].ignore && (hoverCheckResult = isHover(list[i], x, y))) {
+          !out.topTarget && (out.topTarget = list[i]);
+
+          if (hoverCheckResult !== SILENT) {
+            out.target = list[i];
+            break;
+          }
+        }
+      }
+
+      return out;
+    };
+
+    Handler.prototype.processGesture = function (event, stage) {
+      if (!this._gestureMgr) {
+        this._gestureMgr = new GestureMgr();
+      }
+
+      var gestureMgr = this._gestureMgr;
+      stage === 'start' && gestureMgr.clear();
+      var gestureInfo = gestureMgr.recognize(event, this.findHover(event.zrX, event.zrY, null).target, this.proxy.dom);
+      stage === 'end' && gestureMgr.clear();
+
+      if (gestureInfo) {
+        var type = gestureInfo.type;
+        event.gestureEvent = type;
+        var res = new HoveredResult();
+        res.target = gestureInfo.target;
+        this.dispatchToElement(res, type, gestureInfo.event);
+      }
+    };
+
+    return Handler;
+  }(Eventful);
+
+  each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
+    Handler.prototype[name] = function (event) {
+      var x = event.zrX;
+      var y = event.zrY;
+      var isOutside = isOutsideBoundary(this, x, y);
+      var hovered;
+      var hoveredTarget;
+
+      if (name !== 'mouseup' || !isOutside) {
+        hovered = this.findHover(x, y);
+        hoveredTarget = hovered.target;
+      }
+
+      if (name === 'mousedown') {
+        this._downEl = hoveredTarget;
+        this._downPoint = [event.zrX, event.zrY];
+        this._upEl = hoveredTarget;
+      } else if (name === 'mouseup') {
+        this._upEl = hoveredTarget;
+      } else if (name === 'click') {
+        if (this._downEl !== this._upEl || !this._downPoint || dist(this._downPoint, [event.zrX, event.zrY]) > 4) {
+          return;
+        }
+
+        this._downPoint = null;
+      }
+
+      this.dispatchToElement(hovered, name, event);
+    };
+  });
+
+  function isHover(displayable, x, y) {
+    if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {
+      var el = displayable;
+      var isSilent = void 0;
+      var ignoreClip = false;
+
+      while (el) {
+        if (el.ignoreClip) {
+          ignoreClip = true;
+        }
+
+        if (!ignoreClip) {
+          var clipPath = el.getClipPath();
+
+          if (clipPath && !clipPath.contain(x, y)) {
+            return false;
+          }
+
+          if (el.silent) {
+            isSilent = true;
+          }
+        }
+
+        var hostEl = el.__hostTarget;
+        el = hostEl ? hostEl : el.parent;
+      }
+
+      return isSilent ? SILENT : true;
+    }
+
+    return false;
+  }
+
+  function isOutsideBoundary(handlerInstance, x, y) {
+    var painter = handlerInstance.painter;
+    return x < 0 || x > painter.getWidth() || y < 0 || y > painter.getHeight();
+  }
+
+  var DEFAULT_MIN_MERGE = 32;
+  var DEFAULT_MIN_GALLOPING = 7;
+
+  function minRunLength(n) {
+    var r = 0;
+
+    while (n >= DEFAULT_MIN_MERGE) {
+      r |= n & 1;
+      n >>= 1;
+    }
+
+    return n + r;
+  }
+
+  function makeAscendingRun(array, lo, hi, compare) {
+    var runHi = lo + 1;
+
+    if (runHi === hi) {
+      return 1;
+    }
+
+    if (compare(array[runHi++], array[lo]) < 0) {
+      while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
+        runHi++;
+      }
+
+      reverseRun(array, lo, runHi);
+    } else {
+      while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
+        runHi++;
+      }
+    }
+
+    return runHi - lo;
+  }
+
+  function reverseRun(array, lo, hi) {
+    hi--;
+
+    while (lo < hi) {
+      var t = array[lo];
+      array[lo++] = array[hi];
+      array[hi--] = t;
+    }
+  }
+
+  function binaryInsertionSort(array, lo, hi, start, compare) {
+    if (start === lo) {
+      start++;
+    }
+
+    for (; start < hi; start++) {
+      var pivot = array[start];
+      var left = lo;
+      var right = start;
+      var mid;
+
+      while (left < right) {
+        mid = left + right >>> 1;
+
+        if (compare(pivot, array[mid]) < 0) {
+          right = mid;
+        } else {
+          left = mid + 1;
+        }
+      }
+
+      var n = start - left;
+
+      switch (n) {
+        case 3:
+          array[left + 3] = array[left + 2];
+
+        case 2:
+          array[left + 2] = array[left + 1];
+
+        case 1:
+          array[left + 1] = array[left];
+          break;
+
+        default:
+          while (n > 0) {
+            array[left + n] = array[left + n - 1];
+            n--;
+          }
+
+      }
+
+      array[left] = pivot;
+    }
+  }
+
+  function gallopLeft(value, array, start, length, hint, compare) {
+    var lastOffset = 0;
+    var maxOffset = 0;
+    var offset = 1;
+
+    if (compare(value, array[start + hint]) > 0) {
+      maxOffset = length - hint;
+
+      while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
+
+        if (offset <= 0) {
+          offset = maxOffset;
+        }
+      }
+
+      if (offset > maxOffset) {
+        offset = maxOffset;
+      }
+
+      lastOffset += hint;
+      offset += hint;
+    } else {
+      maxOffset = hint + 1;
+
+      while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
+
+        if (offset <= 0) {
+          offset = maxOffset;
+        }
+      }
+
+      if (offset > maxOffset) {
+        offset = maxOffset;
+      }
+
+      var tmp = lastOffset;
+      lastOffset = hint - offset;
+      offset = hint - tmp;
+    }
+
+    lastOffset++;
+
+    while (lastOffset < offset) {
+      var m = lastOffset + (offset - lastOffset >>> 1);
+
+      if (compare(value, array[start + m]) > 0) {
+        lastOffset = m + 1;
+      } else {
+        offset = m;
+      }
+    }
+
+    return offset;
+  }
+
+  function gallopRight(value, array, start, length, hint, compare) {
+    var lastOffset = 0;
+    var maxOffset = 0;
+    var offset = 1;
+
+    if (compare(value, array[start + hint]) < 0) {
+      maxOffset = hint + 1;
+
+      while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
+
+        if (offset <= 0) {
+          offset = maxOffset;
+        }
+      }
+
+      if (offset > maxOffset) {
+        offset = maxOffset;
+      }
+
+      var tmp = lastOffset;
+      lastOffset = hint - offset;
+      offset = hint - tmp;
+    } else {
+      maxOffset = length - hint;
+
+      while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
+
+        if (offset <= 0) {
+          offset = maxOffset;
+        }
+      }
+
+      if (offset > maxOffset) {
+        offset = maxOffset;
+      }
+
+      lastOffset += hint;
+      offset += hint;
+    }
+
+    lastOffset++;
+
+    while (lastOffset < offset) {
+      var m = lastOffset + (offset - lastOffset >>> 1);
+
+      if (compare(value, array[start + m]) < 0) {
+        offset = m;
+      } else {
+        lastOffset = m + 1;
+      }
+    }
+
+    return offset;
+  }
+
+  function TimSort(array, compare) {
+    var minGallop = DEFAULT_MIN_GALLOPING;
+    var runStart;
+    var runLength;
+    var stackSize = 0;
+    var tmp = [];
+    runStart = [];
+    runLength = [];
+
+    function pushRun(_runStart, _runLength) {
+      runStart[stackSize] = _runStart;
+      runLength[stackSize] = _runLength;
+      stackSize += 1;
+    }
+
+    function mergeRuns() {
+      while (stackSize > 1) {
+        var n = stackSize - 2;
+
+        if (n >= 1 && runLength[n - 1] <= runLength[n] + runLength[n + 1] || n >= 2 && runLength[n - 2] <= runLength[n] + runLength[n - 1]) {
+          if (runLength[n - 1] < runLength[n + 1]) {
+            n--;
+          }
+        } else if (runLength[n] > runLength[n + 1]) {
+          break;
+        }
+
+        mergeAt(n);
+      }
+    }
+
+    function forceMergeRuns() {
+      while (stackSize > 1) {
+        var n = stackSize - 2;
+
+        if (n > 0 && runLength[n - 1] < runLength[n + 1]) {
+          n--;
+        }
+
+        mergeAt(n);
+      }
+    }
+
+    function mergeAt(i) {
+      var start1 = runStart[i];
+      var length1 = runLength[i];
+      var start2 = runStart[i + 1];
+      var length2 = runLength[i + 1];
+      runLength[i] = length1 + length2;
+
+      if (i === stackSize - 3) {
+        runStart[i + 1] = runStart[i + 2];
+        runLength[i + 1] = runLength[i + 2];
+      }
+
+      stackSize--;
+      var k = gallopRight(array[start2], array, start1, length1, 0, compare);
+      start1 += k;
+      length1 -= k;
+
+      if (length1 === 0) {
+        return;
+      }
+
+      length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
+
+      if (length2 === 0) {
+        return;
+      }
+
+      if (length1 <= length2) {
+        mergeLow(start1, length1, start2, length2);
+      } else {
+        mergeHigh(start1, length1, start2, length2);
+      }
+    }
+
+    function mergeLow(start1, length1, start2, length2) {
+      var i = 0;
+
+      for (i = 0; i < length1; i++) {
+        tmp[i] = array[start1 + i];
+      }
+
+      var cursor1 = 0;
+      var cursor2 = start2;
+      var dest = start1;
+      array[dest++] = array[cursor2++];
+
+      if (--length2 === 0) {
+        for (i = 0; i < length1; i++) {
+          array[dest + i] = tmp[cursor1 + i];
+        }
+
+        return;
+      }
+
+      if (length1 === 1) {
+        for (i = 0; i < length2; i++) {
+          array[dest + i] = array[cursor2 + i];
+        }
+
+        array[dest + length2] = tmp[cursor1];
+        return;
+      }
+
+      var _minGallop = minGallop;
+      var count1;
+      var count2;
+      var exit;
+
+      while (1) {
+        count1 = 0;
+        count2 = 0;
+        exit = false;
+
+        do {
+          if (compare(array[cursor2], tmp[cursor1]) < 0) {
+            array[dest++] = array[cursor2++];
+            count2++;
+            count1 = 0;
+
+            if (--length2 === 0) {
+              exit = true;
+              break;
+            }
+          } else {
+            array[dest++] = tmp[cursor1++];
+            count1++;
+            count2 = 0;
+
+            if (--length1 === 1) {
+              exit = true;
+              break;
+            }
+          }
+        } while ((count1 | count2) < _minGallop);
+
+        if (exit) {
+          break;
+        }
+
+        do {
+          count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
+
+          if (count1 !== 0) {
+            for (i = 0; i < count1; i++) {
+              array[dest + i] = tmp[cursor1 + i];
+            }
+
+            dest += count1;
+            cursor1 += count1;
+            length1 -= count1;
+
+            if (length1 <= 1) {
+              exit = true;
+              break;
+            }
+          }
+
+          array[dest++] = array[cursor2++];
+
+          if (--length2 === 0) {
+            exit = true;
+            break;
+          }
+
+          count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
+
+          if (count2 !== 0) {
+            for (i = 0; i < count2; i++) {
+              array[dest + i] = array[cursor2 + i];
+            }
+
+            dest += count2;
+            cursor2 += count2;
+            length2 -= count2;
+
+            if (length2 === 0) {
+              exit = true;
+              break;
+            }
+          }
+
+          array[dest++] = tmp[cursor1++];
+
+          if (--length1 === 1) {
+            exit = true;
+            break;
+          }
+
+          _minGallop--;
+        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
+
+        if (exit) {
+          break;
+        }
+
+        if (_minGallop < 0) {
+          _minGallop = 0;
+        }
+
+        _minGallop += 2;
+      }
+
+      minGallop = _minGallop;
+      minGallop < 1 && (minGallop = 1);
+
+      if (length1 === 1) {
+        for (i = 0; i < length2; i++) {
+          array[dest + i] = array[cursor2 + i];
+        }
+
+        array[dest + length2] = tmp[cursor1];
+      } else if (length1 === 0) {
+        throw new Error();
+      } else {
+        for (i = 0; i < length1; i++) {
+          array[dest + i] = tmp[cursor1 + i];
+        }
+      }
+    }
+
+    function mergeHigh(start1, length1, start2, length2) {
+      var i = 0;
+
+      for (i = 0; i < length2; i++) {
+        tmp[i] = array[start2 + i];
+      }
+
+      var cursor1 = start1 + length1 - 1;
+      var cursor2 = length2 - 1;
+      var dest = start2 + length2 - 1;
+      var customCursor = 0;
+      var customDest = 0;
+      array[dest--] = array[cursor1--];
+
+      if (--length1 === 0) {
+        customCursor = dest - (length2 - 1);
+
+        for (i = 0; i < length2; i++) {
+          array[customCursor + i] = tmp[i];
+        }
+
+        return;
+      }
+
+      if (length2 === 1) {
+        dest -= length1;
+        cursor1 -= length1;
+        customDest = dest + 1;
+        customCursor = cursor1 + 1;
+
+        for (i = length1 - 1; i >= 0; i--) {
+          array[customDest + i] = array[customCursor + i];
+        }
+
+        array[dest] = tmp[cursor2];
+        return;
+      }
+
+      var _minGallop = minGallop;
+
+      while (true) {
+        var count1 = 0;
+        var count2 = 0;
+        var exit = false;
+
+        do {
+          if (compare(tmp[cursor2], array[cursor1]) < 0) {
+            array[dest--] = array[cursor1--];
+            count1++;
+            count2 = 0;
+
+            if (--length1 === 0) {
+              exit = true;
+              break;
+            }
+          } else {
+            array[dest--] = tmp[cursor2--];
+            count2++;
+            count1 = 0;
+
+            if (--length2 === 1) {
+              exit = true;
+              break;
+            }
+          }
+        } while ((count1 | count2) < _minGallop);
+
+        if (exit) {
+          break;
+        }
+
+        do {
+          count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
+
+          if (count1 !== 0) {
+            dest -= count1;
+            cursor1 -= count1;
+            length1 -= count1;
+            customDest = dest + 1;
+            customCursor = cursor1 + 1;
+
+            for (i = count1 - 1; i >= 0; i--) {
+              array[customDest + i] = array[customCursor + i];
+            }
+
+            if (length1 === 0) {
+              exit = true;
+              break;
+            }
+          }
+
+          array[dest--] = tmp[cursor2--];
+
+          if (--length2 === 1) {
+            exit = true;
+            break;
+          }
+
+          count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
+
+          if (count2 !== 0) {
+            dest -= count2;
+            cursor2 -= count2;
+            length2 -= count2;
+            customDest = dest + 1;
+            customCursor = cursor2 + 1;
+
+            for (i = 0; i < count2; i++) {
+              array[customDest + i] = tmp[customCursor + i];
+            }
+
+            if (length2 <= 1) {
+              exit = true;
+              break;
+            }
+          }
+
+          array[dest--] = array[cursor1--];
+
+          if (--length1 === 0) {
+            exit = true;
+            break;
+          }
+
+          _minGallop--;
+        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
+
+        if (exit) {
+          break;
+        }
+
+        if (_minGallop < 0) {
+          _minGallop = 0;
+        }
+
+        _minGallop += 2;
+      }
+
+      minGallop = _minGallop;
+
+      if (minGallop < 1) {
+        minGallop = 1;
+      }
+
+      if (length2 === 1) {
+        dest -= length1;
+        cursor1 -= length1;
+        customDest = dest + 1;
+        customCursor = cursor1 + 1;
+
+        for (i = length1 - 1; i >= 0; i--) {
+          array[customDest + i] = array[customCursor + i];
+        }
+
+        array[dest] = tmp[cursor2];
+      } else if (length2 === 0) {
+        throw new Error();
+      } else {
+        customCursor = dest - (length2 - 1);
+
+        for (i = 0; i < length2; i++) {
+          array[customCursor + i] = tmp[i];
+        }
+      }
+    }
+
+    return {
+      mergeRuns: mergeRuns,
+      forceMergeRuns: forceMergeRuns,
+      pushRun: pushRun
+    };
+  }
+
+  function sort(array, compare, lo, hi) {
+    if (!lo) {
+      lo = 0;
+    }
+
+    if (!hi) {
+      hi = array.length;
+    }
+
+    var remaining = hi - lo;
+
+    if (remaining < 2) {
+      return;
+    }
+
+    var runLength = 0;
+
+    if (remaining < DEFAULT_MIN_MERGE) {
+      runLength = makeAscendingRun(array, lo, hi, compare);
+      binaryInsertionSort(array, lo, hi, lo + runLength, compare);
+      return;
+    }
+
+    var ts = TimSort(array, compare);
+    var minRun = minRunLength(remaining);
+
+    do {
+      runLength = makeAscendingRun(array, lo, hi, compare);
+
+      if (runLength < minRun) {
+        var force = remaining;
+
+        if (force > minRun) {
+          force = minRun;
+        }
+
+        binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
+        runLength = force;
+      }
+
+      ts.pushRun(lo, runLength);
+      ts.mergeRuns();
+      remaining -= runLength;
+      lo += runLength;
+    } while (remaining !== 0);
+
+    ts.forceMergeRuns();
+  }
+
+  var REDRAW_BIT = 1;
+  var STYLE_CHANGED_BIT = 2;
+  var SHAPE_CHANGED_BIT = 4;
+  var invalidZErrorLogged = false;
+
+  function logInvalidZError() {
+    if (invalidZErrorLogged) {
+      return;
+    }
+
+    invalidZErrorLogged = true;
+    console.warn('z / z2 / zlevel of displayable is invalid, which may cause unexpected errors');
+  }
+
+  function shapeCompareFunc(a, b) {
+    if (a.zlevel === b.zlevel) {
+      if (a.z === b.z) {
+        return a.z2 - b.z2;
+      }
+
+      return a.z - b.z;
+    }
+
+    return a.zlevel - b.zlevel;
+  }
+
+  var Storage = function () {
+    function Storage() {
+      this._roots = [];
+      this._displayList = [];
+      this._displayListLen = 0;
+      this.displayableSortFunc = shapeCompareFunc;
+    }
+
+    Storage.prototype.traverse = function (cb, context) {
+      for (var i = 0; i < this._roots.length; i++) {
+        this._roots[i].traverse(cb, context);
+      }
+    };
+
+    Storage.prototype.getDisplayList = function (update, includeIgnore) {
+      includeIgnore = includeIgnore || false;
+      var displayList = this._displayList;
+
+      if (update || !displayList.length) {
+        this.updateDisplayList(includeIgnore);
+      }
+
+      return displayList;
+    };
+
+    Storage.prototype.updateDisplayList = function (includeIgnore) {
+      this._displayListLen = 0;
+      var roots = this._roots;
+      var displayList = this._displayList;
+
+      for (var i = 0, len = roots.length; i < len; i++) {
+        this._updateAndAddDisplayable(roots[i], null, includeIgnore);
+      }
+
+      displayList.length = this._displayListLen;
+      sort(displayList, shapeCompareFunc);
+    };
+
+    Storage.prototype._updateAndAddDisplayable = function (el, clipPaths, includeIgnore) {
+      if (el.ignore && !includeIgnore) {
+        return;
+      }
+
+      el.beforeUpdate();
+      el.update();
+      el.afterUpdate();
+      var userSetClipPath = el.getClipPath();
+
+      if (el.ignoreClip) {
+        clipPaths = null;
+      } else if (userSetClipPath) {
+        if (clipPaths) {
+          clipPaths = clipPaths.slice();
+        } else {
+          clipPaths = [];
+        }
+
+        var currentClipPath = userSetClipPath;
+        var parentClipPath = el;
+
+        while (currentClipPath) {
+          currentClipPath.parent = parentClipPath;
+          currentClipPath.updateTransform();
+          clipPaths.push(currentClipPath);
+          parentClipPath = currentClipPath;
+          currentClipPath = currentClipPath.getClipPath();
+        }
+      }
+
+      if (el.childrenRef) {
+        var children = el.childrenRef();
+
+        for (var i = 0; i < children.length; i++) {
+          var child = children[i];
+
+          if (el.__dirty) {
+            child.__dirty |= REDRAW_BIT;
+          }
+
+          this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
+        }
+
+        el.__dirty = 0;
+      } else {
+        var disp = el;
+
+        if (clipPaths && clipPaths.length) {
+          disp.__clipPaths = clipPaths;
+        } else if (disp.__clipPaths && disp.__clipPaths.length > 0) {
+          disp.__clipPaths = [];
+        }
+
+        if (isNaN(disp.z)) {
+          logInvalidZError();
+          disp.z = 0;
+        }
+
+        if (isNaN(disp.z2)) {
+          logInvalidZError();
+          disp.z2 = 0;
+        }
+
+        if (isNaN(disp.zlevel)) {
+          logInvalidZError();
+          disp.zlevel = 0;
+        }
+
+        this._displayList[this._displayListLen++] = disp;
+      }
+
+      var decalEl = el.getDecalElement && el.getDecalElement();
+
+      if (decalEl) {
+        this._updateAndAddDisplayable(decalEl, clipPaths, includeIgnore);
+      }
+
+      var textGuide = el.getTextGuideLine();
+
+      if (textGuide) {
+        this._updateAndAddDisplayable(textGuide, clipPaths, includeIgnore);
+      }
+
+      var textEl = el.getTextContent();
+
+      if (textEl) {
+        this._updateAndAddDisplayable(textEl, clipPaths, includeIgnore);
+      }
+    };
+
+    Storage.prototype.addRoot = function (el) {
+      if (el.__zr && el.__zr.storage === this) {
+        return;
+      }
+
+      this._roots.push(el);
+    };
+
+    Storage.prototype.delRoot = function (el) {
+      if (el instanceof Array) {
+        for (var i = 0, l = el.length; i < l; i++) {
+          this.delRoot(el[i]);
+        }
+
+        return;
+      }
+
+      var idx = indexOf(this._roots, el);
+
+      if (idx >= 0) {
+        this._roots.splice(idx, 1);
+      }
+    };
+
+    Storage.prototype.delAllRoots = function () {
+      this._roots = [];
+      this._displayList = [];
+      this._displayListLen = 0;
+      return;
+    };
+
+    Storage.prototype.getRoots = function () {
+      return this._roots;
+    };
+
+    Storage.prototype.dispose = function () {
+      this._displayList = null;
+      this._roots = null;
+    };
+
+    return Storage;
+  }();
+
+  var requestAnimationFrame;
+
+  requestAnimationFrame = env.hasGlobalWindow && (window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window) || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame) || function (func) {
+    return setTimeout(func, 16);
+  };
+
+  var requestAnimationFrame$1 = requestAnimationFrame;
+  var easingFuncs = {
+    linear: function (k) {
+      return k;
+    },
+    quadraticIn: function (k) {
+      return k * k;
+    },
+    quadraticOut: function (k) {
+      return k * (2 - k);
+    },
+    quadraticInOut: function (k) {
+      if ((k *= 2) < 1) {
+        return 0.5 * k * k;
+      }
+
+      return -0.5 * (--k * (k - 2) - 1);
+    },
+    cubicIn: function (k) {
+      return k * k * k;
+    },
+    cubicOut: function (k) {
+      return --k * k * k + 1;
+    },
+    cubicInOut: function (k) {
+      if ((k *= 2) < 1) {
+        return 0.5 * k * k * k;
+      }
+
+      return 0.5 * ((k -= 2) * k * k + 2);
+    },
+    quarticIn: function (k) {
+      return k * k * k * k;
+    },
+    quarticOut: function (k) {
+      return 1 - --k * k * k * k;
+    },
+    quarticInOut: function (k) {
+      if ((k *= 2) < 1) {
+        return 0.5 * k * k * k * k;
+      }
+
+      return -0.5 * ((k -= 2) * k * k * k - 2);
+    },
+    quinticIn: function (k) {
+      return k * k * k * k * k;
+    },
+    quinticOut: function (k) {
+      return --k * k * k * k * k + 1;
+    },
+    quinticInOut: function (k) {
+      if ((k *= 2) < 1) {
+        return 0.5 * k * k * k * k * k;
+      }
+
+      return 0.5 * ((k -= 2) * k * k * k * k + 2);
+    },
+    sinusoidalIn: function (k) {
+      return 1 - Math.cos(k * Math.PI / 2);
+    },
+    sinusoidalOut: function (k) {
+      return Math.sin(k * Math.PI / 2);
+    },
+    sinusoidalInOut: function (k) {
+      return 0.5 * (1 - Math.cos(Math.PI * k));
+    },
+    exponentialIn: function (k) {
+      return k === 0 ? 0 : Math.pow(1024, k - 1);
+    },
+    exponentialOut: function (k) {
+      return k === 1 ? 1 : 1 - Math.pow(2, -10 * k);
+    },
+    exponentialInOut: function (k) {
+      if (k === 0) {
+        return 0;
+      }
+
+      if (k === 1) {
+        return 1;
+      }
+
+      if ((k *= 2) < 1) {
+        return 0.5 * Math.pow(1024, k - 1);
+      }
+
+      return 0.5 * (-Math.pow(2, -10 * (k - 1)) + 2);
+    },
+    circularIn: function (k) {
+      return 1 - Math.sqrt(1 - k * k);
+    },
+    circularOut: function (k) {
+      return Math.sqrt(1 - --k * k);
+    },
+    circularInOut: function (k) {
+      if ((k *= 2) < 1) {
+        return -0.5 * (Math.sqrt(1 - k * k) - 1);
+      }
+
+      return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
+    },
+    elasticIn: function (k) {
+      var s;
+      var a = 0.1;
+      var p = 0.4;
+
+      if (k === 0) {
+        return 0;
+      }
+
+      if (k === 1) {
+        return 1;
+      }
+
+      if (!a || a < 1) {
+        a = 1;
+        s = p / 4;
+      } else {
+        s = p * Math.asin(1 / a) / (2 * Math.PI);
+      }
+
+      return -(a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
+    },
+    elasticOut: function (k) {
+      var s;
+      var a = 0.1;
+      var p = 0.4;
+
+      if (k === 0) {
+        return 0;
+      }
+
+      if (k === 1) {
+        return 1;
+      }
+
+      if (!a || a < 1) {
+        a = 1;
+        s = p / 4;
+      } else {
+        s = p * Math.asin(1 / a) / (2 * Math.PI);
+      }
+
+      return a * Math.pow(2, -10 * k) * Math.sin((k - s) * (2 * Math.PI) / p) + 1;
+    },
+    elasticInOut: function (k) {
+      var s;
+      var a = 0.1;
+      var p = 0.4;
+
+      if (k === 0) {
+        return 0;
+      }
+
+      if (k === 1) {
+        return 1;
+      }
+
+      if (!a || a < 1) {
+        a = 1;
+        s = p / 4;
+      } else {
+        s = p * Math.asin(1 / a) / (2 * Math.PI);
+      }
+
+      if ((k *= 2) < 1) {
+        return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
+      }
+
+      return a * Math.pow(2, -10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1;
+    },
+    backIn: function (k) {
+      var s = 1.70158;
+      return k * k * ((s + 1) * k - s);
+    },
+    backOut: function (k) {
+      var s = 1.70158;
+      return --k * k * ((s + 1) * k + s) + 1;
+    },
+    backInOut: function (k) {
+      var s = 1.70158 * 1.525;
+
+      if ((k *= 2) < 1) {
+        return 0.5 * (k * k * ((s + 1) * k - s));
+      }
+
+      return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
+    },
+    bounceIn: function (k) {
+      return 1 - easingFuncs.bounceOut(1 - k);
+    },
+    bounceOut: function (k) {
+      if (k < 1 / 2.75) {
+        return 7.5625 * k * k;
+      } else if (k < 2 / 2.75) {
+        return 7.5625 * (k -= 1.5 / 2.75) * k + 0.75;
+      } else if (k < 2.5 / 2.75) {
+        return 7.5625 * (k -= 2.25 / 2.75) * k + 0.9375;
+      } else {
+        return 7.5625 * (k -= 2.625 / 2.75) * k + 0.984375;
+      }
+    },
+    bounceInOut: function (k) {
+      if (k < 0.5) {
+        return easingFuncs.bounceIn(k * 2) * 0.5;
+      }
+
+      return easingFuncs.bounceOut(k * 2 - 1) * 0.5 + 0.5;
+    }
+  };
+  var mathPow = Math.pow;
+  var mathSqrt = Math.sqrt;
+  var EPSILON = 1e-8;
+  var EPSILON_NUMERIC = 1e-4;
+  var THREE_SQRT = mathSqrt(3);
+  var ONE_THIRD = 1 / 3;
+
+  var _v0 = create();
+
+  var _v1 = create();
+
+  var _v2 = create();
+
+  function isAroundZero(val) {
+    return val > -EPSILON && val < EPSILON;
+  }
+
+  function isNotAroundZero(val) {
+    return val > EPSILON || val < -EPSILON;
+  }
+
+  function cubicAt(p0, p1, p2, p3, t) {
+    var onet = 1 - t;
+    return onet * onet * (onet * p0 + 3 * t * p1) + t * t * (t * p3 + 3 * onet * p2);
+  }
+
+  function cubicDerivativeAt(p0, p1, p2, p3, t) {
+    var onet = 1 - t;
+    return 3 * (((p1 - p0) * onet + 2 * (p2 - p1) * t) * onet + (p3 - p2) * t * t);
+  }
+
+  function cubicRootAt(p0, p1, p2, p3, val, roots) {
+    var a = p3 + 3 * (p1 - p2) - p0;
+    var b = 3 * (p2 - p1 * 2 + p0);
+    var c = 3 * (p1 - p0);
+    var d = p0 - val;
+    var A = b * b - 3 * a * c;
+    var B = b * c - 9 * a * d;
+    var C = c * c - 3 * b * d;
+    var n = 0;
+
+    if (isAroundZero(A) && isAroundZero(B)) {
+      if (isAroundZero(b)) {
+        roots[0] = 0;
+      } else {
+        var t1 = -c / b;
+
+        if (t1 >= 0 && t1 <= 1) {
+          roots[n++] = t1;
+        }
+      }
+    } else {
+      var disc = B * B - 4 * A * C;
+
+      if (isAroundZero(disc)) {
+        var K = B / A;
+        var t1 = -b / a + K;
+        var t2 = -K / 2;
+
+        if (t1 >= 0 && t1 <= 1) {
+          roots[n++] = t1;
+        }
+
+        if (t2 >= 0 && t2 <= 1) {
+          roots[n++] = t2;
+        }
+      } else if (disc > 0) {
+        var discSqrt = mathSqrt(disc);
+        var Y1 = A * b + 1.5 * a * (-B + discSqrt);
+        var Y2 = A * b + 1.5 * a * (-B - discSqrt);
+
+        if (Y1 < 0) {
+          Y1 = -mathPow(-Y1, ONE_THIRD);
+        } else {
+          Y1 = mathPow(Y1, ONE_THIRD);
+        }
+
+        if (Y2 < 0) {
+          Y2 = -mathPow(-Y2, ONE_THIRD);
+        } else {
+          Y2 = mathPow(Y2, ONE_THIRD);
+        }
+
+        var t1 = (-b - (Y1 + Y2)) / (3 * a);
+
+        if (t1 >= 0 && t1 <= 1) {
+          roots[n++] = t1;
+        }
+      } else {
+        var T = (2 * A * b - 3 * a * B) / (2 * mathSqrt(A * A * A));
+        var theta = Math.acos(T) / 3;
+        var ASqrt = mathSqrt(A);
+        var tmp = Math.cos(theta);
+        var t1 = (-b - 2 * ASqrt * tmp) / (3 * a);
+        var t2 = (-b + ASqrt * (tmp + THREE_SQRT * Math.sin(theta))) / (3 * a);
+        var t3 = (-b + ASqrt * (tmp - THREE_SQRT * Math.sin(theta))) / (3 * a);
+
+        if (t1 >= 0 && t1 <= 1) {
+          roots[n++] = t1;
+        }
+
+        if (t2 >= 0 && t2 <= 1) {
+          roots[n++] = t2;
+        }
+
+        if (t3 >= 0 && t3 <= 1) {
+          roots[n++] = t3;
+        }
+      }
+    }
+
+    return n;
+  }
+
+  function cubicExtrema(p0, p1, p2, p3, extrema) {
+    var b = 6 * p2 - 12 * p1 + 6 * p0;
+    var a = 9 * p1 + 3 * p3 - 3 * p0 - 9 * p2;
+    var c = 3 * p1 - 3 * p0;
+    var n = 0;
+
+    if (isAroundZero(a)) {
+      if (isNotAroundZero(b)) {
+        var t1 = -c / b;
+
+        if (t1 >= 0 && t1 <= 1) {
+          extrema[n++] = t1;
+        }
+      }
+    } else {
+      var disc = b * b - 4 * a * c;
+
+      if (isAroundZero(disc)) {
+        extrema[0] = -b / (2 * a);
+      } else if (disc > 0) {
+        var discSqrt = mathSqrt(disc);
+        var t1 = (-b + discSqrt) / (2 * a);
+        var t2 = (-b - discSqrt) / (2 * a);
+
+        if (t1 >= 0 && t1 <= 1) {
+          extrema[n++] = t1;
+        }
+
+        if (t2 >= 0 && t2 <= 1) {
+          extrema[n++] = t2;
+        }
+      }
+    }
+
+    return n;
+  }
+
+  function cubicSubdivide(p0, p1, p2, p3, t, out) {
+    var p01 = (p1 - p0) * t + p0;
+    var p12 = (p2 - p1) * t + p1;
+    var p23 = (p3 - p2) * t + p2;
+    var p012 = (p12 - p01) * t + p01;
+    var p123 = (p23 - p12) * t + p12;
+    var p0123 = (p123 - p012) * t + p012;
+    out[0] = p0;
+    out[1] = p01;
+    out[2] = p012;
+    out[3] = p0123;
+    out[4] = p0123;
+    out[5] = p123;
+    out[6] = p23;
+    out[7] = p3;
+  }
+
+  function cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, out) {
+    var t;
+    var interval = 0.005;
+    var d = Infinity;
+    var prev;
+    var next;
+    var d1;
+    var d2;
+    _v0[0] = x;
+    _v0[1] = y;
+
+    for (var _t = 0; _t < 1; _t += 0.05) {
+      _v1[0] = cubicAt(x0, x1, x2, x3, _t);
+      _v1[1] = cubicAt(y0, y1, y2, y3, _t);
+      d1 = distSquare(_v0, _v1);
+
+      if (d1 < d) {
+        t = _t;
+        d = d1;
+      }
+    }
+
+    d = Infinity;
+
+    for (var i = 0; i < 32; i++) {
+      if (interval < EPSILON_NUMERIC) {
+        break;
+      }
+
+      prev = t - interval;
+      next = t + interval;
+      _v1[0] = cubicAt(x0, x1, x2, x3, prev);
+      _v1[1] = cubicAt(y0, y1, y2, y3, prev);
+      d1 = distSquare(_v1, _v0);
+
+      if (prev >= 0 && d1 < d) {
+        t = prev;
+        d = d1;
+      } else {
+        _v2[0] = cubicAt(x0, x1, x2, x3, next);
+        _v2[1] = cubicAt(y0, y1, y2, y3, next);
+        d2 = distSquare(_v2, _v0);
+
+        if (next <= 1 && d2 < d) {
+          t = next;
+          d = d2;
+        } else {
+          interval *= 0.5;
+        }
+      }
+    }
+
+    if (out) {
+      out[0] = cubicAt(x0, x1, x2, x3, t);
+      out[1] = cubicAt(y0, y1, y2, y3, t);
+    }
+
+    return mathSqrt(d);
+  }
+
+  function cubicLength(x0, y0, x1, y1, x2, y2, x3, y3, iteration) {
+    var px = x0;
+    var py = y0;
+    var d = 0;
+    var step = 1 / iteration;
+
+    for (var i = 1; i <= iteration; i++) {
+      var t = i * step;
+      var x = cubicAt(x0, x1, x2, x3, t);
+      var y = cubicAt(y0, y1, y2, y3, t);
+      var dx = x - px;
+      var dy = y - py;
+      d += Math.sqrt(dx * dx + dy * dy);
+      px = x;
+      py = y;
+    }
+
+    return d;
+  }
+
+  function quadraticAt(p0, p1, p2, t) {
+    var onet = 1 - t;
+    return onet * (onet * p0 + 2 * t * p1) + t * t * p2;
+  }
+
+  function quadraticDerivativeAt(p0, p1, p2, t) {
+    return 2 * ((1 - t) * (p1 - p0) + t * (p2 - p1));
+  }
+
+  function quadraticRootAt(p0, p1, p2, val, roots) {
+    var a = p0 - 2 * p1 + p2;
+    var b = 2 * (p1 - p0);
+    var c = p0 - val;
+    var n = 0;
+
+    if (isAroundZero(a)) {
+      if (isNotAroundZero(b)) {
+        var t1 = -c / b;
+
+        if (t1 >= 0 && t1 <= 1) {
+          roots[n++] = t1;
+        }
+      }
+    } else {
+      var disc = b * b - 4 * a * c;
+
+      if (isAroundZero(disc)) {
+        var t1 = -b / (2 * a);
+
+        if (t1 >= 0 && t1 <= 1) {
+          roots[n++] = t1;
+        }
+      } else if (disc > 0) {
+        var discSqrt = mathSqrt(disc);
+        var t1 = (-b + discSqrt) / (2 * a);
+        var t2 = (-b - discSqrt) / (2 * a);
+
+        if (t1 >= 0 && t1 <= 1) {
+          roots[n++] = t1;
+        }
+
+        if (t2 >= 0 && t2 <= 1) {
+          roots[n++] = t2;
+        }
+      }
+    }
+
+    return n;
+  }
+
+  function quadraticExtremum(p0, p1, p2) {
+    var divider = p0 + p2 - 2 * p1;
+
+    if (divider === 0) {
+      return 0.5;
+    } else {
+      return (p0 - p1) / divider;
+    }
+  }
+
+  function quadraticSubdivide(p0, p1, p2, t, out) {
+    var p01 = (p1 - p0) * t + p0;
+    var p12 = (p2 - p1) * t + p1;
+    var p012 = (p12 - p01) * t + p01;
+    out[0] = p0;
+    out[1] = p01;
+    out[2] = p012;
+    out[3] = p012;
+    out[4] = p12;
+    out[5] = p2;
+  }
+
+  function quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, out) {
+    var t;
+    var interval = 0.005;
+    var d = Infinity;
+    _v0[0] = x;
+    _v0[1] = y;
+
+    for (var _t = 0; _t < 1; _t += 0.05) {
+      _v1[0] = quadraticAt(x0, x1, x2, _t);
+      _v1[1] = quadraticAt(y0, y1, y2, _t);
+      var d1 = distSquare(_v0, _v1);
+
+      if (d1 < d) {
+        t = _t;
+        d = d1;
+      }
+    }
+
+    d = Infinity;
+
+    for (var i = 0; i < 32; i++) {
+      if (interval < EPSILON_NUMERIC) {
+        break;
+      }
+
+      var prev = t - interval;
+      var next = t + interval;
+      _v1[0] = quadraticAt(x0, x1, x2, prev);
+      _v1[1] = quadraticAt(y0, y1, y2, prev);
+      var d1 = distSquare(_v1, _v0);
+
+      if (prev >= 0 && d1 < d) {
+        t = prev;
+        d = d1;
+      } else {
+        _v2[0] = quadraticAt(x0, x1, x2, next);
+        _v2[1] = quadraticAt(y0, y1, y2, next);
+        var d2 = distSquare(_v2, _v0);
+
+        if (next <= 1 && d2 < d) {
+          t = next;
+          d = d2;
+        } else {
+          interval *= 0.5;
+        }
+      }
+    }
+
+    if (out) {
+      out[0] = quadraticAt(x0, x1, x2, t);
+      out[1] = quadraticAt(y0, y1, y2, t);
+    }
+
+    return mathSqrt(d);
+  }
+
+  function quadraticLength(x0, y0, x1, y1, x2, y2, iteration) {
+    var px = x0;
+    var py = y0;
+    var d = 0;
+    var step = 1 / iteration;
+
+    for (var i = 1; i <= iteration; i++) {
+      var t = i * step;
+      var x = quadraticAt(x0, x1, x2, t);
+      var y = quadraticAt(y0, y1, y2, t);
+      var dx = x - px;
+      var dy = y - py;
+      d += Math.sqrt(dx * dx + dy * dy);
+      px = x;
+      py = y;
+    }
+
+    return d;
+  }
+
+  var regexp = /cubic-bezier\(([0-9,\.e ]+)\)/;
+
+  function createCubicEasingFunc(cubicEasingStr) {
+    var cubic = cubicEasingStr && regexp.exec(cubicEasingStr);
+
+    if (cubic) {
+      var points = cubic[1].split(',');
+      var a_1 = +trim(points[0]);
+      var b_1 = +trim(points[1]);
+      var c_1 = +trim(points[2]);
+      var d_1 = +trim(points[3]);
+
+      if (isNaN(a_1 + b_1 + c_1 + d_1)) {
+        return;
+      }
+
+      var roots_1 = [];
+      return function (p) {
+        return p <= 0 ? 0 : p >= 1 ? 1 : cubicRootAt(0, a_1, c_1, 1, p, roots_1) && cubicAt(0, b_1, d_1, 1, roots_1[0]);
+      };
+    }
+  }
+
+  var Clip = function () {
+    function Clip(opts) {
+      this._inited = false;
+      this._startTime = 0;
+      this._pausedTime = 0;
+      this._paused = false;
+      this._life = opts.life || 1000;
+      this._delay = opts.delay || 0;
+      this.loop = opts.loop || false;
+      this.onframe = opts.onframe || noop;
+      this.ondestroy = opts.ondestroy || noop;
+      this.onrestart = opts.onrestart || noop;
+      opts.easing && this.setEasing(opts.easing);
+    }
+
+    Clip.prototype.step = function (globalTime, deltaTime) {
+      if (!this._inited) {
+        this._startTime = globalTime + this._delay;
+        this._inited = true;
+      }
+
+      if (this._paused) {
+        this._pausedTime += deltaTime;
+        return;
+      }
+
+      var life = this._life;
+      var elapsedTime = globalTime - this._startTime - this._pausedTime;
+      var percent = elapsedTime / life;
+
+      if (percent < 0) {
+        percent = 0;
+      }
+
+      percent = Math.min(percent, 1);
+      var easingFunc = this.easingFunc;
+      var schedule = easingFunc ? easingFunc(percent) : percent;
+      this.onframe(schedule);
+
+      if (percent === 1) {
+        if (this.loop) {
+          var remainder = elapsedTime % life;
+          this._startTime = globalTime - remainder;
+          this._pausedTime = 0;
+          this.onrestart();
+        } else {
+          return true;
+        }
+      }
+
+      return false;
+    };
+
+    Clip.prototype.pause = function () {
+      this._paused = true;
+    };
+
+    Clip.prototype.resume = function () {
+      this._paused = false;
+    };
+
+    Clip.prototype.setEasing = function (easing) {
+      this.easing = easing;
+      this.easingFunc = isFunction(easing) ? easing : easingFuncs[easing] || createCubicEasingFunc(easing);
+    };
+
+    return Clip;
+  }();
+
+  var Entry = function () {
+    function Entry(val) {
+      this.value = val;
+    }
+
+    return Entry;
+  }();
+
+  var LinkedList = function () {
+    function LinkedList() {
+      this._len = 0;
+    }
+
+    LinkedList.prototype.insert = function (val) {
+      var entry = new Entry(val);
+      this.insertEntry(entry);
+      return entry;
+    };
+
+    LinkedList.prototype.insertEntry = function (entry) {
+      if (!this.head) {
+        this.head = this.tail = entry;
+      } else {
+        this.tail.next = entry;
+        entry.prev = this.tail;
+        entry.next = null;
+        this.tail = entry;
+      }
+
+      this._len++;
+    };
+
+    LinkedList.prototype.remove = function (entry) {
+      var prev = entry.prev;
+      var next = entry.next;
+
+      if (prev) {
+        prev.next = next;
+      } else {
+        this.head = next;
+      }
+
+      if (next) {
+        next.prev = prev;
+      } else {
+        this.tail = prev;
+      }
+
+      entry.next = entry.prev = null;
+      this._len--;
+    };
+
+    LinkedList.prototype.len = function () {
+      return this._len;
+    };
+
+    LinkedList.prototype.clear = function () {
+      this.head = this.tail = null;
+      this._len = 0;
+    };
+
+    return LinkedList;
+  }();
+
+  var LRU = function () {
+    function LRU(maxSize) {
+      this._list = new LinkedList();
+      this._maxSize = 10;
+      this._map = {};
+      this._maxSize = maxSize;
+    }
+
+    LRU.prototype.put = function (key, value) {
+      var list = this._list;
+      var map = this._map;
+      var removed = null;
+
+      if (map[key] == null) {
+        var len = list.len();
+        var entry = this._lastRemovedEntry;
+
+        if (len >= this._maxSize && len > 0) {
+          var leastUsedEntry = list.head;
+          list.remove(leastUsedEntry);
+          delete map[leastUsedEntry.key];
+          removed = leastUsedEntry.value;
+          this._lastRemovedEntry = leastUsedEntry;
+        }
+
+        if (entry) {
+          entry.value = value;
+        } else {
+          entry = new Entry(value);
+        }
+
+        entry.key = key;
+        list.insertEntry(entry);
+        map[key] = entry;
+      }
+
+      return removed;
+    };
+
+    LRU.prototype.get = function (key) {
+      var entry = this._map[key];
+      var list = this._list;
+
+      if (entry != null) {
+        if (entry !== list.tail) {
+          list.remove(entry);
+          list.insertEntry(entry);
+        }
+
+        return entry.value;
+      }
+    };
+
+    LRU.prototype.clear = function () {
+      this._list.clear();
+
+      this._map = {};
+    };
+
+    LRU.prototype.len = function () {
+      return this._list.len();
+    };
+
+    return LRU;
+  }();
+
+  var kCSSColorTable = {
+    'transparent': [0, 0, 0, 0],
+    'aliceblue': [240, 248, 255, 1],
+    'antiquewhite': [250, 235, 215, 1],
+    'aqua': [0, 255, 255, 1],
+    'aquamarine': [127, 255, 212, 1],
+    'azure': [240, 255, 255, 1],
+    'beige': [245, 245, 220, 1],
+    'bisque': [255, 228, 196, 1],
+    'black': [0, 0, 0, 1],
+    'blanchedalmond': [255, 235, 205, 1],
+    'blue': [0, 0, 255, 1],
+    'blueviolet': [138, 43, 226, 1],
+    'brown': [165, 42, 42, 1],
+    'burlywood': [222, 184, 135, 1],
+    'cadetblue': [95, 158, 160, 1],
+    'chartreuse': [127, 255, 0, 1],
+    'chocolate': [210, 105, 30, 1],
+    'coral': [255, 127, 80, 1],
+    'cornflowerblue': [100, 149, 237, 1],
+    'cornsilk': [255, 248, 220, 1],
+    'crimson': [220, 20, 60, 1],
+    'cyan': [0, 255, 255, 1],
+    'darkblue': [0, 0, 139, 1],
+    'darkcyan': [0, 139, 139, 1],
+    'darkgoldenrod': [184, 134, 11, 1],
+    'darkgray': [169, 169, 169, 1],
+    'darkgreen': [0, 100, 0, 1],
+    'darkgrey': [169, 169, 169, 1],
+    'darkkhaki': [189, 183, 107, 1],
+    'darkmagenta': [139, 0, 139, 1],
+    'darkolivegreen': [85, 107, 47, 1],
+    'darkorange': [255, 140, 0, 1],
+    'darkorchid': [153, 50, 204, 1],
+    'darkred': [139, 0, 0, 1],
+    'darksalmon': [233, 150, 122, 1],
+    'darkseagreen': [143, 188, 143, 1],
+    'darkslateblue': [72, 61, 139, 1],
+    'darkslategray': [47, 79, 79, 1],
+    'darkslategrey': [47, 79, 79, 1],
+    'darkturquoise': [0, 206, 209, 1],
+    'darkviolet': [148, 0, 211, 1],
+    'deeppink': [255, 20, 147, 1],
+    'deepskyblue': [0, 191, 255, 1],
+    'dimgray': [105, 105, 105, 1],
+    'dimgrey': [105, 105, 105, 1],
+    'dodgerblue': [30, 144, 255, 1],
+    'firebrick': [178, 34, 34, 1],
+    'floralwhite': [255, 250, 240, 1],
+    'forestgreen': [34, 139, 34, 1],
+    'fuchsia': [255, 0, 255, 1],
+    'gainsboro': [220, 220, 220, 1],
+    'ghostwhite': [248, 248, 255, 1],
+    'gold': [255, 215, 0, 1],
+    'goldenrod': [218, 165, 32, 1],
+    'gray': [128, 128, 128, 1],
+    'green': [0, 128, 0, 1],
+    'greenyellow': [173, 255, 47, 1],
+    'grey': [128, 128, 128, 1],
+    'honeydew': [240, 255, 240, 1],
+    'hotpink': [255, 105, 180, 1],
+    'indianred': [205, 92, 92, 1],
+    'indigo': [75, 0, 130, 1],
+    'ivory': [255, 255, 240, 1],
+    'khaki': [240, 230, 140, 1],
+    'lavender': [230, 230, 250, 1],
+    'lavenderblush': [255, 240, 245, 1],
+    'lawngreen': [124, 252, 0, 1],
+    'lemonchiffon': [255, 250, 205, 1],
+    'lightblue': [173, 216, 230, 1],
+    'lightcoral': [240, 128, 128, 1],
+    'lightcyan': [224, 255, 255, 1],
+    'lightgoldenrodyellow': [250, 250, 210, 1],
+    'lightgray': [211, 211, 211, 1],
+    'lightgreen': [144, 238, 144, 1],
+    'lightgrey': [211, 211, 211, 1],
+    'lightpink': [255, 182, 193, 1],
+    'lightsalmon': [255, 160, 122, 1],
+    'lightseagreen': [32, 178, 170, 1],
+    'lightskyblue': [135, 206, 250, 1],
+    'lightslategray': [119, 136, 153, 1],
+    'lightslategrey': [119, 136, 153, 1],
+    'lightsteelblue': [176, 196, 222, 1],
+    'lightyellow': [255, 255, 224, 1],
+    'lime': [0, 255, 0, 1],
+    'limegreen': [50, 205, 50, 1],
+    'linen': [250, 240, 230, 1],
+    'magenta': [255, 0, 255, 1],
+    'maroon': [128, 0, 0, 1],
+    'mediumaquamarine': [102, 205, 170, 1],
+    'mediumblue': [0, 0, 205, 1],
+    'mediumorchid': [186, 85, 211, 1],
+    'mediumpurple': [147, 112, 219, 1],
+    'mediumseagreen': [60, 179, 113, 1],
+    'mediumslateblue': [123, 104, 238, 1],
+    'mediumspringgreen': [0, 250, 154, 1],
+    'mediumturquoise': [72, 209, 204, 1],
+    'mediumvioletred': [199, 21, 133, 1],
+    'midnightblue': [25, 25, 112, 1],
+    'mintcream': [245, 255, 250, 1],
+    'mistyrose': [255, 228, 225, 1],
+    'moccasin': [255, 228, 181, 1],
+    'navajowhite': [255, 222, 173, 1],
+    'navy': [0, 0, 128, 1],
+    'oldlace': [253, 245, 230, 1],
+    'olive': [128, 128, 0, 1],
+    'olivedrab': [107, 142, 35, 1],
+    'orange': [255, 165, 0, 1],
+    'orangered': [255, 69, 0, 1],
+    'orchid': [218, 112, 214, 1],
+    'palegoldenrod': [238, 232, 170, 1],
+    'palegreen': [152, 251, 152, 1],
+    'paleturquoise': [175, 238, 238, 1],
+    'palevioletred': [219, 112, 147, 1],
+    'papayawhip': [255, 239, 213, 1],
+    'peachpuff': [255, 218, 185, 1],
+    'peru': [205, 133, 63, 1],
+    'pink': [255, 192, 203, 1],
+    'plum': [221, 160, 221, 1],
+    'powderblue': [176, 224, 230, 1],
+    'purple': [128, 0, 128, 1],
+    'red': [255, 0, 0, 1],
+    'rosybrown': [188, 143, 143, 1],
+    'royalblue': [65, 105, 225, 1],
+    'saddlebrown': [139, 69, 19, 1],
+    'salmon': [250, 128, 114, 1],
+    'sandybrown': [244, 164, 96, 1],
+    'seagreen': [46, 139, 87, 1],
+    'seashell': [255, 245, 238, 1],
+    'sienna': [160, 82, 45, 1],
+    'silver': [192, 192, 192, 1],
+    'skyblue': [135, 206, 235, 1],
+    'slateblue': [106, 90, 205, 1],
+    'slategray': [112, 128, 144, 1],
+    'slategrey': [112, 128, 144, 1],
+    'snow': [255, 250, 250, 1],
+    'springgreen': [0, 255, 127, 1],
+    'steelblue': [70, 130, 180, 1],
+    'tan': [210, 180, 140, 1],
+    'teal': [0, 128, 128, 1],
+    'thistle': [216, 191, 216, 1],
+    'tomato': [255, 99, 71, 1],
+    'turquoise': [64, 224, 208, 1],
+    'violet': [238, 130, 238, 1],
+    'wheat': [245, 222, 179, 1],
+    'white': [255, 255, 255, 1],
+    'whitesmoke': [245, 245, 245, 1],
+    'yellow': [255, 255, 0, 1],
+    'yellowgreen': [154, 205, 50, 1]
+  };
+
+  function clampCssByte(i) {
+    i = Math.round(i);
+    return i < 0 ? 0 : i > 255 ? 255 : i;
+  }
+
+  function clampCssAngle(i) {
+    i = Math.round(i);
+    return i < 0 ? 0 : i > 360 ? 360 : i;
+  }
+
+  function clampCssFloat(f) {
+    return f < 0 ? 0 : f > 1 ? 1 : f;
+  }
+
+  function parseCssInt(val) {
+    var str = val;
+
+    if (str.length && str.charAt(str.length - 1) === '%') {
+      return clampCssByte(parseFloat(str) / 100 * 255);
+    }
+
+    return clampCssByte(parseInt(str, 10));
+  }
+
+  function parseCssFloat(val) {
+    var str = val;
+
+    if (str.length && str.charAt(str.length - 1) === '%') {
+      return clampCssFloat(parseFloat(str) / 100);
+    }
+
+    return clampCssFloat(parseFloat(str));
+  }
+
+  function cssHueToRgb(m1, m2, h) {
+    if (h < 0) {
+      h += 1;
+    } else if (h > 1) {
+      h -= 1;
+    }
+
+    if (h * 6 < 1) {
+      return m1 + (m2 - m1) * h * 6;
+    }
+
+    if (h * 2 < 1) {
+      return m2;
+    }
+
+    if (h * 3 < 2) {
+      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
+    }
+
+    return m1;
+  }
+
+  function lerpNumber(a, b, p) {
+    return a + (b - a) * p;
+  }
+
+  function setRgba(out, r, g, b, a) {
+    out[0] = r;
+    out[1] = g;
+    out[2] = b;
+    out[3] = a;
+    return out;
+  }
+
+  function copyRgba(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
+
+  var colorCache = new LRU(20);
+  var lastRemovedArr = null;
+
+  function putToCache(colorStr, rgbaArr) {
+    if (lastRemovedArr) {
+      copyRgba(lastRemovedArr, rgbaArr);
+    }
+
+    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || rgbaArr.slice());
+  }
+
+  function parse(colorStr, rgbaArr) {
+    if (!colorStr) {
+      return;
+    }
+
+    rgbaArr = rgbaArr || [];
+    var cached = colorCache.get(colorStr);
+
+    if (cached) {
+      return copyRgba(rgbaArr, cached);
+    }
+
+    colorStr = colorStr + '';
+    var str = colorStr.replace(/ /g, '').toLowerCase();
+
+    if (str in kCSSColorTable) {
+      copyRgba(rgbaArr, kCSSColorTable[str]);
+      putToCache(colorStr, rgbaArr);
+      return rgbaArr;
+    }
+
+    var strLen = str.length;
+
+    if (str.charAt(0) === '#') {
+      if (strLen === 4 || strLen === 5) {
+        var iv = parseInt(str.slice(1, 4), 16);
+
+        if (!(iv >= 0 && iv <= 0xfff)) {
+          setRgba(rgbaArr, 0, 0, 0, 1);
+          return;
+        }
+
+        setRgba(rgbaArr, (iv & 0xf00) >> 4 | (iv & 0xf00) >> 8, iv & 0xf0 | (iv & 0xf0) >> 4, iv & 0xf | (iv & 0xf) << 4, strLen === 5 ? parseInt(str.slice(4), 16) / 0xf : 1);
+        putToCache(colorStr, rgbaArr);
+        return rgbaArr;
+      } else if (strLen === 7 || strLen === 9) {
+        var iv = parseInt(str.slice(1, 7), 16);
+
+        if (!(iv >= 0 && iv <= 0xffffff)) {
+          setRgba(rgbaArr, 0, 0, 0, 1);
+          return;
+        }
+
+        setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, strLen === 9 ? parseInt(str.slice(7), 16) / 0xff : 1);
+        putToCache(colorStr, rgbaArr);
+        return rgbaArr;
+      }
+
+      return;
+    }
+
+    var op = str.indexOf('(');
+    var ep = str.indexOf(')');
+
+    if (op !== -1 && ep + 1 === strLen) {
+      var fname = str.substr(0, op);
+      var params = str.substr(op + 1, ep - (op + 1)).split(',');
+      var alpha = 1;
+
+      switch (fname) {
+        case 'rgba':
+          if (params.length !== 4) {
+            return params.length === 3 ? setRgba(rgbaArr, +params[0], +params[1], +params[2], 1) : setRgba(rgbaArr, 0, 0, 0, 1);
+          }
+
+          alpha = parseCssFloat(params.pop());
+
+        case 'rgb':
+          if (params.length !== 3) {
+            setRgba(rgbaArr, 0, 0, 0, 1);
+            return;
+          }
+
+          setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), alpha);
+          putToCache(colorStr, rgbaArr);
+          return rgbaArr;
+
+        case 'hsla':
+          if (params.length !== 4) {
+            setRgba(rgbaArr, 0, 0, 0, 1);
+            return;
+          }
+
+          params[3] = parseCssFloat(params[3]);
+          hsla2rgba(params, rgbaArr);
+          putToCache(colorStr, rgbaArr);
+          return rgbaArr;
+
+        case 'hsl':
+          if (params.length !== 3) {
+            setRgba(rgbaArr, 0, 0, 0, 1);
+            return;
+          }
+
+          hsla2rgba(params, rgbaArr);
+          putToCache(colorStr, rgbaArr);
+          return rgbaArr;
+
+        default:
+          return;
+      }
+    }
+
+    setRgba(rgbaArr, 0, 0, 0, 1);
+    return;
+  }
+
+  function hsla2rgba(hsla, rgba) {
+    var h = (parseFloat(hsla[0]) % 360 + 360) % 360 / 360;
+    var s = parseCssFloat(hsla[1]);
+    var l = parseCssFloat(hsla[2]);
+    var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
+    var m1 = l * 2 - m2;
+    rgba = rgba || [];
+    setRgba(rgba, clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), clampCssByte(cssHueToRgb(m1, m2, h) * 255), clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), 1);
+
+    if (hsla.length === 4) {
+      rgba[3] = hsla[3];
+    }
+
+    return rgba;
+  }
+
+  function rgba2hsla(rgba) {
+    if (!rgba) {
+      return;
+    }
+
+    var R = rgba[0] / 255;
+    var G = rgba[1] / 255;
+    var B = rgba[2] / 255;
+    var vMin = Math.min(R, G, B);
+    var vMax = Math.max(R, G, B);
+    var delta = vMax - vMin;
+    var L = (vMax + vMin) / 2;
+    var H;
+    var S;
+
+    if (delta === 0) {
+      H = 0;
+      S = 0;
+    } else {
+      if (L < 0.5) {
+        S = delta / (vMax + vMin);
+      } else {
+        S = delta / (2 - vMax - vMin);
+      }
+
+      var deltaR = ((vMax - R) / 6 + delta / 2) / delta;
+      var deltaG = ((vMax - G) / 6 + delta / 2) / delta;
+      var deltaB = ((vMax - B) / 6 + delta / 2) / delta;
+
+      if (R === vMax) {
+        H = deltaB - deltaG;
+      } else if (G === vMax) {
+        H = 1 / 3 + deltaR - deltaB;
+      } else if (B === vMax) {
+        H = 2 / 3 + deltaG - deltaR;
+      }
+
+      if (H < 0) {
+        H += 1;
+      }
+
+      if (H > 1) {
+        H -= 1;
+      }
+    }
+
+    var hsla = [H * 360, S, L];
+
+    if (rgba[3] != null) {
+      hsla.push(rgba[3]);
+    }
+
+    return hsla;
+  }
+
+  function lift(color, level) {
+    var colorArr = parse(color);
+
+    if (colorArr) {
+      for (var i = 0; i < 3; i++) {
+        if (level < 0) {
+          colorArr[i] = colorArr[i] * (1 - level) | 0;
+        } else {
+          colorArr[i] = (255 - colorArr[i]) * level + colorArr[i] | 0;
+        }
+
+        if (colorArr[i] > 255) {
+          colorArr[i] = 255;
+        } else if (colorArr[i] < 0) {
+          colorArr[i] = 0;
+        }
+      }
+
+      return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
+    }
+  }
+
+  function toHex(color) {
+    var colorArr = parse(color);
+
+    if (colorArr) {
+      return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + +colorArr[2]).toString(16).slice(1);
+    }
+  }
+
+  function fastLerp(normalizedValue, colors, out) {
+    if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) {
+      return;
+    }
+
+    out = out || [];
+    var value = normalizedValue * (colors.length - 1);
+    var leftIndex = Math.floor(value);
+    var rightIndex = Math.ceil(value);
+    var leftColor = colors[leftIndex];
+    var rightColor = colors[rightIndex];
+    var dv = value - leftIndex;
+    out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv));
+    out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv));
+    out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv));
+    out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv));
+    return out;
+  }
+
+  var fastMapToColor = fastLerp;
+
+  function lerp$1(normalizedValue, colors, fullOutput) {
+    if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) {
+      return;
+    }
+
+    var value = normalizedValue * (colors.length - 1);
+    var leftIndex = Math.floor(value);
+    var rightIndex = Math.ceil(value);
+    var leftColor = parse(colors[leftIndex]);
+    var rightColor = parse(colors[rightIndex]);
+    var dv = value - leftIndex;
+    var color = stringify([clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)), clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)), clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)), clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv))], 'rgba');
+    return fullOutput ? {
+      color: color,
+      leftIndex: leftIndex,
+      rightIndex: rightIndex,
+      value: value
+    } : color;
+  }
+
+  var mapToColor = lerp$1;
+
+  function modifyHSL(color, h, s, l) {
+    var colorArr = parse(color);
+
+    if (color) {
+      colorArr = rgba2hsla(colorArr);
+      h != null && (colorArr[0] = clampCssAngle(h));
+      s != null && (colorArr[1] = parseCssFloat(s));
+      l != null && (colorArr[2] = parseCssFloat(l));
+      return stringify(hsla2rgba(colorArr), 'rgba');
+    }
+  }
+
+  function modifyAlpha(color, alpha) {
+    var colorArr = parse(color);
+
+    if (colorArr && alpha != null) {
+      colorArr[3] = clampCssFloat(alpha);
+      return stringify(colorArr, 'rgba');
+    }
+  }
+
+  function stringify(arrColor, type) {
+    if (!arrColor || !arrColor.length) {
+      return;
+    }
+
+    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
+
+    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
+      colorStr += ',' + arrColor[3];
+    }
+
+    return type + '(' + colorStr + ')';
+  }
+
+  function lum(color, backgroundLum) {
+    var arr = parse(color);
+    return arr ? (0.299 * arr[0] + 0.587 * arr[1] + 0.114 * arr[2]) * arr[3] / 255 + (1 - arr[3]) * backgroundLum : 0;
+  }
+
+  function random() {
+    return stringify([Math.round(Math.random() * 255), Math.round(Math.random() * 255), Math.round(Math.random() * 255)], 'rgb');
+  }
+
+  var color = (Object.freeze || Object)({
+    parse: parse,
+    lift: lift,
+    toHex: toHex,
+    fastLerp: fastLerp,
+    fastMapToColor: fastMapToColor,
+    lerp: lerp$1,
+    mapToColor: mapToColor,
+    modifyHSL: modifyHSL,
+    modifyAlpha: modifyAlpha,
+    stringify: stringify,
+    lum: lum,
+    random: random
+  });
+
+  function isLinearGradient(val) {
+    return val.type === 'linear';
+  }
+
+  function isRadialGradient(val) {
+    return val.type === 'radial';
+  }
+
+  var encodeBase64 = function () {
+    if (env.hasGlobalWindow && isFunction(window.btoa)) {
+      return function (str) {
+        return window.btoa(unescape(str));
+      };
+    }
+
+    if (typeof Buffer !== 'undefined') {
+      return function (str) {
+        return Buffer.from(str).toString('base64');
+      };
+    }
+
+    return function (str) {
+      {
+        logError('Base64 isn\'t natively supported in the current environment.');
+      }
+      return null;
+    };
+  }();
+
+  var arraySlice = Array.prototype.slice;
+
+  function interpolateNumber(p0, p1, percent) {
+    return (p1 - p0) * percent + p0;
+  }
+
+  function interpolate1DArray(out, p0, p1, percent) {
+    var len = p0.length;
+
+    for (var i = 0; i < len; i++) {
+      out[i] = interpolateNumber(p0[i], p1[i], percent);
+    }
+
+    return out;
+  }
+
+  function interpolate2DArray(out, p0, p1, percent) {
+    var len = p0.length;
+    var len2 = len && p0[0].length;
+
+    for (var i = 0; i < len; i++) {
+      if (!out[i]) {
+        out[i] = [];
+      }
+
+      for (var j = 0; j < len2; j++) {
+        out[i][j] = interpolateNumber(p0[i][j], p1[i][j], percent);
+      }
+    }
+
+    return out;
+  }
+
+  function add1DArray(out, p0, p1, sign) {
+    var len = p0.length;
+
+    for (var i = 0; i < len; i++) {
+      out[i] = p0[i] + p1[i] * sign;
+    }
+
+    return out;
+  }
+
+  function add2DArray(out, p0, p1, sign) {
+    var len = p0.length;
+    var len2 = len && p0[0].length;
+
+    for (var i = 0; i < len; i++) {
+      if (!out[i]) {
+        out[i] = [];
+      }
+
+      for (var j = 0; j < len2; j++) {
+        out[i][j] = p0[i][j] + p1[i][j] * sign;
+      }
+    }
+
+    return out;
+  }
+
+  function fillColorStops(val0, val1) {
+    var len0 = val0.length;
+    var len1 = val1.length;
+    var shorterArr = len0 > len1 ? val1 : val0;
+    var shorterLen = Math.min(len0, len1);
+    var last = shorterArr[shorterLen - 1] || {
+      color: [0, 0, 0, 0],
+      offset: 0
+    };
+
+    for (var i = shorterLen; i < Math.max(len0, len1); i++) {
+      shorterArr.push({
+        offset: last.offset,
+        color: last.color.slice()
+      });
+    }
+  }
+
+  function fillArray(val0, val1, arrDim) {
+    var arr0 = val0;
+    var arr1 = val1;
+
+    if (!arr0.push || !arr1.push) {
+      return;
+    }
+
+    var arr0Len = arr0.length;
+    var arr1Len = arr1.length;
+
+    if (arr0Len !== arr1Len) {
+      var isPreviousLarger = arr0Len > arr1Len;
+
+      if (isPreviousLarger) {
+        arr0.length = arr1Len;
+      } else {
+        for (var i = arr0Len; i < arr1Len; i++) {
+          arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i]));
+        }
+      }
+    }
+
+    var len2 = arr0[0] && arr0[0].length;
+
+    for (var i = 0; i < arr0.length; i++) {
+      if (arrDim === 1) {
+        if (isNaN(arr0[i])) {
+          arr0[i] = arr1[i];
+        }
+      } else {
+        for (var j = 0; j < len2; j++) {
+          if (isNaN(arr0[i][j])) {
+            arr0[i][j] = arr1[i][j];
+          }
+        }
+      }
+    }
+  }
+
+  function cloneValue(value) {
+    if (isArrayLike(value)) {
+      var len = value.length;
+
+      if (isArrayLike(value[0])) {
+        var ret = [];
+
+        for (var i = 0; i < len; i++) {
+          ret.push(arraySlice.call(value[i]));
+        }
+
+        return ret;
+      }
+
+      return arraySlice.call(value);
+    }
+
+    return value;
+  }
+
+  function rgba2String(rgba) {
+    rgba[0] = Math.floor(rgba[0]) || 0;
+    rgba[1] = Math.floor(rgba[1]) || 0;
+    rgba[2] = Math.floor(rgba[2]) || 0;
+    rgba[3] = rgba[3] == null ? 1 : rgba[3];
+    return 'rgba(' + rgba.join(',') + ')';
+  }
+
+  function guessArrayDim(value) {
+    return isArrayLike(value && value[0]) ? 2 : 1;
+  }
+
+  var VALUE_TYPE_NUMBER = 0;
+  var VALUE_TYPE_1D_ARRAY = 1;
+  var VALUE_TYPE_2D_ARRAY = 2;
+  var VALUE_TYPE_COLOR = 3;
+  var VALUE_TYPE_LINEAR_GRADIENT = 4;
+  var VALUE_TYPE_RADIAL_GRADIENT = 5;
+  var VALUE_TYPE_UNKOWN = 6;
+
+  function isGradientValueType(valType) {
+    return valType === VALUE_TYPE_LINEAR_GRADIENT || valType === VALUE_TYPE_RADIAL_GRADIENT;
+  }
+
+  function isArrayValueType(valType) {
+    return valType === VALUE_TYPE_1D_ARRAY || valType === VALUE_TYPE_2D_ARRAY;
+  }
+
+  var tmpRgba = [0, 0, 0, 0];
+
+  var Track = function () {
+    function Track(propName) {
+      this.keyframes = [];
+      this.discrete = false;
+      this._invalid = false;
+      this._needsSort = false;
+      this._lastFr = 0;
+      this._lastFrP = 0;
+      this.propName = propName;
+    }
+
+    Track.prototype.isFinished = function () {
+      return this._finished;
+    };
+
+    Track.prototype.setFinished = function () {
+      this._finished = true;
+
+      if (this._additiveTrack) {
+        this._additiveTrack.setFinished();
+      }
+    };
+
+    Track.prototype.needsAnimate = function () {
+      return this.keyframes.length >= 1;
+    };
+
+    Track.prototype.getAdditiveTrack = function () {
+      return this._additiveTrack;
+    };
+
+    Track.prototype.addKeyframe = function (time, rawValue, easing) {
+      this._needsSort = true;
+      var keyframes = this.keyframes;
+      var len = keyframes.length;
+      var discrete = false;
+      var valType = VALUE_TYPE_UNKOWN;
+      var value = rawValue;
+
+      if (isArrayLike(rawValue)) {
+        var arrayDim = guessArrayDim(rawValue);
+        valType = arrayDim;
+
+        if (arrayDim === 1 && !isNumber(rawValue[0]) || arrayDim === 2 && !isNumber(rawValue[0][0])) {
+          discrete = true;
+        }
+      } else {
+        if (isNumber(rawValue) && !eqNaN(rawValue)) {
+          valType = VALUE_TYPE_NUMBER;
+        } else if (isString(rawValue)) {
+          if (!isNaN(+rawValue)) {
+            valType = VALUE_TYPE_NUMBER;
+          } else {
+            var colorArray = parse(rawValue);
+
+            if (colorArray) {
+              value = colorArray;
+              valType = VALUE_TYPE_COLOR;
+            }
+          }
+        } else if (isGradientObject(rawValue)) {
+          var parsedGradient = extend({}, value);
+          parsedGradient.colorStops = map(rawValue.colorStops, function (colorStop) {
+            return {
+              offset: colorStop.offset,
+              color: parse(colorStop.color)
+            };
+          });
+
+          if (isLinearGradient(rawValue)) {
+            valType = VALUE_TYPE_LINEAR_GRADIENT;
+          } else if (isRadialGradient(rawValue)) {
+            valType = VALUE_TYPE_RADIAL_GRADIENT;
+          }
+
+          value = parsedGradient;
+        }
+      }
+
+      if (len === 0) {
+        this.valType = valType;
+      } else if (valType !== this.valType || valType === VALUE_TYPE_UNKOWN) {
+        discrete = true;
+      }
+
+      this.discrete = this.discrete || discrete;
+      var kf = {
+        time: time,
+        value: value,
+        rawValue: rawValue,
+        percent: 0
+      };
+
+      if (easing) {
+        kf.easing = easing;
+        kf.easingFunc = isFunction(easing) ? easing : easingFuncs[easing] || createCubicEasingFunc(easing);
+      }
+
+      keyframes.push(kf);
+      return kf;
+    };
+
+    Track.prototype.prepare = function (maxTime, additiveTrack) {
+      var kfs = this.keyframes;
+
+      if (this._needsSort) {
+        kfs.sort(function (a, b) {
+          return a.time - b.time;
+        });
+      }
+
+      var valType = this.valType;
+      var kfsLen = kfs.length;
+      var lastKf = kfs[kfsLen - 1];
+      var isDiscrete = this.discrete;
+      var isArr = isArrayValueType(valType);
+      var isGradient$$1 = isGradientValueType(valType);
+
+      for (var i = 0; i < kfsLen; i++) {
+        var kf = kfs[i];
+        var value = kf.value;
+        var lastValue = lastKf.value;
+        kf.percent = kf.time / maxTime;
+
+        if (!isDiscrete) {
+          if (isArr && i !== kfsLen - 1) {
+            fillArray(value, lastValue, valType);
+          } else if (isGradient$$1) {
+            fillColorStops(value.colorStops, lastValue.colorStops);
+          }
+        }
+      }
+
+      if (!isDiscrete && valType !== VALUE_TYPE_RADIAL_GRADIENT && additiveTrack && this.needsAnimate() && additiveTrack.needsAnimate() && valType === additiveTrack.valType && !additiveTrack._finished) {
+        this._additiveTrack = additiveTrack;
+        var startValue = kfs[0].value;
+
+        for (var i = 0; i < kfsLen; i++) {
+          if (valType === VALUE_TYPE_NUMBER) {
+            kfs[i].additiveValue = kfs[i].value - startValue;
+          } else if (valType === VALUE_TYPE_COLOR) {
+            kfs[i].additiveValue = add1DArray([], kfs[i].value, startValue, -1);
+          } else if (isArrayValueType(valType)) {
+            kfs[i].additiveValue = valType === VALUE_TYPE_1D_ARRAY ? add1DArray([], kfs[i].value, startValue, -1) : add2DArray([], kfs[i].value, startValue, -1);
+          }
+        }
+      }
+    };
+
+    Track.prototype.step = function (target, percent) {
+      if (this._finished) {
+        return;
+      }
+
+      if (this._additiveTrack && this._additiveTrack._finished) {
+        this._additiveTrack = null;
+      }
+
+      var isAdditive = this._additiveTrack != null;
+      var valueKey = isAdditive ? 'additiveValue' : 'value';
+      var valType = this.valType;
+      var keyframes = this.keyframes;
+      var kfsNum = keyframes.length;
+      var propName = this.propName;
+      var isValueColor = valType === VALUE_TYPE_COLOR;
+      var frameIdx;
+      var lastFrame = this._lastFr;
+      var mathMin = Math.min;
+      var frame;
+      var nextFrame;
+
+      if (kfsNum === 1) {
+        frame = nextFrame = keyframes[0];
+      } else {
+        if (percent < 0) {
+          frameIdx = 0;
+        } else if (percent < this._lastFrP) {
+          var start = mathMin(lastFrame + 1, kfsNum - 1);
+
+          for (frameIdx = start; frameIdx >= 0; frameIdx--) {
+            if (keyframes[frameIdx].percent <= percent) {
+              break;
+            }
+          }
+
+          frameIdx = mathMin(frameIdx, kfsNum - 2);
+        } else {
+          for (frameIdx = lastFrame; frameIdx < kfsNum; frameIdx++) {
+            if (keyframes[frameIdx].percent > percent) {
+              break;
+            }
+          }
+
+          frameIdx = mathMin(frameIdx - 1, kfsNum - 2);
+        }
+
+        nextFrame = keyframes[frameIdx + 1];
+        frame = keyframes[frameIdx];
+      }
+
+      if (!(frame && nextFrame)) {
+        return;
+      }
+
+      this._lastFr = frameIdx;
+      this._lastFrP = percent;
+      var interval = nextFrame.percent - frame.percent;
+      var w = interval === 0 ? 1 : mathMin((percent - frame.percent) / interval, 1);
+
+      if (nextFrame.easingFunc) {
+        w = nextFrame.easingFunc(w);
+      }
+
+      var targetArr = isAdditive ? this._additiveValue : isValueColor ? tmpRgba : target[propName];
+
+      if ((isArrayValueType(valType) || isValueColor) && !targetArr) {
+        targetArr = this._additiveValue = [];
+      }
+
+      if (this.discrete) {
+        target[propName] = w < 1 ? frame.rawValue : nextFrame.rawValue;
+      } else if (isArrayValueType(valType)) {
+        valType === VALUE_TYPE_1D_ARRAY ? interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w) : interpolate2DArray(targetArr, frame[valueKey], nextFrame[valueKey], w);
+      } else if (isGradientValueType(valType)) {
+        var val = frame[valueKey];
+        var nextVal_1 = nextFrame[valueKey];
+        var isLinearGradient_1 = valType === VALUE_TYPE_LINEAR_GRADIENT;
+        target[propName] = {
+          type: isLinearGradient_1 ? 'linear' : 'radial',
+          x: interpolateNumber(val.x, nextVal_1.x, w),
+          y: interpolateNumber(val.y, nextVal_1.y, w),
+          colorStops: map(val.colorStops, function (colorStop, idx) {
+            var nextColorStop = nextVal_1.colorStops[idx];
+            return {
+              offset: interpolateNumber(colorStop.offset, nextColorStop.offset, w),
+              color: rgba2String(interpolate1DArray([], colorStop.color, nextColorStop.color, w))
+            };
+          }),
+          global: nextVal_1.global
+        };
+
+        if (isLinearGradient_1) {
+          target[propName].x2 = interpolateNumber(val.x2, nextVal_1.x2, w);
+          target[propName].y2 = interpolateNumber(val.y2, nextVal_1.y2, w);
+        } else {
+          target[propName].r = interpolateNumber(val.r, nextVal_1.r, w);
+        }
+      } else if (isValueColor) {
+        interpolate1DArray(targetArr, frame[valueKey], nextFrame[valueKey], w);
+
+        if (!isAdditive) {
+          target[propName] = rgba2String(targetArr);
+        }
+      } else {
+        var value = interpolateNumber(frame[valueKey], nextFrame[valueKey], w);
+
+        if (isAdditive) {
+          this._additiveValue = value;
+        } else {
+          target[propName] = value;
+        }
+      }
+
+      if (isAdditive) {
+        this._addToTarget(target);
+      }
+    };
+
+    Track.prototype._addToTarget = function (target) {
+      var valType = this.valType;
+      var propName = this.propName;
+      var additiveValue = this._additiveValue;
+
+      if (valType === VALUE_TYPE_NUMBER) {
+        target[propName] = target[propName] + additiveValue;
+      } else if (valType === VALUE_TYPE_COLOR) {
+        parse(target[propName], tmpRgba);
+        add1DArray(tmpRgba, tmpRgba, additiveValue, 1);
+        target[propName] = rgba2String(tmpRgba);
+      } else if (valType === VALUE_TYPE_1D_ARRAY) {
+        add1DArray(target[propName], target[propName], additiveValue, 1);
+      } else if (valType === VALUE_TYPE_2D_ARRAY) {
+        add2DArray(target[propName], target[propName], additiveValue, 1);
+      }
+    };
+
+    return Track;
+  }();
+
+  var Animator = function () {
+    function Animator(target, loop, allowDiscreteAnimation, additiveTo) {
+      this._tracks = {};
+      this._trackKeys = [];
+      this._maxTime = 0;
+      this._started = 0;
+      this._clip = null;
+      this._target = target;
+      this._loop = loop;
+
+      if (loop && additiveTo) {
+        logError('Can\' use additive animation on looped animation.');
+        return;
+      }
+
+      this._additiveAnimators = additiveTo;
+      this._allowDiscrete = allowDiscreteAnimation;
+    }
+
+    Animator.prototype.getMaxTime = function () {
+      return this._maxTime;
+    };
+
+    Animator.prototype.getDelay = function () {
+      return this._delay;
+    };
+
+    Animator.prototype.getLoop = function () {
+      return this._loop;
+    };
+
+    Animator.prototype.getTarget = function () {
+      return this._target;
+    };
+
+    Animator.prototype.changeTarget = function (target) {
+      this._target = target;
+    };
+
+    Animator.prototype.when = function (time, props, easing) {
+      return this.whenWithKeys(time, props, keys(props), easing);
+    };
+
+    Animator.prototype.whenWithKeys = function (time, props, propNames, easing) {
+      var tracks = this._tracks;
+
+      for (var i = 0; i < propNames.length; i++) {
+        var propName = propNames[i];
+        var track = tracks[propName];
+
+        if (!track) {
+          track = tracks[propName] = new Track(propName);
+          var initialValue = void 0;
+
+          var additiveTrack = this._getAdditiveTrack(propName);
+
+          if (additiveTrack) {
+            var addtiveTrackKfs = additiveTrack.keyframes;
+            var lastFinalKf = addtiveTrackKfs[addtiveTrackKfs.length - 1];
+            initialValue = lastFinalKf && lastFinalKf.value;
+
+            if (additiveTrack.valType === VALUE_TYPE_COLOR && initialValue) {
+              initialValue = rgba2String(initialValue);
+            }
+          } else {
+            initialValue = this._target[propName];
+          }
+
+          if (initialValue == null) {
+            continue;
+          }
+
+          if (time > 0) {
+            track.addKeyframe(0, cloneValue(initialValue), easing);
+          }
+
+          this._trackKeys.push(propName);
+        }
+
+        track.addKeyframe(time, cloneValue(props[propName]), easing);
+      }
+
+      this._maxTime = Math.max(this._maxTime, time);
+      return this;
+    };
+
+    Animator.prototype.pause = function () {
+      this._clip.pause();
+
+      this._paused = true;
+    };
+
+    Animator.prototype.resume = function () {
+      this._clip.resume();
+
+      this._paused = false;
+    };
+
+    Animator.prototype.isPaused = function () {
+      return !!this._paused;
+    };
+
+    Animator.prototype.duration = function (duration) {
+      this._maxTime = duration;
+      this._force = true;
+      return this;
+    };
+
+    Animator.prototype._doneCallback = function () {
+      this._setTracksFinished();
+
+      this._clip = null;
+      var doneList = this._doneCbs;
+
+      if (doneList) {
+        var len = doneList.length;
+
+        for (var i = 0; i < len; i++) {
+          doneList[i].call(this);
+        }
+      }
+    };
+
+    Animator.prototype._abortedCallback = function () {
+      this._setTracksFinished();
+
+      var animation = this.animation;
+      var abortedList = this._abortedCbs;
+
+      if (animation) {
+        animation.removeClip(this._clip);
+      }
+
+      this._clip = null;
+
+      if (abortedList) {
+        for (var i = 0; i < abortedList.length; i++) {
+          abortedList[i].call(this);
+        }
+      }
+    };
+
+    Animator.prototype._setTracksFinished = function () {
+      var tracks = this._tracks;
+      var tracksKeys = this._trackKeys;
+
+      for (var i = 0; i < tracksKeys.length; i++) {
+        tracks[tracksKeys[i]].setFinished();
+      }
+    };
+
+    Animator.prototype._getAdditiveTrack = function (trackName) {
+      var additiveTrack;
+      var additiveAnimators = this._additiveAnimators;
+
+      if (additiveAnimators) {
+        for (var i = 0; i < additiveAnimators.length; i++) {
+          var track = additiveAnimators[i].getTrack(trackName);
+
+          if (track) {
+            additiveTrack = track;
+          }
+        }
+      }
+
+      return additiveTrack;
+    };
+
+    Animator.prototype.start = function (easing) {
+      if (this._started > 0) {
+        return;
+      }
+
+      this._started = 1;
+      var self = this;
+      var tracks = [];
+      var maxTime = this._maxTime || 0;
+
+      for (var i = 0; i < this._trackKeys.length; i++) {
+        var propName = this._trackKeys[i];
+        var track = this._tracks[propName];
+
+        var additiveTrack = this._getAdditiveTrack(propName);
+
+        var kfs = track.keyframes;
+        var kfsNum = kfs.length;
+        track.prepare(maxTime, additiveTrack);
+
+        if (track.needsAnimate()) {
+          if (!this._allowDiscrete && track.discrete) {
+            var lastKf = kfs[kfsNum - 1];
+
+            if (lastKf) {
+              self._target[track.propName] = lastKf.rawValue;
+            }
+
+            track.setFinished();
+          } else {
+            tracks.push(track);
+          }
+        }
+      }
+
+      if (tracks.length || this._force) {
+        var clip = new Clip({
+          life: maxTime,
+          loop: this._loop,
+          delay: this._delay || 0,
+          onframe: function (percent) {
+            self._started = 2;
+            var additiveAnimators = self._additiveAnimators;
+
+            if (additiveAnimators) {
+              var stillHasAdditiveAnimator = false;
+
+              for (var i = 0; i < additiveAnimators.length; i++) {
+                if (additiveAnimators[i]._clip) {
+                  stillHasAdditiveAnimator = true;
+                  break;
+                }
+              }
+
+              if (!stillHasAdditiveAnimator) {
+                self._additiveAnimators = null;
+              }
+            }
+
+            for (var i = 0; i < tracks.length; i++) {
+              tracks[i].step(self._target, percent);
+            }
+
+            var onframeList = self._onframeCbs;
+
+            if (onframeList) {
+              for (var i = 0; i < onframeList.length; i++) {
+                onframeList[i](self._target, percent);
+              }
+            }
+          },
+          ondestroy: function () {
+            self._doneCallback();
+          }
+        });
+        this._clip = clip;
+
+        if (this.animation) {
+          this.animation.addClip(clip);
+        }
+
+        if (easing) {
+          clip.setEasing(easing);
+        }
+      } else {
+        this._doneCallback();
+      }
+
+      return this;
+    };
+
+    Animator.prototype.stop = function (forwardToLast) {
+      if (!this._clip) {
+        return;
+      }
+
+      var clip = this._clip;
+
+      if (forwardToLast) {
+        clip.onframe(1);
+      }
+
+      this._abortedCallback();
+    };
+
+    Animator.prototype.delay = function (time) {
+      this._delay = time;
+      return this;
+    };
+
+    Animator.prototype.during = function (cb) {
+      if (cb) {
+        if (!this._onframeCbs) {
+          this._onframeCbs = [];
+        }
+
+        this._onframeCbs.push(cb);
+      }
+
+      return this;
+    };
+
+    Animator.prototype.done = function (cb) {
+      if (cb) {
+        if (!this._doneCbs) {
+          this._doneCbs = [];
+        }
+
+        this._doneCbs.push(cb);
+      }
+
+      return this;
+    };
+
+    Animator.prototype.aborted = function (cb) {
+      if (cb) {
+        if (!this._abortedCbs) {
+          this._abortedCbs = [];
+        }
+
+        this._abortedCbs.push(cb);
+      }
+
+      return this;
+    };
+
+    Animator.prototype.getClip = function () {
+      return this._clip;
+    };
+
+    Animator.prototype.getTrack = function (propName) {
+      return this._tracks[propName];
+    };
+
+    Animator.prototype.getTracks = function () {
+      var _this = this;
+
+      return map(this._trackKeys, function (key) {
+        return _this._tracks[key];
+      });
+    };
+
+    Animator.prototype.stopTracks = function (propNames, forwardToLast) {
+      if (!propNames.length || !this._clip) {
+        return true;
+      }
+
+      var tracks = this._tracks;
+      var tracksKeys = this._trackKeys;
+
+      for (var i = 0; i < propNames.length; i++) {
+        var track = tracks[propNames[i]];
+
+        if (track && !track.isFinished()) {
+          if (forwardToLast) {
+            track.step(this._target, 1);
+          } else if (this._started === 1) {
+            track.step(this._target, 0);
+          }
+
+          track.setFinished();
+        }
+      }
+
+      var allAborted = true;
+
+      for (var i = 0; i < tracksKeys.length; i++) {
+        if (!tracks[tracksKeys[i]].isFinished()) {
+          allAborted = false;
+          break;
+        }
+      }
+
+      if (allAborted) {
+        this._abortedCallback();
+      }
+
+      return allAborted;
+    };
+
+    Animator.prototype.saveTo = function (target, trackKeys, firstOrLast) {
+      if (!target) {
+        return;
+      }
+
+      trackKeys = trackKeys || this._trackKeys;
+
+      for (var i = 0; i < trackKeys.length; i++) {
+        var propName = trackKeys[i];
+        var track = this._tracks[propName];
+
+        if (!track || track.isFinished()) {
+          continue;
+        }
+
+        var kfs = track.keyframes;
+        var kf = kfs[firstOrLast ? 0 : kfs.length - 1];
+
+        if (kf) {
+          target[propName] = cloneValue(kf.rawValue);
+        }
+      }
+    };
+
+    Animator.prototype.__changeFinalValue = function (finalProps, trackKeys) {
+      trackKeys = trackKeys || keys(finalProps);
+
+      for (var i = 0; i < trackKeys.length; i++) {
+        var propName = trackKeys[i];
+        var track = this._tracks[propName];
+
+        if (!track) {
+          continue;
+        }
+
+        var kfs = track.keyframes;
+
+        if (kfs.length > 1) {
+          var lastKf = kfs.pop();
+          track.addKeyframe(lastKf.time, finalProps[propName]);
+          track.prepare(this._maxTime, track.getAdditiveTrack());
+        }
+      }
+    };
+
+    return Animator;
+  }();
+
+  function getTime() {
+    return new Date().getTime();
+  }
+
+  var Animation = function (_super) {
+    __extends(Animation, _super);
+
+    function Animation(opts) {
+      var _this = _super.call(this) || this;
+
+      _this._running = false;
+      _this._time = 0;
+      _this._pausedTime = 0;
+      _this._pauseStart = 0;
+      _this._paused = false;
+      opts = opts || {};
+      _this.stage = opts.stage || {};
+      return _this;
+    }
+
+    Animation.prototype.addClip = function (clip) {
+      if (clip.animation) {
+        this.removeClip(clip);
+      }
+
+      if (!this._head) {
+        this._head = this._tail = clip;
+      } else {
+        this._tail.next = clip;
+        clip.prev = this._tail;
+        clip.next = null;
+        this._tail = clip;
+      }
+
+      clip.animation = this;
+    };
+
+    Animation.prototype.addAnimator = function (animator) {
+      animator.animation = this;
+      var clip = animator.getClip();
+
+      if (clip) {
+        this.addClip(clip);
+      }
+    };
+
+    Animation.prototype.removeClip = function (clip) {
+      if (!clip.animation) {
+        return;
+      }
+
+      var prev = clip.prev;
+      var next = clip.next;
+
+      if (prev) {
+        prev.next = next;
+      } else {
+        this._head = next;
+      }
+
+      if (next) {
+        next.prev = prev;
+      } else {
+        this._tail = prev;
+      }
+
+      clip.next = clip.prev = clip.animation = null;
+    };
+
+    Animation.prototype.removeAnimator = function (animator) {
+      var clip = animator.getClip();
+
+      if (clip) {
+        this.removeClip(clip);
+      }
+
+      animator.animation = null;
+    };
+
+    Animation.prototype.update = function (notTriggerFrameAndStageUpdate) {
+      var time = getTime() - this._pausedTime;
+
+      var delta = time - this._time;
+      var clip = this._head;
+
+      while (clip) {
+        var nextClip = clip.next;
+        var finished = clip.step(time, delta);
+
+        if (finished) {
+          clip.ondestroy();
+          this.removeClip(clip);
+          clip = nextClip;
+        } else {
+          clip = nextClip;
+        }
+      }
+
+      this._time = time;
+
+      if (!notTriggerFrameAndStageUpdate) {
+        this.trigger('frame', delta);
+        this.stage.update && this.stage.update();
+      }
+    };
+
+    Animation.prototype._startLoop = function () {
+      var self = this;
+      this._running = true;
+
+      function step() {
+        if (self._running) {
+          requestAnimationFrame$1(step);
+          !self._paused && self.update();
+        }
+      }
+
+      requestAnimationFrame$1(step);
+    };
+
+    Animation.prototype.start = function () {
+      if (this._running) {
+        return;
+      }
+
+      this._time = getTime();
+      this._pausedTime = 0;
+
+      this._startLoop();
+    };
+
+    Animation.prototype.stop = function () {
+      this._running = false;
+    };
+
+    Animation.prototype.pause = function () {
+      if (!this._paused) {
+        this._pauseStart = getTime();
+        this._paused = true;
+      }
+    };
+
+    Animation.prototype.resume = function () {
+      if (this._paused) {
+        this._pausedTime += getTime() - this._pauseStart;
+        this._paused = false;
+      }
+    };
+
+    Animation.prototype.clear = function () {
+      var clip = this._head;
+
+      while (clip) {
+        var nextClip = clip.next;
+        clip.prev = clip.next = clip.animation = null;
+        clip = nextClip;
+      }
+
+      this._head = this._tail = null;
+    };
+
+    Animation.prototype.isFinished = function () {
+      return this._head == null;
+    };
+
+    Animation.prototype.animate = function (target, options) {
+      options = options || {};
+      this.start();
+      var animator = new Animator(target, options.loop);
+      this.addAnimator(animator);
+      return animator;
+    };
+
+    return Animation;
+  }(Eventful);
+
+  var TOUCH_CLICK_DELAY = 300;
+  var globalEventSupported = env.domSupported;
+
+  var localNativeListenerNames = function () {
+    var mouseHandlerNames = ['click', 'dblclick', 'mousewheel', 'wheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu'];
+    var touchHandlerNames = ['touchstart', 'touchend', 'touchmove'];
+    var pointerEventNameMap = {
+      pointerdown: 1,
+      pointerup: 1,
+      pointermove: 1,
+      pointerout: 1
+    };
+    var pointerHandlerNames = map(mouseHandlerNames, function (name) {
+      var nm = name.replace('mouse', 'pointer');
+      return pointerEventNameMap.hasOwnProperty(nm) ? nm : name;
+    });
+    return {
+      mouse: mouseHandlerNames,
+      touch: touchHandlerNames,
+      pointer: pointerHandlerNames
+    };
+  }();
+
+  var globalNativeListenerNames = {
+    mouse: ['mousemove', 'mouseup'],
+    pointer: ['pointermove', 'pointerup']
+  };
+  var wheelEventSupported = false;
+
+  function isPointerFromTouch(event) {
+    var pointerType = event.pointerType;
+    return pointerType === 'pen' || pointerType === 'touch';
+  }
+
+  function setTouchTimer(scope) {
+    scope.touching = true;
+
+    if (scope.touchTimer != null) {
+      clearTimeout(scope.touchTimer);
+      scope.touchTimer = null;
+    }
+
+    scope.touchTimer = setTimeout(function () {
+      scope.touching = false;
+      scope.touchTimer = null;
+    }, 700);
+  }
+
+  function markTouch(event) {
+    event && (event.zrByTouch = true);
+  }
+
+  function normalizeGlobalEvent(instance, event) {
+    return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true);
+  }
+
+  function isLocalEl(instance, el) {
+    var elTmp = el;
+    var isLocal = false;
+
+    while (elTmp && elTmp.nodeType !== 9 && !(isLocal = elTmp.domBelongToZr || elTmp !== el && elTmp === instance.painterRoot)) {
+      elTmp = elTmp.parentNode;
+    }
+
+    return isLocal;
+  }
+
+  var FakeGlobalEvent = function () {
+    function FakeGlobalEvent(instance, event) {
+      this.stopPropagation = noop;
+      this.stopImmediatePropagation = noop;
+      this.preventDefault = noop;
+      this.type = event.type;
+      this.target = this.currentTarget = instance.dom;
+      this.pointerType = event.pointerType;
+      this.clientX = event.clientX;
+      this.clientY = event.clientY;
+    }
+
+    return FakeGlobalEvent;
+  }();
+
+  var localDOMHandlers = {
+    mousedown: function (event) {
+      event = normalizeEvent(this.dom, event);
+      this.__mayPointerCapture = [event.zrX, event.zrY];
+      this.trigger('mousedown', event);
+    },
+    mousemove: function (event) {
+      event = normalizeEvent(this.dom, event);
+      var downPoint = this.__mayPointerCapture;
+
+      if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) {
+        this.__togglePointerCapture(true);
+      }
+
+      this.trigger('mousemove', event);
+    },
+    mouseup: function (event) {
+      event = normalizeEvent(this.dom, event);
+
+      this.__togglePointerCapture(false);
+
+      this.trigger('mouseup', event);
+    },
+    mouseout: function (event) {
+      event = normalizeEvent(this.dom, event);
+      var element = event.toElement || event.relatedTarget;
+
+      if (!isLocalEl(this, element)) {
+        if (this.__pointerCapturing) {
+          event.zrEventControl = 'no_globalout';
+        }
+
+        this.trigger('mouseout', event);
+      }
+    },
+    wheel: function (event) {
+      wheelEventSupported = true;
+      event = normalizeEvent(this.dom, event);
+      this.trigger('mousewheel', event);
+    },
+    mousewheel: function (event) {
+      if (wheelEventSupported) {
+        return;
+      }
+
+      event = normalizeEvent(this.dom, event);
+      this.trigger('mousewheel', event);
+    },
+    touchstart: function (event) {
+      event = normalizeEvent(this.dom, event);
+      markTouch(event);
+      this.__lastTouchMoment = new Date();
+      this.handler.processGesture(event, 'start');
+      localDOMHandlers.mousemove.call(this, event);
+      localDOMHandlers.mousedown.call(this, event);
+    },
+    touchmove: function (event) {
+      event = normalizeEvent(this.dom, event);
+      markTouch(event);
+      this.handler.processGesture(event, 'change');
+      localDOMHandlers.mousemove.call(this, event);
+    },
+    touchend: function (event) {
+      event = normalizeEvent(this.dom, event);
+      markTouch(event);
+      this.handler.processGesture(event, 'end');
+      localDOMHandlers.mouseup.call(this, event);
+
+      if (+new Date() - +this.__lastTouchMoment < TOUCH_CLICK_DELAY) {
+        localDOMHandlers.click.call(this, event);
+      }
+    },
+    pointerdown: function (event) {
+      localDOMHandlers.mousedown.call(this, event);
+    },
+    pointermove: function (event) {
+      if (!isPointerFromTouch(event)) {
+        localDOMHandlers.mousemove.call(this, event);
+      }
+    },
+    pointerup: function (event) {
+      localDOMHandlers.mouseup.call(this, event);
+    },
+    pointerout: function (event) {
+      if (!isPointerFromTouch(event)) {
+        localDOMHandlers.mouseout.call(this, event);
+      }
+    }
+  };
+  each(['click', 'dblclick', 'contextmenu'], function (name) {
+    localDOMHandlers[name] = function (event) {
+      event = normalizeEvent(this.dom, event);
+      this.trigger(name, event);
+    };
+  });
+  var globalDOMHandlers = {
+    pointermove: function (event) {
+      if (!isPointerFromTouch(event)) {
+        globalDOMHandlers.mousemove.call(this, event);
+      }
+    },
+    pointerup: function (event) {
+      globalDOMHandlers.mouseup.call(this, event);
+    },
+    mousemove: function (event) {
+      this.trigger('mousemove', event);
+    },
+    mouseup: function (event) {
+      var pointerCaptureReleasing = this.__pointerCapturing;
+
+      this.__togglePointerCapture(false);
+
+      this.trigger('mouseup', event);
+
+      if (pointerCaptureReleasing) {
+        event.zrEventControl = 'only_globalout';
+        this.trigger('mouseout', event);
+      }
+    }
+  };
+
+  function mountLocalDOMEventListeners(instance, scope) {
+    var domHandlers = scope.domHandlers;
+
+    if (env.pointerEventsSupported) {
+      each(localNativeListenerNames.pointer, function (nativeEventName) {
+        mountSingleDOMEventListener(scope, nativeEventName, function (event) {
+          domHandlers[nativeEventName].call(instance, event);
+        });
+      });
+    } else {
+      if (env.touchEventsSupported) {
+        each(localNativeListenerNames.touch, function (nativeEventName) {
+          mountSingleDOMEventListener(scope, nativeEventName, function (event) {
+            domHandlers[nativeEventName].call(instance, event);
+            setTouchTimer(scope);
+          });
+        });
+      }
+
+      each(localNativeListenerNames.mouse, function (nativeEventName) {
+        mountSingleDOMEventListener(scope, nativeEventName, function (event) {
+          event = getNativeEvent(event);
+
+          if (!scope.touching) {
+            domHandlers[nativeEventName].call(instance, event);
+          }
+        });
+      });
+    }
+  }
+
+  function mountGlobalDOMEventListeners(instance, scope) {
+    if (env.pointerEventsSupported) {
+      each(globalNativeListenerNames.pointer, mount);
+    } else if (!env.touchEventsSupported) {
+      each(globalNativeListenerNames.mouse, mount);
+    }
+
+    function mount(nativeEventName) {
+      function nativeEventListener(event) {
+        event = getNativeEvent(event);
+
+        if (!isLocalEl(instance, event.target)) {
+          event = normalizeGlobalEvent(instance, event);
+          scope.domHandlers[nativeEventName].call(instance, event);
+        }
+      }
+
+      mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, {
+        capture: true
+      });
+    }
+  }
+
+  function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) {
+    scope.mounted[nativeEventName] = listener;
+    scope.listenerOpts[nativeEventName] = opt;
+    addEventListener(scope.domTarget, nativeEventName, listener, opt);
+  }
+
+  function unmountDOMEventListeners(scope) {
+    var mounted = scope.mounted;
+
+    for (var nativeEventName in mounted) {
+      if (mounted.hasOwnProperty(nativeEventName)) {
+        removeEventListener(scope.domTarget, nativeEventName, mounted[nativeEventName], scope.listenerOpts[nativeEventName]);
+      }
+    }
+
+    scope.mounted = {};
+  }
+
+  var DOMHandlerScope = function () {
+    function DOMHandlerScope(domTarget, domHandlers) {
+      this.mounted = {};
+      this.listenerOpts = {};
+      this.touching = false;
+      this.domTarget = domTarget;
+      this.domHandlers = domHandlers;
+    }
+
+    return DOMHandlerScope;
+  }();
+
+  var HandlerDomProxy = function (_super) {
+    __extends(HandlerDomProxy, _super);
+
+    function HandlerDomProxy(dom, painterRoot) {
+      var _this = _super.call(this) || this;
+
+      _this.__pointerCapturing = false;
+      _this.dom = dom;
+      _this.painterRoot = painterRoot;
+      _this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers);
+
+      if (globalEventSupported) {
+        _this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers);
+      }
+
+      mountLocalDOMEventListeners(_this, _this._localHandlerScope);
+      return _this;
+    }
+
+    HandlerDomProxy.prototype.dispose = function () {
+      unmountDOMEventListeners(this._localHandlerScope);
+
+      if (globalEventSupported) {
+        unmountDOMEventListeners(this._globalHandlerScope);
+      }
+    };
+
+    HandlerDomProxy.prototype.setCursor = function (cursorStyle) {
+      this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');
+    };
+
+    HandlerDomProxy.prototype.__togglePointerCapture = function (isPointerCapturing) {
+      this.__mayPointerCapture = null;
+
+      if (globalEventSupported && +this.__pointerCapturing ^ +isPointerCapturing) {
+        this.__pointerCapturing = isPointerCapturing;
+        var globalHandlerScope = this._globalHandlerScope;
+        isPointerCapturing ? mountGlobalDOMEventListeners(this, globalHandlerScope) : unmountDOMEventListeners(globalHandlerScope);
+      }
+    };
+
+    return HandlerDomProxy;
+  }(Eventful);
+
+  var dpr = 1;
+
+  if (env.hasGlobalWindow) {
+    dpr = Math.max(window.devicePixelRatio || window.screen && window.screen.deviceXDPI / window.screen.logicalXDPI || 1, 1);
+  }
+
+  var devicePixelRatio = dpr;
+  var DARK_MODE_THRESHOLD = 0.4;
+  var DARK_LABEL_COLOR = '#333';
+  var LIGHT_LABEL_COLOR = '#ccc';
+  var LIGHTER_LABEL_COLOR = '#eee';
+
+  function create$1() {
+    return [1, 0, 0, 1, 0, 0];
+  }
+
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
+
+  function copy$1(out, m) {
+    out[0] = m[0];
+    out[1] = m[1];
+    out[2] = m[2];
+    out[3] = m[3];
+    out[4] = m[4];
+    out[5] = m[5];
+    return out;
+  }
+
+  function mul$1(out, m1, m2) {
+    var out0 = m1[0] * m2[0] + m1[2] * m2[1];
+    var out1 = m1[1] * m2[0] + m1[3] * m2[1];
+    var out2 = m1[0] * m2[2] + m1[2] * m2[3];
+    var out3 = m1[1] * m2[2] + m1[3] * m2[3];
+    var out4 = m1[0] * m2[4] + m1[2] * m2[5] + m1[4];
+    var out5 = m1[1] * m2[4] + m1[3] * m2[5] + m1[5];
+    out[0] = out0;
+    out[1] = out1;
+    out[2] = out2;
+    out[3] = out3;
+    out[4] = out4;
+    out[5] = out5;
+    return out;
+  }
+
+  function translate(out, a, v) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    out[4] = a[4] + v[0];
+    out[5] = a[5] + v[1];
+    return out;
+  }
+
+  function rotate(out, a, rad) {
+    var aa = a[0];
+    var ac = a[2];
+    var atx = a[4];
+    var ab = a[1];
+    var ad = a[3];
+    var aty = a[5];
+    var st = Math.sin(rad);
+    var ct = Math.cos(rad);
+    out[0] = aa * ct + ab * st;
+    out[1] = -aa * st + ab * ct;
+    out[2] = ac * ct + ad * st;
+    out[3] = -ac * st + ct * ad;
+    out[4] = ct * atx + st * aty;
+    out[5] = ct * aty - st * atx;
+    return out;
+  }
+
+  function scale$1(out, a, v) {
+    var vx = v[0];
+    var vy = v[1];
+    out[0] = a[0] * vx;
+    out[1] = a[1] * vy;
+    out[2] = a[2] * vx;
+    out[3] = a[3] * vy;
+    out[4] = a[4] * vx;
+    out[5] = a[5] * vy;
+    return out;
+  }
+
+  function invert(out, a) {
+    var aa = a[0];
+    var ac = a[2];
+    var atx = a[4];
+    var ab = a[1];
+    var ad = a[3];
+    var aty = a[5];
+    var det = aa * ad - ab * ac;
+
+    if (!det) {
+      return null;
+    }
+
+    det = 1.0 / det;
+    out[0] = ad * det;
+    out[1] = -ab * det;
+    out[2] = -ac * det;
+    out[3] = aa * det;
+    out[4] = (ac * aty - ad * atx) * det;
+    out[5] = (ab * atx - aa * aty) * det;
+    return out;
+  }
+
+  function clone$2(a) {
+    var b = create$1();
+    copy$1(b, a);
+    return b;
+  }
+
+  var matrix = (Object.freeze || Object)({
+    create: create$1,
+    identity: identity,
+    copy: copy$1,
+    mul: mul$1,
+    translate: translate,
+    rotate: rotate,
+    scale: scale$1,
+    invert: invert,
+    clone: clone$2
+  });
+  var mIdentity = identity;
+  var EPSILON$2 = 5e-5;
+
+  function isNotAroundZero$1(val) {
+    return val > EPSILON$2 || val < -EPSILON$2;
+  }
+
+  var scaleTmp = [];
+  var tmpTransform = [];
+  var originTransform = create$1();
+  var abs = Math.abs;
+
+  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];
+    };
+
+    Transformable.prototype.setScale = function (arr) {
+      this.scaleX = arr[0];
+      this.scaleY = arr[1];
+    };
+
+    Transformable.prototype.setSkew = function (arr) {
+      this.skewX = arr[0];
+      this.skewY = arr[1];
+    };
+
+    Transformable.prototype.setOrigin = function (arr) {
+      this.originX = arr[0];
+      this.originY = arr[1];
+    };
+
+    Transformable.prototype.needLocalTransform = function () {
+      return isNotAroundZero$1(this.rotation) || isNotAroundZero$1(this.x) || isNotAroundZero$1(this.y) || isNotAroundZero$1(this.scaleX - 1) || isNotAroundZero$1(this.scaleY - 1) || isNotAroundZero$1(this.skewX) || isNotAroundZero$1(this.skewY);
+    };
+
+    Transformable.prototype.updateTransform = function () {
+      var parentTransform = this.parent && this.parent.transform;
+      var needLocalTransform = this.needLocalTransform();
+      var m = this.transform;
+
+      if (!(needLocalTransform || parentTransform)) {
+        m && mIdentity(m);
+        return;
+      }
+
+      m = m || create$1();
+
+      if (needLocalTransform) {
+        this.getLocalTransform(m);
+      } else {
+        mIdentity(m);
+      }
+
+      if (parentTransform) {
+        if (needLocalTransform) {
+          mul$1(m, parentTransform, m);
+        } else {
+          copy$1(m, parentTransform);
+        }
+      }
+
+      this.transform = m;
+
+      this._resolveGlobalScaleRatio(m);
+    };
+
+    Transformable.prototype._resolveGlobalScaleRatio = function (m) {
+      var globalScaleRatio = this.globalScaleRatio;
+
+      if (globalScaleRatio != null && globalScaleRatio !== 1) {
+        this.getGlobalScale(scaleTmp);
+        var relX = scaleTmp[0] < 0 ? -1 : 1;
+        var relY = scaleTmp[1] < 0 ? -1 : 1;
+        var sx = ((scaleTmp[0] - relX) * globalScaleRatio + relX) / scaleTmp[0] || 0;
+        var sy = ((scaleTmp[1] - relY) * globalScaleRatio + relY) / scaleTmp[1] || 0;
+        m[0] *= sx;
+        m[1] *= sx;
+        m[2] *= sy;
+        m[3] *= sy;
+      }
+
+      this.invTransform = this.invTransform || create$1();
+      invert(this.invTransform, m);
+    };
+
+    Transformable.prototype.getComputedTransform = function () {
+      var transformNode = this;
+      var ancestors = [];
+
+      while (transformNode) {
+        ancestors.push(transformNode);
+        transformNode = transformNode.parent;
+      }
+
+      while (transformNode = ancestors.pop()) {
+        transformNode.updateTransform();
+      }
+
+      return this.transform;
+    };
+
+    Transformable.prototype.setLocalTransform = function (m) {
+      if (!m) {
+        return;
+      }
+
+      var sx = m[0] * m[0] + m[1] * m[1];
+      var sy = m[2] * m[2] + m[3] * m[3];
+      var rotation = Math.atan2(m[1], m[0]);
+      var shearX = Math.PI / 2 + rotation - Math.atan2(m[3], m[2]);
+      sy = Math.sqrt(sy) * Math.cos(shearX);
+      sx = Math.sqrt(sx);
+      this.skewX = shearX;
+      this.skewY = 0;
+      this.rotation = -rotation;
+      this.x = +m[4];
+      this.y = +m[5];
+      this.scaleX = sx;
+      this.scaleY = sy;
+      this.originX = 0;
+      this.originY = 0;
+    };
+
+    Transformable.prototype.decomposeTransform = function () {
+      if (!this.transform) {
+        return;
+      }
+
+      var parent = this.parent;
+      var m = this.transform;
+
+      if (parent && parent.transform) {
+        mul$1(tmpTransform, parent.invTransform, m);
+        m = tmpTransform;
+      }
+
+      var ox = this.originX;
+      var oy = this.originY;
+
+      if (ox || oy) {
+        originTransform[4] = ox;
+        originTransform[5] = oy;
+        mul$1(tmpTransform, m, originTransform);
+        tmpTransform[4] -= ox;
+        tmpTransform[5] -= oy;
+        m = tmpTransform;
+      }
+
+      this.setLocalTransform(m);
+    };
+
+    Transformable.prototype.getGlobalScale = function (out) {
+      var m = this.transform;
+      out = out || [];
+
+      if (!m) {
+        out[0] = 1;
+        out[1] = 1;
+        return out;
+      }
+
+      out[0] = Math.sqrt(m[0] * m[0] + m[1] * m[1]);
+      out[1] = Math.sqrt(m[2] * m[2] + m[3] * m[3]);
+
+      if (m[0] < 0) {
+        out[0] = -out[0];
+      }
+
+      if (m[3] < 0) {
+        out[1] = -out[1];
+      }
+
+      return out;
+    };
+
+    Transformable.prototype.transformCoordToLocal = function (x, y) {
+      var v2 = [x, y];
+      var invTransform = this.invTransform;
+
+      if (invTransform) {
+        applyTransform(v2, v2, invTransform);
+      }
+
+      return v2;
+    };
+
+    Transformable.prototype.transformCoordToGlobal = function (x, y) {
+      var v2 = [x, y];
+      var transform = this.transform;
+
+      if (transform) {
+        applyTransform(v2, v2, transform);
+      }
+
+      return v2;
+    };
+
+    Transformable.prototype.getLineScale = function () {
+      var m = this.transform;
+      return m && abs(m[0] - 1) > 1e-10 && abs(m[3] - 1) > 1e-10 ? Math.sqrt(abs(m[0] * m[3] - m[2] * m[1])) : 1;
+    };
+
+    Transformable.prototype.copyTransform = function (source) {
+      copyTransform(this, source);
+    };
+
+    Transformable.getLocalTransform = function (target, m) {
+      m = m || [];
+      var ox = target.originX || 0;
+      var oy = target.originY || 0;
+      var sx = target.scaleX;
+      var sy = target.scaleY;
+      var ax = target.anchorX;
+      var ay = target.anchorY;
+      var rotation = target.rotation || 0;
+      var x = target.x;
+      var y = target.y;
+      var skewX = target.skewX ? Math.tan(target.skewX) : 0;
+      var skewY = target.skewY ? Math.tan(-target.skewY) : 0;
+
+      if (ox || oy || ax || ay) {
+        var dx = ox + ax;
+        var dy = oy + ay;
+        m[4] = -dx * sx - skewX * dy * sy;
+        m[5] = -dy * sy - skewY * dx * sx;
+      } else {
+        m[4] = m[5] = 0;
+      }
+
+      m[0] = sx;
+      m[3] = sy;
+      m[1] = skewY * sx;
+      m[2] = skewX * sy;
+      rotation && rotate(m, m, rotation);
+      m[4] += ox + x;
+      m[5] += oy + y;
+      return m;
+    };
+
+    Transformable.initDefaultProps = function () {
+      var proto = Transformable.prototype;
+      proto.scaleX = proto.scaleY = proto.globalScaleRatio = 1;
+      proto.x = proto.y = proto.originX = proto.originY = proto.skewX = proto.skewY = proto.rotation = proto.anchorX = proto.anchorY = 0;
+    }();
+
+    return Transformable;
+  }();
+
+  var TRANSFORMABLE_PROPS = ['x', 'y', 'originX', 'originY', 'anchorX', 'anchorY', 'rotation', 'scaleX', 'scaleY', 'skewX', 'skewY'];
+
+  function copyTransform(target, source) {
+    for (var i = 0; i < TRANSFORMABLE_PROPS.length; i++) {
+      var propName = TRANSFORMABLE_PROPS[i];
+      target[propName] = source[propName];
+    }
+  }
+
+  var Point = function () {
+    function Point(x, y) {
+      this.x = x || 0;
+      this.y = y || 0;
+    }
+
+    Point.prototype.copy = function (other) {
+      this.x = other.x;
+      this.y = other.y;
+      return this;
+    };
+
+    Point.prototype.clone = function () {
+      return new Point(this.x, this.y);
+    };
+
+    Point.prototype.set = function (x, y) {
+      this.x = x;
+      this.y = y;
+      return this;
+    };
+
+    Point.prototype.equal = function (other) {
+      return other.x === this.x && other.y === this.y;
+    };
+
+    Point.prototype.add = function (other) {
+      this.x += other.x;
+      this.y += other.y;
+      return this;
+    };
+
+    Point.prototype.scale = function (scalar) {
+      this.x *= scalar;
+      this.y *= scalar;
+    };
+
+    Point.prototype.scaleAndAdd = function (other, scalar) {
+      this.x += other.x * scalar;
+      this.y += other.y * scalar;
+    };
+
+    Point.prototype.sub = function (other) {
+      this.x -= other.x;
+      this.y -= other.y;
+      return this;
+    };
+
+    Point.prototype.dot = function (other) {
+      return this.x * other.x + this.y * other.y;
+    };
+
+    Point.prototype.len = function () {
+      return Math.sqrt(this.x * this.x + this.y * this.y);
+    };
+
+    Point.prototype.lenSquare = function () {
+      return this.x * this.x + this.y * this.y;
+    };
+
+    Point.prototype.normalize = function () {
+      var len = this.len();
+      this.x /= len;
+      this.y /= len;
+      return this;
+    };
+
+    Point.prototype.distance = function (other) {
+      var dx = this.x - other.x;
+      var dy = this.y - other.y;
+      return Math.sqrt(dx * dx + dy * dy);
+    };
+
+    Point.prototype.distanceSquare = function (other) {
+      var dx = this.x - other.x;
+      var dy = this.y - other.y;
+      return dx * dx + dy * dy;
+    };
+
+    Point.prototype.negate = function () {
+      this.x = -this.x;
+      this.y = -this.y;
+      return this;
+    };
+
+    Point.prototype.transform = function (m) {
+      if (!m) {
+        return;
+      }
+
+      var x = this.x;
+      var y = this.y;
+      this.x = m[0] * x + m[2] * y + m[4];
+      this.y = m[1] * x + m[3] * y + m[5];
+      return this;
+    };
+
+    Point.prototype.toArray = function (out) {
+      out[0] = this.x;
+      out[1] = this.y;
+      return out;
+    };
+
+    Point.prototype.fromArray = function (input) {
+      this.x = input[0];
+      this.y = input[1];
+    };
+
+    Point.set = function (p, x, y) {
+      p.x = x;
+      p.y = y;
+    };
+
+    Point.copy = function (p, p2) {
+      p.x = p2.x;
+      p.y = p2.y;
+    };
+
+    Point.len = function (p) {
+      return Math.sqrt(p.x * p.x + p.y * p.y);
+    };
+
+    Point.lenSquare = function (p) {
+      return p.x * p.x + p.y * p.y;
+    };
+
+    Point.dot = function (p0, p1) {
+      return p0.x * p1.x + p0.y * p1.y;
+    };
+
+    Point.add = function (out, p0, p1) {
+      out.x = p0.x + p1.x;
+      out.y = p0.y + p1.y;
+    };
+
+    Point.sub = function (out, p0, p1) {
+      out.x = p0.x - p1.x;
+      out.y = p0.y - p1.y;
+    };
+
+    Point.scale = function (out, p0, scalar) {
+      out.x = p0.x * scalar;
+      out.y = p0.y * scalar;
+    };
+
+    Point.scaleAndAdd = function (out, p0, p1, scalar) {
+      out.x = p0.x + p1.x * scalar;
+      out.y = p0.y + p1.y * scalar;
+    };
+
+    Point.lerp = function (out, p0, p1, t) {
+      var onet = 1 - t;
+      out.x = onet * p0.x + t * p1.x;
+      out.y = onet * p0.y + t * p1.y;
+    };
+
+    return Point;
+  }();
+
+  var mathMin = Math.min;
+  var mathMax = Math.max;
+  var lt = new Point();
+  var rb = new Point();
+  var lb = new Point();
+  var rt = new Point();
+  var minTv = new Point();
+  var maxTv = new Point();
+
+  var BoundingRect = function () {
+    function BoundingRect(x, y, width, height) {
+      if (width < 0) {
+        x = x + width;
+        width = -width;
+      }
+
+      if (height < 0) {
+        y = y + height;
+        height = -height;
+      }
+
+      this.x = x;
+      this.y = y;
+      this.width = width;
+      this.height = height;
+    }
+
+    BoundingRect.prototype.union = function (other) {
+      var x = mathMin(other.x, this.x);
+      var y = mathMin(other.y, this.y);
+
+      if (isFinite(this.x) && isFinite(this.width)) {
+        this.width = mathMax(other.x + other.width, this.x + this.width) - x;
+      } else {
+        this.width = other.width;
+      }
+
+      if (isFinite(this.y) && isFinite(this.height)) {
+        this.height = mathMax(other.y + other.height, this.y + this.height) - y;
+      } else {
+        this.height = other.height;
+      }
+
+      this.x = x;
+      this.y = y;
+    };
+
+    BoundingRect.prototype.applyTransform = function (m) {
+      BoundingRect.applyTransform(this, this, m);
+    };
+
+    BoundingRect.prototype.calculateTransform = function (b) {
+      var a = this;
+      var sx = b.width / a.width;
+      var sy = b.height / a.height;
+      var m = create$1();
+      translate(m, m, [-a.x, -a.y]);
+      scale$1(m, m, [sx, sy]);
+      translate(m, m, [b.x, b.y]);
+      return m;
+    };
+
+    BoundingRect.prototype.intersect = function (b, mtv) {
+      if (!b) {
+        return false;
+      }
+
+      if (!(b instanceof BoundingRect)) {
+        b = BoundingRect.create(b);
+      }
+
+      var a = this;
+      var ax0 = a.x;
+      var ax1 = a.x + a.width;
+      var ay0 = a.y;
+      var ay1 = a.y + a.height;
+      var bx0 = b.x;
+      var bx1 = b.x + b.width;
+      var by0 = b.y;
+      var by1 = b.y + b.height;
+      var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);
+
+      if (mtv) {
+        var dMin = Infinity;
+        var dMax = 0;
+        var d0 = Math.abs(ax1 - bx0);
+        var d1 = Math.abs(bx1 - ax0);
+        var d2 = Math.abs(ay1 - by0);
+        var d3 = Math.abs(by1 - ay0);
+        var dx = Math.min(d0, d1);
+        var dy = Math.min(d2, d3);
+
+        if (ax1 < bx0 || bx1 < ax0) {
+          if (dx > dMax) {
+            dMax = dx;
+
+            if (d0 < d1) {
+              Point.set(maxTv, -d0, 0);
+            } else {
+              Point.set(maxTv, d1, 0);
+            }
+          }
+        } else {
+          if (dx < dMin) {
+            dMin = dx;
+
+            if (d0 < d1) {
+              Point.set(minTv, d0, 0);
+            } else {
+              Point.set(minTv, -d1, 0);
+            }
+          }
+        }
+
+        if (ay1 < by0 || by1 < ay0) {
+          if (dy > dMax) {
+            dMax = dy;
+
+            if (d2 < d3) {
+              Point.set(maxTv, 0, -d2);
+            } else {
+              Point.set(maxTv, 0, d3);
+            }
+          }
+        } else {
+          if (dx < dMin) {
+            dMin = dx;
+
+            if (d2 < d3) {
+              Point.set(minTv, 0, d2);
+            } else {
+              Point.set(minTv, 0, -d3);
+            }
+          }
+        }
+      }
+
+      if (mtv) {
+        Point.copy(mtv, overlap ? minTv : maxTv);
+      }
+
+      return overlap;
+    };
+
+    BoundingRect.prototype.contain = function (x, y) {
+      var rect = this;
+      return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
+    };
+
+    BoundingRect.prototype.clone = function () {
+      return new BoundingRect(this.x, this.y, this.width, this.height);
+    };
+
+    BoundingRect.prototype.copy = function (other) {
+      BoundingRect.copy(this, other);
+    };
+
+    BoundingRect.prototype.plain = function () {
+      return {
+        x: this.x,
+        y: this.y,
+        width: this.width,
+        height: this.height
+      };
+    };
+
+    BoundingRect.prototype.isFinite = function () {
+      return isFinite(this.x) && isFinite(this.y) && isFinite(this.width) && isFinite(this.height);
+    };
+
+    BoundingRect.prototype.isZero = function () {
+      return this.width === 0 || this.height === 0;
+    };
+
+    BoundingRect.create = function (rect) {
+      return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
+    };
+
+    BoundingRect.copy = function (target, source) {
+      target.x = source.x;
+      target.y = source.y;
+      target.width = source.width;
+      target.height = source.height;
+    };
+
+    BoundingRect.applyTransform = function (target, source, m) {
+      if (!m) {
+        if (target !== source) {
+          BoundingRect.copy(target, source);
+        }
+
+        return;
+      }
+
+      if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) {
+        var sx = m[0];
+        var sy = m[3];
+        var tx = m[4];
+        var ty = m[5];
+        target.x = source.x * sx + tx;
+        target.y = source.y * sy + ty;
+        target.width = source.width * sx;
+        target.height = source.height * sy;
+
+        if (target.width < 0) {
+          target.x += target.width;
+          target.width = -target.width;
+        }
+
+        if (target.height < 0) {
+          target.y += target.height;
+          target.height = -target.height;
+        }
+
+        return;
+      }
+
+      lt.x = lb.x = source.x;
+      lt.y = rt.y = source.y;
+      rb.x = rt.x = source.x + source.width;
+      rb.y = lb.y = source.y + source.height;
+      lt.transform(m);
+      rt.transform(m);
+      rb.transform(m);
+      lb.transform(m);
+      target.x = mathMin(lt.x, rb.x, lb.x, rt.x);
+      target.y = mathMin(lt.y, rb.y, lb.y, rt.y);
+      var maxX = mathMax(lt.x, rb.x, lb.x, rt.x);
+      var maxY = mathMax(lt.y, rb.y, lb.y, rt.y);
+      target.width = maxX - target.x;
+      target.height = maxY - target.y;
+    };
+
+    return BoundingRect;
+  }();
+
+  var textWidthCache = {};
+
+  function getWidth(text, font) {
+    font = font || DEFAULT_FONT;
+    var cacheOfFont = textWidthCache[font];
+
+    if (!cacheOfFont) {
+      cacheOfFont = textWidthCache[font] = new LRU(500);
+    }
+
+    var width = cacheOfFont.get(text);
+
+    if (width == null) {
+      width = platformApi.measureText(text, font).width;
+      cacheOfFont.put(text, width);
+    }
+
+    return width;
+  }
+
+  function innerGetBoundingRect(text, font, textAlign, textBaseline) {
+    var width = getWidth(text, font);
+    var height = getLineHeight(font);
+    var x = adjustTextX(0, width, textAlign);
+    var y = adjustTextY$1(0, height, textBaseline);
+    var rect = new BoundingRect(x, y, width, height);
+    return rect;
+  }
+
+  function getBoundingRect(text, font, textAlign, textBaseline) {
+    var textLines = ((text || '') + '').split('\n');
+    var len = textLines.length;
+
+    if (len === 1) {
+      return innerGetBoundingRect(textLines[0], font, textAlign, textBaseline);
+    } else {
+      var uniondRect = new BoundingRect(0, 0, 0, 0);
+
+      for (var i = 0; i < textLines.length; i++) {
+        var rect = innerGetBoundingRect(textLines[i], font, textAlign, textBaseline);
+        i === 0 ? uniondRect.copy(rect) : uniondRect.union(rect);
+      }
+
+      return uniondRect;
+    }
+  }
+
+  function adjustTextX(x, width, textAlign) {
+    if (textAlign === 'right') {
+      x -= width;
+    } else if (textAlign === 'center') {
+      x -= width / 2;
+    }
+
+    return x;
+  }
+
+  function adjustTextY$1(y, height, verticalAlign) {
+    if (verticalAlign === 'middle') {
+      y -= height / 2;
+    } else if (verticalAlign === 'bottom') {
+      y -= height;
+    }
+
+    return y;
+  }
+
+  function getLineHeight(font) {
+    return getWidth('国', font);
+  }
+
+  function parsePercent(value, maxValue) {
+    if (typeof value === 'string') {
+      if (value.lastIndexOf('%') >= 0) {
+        return parseFloat(value) / 100 * maxValue;
+      }
+
+      return parseFloat(value);
+    }
+
+    return value;
+  }
+
+  function calculateTextPosition(out, opts, rect) {
+    var textPosition = opts.position || 'inside';
+    var distance = opts.distance != null ? opts.distance : 5;
+    var height = rect.height;
+    var width = rect.width;
+    var halfHeight = height / 2;
+    var x = rect.x;
+    var y = rect.y;
+    var textAlign = 'left';
+    var textVerticalAlign = 'top';
+
+    if (textPosition instanceof Array) {
+      x += parsePercent(textPosition[0], rect.width);
+      y += parsePercent(textPosition[1], rect.height);
+      textAlign = null;
+      textVerticalAlign = null;
+    } else {
+      switch (textPosition) {
+        case 'left':
+          x -= distance;
+          y += halfHeight;
+          textAlign = 'right';
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'right':
+          x += distance + width;
+          y += halfHeight;
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'top':
+          x += width / 2;
+          y -= distance;
+          textAlign = 'center';
+          textVerticalAlign = 'bottom';
+          break;
+
+        case 'bottom':
+          x += width / 2;
+          y += height + distance;
+          textAlign = 'center';
+          break;
+
+        case 'inside':
+          x += width / 2;
+          y += halfHeight;
+          textAlign = 'center';
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'insideLeft':
+          x += distance;
+          y += halfHeight;
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'insideRight':
+          x += width - distance;
+          y += halfHeight;
+          textAlign = 'right';
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'insideTop':
+          x += width / 2;
+          y += distance;
+          textAlign = 'center';
+          break;
+
+        case 'insideBottom':
+          x += width / 2;
+          y += height - distance;
+          textAlign = 'center';
+          textVerticalAlign = 'bottom';
+          break;
+
+        case 'insideTopLeft':
+          x += distance;
+          y += distance;
+          break;
+
+        case 'insideTopRight':
+          x += width - distance;
+          y += distance;
+          textAlign = 'right';
+          break;
+
+        case 'insideBottomLeft':
+          x += distance;
+          y += height - distance;
+          textVerticalAlign = 'bottom';
+          break;
+
+        case 'insideBottomRight':
+          x += width - distance;
+          y += height - distance;
+          textAlign = 'right';
+          textVerticalAlign = 'bottom';
+          break;
+      }
+    }
+
+    out = out || {};
+    out.x = x;
+    out.y = y;
+    out.align = textAlign;
+    out.verticalAlign = textVerticalAlign;
+    return out;
+  }
+
+  var PRESERVED_NORMAL_STATE = '__zr_normal__';
+  var PRIMARY_STATES_KEYS = TRANSFORMABLE_PROPS.concat(['ignore']);
+  var DEFAULT_ANIMATABLE_MAP = reduce(TRANSFORMABLE_PROPS, function (obj, key) {
+    obj[key] = true;
+    return obj;
+  }, {
+    ignore: false
+  });
+  var tmpTextPosCalcRes = {};
+  var tmpBoundingRect = new BoundingRect(0, 0, 0, 0);
+
+  var Element = function () {
+    function Element(props) {
+      this.id = guid();
+      this.animators = [];
+      this.currentStates = [];
+      this.states = {};
+
+      this._init(props);
+    }
+
+    Element.prototype._init = function (props) {
+      this.attr(props);
+    };
+
+    Element.prototype.drift = function (dx, dy, e) {
+      switch (this.draggable) {
+        case 'horizontal':
+          dy = 0;
+          break;
+
+        case 'vertical':
+          dx = 0;
+          break;
+      }
+
+      var m = this.transform;
+
+      if (!m) {
+        m = this.transform = [1, 0, 0, 1, 0, 0];
+      }
+
+      m[4] += dx;
+      m[5] += dy;
+      this.decomposeTransform();
+      this.markRedraw();
+    };
+
+    Element.prototype.beforeUpdate = function () {};
+
+    Element.prototype.afterUpdate = function () {};
+
+    Element.prototype.update = function () {
+      this.updateTransform();
+
+      if (this.__dirty) {
+        this.updateInnerText();
+      }
+    };
+
+    Element.prototype.updateInnerText = function (forceUpdate) {
+      var textEl = this._textContent;
+
+      if (textEl && (!textEl.ignore || forceUpdate)) {
+        if (!this.textConfig) {
+          this.textConfig = {};
+        }
+
+        var textConfig = this.textConfig;
+        var isLocal = textConfig.local;
+        var innerTransformable = textEl.innerTransformable;
+        var textAlign = void 0;
+        var textVerticalAlign = void 0;
+        var textStyleChanged = false;
+        innerTransformable.parent = isLocal ? this : null;
+        var innerOrigin = false;
+        innerTransformable.copyTransform(textEl);
+
+        if (textConfig.position != null) {
+          var layoutRect = tmpBoundingRect;
+
+          if (textConfig.layoutRect) {
+            layoutRect.copy(textConfig.layoutRect);
+          } else {
+            layoutRect.copy(this.getBoundingRect());
+          }
+
+          if (!isLocal) {
+            layoutRect.applyTransform(this.transform);
+          }
+
+          if (this.calculateTextPosition) {
+            this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
+          } else {
+            calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
+          }
+
+          innerTransformable.x = tmpTextPosCalcRes.x;
+          innerTransformable.y = tmpTextPosCalcRes.y;
+          textAlign = tmpTextPosCalcRes.align;
+          textVerticalAlign = tmpTextPosCalcRes.verticalAlign;
+          var textOrigin = textConfig.origin;
+
+          if (textOrigin && textConfig.rotation != null) {
+            var relOriginX = void 0;
+            var relOriginY = void 0;
+
+            if (textOrigin === 'center') {
+              relOriginX = layoutRect.width * 0.5;
+              relOriginY = layoutRect.height * 0.5;
+            } else {
+              relOriginX = parsePercent(textOrigin[0], layoutRect.width);
+              relOriginY = parsePercent(textOrigin[1], layoutRect.height);
+            }
+
+            innerOrigin = true;
+            innerTransformable.originX = -innerTransformable.x + relOriginX + (isLocal ? 0 : layoutRect.x);
+            innerTransformable.originY = -innerTransformable.y + relOriginY + (isLocal ? 0 : layoutRect.y);
+          }
+        }
+
+        if (textConfig.rotation != null) {
+          innerTransformable.rotation = textConfig.rotation;
+        }
+
+        var textOffset = textConfig.offset;
+
+        if (textOffset) {
+          innerTransformable.x += textOffset[0];
+          innerTransformable.y += textOffset[1];
+
+          if (!innerOrigin) {
+            innerTransformable.originX = -textOffset[0];
+            innerTransformable.originY = -textOffset[1];
+          }
+        }
+
+        var isInside = textConfig.inside == null ? typeof textConfig.position === 'string' && textConfig.position.indexOf('inside') >= 0 : textConfig.inside;
+        var innerTextDefaultStyle = this._innerTextDefaultStyle || (this._innerTextDefaultStyle = {});
+        var textFill = void 0;
+        var textStroke = void 0;
+        var autoStroke = void 0;
+
+        if (isInside && this.canBeInsideText()) {
+          textFill = textConfig.insideFill;
+          textStroke = textConfig.insideStroke;
+
+          if (textFill == null || textFill === 'auto') {
+            textFill = this.getInsideTextFill();
+          }
+
+          if (textStroke == null || textStroke === 'auto') {
+            textStroke = this.getInsideTextStroke(textFill);
+            autoStroke = true;
+          }
+        } else {
+          textFill = textConfig.outsideFill;
+          textStroke = textConfig.outsideStroke;
+
+          if (textFill == null || textFill === 'auto') {
+            textFill = this.getOutsideFill();
+          }
+
+          if (textStroke == null || textStroke === 'auto') {
+            textStroke = this.getOutsideStroke(textFill);
+            autoStroke = true;
+          }
+        }
+
+        textFill = textFill || '#000';
+
+        if (textFill !== innerTextDefaultStyle.fill || textStroke !== innerTextDefaultStyle.stroke || autoStroke !== innerTextDefaultStyle.autoStroke || textAlign !== innerTextDefaultStyle.align || textVerticalAlign !== innerTextDefaultStyle.verticalAlign) {
+          textStyleChanged = true;
+          innerTextDefaultStyle.fill = textFill;
+          innerTextDefaultStyle.stroke = textStroke;
+          innerTextDefaultStyle.autoStroke = autoStroke;
+          innerTextDefaultStyle.align = textAlign;
+          innerTextDefaultStyle.verticalAlign = textVerticalAlign;
+          textEl.setDefaultTextStyle(innerTextDefaultStyle);
+        }
+
+        textEl.__dirty |= REDRAW_BIT;
+
+        if (textStyleChanged) {
+          textEl.dirtyStyle(true);
+        }
+      }
+    };
+
+    Element.prototype.canBeInsideText = function () {
+      return true;
+    };
+
+    Element.prototype.getInsideTextFill = function () {
+      return '#fff';
+    };
+
+    Element.prototype.getInsideTextStroke = function (textFill) {
+      return '#000';
+    };
+
+    Element.prototype.getOutsideFill = function () {
+      return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR;
+    };
+
+    Element.prototype.getOutsideStroke = function (textFill) {
+      var backgroundColor = this.__zr && this.__zr.getBackgroundColor();
+
+      var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor);
+
+      if (!colorArr) {
+        colorArr = [255, 255, 255, 1];
+      }
+
+      var alpha = colorArr[3];
+
+      var isDark = this.__zr.isDarkMode();
+
+      for (var i = 0; i < 3; i++) {
+        colorArr[i] = colorArr[i] * alpha + (isDark ? 0 : 255) * (1 - alpha);
+      }
+
+      colorArr[3] = 1;
+      return stringify(colorArr, 'rgba');
+    };
+
+    Element.prototype.traverse = function (cb, context) {};
+
+    Element.prototype.attrKV = function (key, value) {
+      if (key === 'textConfig') {
+        this.setTextConfig(value);
+      } else if (key === 'textContent') {
+        this.setTextContent(value);
+      } else if (key === 'clipPath') {
+        this.setClipPath(value);
+      } else if (key === 'extra') {
+        this.extra = this.extra || {};
+        extend(this.extra, value);
+      } else {
+        this[key] = value;
+      }
+    };
+
+    Element.prototype.hide = function () {
+      this.ignore = true;
+      this.markRedraw();
+    };
+
+    Element.prototype.show = function () {
+      this.ignore = false;
+      this.markRedraw();
+    };
+
+    Element.prototype.attr = function (keyOrObj, value) {
+      if (typeof keyOrObj === 'string') {
+        this.attrKV(keyOrObj, value);
+      } else if (isObject(keyOrObj)) {
+        var obj = keyOrObj;
+        var keysArr = keys(obj);
+
+        for (var i = 0; i < keysArr.length; i++) {
+          var key = keysArr[i];
+          this.attrKV(key, keyOrObj[key]);
+        }
+      }
+
+      this.markRedraw();
+      return this;
+    };
+
+    Element.prototype.saveCurrentToNormalState = function (toState) {
+      this._innerSaveToNormal(toState);
+
+      var normalState = this._normalState;
+
+      for (var i = 0; i < this.animators.length; i++) {
+        var animator = this.animators[i];
+        var fromStateTransition = animator.__fromStateTransition;
+
+        if (animator.getLoop() || fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) {
+          continue;
+        }
+
+        var targetName = animator.targetName;
+        var target = targetName ? normalState[targetName] : normalState;
+        animator.saveTo(target);
+      }
+    };
+
+    Element.prototype._innerSaveToNormal = function (toState) {
+      var normalState = this._normalState;
+
+      if (!normalState) {
+        normalState = this._normalState = {};
+      }
+
+      if (toState.textConfig && !normalState.textConfig) {
+        normalState.textConfig = this.textConfig;
+      }
+
+      this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS);
+    };
+
+    Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) {
+      for (var i = 0; i < primaryKeys.length; i++) {
+        var key = primaryKeys[i];
+
+        if (toState[key] != null && !(key in normalState)) {
+          normalState[key] = this[key];
+        }
+      }
+    };
+
+    Element.prototype.hasState = function () {
+      return this.currentStates.length > 0;
+    };
+
+    Element.prototype.getState = function (name) {
+      return this.states[name];
+    };
+
+    Element.prototype.ensureState = function (name) {
+      var states = this.states;
+
+      if (!states[name]) {
+        states[name] = {};
+      }
+
+      return states[name];
+    };
+
+    Element.prototype.clearStates = function (noAnimation) {
+      this.useState(PRESERVED_NORMAL_STATE, false, noAnimation);
+    };
+
+    Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation, forceUseHoverLayer) {
+      var toNormalState = stateName === PRESERVED_NORMAL_STATE;
+      var hasStates = this.hasState();
+
+      if (!hasStates && toNormalState) {
+        return;
+      }
+
+      var currentStates = this.currentStates;
+      var animationCfg = this.stateTransition;
+
+      if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) {
+        return;
+      }
+
+      var state;
+
+      if (this.stateProxy && !toNormalState) {
+        state = this.stateProxy(stateName);
+      }
+
+      if (!state) {
+        state = this.states && this.states[stateName];
+      }
+
+      if (!state && !toNormalState) {
+        logError("State " + stateName + " not exists.");
+        return;
+      }
+
+      if (!toNormalState) {
+        this.saveCurrentToNormalState(state);
+      }
+
+      var useHoverLayer = !!(state && state.hoverLayer || forceUseHoverLayer);
+
+      if (useHoverLayer) {
+        this._toggleHoverLayerFlag(true);
+      }
+
+      this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
+
+      var textContent = this._textContent;
+      var textGuide = this._textGuide;
+
+      if (textContent) {
+        textContent.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer);
+      }
+
+      if (textGuide) {
+        textGuide.useState(stateName, keepCurrentStates, noAnimation, useHoverLayer);
+      }
+
+      if (toNormalState) {
+        this.currentStates = [];
+        this._normalState = {};
+      } else {
+        if (!keepCurrentStates) {
+          this.currentStates = [stateName];
+        } else {
+          this.currentStates.push(stateName);
+        }
+      }
+
+      this._updateAnimationTargets();
+
+      this.markRedraw();
+
+      if (!useHoverLayer && this.__inHover) {
+        this._toggleHoverLayerFlag(false);
+
+        this.__dirty &= ~REDRAW_BIT;
+      }
+
+      return state;
+    };
+
+    Element.prototype.useStates = function (states, noAnimation, forceUseHoverLayer) {
+      if (!states.length) {
+        this.clearStates();
+      } else {
+        var stateObjects = [];
+        var currentStates = this.currentStates;
+        var len = states.length;
+        var notChange = len === currentStates.length;
+
+        if (notChange) {
+          for (var i = 0; i < len; i++) {
+            if (states[i] !== currentStates[i]) {
+              notChange = false;
+              break;
+            }
+          }
+        }
+
+        if (notChange) {
+          return;
+        }
+
+        for (var i = 0; i < len; i++) {
+          var stateName = states[i];
+          var stateObj = void 0;
+
+          if (this.stateProxy) {
+            stateObj = this.stateProxy(stateName, states);
+          }
+
+          if (!stateObj) {
+            stateObj = this.states[stateName];
+          }
+
+          if (stateObj) {
+            stateObjects.push(stateObj);
+          }
+        }
+
+        var lastStateObj = stateObjects[len - 1];
+        var useHoverLayer = !!(lastStateObj && lastStateObj.hoverLayer || forceUseHoverLayer);
+
+        if (useHoverLayer) {
+          this._toggleHoverLayerFlag(true);
+        }
+
+        var mergedState = this._mergeStates(stateObjects);
+
+        var animationCfg = this.stateTransition;
+        this.saveCurrentToNormalState(mergedState);
+
+        this._applyStateObj(states.join(','), mergedState, this._normalState, false, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
+
+        var textContent = this._textContent;
+        var textGuide = this._textGuide;
+
+        if (textContent) {
+          textContent.useStates(states, noAnimation, useHoverLayer);
+        }
+
+        if (textGuide) {
+          textGuide.useStates(states, noAnimation, useHoverLayer);
+        }
+
+        this._updateAnimationTargets();
+
+        this.currentStates = states.slice();
+        this.markRedraw();
+
+        if (!useHoverLayer && this.__inHover) {
+          this._toggleHoverLayerFlag(false);
+
+          this.__dirty &= ~REDRAW_BIT;
+        }
+      }
+    };
+
+    Element.prototype._updateAnimationTargets = function () {
+      for (var i = 0; i < this.animators.length; i++) {
+        var animator = this.animators[i];
+
+        if (animator.targetName) {
+          animator.changeTarget(this[animator.targetName]);
+        }
+      }
+    };
+
+    Element.prototype.removeState = function (state) {
+      var idx = indexOf(this.currentStates, state);
+
+      if (idx >= 0) {
+        var currentStates = this.currentStates.slice();
+        currentStates.splice(idx, 1);
+        this.useStates(currentStates);
+      }
+    };
+
+    Element.prototype.replaceState = function (oldState, newState, forceAdd) {
+      var currentStates = this.currentStates.slice();
+      var idx = indexOf(currentStates, oldState);
+      var newStateExists = indexOf(currentStates, newState) >= 0;
+
+      if (idx >= 0) {
+        if (!newStateExists) {
+          currentStates[idx] = newState;
+        } else {
+          currentStates.splice(idx, 1);
+        }
+      } else if (forceAdd && !newStateExists) {
+        currentStates.push(newState);
+      }
+
+      this.useStates(currentStates);
+    };
+
+    Element.prototype.toggleState = function (state, enable) {
+      if (enable) {
+        this.useState(state, true);
+      } else {
+        this.removeState(state);
+      }
+    };
+
+    Element.prototype._mergeStates = function (states) {
+      var mergedState = {};
+      var mergedTextConfig;
+
+      for (var i = 0; i < states.length; i++) {
+        var state = states[i];
+        extend(mergedState, state);
+
+        if (state.textConfig) {
+          mergedTextConfig = mergedTextConfig || {};
+          extend(mergedTextConfig, state.textConfig);
+        }
+      }
+
+      if (mergedTextConfig) {
+        mergedState.textConfig = mergedTextConfig;
+      }
+
+      return mergedState;
+    };
+
+    Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
+      var needsRestoreToNormal = !(state && keepCurrentStates);
+
+      if (state && state.textConfig) {
+        this.textConfig = extend({}, keepCurrentStates ? this.textConfig : normalState.textConfig);
+        extend(this.textConfig, state.textConfig);
+      } else if (needsRestoreToNormal) {
+        if (normalState.textConfig) {
+          this.textConfig = normalState.textConfig;
+        }
+      }
+
+      var transitionTarget = {};
+      var hasTransition = false;
+
+      for (var i = 0; i < PRIMARY_STATES_KEYS.length; i++) {
+        var key = PRIMARY_STATES_KEYS[i];
+        var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key];
+
+        if (state && state[key] != null) {
+          if (propNeedsTransition) {
+            hasTransition = true;
+            transitionTarget[key] = state[key];
+          } else {
+            this[key] = state[key];
+          }
+        } else if (needsRestoreToNormal) {
+          if (normalState[key] != null) {
+            if (propNeedsTransition) {
+              hasTransition = true;
+              transitionTarget[key] = normalState[key];
+            } else {
+              this[key] = normalState[key];
+            }
+          }
+        }
+      }
+
+      if (!transition) {
+        for (var i = 0; i < this.animators.length; i++) {
+          var animator = this.animators[i];
+          var targetName = animator.targetName;
+
+          if (!animator.getLoop()) {
+            animator.__changeFinalValue(targetName ? (state || normalState)[targetName] : state || normalState);
+          }
+        }
+      }
+
+      if (hasTransition) {
+        this._transitionState(stateName, transitionTarget, animationCfg);
+      }
+    };
+
+    Element.prototype._attachComponent = function (componentEl) {
+      if (componentEl.__zr && !componentEl.__hostTarget) {
+        {
+          throw new Error('Text element has been added to zrender.');
+        }
+        return;
+      }
+
+      if (componentEl === this) {
+        {
+          throw new Error('Recursive component attachment.');
+        }
+        return;
+      }
+
+      var zr = this.__zr;
+
+      if (zr) {
+        componentEl.addSelfToZr(zr);
+      }
+
+      componentEl.__zr = zr;
+      componentEl.__hostTarget = this;
+    };
+
+    Element.prototype._detachComponent = function (componentEl) {
+      if (componentEl.__zr) {
+        componentEl.removeSelfFromZr(componentEl.__zr);
+      }
+
+      componentEl.__zr = null;
+      componentEl.__hostTarget = null;
+    };
+
+    Element.prototype.getClipPath = function () {
+      return this._clipPath;
+    };
+
+    Element.prototype.setClipPath = function (clipPath) {
+      if (this._clipPath && this._clipPath !== clipPath) {
+        this.removeClipPath();
+      }
+
+      this._attachComponent(clipPath);
+
+      this._clipPath = clipPath;
+      this.markRedraw();
+    };
+
+    Element.prototype.removeClipPath = function () {
+      var clipPath = this._clipPath;
+
+      if (clipPath) {
+        this._detachComponent(clipPath);
+
+        this._clipPath = null;
+        this.markRedraw();
+      }
+    };
+
+    Element.prototype.getTextContent = function () {
+      return this._textContent;
+    };
+
+    Element.prototype.setTextContent = function (textEl) {
+      var previousTextContent = this._textContent;
+
+      if (previousTextContent === textEl) {
+        return;
+      }
+
+      if (previousTextContent && previousTextContent !== textEl) {
+        this.removeTextContent();
+      }
+
+      {
+        if (textEl.__zr && !textEl.__hostTarget) {
+          throw new Error('Text element has been added to zrender.');
+        }
+      }
+      textEl.innerTransformable = new Transformable();
+
+      this._attachComponent(textEl);
+
+      this._textContent = textEl;
+      this.markRedraw();
+    };
+
+    Element.prototype.setTextConfig = function (cfg) {
+      if (!this.textConfig) {
+        this.textConfig = {};
+      }
+
+      extend(this.textConfig, cfg);
+      this.markRedraw();
+    };
+
+    Element.prototype.removeTextConfig = function () {
+      this.textConfig = null;
+      this.markRedraw();
+    };
+
+    Element.prototype.removeTextContent = function () {
+      var textEl = this._textContent;
+
+      if (textEl) {
+        textEl.innerTransformable = null;
+
+        this._detachComponent(textEl);
+
+        this._textContent = null;
+        this._innerTextDefaultStyle = null;
+        this.markRedraw();
+      }
+    };
+
+    Element.prototype.getTextGuideLine = function () {
+      return this._textGuide;
+    };
+
+    Element.prototype.setTextGuideLine = function (guideLine) {
+      if (this._textGuide && this._textGuide !== guideLine) {
+        this.removeTextGuideLine();
+      }
+
+      this._attachComponent(guideLine);
+
+      this._textGuide = guideLine;
+      this.markRedraw();
+    };
+
+    Element.prototype.removeTextGuideLine = function () {
+      var textGuide = this._textGuide;
+
+      if (textGuide) {
+        this._detachComponent(textGuide);
+
+        this._textGuide = null;
+        this.markRedraw();
+      }
+    };
+
+    Element.prototype.markRedraw = function () {
+      this.__dirty |= REDRAW_BIT;
+      var zr = this.__zr;
+
+      if (zr) {
+        if (this.__inHover) {
+          zr.refreshHover();
+        } else {
+          zr.refresh();
+        }
+      }
+
+      if (this.__hostTarget) {
+        this.__hostTarget.markRedraw();
+      }
+    };
+
+    Element.prototype.dirty = function () {
+      this.markRedraw();
+    };
+
+    Element.prototype._toggleHoverLayerFlag = function (inHover) {
+      this.__inHover = inHover;
+      var textContent = this._textContent;
+      var textGuide = this._textGuide;
+
+      if (textContent) {
+        textContent.__inHover = inHover;
+      }
+
+      if (textGuide) {
+        textGuide.__inHover = inHover;
+      }
+    };
+
+    Element.prototype.addSelfToZr = function (zr) {
+      if (this.__zr === zr) {
+        return;
+      }
+
+      this.__zr = zr;
+      var animators = this.animators;
+
+      if (animators) {
+        for (var i = 0; i < animators.length; i++) {
+          zr.animation.addAnimator(animators[i]);
+        }
+      }
+
+      if (this._clipPath) {
+        this._clipPath.addSelfToZr(zr);
+      }
+
+      if (this._textContent) {
+        this._textContent.addSelfToZr(zr);
+      }
+
+      if (this._textGuide) {
+        this._textGuide.addSelfToZr(zr);
+      }
+    };
+
+    Element.prototype.removeSelfFromZr = function (zr) {
+      if (!this.__zr) {
+        return;
+      }
+
+      this.__zr = null;
+      var animators = this.animators;
+
+      if (animators) {
+        for (var i = 0; i < animators.length; i++) {
+          zr.animation.removeAnimator(animators[i]);
+        }
+      }
+
+      if (this._clipPath) {
+        this._clipPath.removeSelfFromZr(zr);
+      }
+
+      if (this._textContent) {
+        this._textContent.removeSelfFromZr(zr);
+      }
+
+      if (this._textGuide) {
+        this._textGuide.removeSelfFromZr(zr);
+      }
+    };
+
+    Element.prototype.animate = function (key, loop, allowDiscreteAnimation) {
+      var target = key ? this[key] : this;
+      {
+        if (!target) {
+          logError('Property "' + key + '" is not existed in element ' + this.id);
+          return;
+        }
+      }
+      var animator = new Animator(target, loop, allowDiscreteAnimation);
+      key && (animator.targetName = key);
+      this.addAnimator(animator, key);
+      return animator;
+    };
+
+    Element.prototype.addAnimator = function (animator, key) {
+      var zr = this.__zr;
+      var el = this;
+      animator.during(function () {
+        el.updateDuringAnimation(key);
+      }).done(function () {
+        var animators = el.animators;
+        var idx = indexOf(animators, animator);
+
+        if (idx >= 0) {
+          animators.splice(idx, 1);
+        }
+      });
+      this.animators.push(animator);
+
+      if (zr) {
+        zr.animation.addAnimator(animator);
+      }
+
+      zr && zr.wakeUp();
+    };
+
+    Element.prototype.updateDuringAnimation = function (key) {
+      this.markRedraw();
+    };
+
+    Element.prototype.stopAnimation = function (scope, forwardToLast) {
+      var animators = this.animators;
+      var len = animators.length;
+      var leftAnimators = [];
+
+      for (var i = 0; i < len; i++) {
+        var animator = animators[i];
+
+        if (!scope || scope === animator.scope) {
+          animator.stop(forwardToLast);
+        } else {
+          leftAnimators.push(animator);
+        }
+      }
+
+      this.animators = leftAnimators;
+      return this;
+    };
+
+    Element.prototype.animateTo = function (target, cfg, animationProps) {
+      animateTo(this, target, cfg, animationProps);
+    };
+
+    Element.prototype.animateFrom = function (target, cfg, animationProps) {
+      animateTo(this, target, cfg, animationProps, true);
+    };
+
+    Element.prototype._transitionState = function (stateName, target, cfg, animationProps) {
+      var animators = animateTo(this, target, cfg, animationProps);
+
+      for (var i = 0; i < animators.length; i++) {
+        animators[i].__fromStateTransition = stateName;
+      }
+    };
+
+    Element.prototype.getBoundingRect = function () {
+      return null;
+    };
+
+    Element.prototype.getPaintRect = function () {
+      return null;
+    };
+
+    Element.initDefaultProps = function () {
+      var elProto = Element.prototype;
+      elProto.type = 'element';
+      elProto.name = '';
+      elProto.ignore = elProto.silent = elProto.isGroup = elProto.draggable = elProto.dragging = elProto.ignoreClip = elProto.__inHover = false;
+      elProto.__dirty = REDRAW_BIT;
+      var logs = {};
+
+      function logDeprecatedError(key, xKey, yKey) {
+        if (!logs[key + xKey + yKey]) {
+          console.warn("DEPRECATED: '" + key + "' has been deprecated. use '" + xKey + "', '" + yKey + "' instead");
+          logs[key + xKey + yKey] = true;
+        }
+      }
+
+      function createLegacyProperty(key, privateKey, xKey, yKey) {
+        Object.defineProperty(elProto, key, {
+          get: function () {
+            {
+              logDeprecatedError(key, xKey, yKey);
+            }
+
+            if (!this[privateKey]) {
+              var pos = this[privateKey] = [];
+              enhanceArray(this, pos);
+            }
+
+            return this[privateKey];
+          },
+          set: function (pos) {
+            {
+              logDeprecatedError(key, xKey, yKey);
+            }
+            this[xKey] = pos[0];
+            this[yKey] = pos[1];
+            this[privateKey] = pos;
+            enhanceArray(this, pos);
+          }
+        });
+
+        function enhanceArray(self, pos) {
+          Object.defineProperty(pos, 0, {
+            get: function () {
+              return self[xKey];
+            },
+            set: function (val) {
+              self[xKey] = val;
+            }
+          });
+          Object.defineProperty(pos, 1, {
+            get: function () {
+              return self[yKey];
+            },
+            set: function (val) {
+              self[yKey] = val;
+            }
+          });
+        }
+      }
+
+      if (Object.defineProperty) {
+        createLegacyProperty('position', '_legacyPos', 'x', 'y');
+        createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY');
+        createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY');
+      }
+    }();
+
+    return Element;
+  }();
+
+  mixin(Element, Eventful);
+  mixin(Element, Transformable);
+
+  function animateTo(animatable, target, cfg, animationProps, reverse) {
+    cfg = cfg || {};
+    var animators = [];
+    animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse);
+    var finishCount = animators.length;
+    var doneHappened = false;
+    var cfgDone = cfg.done;
+    var cfgAborted = cfg.aborted;
+
+    var doneCb = function () {
+      doneHappened = true;
+      finishCount--;
+
+      if (finishCount <= 0) {
+        doneHappened ? cfgDone && cfgDone() : cfgAborted && cfgAborted();
+      }
+    };
+
+    var abortedCb = function () {
+      finishCount--;
+
+      if (finishCount <= 0) {
+        doneHappened ? cfgDone && cfgDone() : cfgAborted && cfgAborted();
+      }
+    };
+
+    if (!finishCount) {
+      cfgDone && cfgDone();
+    }
+
+    if (animators.length > 0 && cfg.during) {
+      animators[0].during(function (target, percent) {
+        cfg.during(percent);
+      });
+    }
+
+    for (var i = 0; i < animators.length; i++) {
+      var animator = animators[i];
+
+      if (doneCb) {
+        animator.done(doneCb);
+      }
+
+      if (abortedCb) {
+        animator.aborted(abortedCb);
+      }
+
+      if (cfg.force) {
+        animator.duration(cfg.duration);
+      }
+
+      animator.start(cfg.easing);
+    }
+
+    return animators;
+  }
+
+  function copyArrShallow(source, target, len) {
+    for (var i = 0; i < len; i++) {
+      source[i] = target[i];
+    }
+  }
+
+  function is2DArray(value) {
+    return isArrayLike(value[0]);
+  }
+
+  function copyValue(target, source, key) {
+    if (isArrayLike(source[key])) {
+      if (!isArrayLike(target[key])) {
+        target[key] = [];
+      }
+
+      if (isTypedArray(source[key])) {
+        var len = source[key].length;
+
+        if (target[key].length !== len) {
+          target[key] = new source[key].constructor(len);
+          copyArrShallow(target[key], source[key], len);
+        }
+      } else {
+        var sourceArr = source[key];
+        var targetArr = target[key];
+        var len0 = sourceArr.length;
+
+        if (is2DArray(sourceArr)) {
+          var len1 = sourceArr[0].length;
+
+          for (var i = 0; i < len0; i++) {
+            if (!targetArr[i]) {
+              targetArr[i] = Array.prototype.slice.call(sourceArr[i]);
+            } else {
+              copyArrShallow(targetArr[i], sourceArr[i], len1);
+            }
+          }
+        } else {
+          copyArrShallow(targetArr, sourceArr, len0);
+        }
+
+        targetArr.length = sourceArr.length;
+      }
+    } else {
+      target[key] = source[key];
+    }
+  }
+
+  function isValueSame(val1, val2) {
+    return val1 === val2 || isArrayLike(val1) && isArrayLike(val2) && is1DArraySame(val1, val2);
+  }
+
+  function is1DArraySame(arr0, arr1) {
+    var len = arr0.length;
+
+    if (len !== arr1.length) {
+      return false;
+    }
+
+    for (var i = 0; i < len; i++) {
+      if (arr0[i] !== arr1[i]) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  function animateToShallow(animatable, topKey, animateObj, target, cfg, animationProps, animators, reverse) {
+    var targetKeys = keys(target);
+    var duration = cfg.duration;
+    var delay = cfg.delay;
+    var additive = cfg.additive;
+    var setToFinal = cfg.setToFinal;
+    var animateAll = !isObject(animationProps);
+    var existsAnimators = animatable.animators;
+    var animationKeys = [];
+
+    for (var k = 0; k < targetKeys.length; k++) {
+      var innerKey = targetKeys[k];
+      var targetVal = target[innerKey];
+
+      if (targetVal != null && animateObj[innerKey] != null && (animateAll || animationProps[innerKey])) {
+        if (isObject(targetVal) && !isArrayLike(targetVal) && !isGradientObject(targetVal)) {
+          if (topKey) {
+            if (!reverse) {
+              animateObj[innerKey] = targetVal;
+              animatable.updateDuringAnimation(topKey);
+            }
+
+            continue;
+          }
+
+          animateToShallow(animatable, innerKey, animateObj[innerKey], targetVal, cfg, animationProps && animationProps[innerKey], animators, reverse);
+        } else {
+          animationKeys.push(innerKey);
+        }
+      } else if (!reverse) {
+        animateObj[innerKey] = targetVal;
+        animatable.updateDuringAnimation(topKey);
+        animationKeys.push(innerKey);
+      }
+    }
+
+    var keyLen = animationKeys.length;
+
+    if (!additive && keyLen) {
+      for (var i = 0; i < existsAnimators.length; i++) {
+        var animator = existsAnimators[i];
+
+        if (animator.targetName === topKey) {
+          var allAborted = animator.stopTracks(animationKeys);
+
+          if (allAborted) {
+            var idx = indexOf(existsAnimators, animator);
+            existsAnimators.splice(idx, 1);
+          }
+        }
+      }
+    }
+
+    if (!cfg.force) {
+      animationKeys = filter(animationKeys, function (key) {
+        return !isValueSame(target[key], animateObj[key]);
+      });
+      keyLen = animationKeys.length;
+    }
+
+    if (keyLen > 0 || cfg.force && !animators.length) {
+      var revertedSource = void 0;
+      var reversedTarget = void 0;
+      var sourceClone = void 0;
+
+      if (reverse) {
+        reversedTarget = {};
+
+        if (setToFinal) {
+          revertedSource = {};
+        }
+
+        for (var i = 0; i < keyLen; i++) {
+          var innerKey = animationKeys[i];
+          reversedTarget[innerKey] = animateObj[innerKey];
+
+          if (setToFinal) {
+            revertedSource[innerKey] = target[innerKey];
+          } else {
+            animateObj[innerKey] = target[innerKey];
+          }
+        }
+      } else if (setToFinal) {
+        sourceClone = {};
+
+        for (var i = 0; i < keyLen; i++) {
+          var innerKey = animationKeys[i];
+          sourceClone[innerKey] = cloneValue(animateObj[innerKey]);
+          copyValue(animateObj, target, innerKey);
+        }
+      }
+
+      var animator = new Animator(animateObj, false, false, additive ? filter(existsAnimators, function (animator) {
+        return animator.targetName === topKey;
+      }) : null);
+      animator.targetName = topKey;
+
+      if (cfg.scope) {
+        animator.scope = cfg.scope;
+      }
+
+      if (setToFinal && revertedSource) {
+        animator.whenWithKeys(0, revertedSource, animationKeys);
+      }
+
+      if (sourceClone) {
+        animator.whenWithKeys(0, sourceClone, animationKeys);
+      }
+
+      animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animationKeys).delay(delay || 0);
+      animatable.addAnimator(animator, topKey);
+      animators.push(animator);
+    }
+  }
+
+  var Group = function (_super) {
+    __extends(Group, _super);
+
+    function Group(opts) {
+      var _this = _super.call(this) || this;
+
+      _this.isGroup = true;
+      _this._children = [];
+
+      _this.attr(opts);
+
+      return _this;
+    }
+
+    Group.prototype.childrenRef = function () {
+      return this._children;
+    };
+
+    Group.prototype.children = function () {
+      return this._children.slice();
+    };
+
+    Group.prototype.childAt = function (idx) {
+      return this._children[idx];
+    };
+
+    Group.prototype.childOfName = function (name) {
+      var children = this._children;
+
+      for (var i = 0; i < children.length; i++) {
+        if (children[i].name === name) {
+          return children[i];
+        }
+      }
+    };
+
+    Group.prototype.childCount = function () {
+      return this._children.length;
+    };
+
+    Group.prototype.add = function (child) {
+      if (child) {
+        if (child !== this && child.parent !== this) {
+          this._children.push(child);
+
+          this._doAdd(child);
+        }
+
+        {
+          if (child.__hostTarget) {
+            throw 'This elemenet has been used as an attachment';
+          }
+        }
+      }
+
+      return this;
+    };
+
+    Group.prototype.addBefore = function (child, nextSibling) {
+      if (child && child !== this && child.parent !== this && nextSibling && nextSibling.parent === this) {
+        var children = this._children;
+        var idx = children.indexOf(nextSibling);
+
+        if (idx >= 0) {
+          children.splice(idx, 0, child);
+
+          this._doAdd(child);
+        }
+      }
+
+      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];
+
+      if (child && child !== this && child.parent !== this && child !== old) {
+        children[index] = child;
+        old.parent = null;
+        var zr = this.__zr;
+
+        if (zr) {
+          old.removeSelfFromZr(zr);
+        }
+
+        this._doAdd(child);
+      }
+
+      return this;
+    };
+
+    Group.prototype._doAdd = function (child) {
+      if (child.parent) {
+        child.parent.remove(child);
+      }
+
+      child.parent = this;
+      var zr = this.__zr;
+
+      if (zr && zr !== child.__zr) {
+        child.addSelfToZr(zr);
+      }
+
+      zr && zr.refresh();
+    };
+
+    Group.prototype.remove = function (child) {
+      var zr = this.__zr;
+      var children = this._children;
+      var idx = indexOf(children, child);
+
+      if (idx < 0) {
+        return this;
+      }
+
+      children.splice(idx, 1);
+      child.parent = null;
+
+      if (zr) {
+        child.removeSelfFromZr(zr);
+      }
+
+      zr && zr.refresh();
+      return this;
+    };
+
+    Group.prototype.removeAll = function () {
+      var children = this._children;
+      var zr = this.__zr;
+
+      for (var i = 0; i < children.length; i++) {
+        var child = children[i];
+
+        if (zr) {
+          child.removeSelfFromZr(zr);
+        }
+
+        child.parent = null;
+      }
+
+      children.length = 0;
+      return this;
+    };
+
+    Group.prototype.eachChild = function (cb, context) {
+      var children = this._children;
+
+      for (var i = 0; i < children.length; i++) {
+        var child = children[i];
+        cb.call(context, child, i);
+      }
+
+      return this;
+    };
+
+    Group.prototype.traverse = function (cb, context) {
+      for (var i = 0; i < this._children.length; i++) {
+        var child = this._children[i];
+        var stopped = cb.call(context, child);
+
+        if (child.isGroup && !stopped) {
+          child.traverse(cb, context);
+        }
+      }
+
+      return this;
+    };
+
+    Group.prototype.addSelfToZr = function (zr) {
+      _super.prototype.addSelfToZr.call(this, zr);
+
+      for (var i = 0; i < this._children.length; i++) {
+        var child = this._children[i];
+        child.addSelfToZr(zr);
+      }
+    };
+
+    Group.prototype.removeSelfFromZr = function (zr) {
+      _super.prototype.removeSelfFromZr.call(this, zr);
+
+      for (var i = 0; i < this._children.length; i++) {
+        var child = this._children[i];
+        child.removeSelfFromZr(zr);
+      }
+    };
+
+    Group.prototype.getBoundingRect = function (includeChildren) {
+      var tmpRect = new BoundingRect(0, 0, 0, 0);
+      var children = includeChildren || this._children;
+      var tmpMat = [];
+      var rect = null;
+
+      for (var i = 0; i < children.length; i++) {
+        var child = children[i];
+
+        if (child.ignore || child.invisible) {
+          continue;
+        }
+
+        var childRect = child.getBoundingRect();
+        var transform = child.getLocalTransform(tmpMat);
+
+        if (transform) {
+          BoundingRect.applyTransform(tmpRect, childRect, transform);
+          rect = rect || tmpRect.clone();
+          rect.union(tmpRect);
+        } else {
+          rect = rect || childRect.clone();
+          rect.union(childRect);
+        }
+      }
+
+      return rect || tmpRect;
+    };
+
+    return Group;
+  }(Element);
+
+  Group.prototype.type = 'group';
+  /*!
+  * ZRender, a high performance 2d drawing library.
+  *
+  * Copyright (c) 2013, Baidu Inc.
+  * All rights reserved.
+  *
+  * LICENSE
+  * https://github.com/ecomfe/zrender/blob/master/LICENSE.txt
+  */
+
+  var painterCtors = {};
+  var instances$1 = {};
+
+  function delInstance(id) {
+    delete instances$1[id];
+  }
+
+  function isDarkMode(backgroundColor) {
+    if (!backgroundColor) {
+      return false;
+    }
+
+    if (typeof backgroundColor === 'string') {
+      return lum(backgroundColor, 1) < DARK_MODE_THRESHOLD;
+    } else if (backgroundColor.colorStops) {
+      var colorStops = backgroundColor.colorStops;
+      var totalLum = 0;
+      var len = colorStops.length;
+
+      for (var i = 0; i < len; i++) {
+        totalLum += lum(colorStops[i].color, 1);
+      }
+
+      totalLum /= len;
+      return totalLum < DARK_MODE_THRESHOLD;
+    }
+
+    return false;
+  }
+
+  var ZRender = function () {
+    function ZRender(id, dom, opts) {
+      var _this = this;
+
+      this._sleepAfterStill = 10;
+      this._stillFrameAccum = 0;
+      this._needsRefresh = true;
+      this._needsRefreshHover = true;
+      this._darkMode = false;
+      opts = opts || {};
+      this.dom = dom;
+      this.id = id;
+      var storage = new Storage();
+      var rendererType = opts.renderer || 'canvas';
+
+      if (!painterCtors[rendererType]) {
+        rendererType = keys(painterCtors)[0];
+      }
+
+      {
+        if (!painterCtors[rendererType]) {
+          throw new Error("Renderer '" + rendererType + "' is not imported. Please import it first.");
+        }
+      }
+      opts.useDirtyRect = opts.useDirtyRect == null ? false : opts.useDirtyRect;
+      var painter = new painterCtors[rendererType](dom, storage, opts, id);
+      var ssrMode = opts.ssr || painter.ssrOnly;
+      this.storage = storage;
+      this.painter = painter;
+      var handerProxy = !env.node && !env.worker && !ssrMode ? new HandlerDomProxy(painter.getViewportRoot(), painter.root) : null;
+      this.handler = new Handler(storage, painter, handerProxy, painter.root);
+      this.animation = new Animation({
+        stage: {
+          update: ssrMode ? null : function () {
+            return _this._flush(true);
+          }
+        }
+      });
+
+      if (!ssrMode) {
+        this.animation.start();
+      }
+    }
+
+    ZRender.prototype.add = function (el) {
+      if (!el) {
+        return;
+      }
+
+      this.storage.addRoot(el);
+      el.addSelfToZr(this);
+      this.refresh();
+    };
+
+    ZRender.prototype.remove = function (el) {
+      if (!el) {
+        return;
+      }
+
+      this.storage.delRoot(el);
+      el.removeSelfFromZr(this);
+      this.refresh();
+    };
+
+    ZRender.prototype.configLayer = function (zLevel, config) {
+      if (this.painter.configLayer) {
+        this.painter.configLayer(zLevel, config);
+      }
+
+      this.refresh();
+    };
+
+    ZRender.prototype.setBackgroundColor = function (backgroundColor) {
+      if (this.painter.setBackgroundColor) {
+        this.painter.setBackgroundColor(backgroundColor);
+      }
+
+      this.refresh();
+      this._backgroundColor = backgroundColor;
+      this._darkMode = isDarkMode(backgroundColor);
+    };
+
+    ZRender.prototype.getBackgroundColor = function () {
+      return this._backgroundColor;
+    };
+
+    ZRender.prototype.setDarkMode = function (darkMode) {
+      this._darkMode = darkMode;
+    };
+
+    ZRender.prototype.isDarkMode = function () {
+      return this._darkMode;
+    };
+
+    ZRender.prototype.refreshImmediately = function (fromInside) {
+      if (!fromInside) {
+        this.animation.update(true);
+      }
+
+      this._needsRefresh = false;
+      this.painter.refresh();
+      this._needsRefresh = false;
+    };
+
+    ZRender.prototype.refresh = function () {
+      this._needsRefresh = true;
+      this.animation.start();
+    };
+
+    ZRender.prototype.flush = function () {
+      this._flush(false);
+    };
+
+    ZRender.prototype._flush = function (fromInside) {
+      var triggerRendered;
+      var start = getTime();
+
+      if (this._needsRefresh) {
+        triggerRendered = true;
+        this.refreshImmediately(fromInside);
+      }
+
+      if (this._needsRefreshHover) {
+        triggerRendered = true;
+        this.refreshHoverImmediately();
+      }
+
+      var end = getTime();
+
+      if (triggerRendered) {
+        this._stillFrameAccum = 0;
+        this.trigger('rendered', {
+          elapsedTime: end - start
+        });
+      } else if (this._sleepAfterStill > 0) {
+        this._stillFrameAccum++;
+
+        if (this._stillFrameAccum > this._sleepAfterStill) {
+          this.animation.stop();
+        }
+      }
+    };
+
+    ZRender.prototype.setSleepAfterStill = function (stillFramesCount) {
+      this._sleepAfterStill = stillFramesCount;
+    };
+
+    ZRender.prototype.wakeUp = function () {
+      this.animation.start();
+      this._stillFrameAccum = 0;
+    };
+
+    ZRender.prototype.refreshHover = function () {
+      this._needsRefreshHover = true;
+    };
+
+    ZRender.prototype.refreshHoverImmediately = function () {
+      this._needsRefreshHover = false;
+
+      if (this.painter.refreshHover && this.painter.getType() === 'canvas') {
+        this.painter.refreshHover();
+      }
+    };
+
+    ZRender.prototype.resize = function (opts) {
+      opts = opts || {};
+      this.painter.resize(opts.width, opts.height);
+      this.handler.resize();
+    };
+
+    ZRender.prototype.clearAnimation = function () {
+      this.animation.clear();
+    };
+
+    ZRender.prototype.getWidth = function () {
+      return this.painter.getWidth();
+    };
+
+    ZRender.prototype.getHeight = function () {
+      return this.painter.getHeight();
+    };
+
+    ZRender.prototype.setCursorStyle = function (cursorStyle) {
+      this.handler.setCursorStyle(cursorStyle);
+    };
+
+    ZRender.prototype.findHover = function (x, y) {
+      return this.handler.findHover(x, y);
+    };
+
+    ZRender.prototype.on = function (eventName, eventHandler, context) {
+      this.handler.on(eventName, eventHandler, context);
+      return this;
+    };
+
+    ZRender.prototype.off = function (eventName, eventHandler) {
+      this.handler.off(eventName, eventHandler);
+    };
+
+    ZRender.prototype.trigger = function (eventName, event) {
+      this.handler.trigger(eventName, event);
+    };
+
+    ZRender.prototype.clear = function () {
+      var roots = this.storage.getRoots();
+
+      for (var i = 0; i < roots.length; i++) {
+        if (roots[i] instanceof Group) {
+          roots[i].removeSelfFromZr(this);
+        }
+      }
+
+      this.storage.delAllRoots();
+      this.painter.clear();
+    };
+
+    ZRender.prototype.dispose = function () {
+      this.animation.stop();
+      this.clear();
+      this.storage.dispose();
+      this.painter.dispose();
+      this.handler.dispose();
+      this.animation = this.storage = this.painter = this.handler = null;
+      delInstance(this.id);
+    };
+
+    return ZRender;
+  }();
+
+  function init$1(dom, opts) {
+    var zr = new ZRender(guid(), dom, opts);
+    instances$1[zr.id] = zr;
+    return zr;
+  }
+
+  function dispose$1(zr) {
+    zr.dispose();
+  }
+
+  function disposeAll() {
+    for (var key in instances$1) {
+      if (instances$1.hasOwnProperty(key)) {
+        instances$1[key].dispose();
+      }
+    }
+
+    instances$1 = {};
+  }
+
+  function getInstance(id) {
+    return instances$1[id];
+  }
+
+  function registerPainter(name, Ctor) {
+    painterCtors[name] = Ctor;
+  }
+
+  var version$1 = '5.3.2';
+  var zrender = (Object.freeze || Object)({
+    init: init$1,
+    dispose: dispose$1,
+    disposeAll: disposeAll,
+    getInstance: getInstance,
+    registerPainter: registerPainter,
+    version: version$1
+  });
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /*
+  * A third-party license is embeded for some of the code in this file:
+  * The method "quantile" was copied from "d3.js".
+  * (See more details in the comment of the method below.)
+  * The use of the source code of this file is also subject to the terms
+  * and consitions of the license of "d3.js" (BSD-3Clause, see
+  * </licenses/LICENSE-d3>).
+  */
+
+  var RADIAN_EPSILON = 1e-4; // Although chrome already enlarge this number to 100 for `toFixed`, but
+  // we sill follow the spec for compatibility.
+
+  var ROUND_SUPPORTED_PRECISION_MAX = 20;
+
+  function _trim(str) {
+    return str.replace(/^\s+|\s+$/g, '');
+  }
+  /**
+   * Linear mapping a value from domain to range
+   * @param  val
+   * @param  domain Domain extent domain[0] can be bigger than domain[1]
+   * @param  range  Range extent range[0] can be bigger than range[1]
+   * @param  clamp Default to be false
+   */
+
+
+  function linearMap(val, domain, range, clamp) {
+    var d0 = domain[0];
+    var d1 = domain[1];
+    var r0 = range[0];
+    var r1 = range[1];
+    var subDomain = d1 - d0;
+    var subRange = r1 - r0;
+
+    if (subDomain === 0) {
+      return subRange === 0 ? r0 : (r0 + r1) / 2;
+    } // Avoid accuracy problem in edge, such as
+    // 146.39 - 62.83 === 83.55999999999999.
+    // See echarts/test/ut/spec/util/number.js#linearMap#accuracyError
+    // It is a little verbose for efficiency considering this method
+    // is a hotspot.
+
+
+    if (clamp) {
+      if (subDomain > 0) {
+        if (val <= d0) {
+          return r0;
+        } else if (val >= d1) {
+          return r1;
+        }
+      } else {
+        if (val >= d0) {
+          return r0;
+        } else if (val <= d1) {
+          return r1;
+        }
+      }
+    } else {
+      if (val === d0) {
+        return r0;
+      }
+
+      if (val === d1) {
+        return r1;
+      }
+    }
+
+    return (val - d0) / subDomain * subRange + r0;
+  }
+  /**
+   * Convert a percent string to absolute number.
+   * Returns NaN if percent is not a valid string or number
+   */
+
+
+  function parsePercent$1(percent, all) {
+    switch (percent) {
+      case 'center':
+      case 'middle':
+        percent = '50%';
+        break;
+
+      case 'left':
+      case 'top':
+        percent = '0%';
+        break;
+
+      case 'right':
+      case 'bottom':
+        percent = '100%';
+        break;
+    }
+
+    if (isString(percent)) {
+      if (_trim(percent).match(/%$/)) {
+        return parseFloat(percent) / 100 * all;
+      }
+
+      return parseFloat(percent);
+    }
+
+    return percent == null ? NaN : +percent;
+  }
+
+  function round(x, precision, returnStr) {
+    if (precision == null) {
+      precision = 10;
+    } // Avoid range error
+
+
+    precision = Math.min(Math.max(0, precision), ROUND_SUPPORTED_PRECISION_MAX); // PENDING: 1.005.toFixed(2) is '1.00' rather than '1.01'
+
+    x = (+x).toFixed(precision);
+    return returnStr ? x : +x;
+  }
+  /**
+   * Inplacd asc sort arr.
+   * The input arr will be modified.
+   */
+
+
+  function asc(arr) {
+    arr.sort(function (a, b) {
+      return a - b;
+    });
+    return arr;
+  }
+  /**
+   * Get precision.
+   */
+
+
+  function getPrecision(val) {
+    val = +val;
+
+    if (isNaN(val)) {
+      return 0;
+    } // It is much faster than methods converting number to string as follows
+    //      let tmp = val.toString();
+    //      return tmp.length - 1 - tmp.indexOf('.');
+    // especially when precision is low
+    // Notice:
+    // (1) If the loop count is over about 20, it is slower than `getPrecisionSafe`.
+    //     (see https://jsbench.me/2vkpcekkvw/1)
+    // (2) If the val is less than for example 1e-15, the result may be incorrect.
+    //     (see test/ut/spec/util/number.test.ts `getPrecision_equal_random`)
+
+
+    if (val > 1e-14) {
+      var e = 1;
+
+      for (var i = 0; i < 15; i++, e *= 10) {
+        if (Math.round(val * e) / e === val) {
+          return i;
+        }
+      }
+    }
+
+    return getPrecisionSafe(val);
+  }
+  /**
+   * Get precision with slow but safe method
+   */
+
+
+  function getPrecisionSafe(val) {
+    // toLowerCase for: '3.4E-12'
+    var str = val.toString().toLowerCase(); // Consider scientific notation: '3.4e-12' '3.4e+12'
+
+    var eIndex = str.indexOf('e');
+    var exp = eIndex > 0 ? +str.slice(eIndex + 1) : 0;
+    var significandPartLen = eIndex > 0 ? eIndex : str.length;
+    var dotIndex = str.indexOf('.');
+    var decimalPartLen = dotIndex < 0 ? 0 : significandPartLen - 1 - dotIndex;
+    return Math.max(0, decimalPartLen - exp);
+  }
+  /**
+   * Minimal dicernible data precisioin according to a single pixel.
+   */
+
+
+  function getPixelPrecision(dataExtent, pixelExtent) {
+    var log = Math.log;
+    var LN10 = Math.LN10;
+    var dataQuantity = Math.floor(log(dataExtent[1] - dataExtent[0]) / LN10);
+    var sizeQuantity = Math.round(log(Math.abs(pixelExtent[1] - pixelExtent[0])) / LN10); // toFixed() digits argument must be between 0 and 20.
+
+    var precision = Math.min(Math.max(-dataQuantity + sizeQuantity, 0), 20);
+    return !isFinite(precision) ? 20 : precision;
+  }
+  /**
+   * Get a data of given precision, assuring the sum of percentages
+   * in valueList is 1.
+   * The largest remainer method is used.
+   * https://en.wikipedia.org/wiki/Largest_remainder_method
+   *
+   * @param valueList a list of all data
+   * @param idx index of the data to be processed in valueList
+   * @param precision integer number showing digits of precision
+   * @return percent ranging from 0 to 100
+   */
+
+
+  function getPercentWithPrecision(valueList, idx, precision) {
+    if (!valueList[idx]) {
+      return 0;
+    }
+
+    var sum = reduce(valueList, function (acc, val) {
+      return acc + (isNaN(val) ? 0 : val);
+    }, 0);
+
+    if (sum === 0) {
+      return 0;
+    }
+
+    var digits = Math.pow(10, precision);
+    var votesPerQuota = map(valueList, function (val) {
+      return (isNaN(val) ? 0 : val) / sum * digits * 100;
+    });
+    var targetSeats = digits * 100;
+    var seats = map(votesPerQuota, function (votes) {
+      // Assign automatic seats.
+      return Math.floor(votes);
+    });
+    var currentSum = reduce(seats, function (acc, val) {
+      return acc + val;
+    }, 0);
+    var remainder = map(votesPerQuota, function (votes, idx) {
+      return votes - seats[idx];
+    }); // Has remainding votes.
+
+    while (currentSum < targetSeats) {
+      // Find next largest remainder.
+      var max = Number.NEGATIVE_INFINITY;
+      var maxId = null;
+
+      for (var i = 0, len = remainder.length; i < len; ++i) {
+        if (remainder[i] > max) {
+          max = remainder[i];
+          maxId = i;
+        }
+      } // Add a vote to max remainder.
+
+
+      ++seats[maxId];
+      remainder[maxId] = 0;
+      ++currentSum;
+    }
+
+    return seats[idx] / digits;
+  }
+  /**
+   * Solve the floating point adding problem like 0.1 + 0.2 === 0.30000000000000004
+   * See <http://0.30000000000000004.com/>
+   */
+
+
+  function addSafe(val0, val1) {
+    var maxPrecision = Math.max(getPrecision(val0), getPrecision(val1)); // const multiplier = Math.pow(10, maxPrecision);
+    // return (Math.round(val0 * multiplier) + Math.round(val1 * multiplier)) / multiplier;
+
+    var sum = val0 + val1; // // PENDING: support more?
+
+    return maxPrecision > ROUND_SUPPORTED_PRECISION_MAX ? sum : round(sum, maxPrecision);
+  } // Number.MAX_SAFE_INTEGER, ie do not support.
+
+
+  var MAX_SAFE_INTEGER = 9007199254740991;
+  /**
+   * To 0 - 2 * PI, considering negative radian.
+   */
+
+  function remRadian(radian) {
+    var pi2 = Math.PI * 2;
+    return (radian % pi2 + pi2) % pi2;
+  }
+  /**
+   * @param {type} radian
+   * @return {boolean}
+   */
+
+
+  function isRadianAroundZero(val) {
+    return val > -RADIAN_EPSILON && val < RADIAN_EPSILON;
+  } // eslint-disable-next-line
+
+
+  var TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // jshint ignore:line
+
+  /**
+   * @param value valid type: number | string | Date, otherwise return `new Date(NaN)`
+   *   These values can be accepted:
+   *   + An instance of Date, represent a time in its own time zone.
+   *   + Or string in a subset of ISO 8601, only including:
+   *     + only year, month, date: '2012-03', '2012-03-01', '2012-03-01 05', '2012-03-01 05:06',
+   *     + separated with T or space: '2012-03-01T12:22:33.123', '2012-03-01 12:22:33.123',
+   *     + time zone: '2012-03-01T12:22:33Z', '2012-03-01T12:22:33+8000', '2012-03-01T12:22:33-05:00',
+   *     all of which will be treated as local time if time zone is not specified
+   *     (see <https://momentjs.com/>).
+   *   + Or other string format, including (all of which will be treated as loacal time):
+   *     '2012', '2012-3-1', '2012/3/1', '2012/03/01',
+   *     '2009/6/12 2:00', '2009/6/12 2:05:08', '2009/6/12 2:05:08.123'
+   *   + a timestamp, which represent a time in UTC.
+   * @return date Never be null/undefined. If invalid, return `new Date(NaN)`.
+   */
+
+  function parseDate(value) {
+    if (value instanceof Date) {
+      return value;
+    } else if (isString(value)) {
+      // Different browsers parse date in different way, so we parse it manually.
+      // Some other issues:
+      // new Date('1970-01-01') is UTC,
+      // new Date('1970/01/01') and new Date('1970-1-01') is local.
+      // See issue #3623
+      var match = TIME_REG.exec(value);
+
+      if (!match) {
+        // return Invalid Date.
+        return new Date(NaN);
+      } // Use local time when no timezone offset specifed.
+
+
+      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] ? +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",
+      // then these code will get different result:
+      // `new Date(1478411999999).getTimezoneOffset();  // get 240`
+      // `new Date(1478412000000).getTimezoneOffset();  // get 300`
+      // So we should not use `new Date`, but use `Date.UTC`.
+      else {
+          var hour = +match[4] || 0;
+
+          if (match[8].toUpperCase() !== 'Z') {
+            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] ? +match[7].substring(0, 3) : 0));
+        }
+    } else if (value == null) {
+      return new Date(NaN);
+    }
+
+    return new Date(Math.round(value));
+  }
+  /**
+   * Quantity of a number. e.g. 0.1, 1, 10, 100
+   *
+   * @param val
+   * @return
+   */
+
+
+  function quantity(val) {
+    return Math.pow(10, quantityExponent(val));
+  }
+  /**
+   * Exponent of the quantity of a number
+   * e.g., 1234 equals to 1.234*10^3, so quantityExponent(1234) is 3
+   *
+   * @param val non-negative value
+   * @return
+   */
+
+
+  function quantityExponent(val) {
+    if (val === 0) {
+      return 0;
+    }
+
+    var exp = Math.floor(Math.log(val) / Math.LN10);
+    /**
+     * exp is expected to be the rounded-down result of the base-10 log of val.
+     * But due to the precision loss with Math.log(val), we need to restore it
+     * using 10^exp to make sure we can get val back from exp. #11249
+     */
+
+    if (val / Math.pow(10, exp) >= 10) {
+      exp++;
+    }
+
+    return exp;
+  }
+  /**
+   * find a “nice” number approximately equal to x. Round the number if round = true,
+   * take ceiling if round = false. The primary observation is that the “nicest”
+   * numbers in decimal are 1, 2, and 5, and all power-of-ten multiples of these numbers.
+   *
+   * See "Nice Numbers for Graph Labels" of Graphic Gems.
+   *
+   * @param  val Non-negative value.
+   * @param  round
+   * @return Niced number
+   */
+
+
+  function nice(val, round) {
+    var exponent = quantityExponent(val);
+    var exp10 = Math.pow(10, exponent);
+    var f = val / exp10; // 1 <= f < 10
+
+    var nf;
+
+    if (round) {
+      if (f < 1.5) {
+        nf = 1;
+      } else if (f < 2.5) {
+        nf = 2;
+      } else if (f < 4) {
+        nf = 3;
+      } else if (f < 7) {
+        nf = 5;
+      } else {
+        nf = 10;
+      }
+    } else {
+      if (f < 1) {
+        nf = 1;
+      } else if (f < 2) {
+        nf = 2;
+      } else if (f < 3) {
+        nf = 3;
+      } else if (f < 5) {
+        nf = 5;
+      } else {
+        nf = 10;
+      }
+    }
+
+    val = nf * exp10; // Fix 3 * 0.1 === 0.30000000000000004 issue (see IEEE 754).
+    // 20 is the uppper bound of toFixed.
+
+    return exponent >= -20 ? +val.toFixed(exponent < 0 ? -exponent : 0) : val;
+  }
+  /**
+   * This code was copied from "d3.js"
+   * <https://github.com/d3/d3/blob/9cc9a875e636a1dcf36cc1e07bdf77e1ad6e2c74/src/arrays/quantile.js>.
+   * See the license statement at the head of this file.
+   * @param ascArr
+   */
+
+
+  function quantile(ascArr, p) {
+    var H = (ascArr.length - 1) * p + 1;
+    var h = Math.floor(H);
+    var v = +ascArr[h - 1];
+    var e = H - h;
+    return e ? v + e * (ascArr[h] - v) : v;
+  }
+  /**
+   * Order intervals asc, and split them when overlap.
+   * expect(numberUtil.reformIntervals([
+   *     {interval: [18, 62], close: [1, 1]},
+   *     {interval: [-Infinity, -70], close: [0, 0]},
+   *     {interval: [-70, -26], close: [1, 1]},
+   *     {interval: [-26, 18], close: [1, 1]},
+   *     {interval: [62, 150], close: [1, 1]},
+   *     {interval: [106, 150], close: [1, 1]},
+   *     {interval: [150, Infinity], close: [0, 0]}
+   * ])).toEqual([
+   *     {interval: [-Infinity, -70], close: [0, 0]},
+   *     {interval: [-70, -26], close: [1, 1]},
+   *     {interval: [-26, 18], close: [0, 1]},
+   *     {interval: [18, 62], close: [0, 1]},
+   *     {interval: [62, 150], close: [0, 1]},
+   *     {interval: [150, Infinity], close: [0, 0]}
+   * ]);
+   * @param list, where `close` mean open or close
+   *        of the interval, and Infinity can be used.
+   * @return The origin list, which has been reformed.
+   */
+
+
+  function reformIntervals(list) {
+    list.sort(function (a, b) {
+      return littleThan(a, b, 0) ? -1 : 1;
+    });
+    var curr = -Infinity;
+    var currClose = 1;
+
+    for (var i = 0; i < list.length;) {
+      var interval = list[i].interval;
+      var close_1 = list[i].close;
+
+      for (var lg = 0; lg < 2; lg++) {
+        if (interval[lg] <= curr) {
+          interval[lg] = curr;
+          close_1[lg] = !lg ? 1 - currClose : 1;
+        }
+
+        curr = interval[lg];
+        currClose = close_1[lg];
+      }
+
+      if (interval[0] === interval[1] && close_1[0] * close_1[1] !== 1) {
+        list.splice(i, 1);
+      } else {
+        i++;
+      }
+    }
+
+    return list;
+
+    function littleThan(a, b, lg) {
+      return a.interval[lg] < b.interval[lg] || a.interval[lg] === b.interval[lg] && (a.close[lg] - b.close[lg] === (!lg ? 1 : -1) || !lg && littleThan(a, b, 1));
+    }
+  }
+  /**
+   * [Numberic is defined as]:
+   *     `parseFloat(val) == val`
+   * For example:
+   * numeric:
+   *     typeof number except NaN, '-123', '123', '2e3', '-2e3', '011', 'Infinity', Infinity,
+   *     and they rounded by white-spaces or line-terminal like ' -123 \n ' (see es spec)
+   * not-numeric:
+   *     null, undefined, [], {}, true, false, 'NaN', NaN, '123ab',
+   *     empty string, string with only white-spaces or line-terminal (see es spec),
+   *     0x12, '0x12', '-0x12', 012, '012', '-012',
+   *     non-string, ...
+   *
+   * @test See full test cases in `test/ut/spec/util/number.js`.
+   * @return Must be a typeof number. If not numeric, return NaN.
+   */
+
+
+  function numericToNumber(val) {
+    var valFloat = parseFloat(val);
+    return valFloat == val // eslint-disable-line eqeqeq
+    && (valFloat !== 0 || !isString(val) || val.indexOf('x') <= 0) // For case ' 0x0 '.
+    ? valFloat : NaN;
+  }
+  /**
+   * Definition of "numeric": see `numericToNumber`.
+   */
+
+
+  function isNumeric(val) {
+    return !isNaN(numericToNumber(val));
+  }
+  /**
+   * Use random base to prevent users hard code depending on
+   * this auto generated marker id.
+   * @return An positive integer.
+   */
+
+
+  function getRandomIdBase() {
+    return Math.round(Math.random() * 9);
+  }
+  /**
+   * Get the greatest common dividor
+   *
+   * @param {number} a one number
+   * @param {number} b the other number
+   */
+
+
+  function getGreatestCommonDividor(a, b) {
+    if (b === 0) {
+      return a;
+    }
+
+    return getGreatestCommonDividor(b, a % b);
+  }
+  /**
+   * Get the least common multiple
+   *
+   * @param {number} a one number
+   * @param {number} b the other number
+   */
+
+
+  function getLeastCommonMultiple(a, b) {
+    if (a == null) {
+      return b;
+    }
+
+    if (b == null) {
+      return a;
+    }
+
+    return a * b / getGreatestCommonDividor(a, b);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 ECHARTS_PREFIX = '[ECharts] ';
+  var storedLogs = {};
+  var hasConsole = typeof console !== 'undefined' // eslint-disable-next-line
+  && console.warn && console.log;
+
+  function outputLog(type, str, onlyOnce) {
+    if (hasConsole) {
+      if (onlyOnce) {
+        if (storedLogs[str]) {
+          return;
+        }
+
+        storedLogs[str] = true;
+      } // eslint-disable-next-line
+
+
+      console[type](ECHARTS_PREFIX + str);
+    }
+  }
+
+  function log(str, onlyOnce) {
+    outputLog('log', str, onlyOnce);
+  }
+
+  function warn(str, onlyOnce) {
+    outputLog('warn', str, onlyOnce);
+  }
+
+  function error(str, onlyOnce) {
+    outputLog('error', str, onlyOnce);
+  }
+
+  function deprecateLog(str) {
+    {
+      // Not display duplicate message.
+      outputLog('warn', 'DEPRECATED: ' + str, true);
+    }
+  }
+
+  function deprecateReplaceLog(oldOpt, newOpt, scope) {
+    {
+      deprecateLog((scope ? "[" + scope + "]" : '') + (oldOpt + " is deprecated, use " + newOpt + " instead."));
+    }
+  }
+  /**
+   * If in __DEV__ environment, get console printable message for users hint.
+   * Parameters are separated by ' '.
+   * @usuage
+   * makePrintable('This is an error on', someVar, someObj);
+   *
+   * @param hintInfo anything about the current execution context to hint users.
+   * @throws Error
+   */
+
+
+  function makePrintable() {
+    var hintInfo = [];
+
+    for (var _i = 0; _i < arguments.length; _i++) {
+      hintInfo[_i] = arguments[_i];
+    }
+
+    var msg = '';
+    {
+      // Fuzzy stringify for print.
+      // This code only exist in dev environment.
+      var makePrintableStringIfPossible_1 = function (val) {
+        return val === void 0 ? 'undefined' : val === Infinity ? 'Infinity' : val === -Infinity ? '-Infinity' : eqNaN(val) ? 'NaN' : val instanceof Date ? 'Date(' + val.toISOString() + ')' : isFunction(val) ? 'function () { ... }' : isRegExp(val) ? val + '' : null;
+      };
+
+      msg = map(hintInfo, function (arg) {
+        if (isString(arg)) {
+          // Print without quotation mark for some statement.
+          return arg;
+        } else {
+          var printableStr = makePrintableStringIfPossible_1(arg);
+
+          if (printableStr != null) {
+            return printableStr;
+          } else if (typeof JSON !== 'undefined' && JSON.stringify) {
+            try {
+              return JSON.stringify(arg, function (n, val) {
+                var printableStr = makePrintableStringIfPossible_1(val);
+                return printableStr == null ? val : printableStr;
+              }); // In most cases the info object is small, so do not line break.
+            } catch (err) {
+              return '?';
+            }
+          } else {
+            return '?';
+          }
+        }
+      }).join(' ');
+    }
+    return msg;
+  }
+  /**
+   * @throws Error
+   */
+
+
+  function throwError(msg) {
+    throw new Error(msg);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 interpolateNumber$1(p0, p1, percent) {
+    return (p1 - p0) * percent + p0;
+  }
+  /**
+   * Make the name displayable. But we should
+   * make sure it is not duplicated with user
+   * specified name, so use '\0';
+   */
+
+
+  var DUMMY_COMPONENT_NAME_PREFIX = 'series\0';
+  var INTERNAL_COMPONENT_ID_PREFIX = '\0_ec_\0';
+  /**
+   * If value is not array, then translate it to array.
+   * @param  {*} value
+   * @return {Array} [value] or value
+   */
+
+  function normalizeToArray(value) {
+    return value instanceof Array ? value : value == null ? [] : [value];
+  }
+  /**
+   * Sync default option between normal and emphasis like `position` and `show`
+   * In case some one will write code like
+   *     label: {
+   *          show: false,
+   *          position: 'outside',
+   *          fontSize: 18
+   *     },
+   *     emphasis: {
+   *          label: { show: true }
+   *     }
+   */
+
+
+  function defaultEmphasis(opt, key, subOpts) {
+    // Caution: performance sensitive.
+    if (opt) {
+      opt[key] = opt[key] || {};
+      opt.emphasis = opt.emphasis || {};
+      opt.emphasis[key] = opt.emphasis[key] || {}; // Default emphasis option from normal
+
+      for (var i = 0, len = subOpts.length; i < len; i++) {
+        var subOptName = subOpts[i];
+
+        if (!opt.emphasis[key].hasOwnProperty(subOptName) && opt[key].hasOwnProperty(subOptName)) {
+          opt.emphasis[key][subOptName] = opt[key][subOptName];
+        }
+      }
+    }
+  }
+
+  var TEXT_STYLE_OPTIONS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'rich', 'tag', 'color', 'textBorderColor', 'textBorderWidth', 'width', 'height', 'lineHeight', 'align', 'verticalAlign', 'baseline', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY', 'backgroundColor', 'borderColor', 'borderWidth', 'borderRadius', 'padding']; // modelUtil.LABEL_OPTIONS = modelUtil.TEXT_STYLE_OPTIONS.concat([
+  //     'position', 'offset', 'rotate', 'origin', 'show', 'distance', 'formatter',
+  //     'fontStyle', 'fontWeight', 'fontSize', 'fontFamily',
+  //     // FIXME: deprecated, check and remove it.
+  //     'textStyle'
+  // ]);
+
+  /**
+   * The method do not ensure performance.
+   * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]
+   * This helper method retieves value from data.
+   */
+
+  function getDataItemValue(dataItem) {
+    return isObject(dataItem) && !isArray(dataItem) && !(dataItem instanceof Date) ? dataItem.value : dataItem;
+  }
+  /**
+   * data could be [12, 2323, {value: 223}, [1221, 23], {value: [2, 23]}]
+   * This helper method determine if dataItem has extra option besides value
+   */
+
+
+  function isDataItemOption(dataItem) {
+    return isObject(dataItem) && !(dataItem instanceof Array); // // markLine data can be array
+    // && !(dataItem[0] && isObject(dataItem[0]) && !(dataItem[0] instanceof Array));
+  }
+  /**
+   * Mapping to existings for merge.
+   *
+   * Mode "normalMege":
+   *     The mapping result (merge result) will keep the order of the existing
+   *     component, rather than the order of new option. Because we should ensure
+   *     some specified index reference (like xAxisIndex) keep work.
+   *     And in most cases, "merge option" is used to update partial option but not
+   *     be expected to change the order.
+   *
+   * Mode "replaceMege":
+   *     (1) Only the id mapped components will be merged.
+   *     (2) Other existing components (except internal compoonets) will be removed.
+   *     (3) Other new options will be used to create new component.
+   *     (4) The index of the existing compoents will not be modified.
+   *     That means their might be "hole" after the removal.
+   *     The new components are created first at those available index.
+   *
+   * Mode "replaceAll":
+   *     This mode try to support that reproduce an echarts instance from another
+   *     echarts instance (via `getOption`) in some simple cases.
+   *     In this senario, the `result` index are exactly the consistent with the `newCmptOptions`,
+   *     which ensures the compoennt index referring (like `xAxisIndex: ?`) corrent. That is,
+   *     the "hole" in `newCmptOptions` will also be kept.
+   *     On the contrary, other modes try best to eliminate holes.
+   *     PENDING: This is an experimental mode yet.
+   *
+   * @return See the comment of <MappingResult>.
+   */
+
+
+  function mappingToExists(existings, newCmptOptions, mode) {
+    var isNormalMergeMode = mode === 'normalMerge';
+    var isReplaceMergeMode = mode === 'replaceMerge';
+    var isReplaceAllMode = mode === 'replaceAll';
+    existings = existings || [];
+    newCmptOptions = (newCmptOptions || []).slice();
+    var existingIdIdxMap = createHashMap(); // Validate id and name on user input option.
+
+    each(newCmptOptions, function (cmptOption, index) {
+      if (!isObject(cmptOption)) {
+        newCmptOptions[index] = null;
+        return;
+      }
+
+      {
+        // There is some legacy case that name is set as `false`.
+        // But should work normally rather than throw error.
+        if (cmptOption.id != null && !isValidIdOrName(cmptOption.id)) {
+          warnInvalidateIdOrName(cmptOption.id);
+        }
+
+        if (cmptOption.name != null && !isValidIdOrName(cmptOption.name)) {
+          warnInvalidateIdOrName(cmptOption.name);
+        }
+      }
+    });
+    var result = prepareResult(existings, existingIdIdxMap, mode);
+
+    if (isNormalMergeMode || isReplaceMergeMode) {
+      mappingById(result, existings, existingIdIdxMap, newCmptOptions);
+    }
+
+    if (isNormalMergeMode) {
+      mappingByName(result, newCmptOptions);
+    }
+
+    if (isNormalMergeMode || isReplaceMergeMode) {
+      mappingByIndex(result, newCmptOptions, isReplaceMergeMode);
+    } else if (isReplaceAllMode) {
+      mappingInReplaceAllMode(result, newCmptOptions);
+    }
+
+    makeIdAndName(result); // The array `result` MUST NOT contain elided items, otherwise the
+    // forEach will ommit those items and result in incorrect result.
+
+    return result;
+  }
+
+  function prepareResult(existings, existingIdIdxMap, mode) {
+    var result = [];
+
+    if (mode === 'replaceAll') {
+      return result;
+    } // Do not use native `map` to in case that the array `existings`
+    // contains elided items, which will be ommited.
+
+
+    for (var index = 0; index < existings.length; index++) {
+      var existing = existings[index]; // Because of replaceMerge, `existing` may be null/undefined.
+
+      if (existing && existing.id != null) {
+        existingIdIdxMap.set(existing.id, index);
+      } // For non-internal-componnets:
+      //     Mode "normalMerge": all existings kept.
+      //     Mode "replaceMerge": all existing removed unless mapped by id.
+      // For internal-components:
+      //     go with "replaceMerge" approach in both mode.
+
+
+      result.push({
+        existing: mode === 'replaceMerge' || isComponentIdInternal(existing) ? null : existing,
+        newOption: null,
+        keyInfo: null,
+        brandNew: null
+      });
+    }
+
+    return result;
+  }
+
+  function mappingById(result, existings, existingIdIdxMap, newCmptOptions) {
+    // Mapping by id if specified.
+    each(newCmptOptions, function (cmptOption, index) {
+      if (!cmptOption || cmptOption.id == null) {
+        return;
+      }
+
+      var optionId = makeComparableKey(cmptOption.id);
+      var existingIdx = existingIdIdxMap.get(optionId);
+
+      if (existingIdx != null) {
+        var resultItem = result[existingIdx];
+        assert(!resultItem.newOption, 'Duplicated option on id "' + optionId + '".');
+        resultItem.newOption = cmptOption; // In both mode, if id matched, new option will be merged to
+        // the existings rather than creating new component model.
+
+        resultItem.existing = existings[existingIdx];
+        newCmptOptions[index] = null;
+      }
+    });
+  }
+
+  function mappingByName(result, newCmptOptions) {
+    // Mapping by name if specified.
+    each(newCmptOptions, function (cmptOption, index) {
+      if (!cmptOption || cmptOption.name == null) {
+        return;
+      }
+
+      for (var i = 0; i < result.length; i++) {
+        var existing = result[i].existing;
+
+        if (!result[i].newOption // Consider name: two map to one.
+        // Can not match when both ids existing but different.
+        && existing && (existing.id == null || cmptOption.id == null) && !isComponentIdInternal(cmptOption) && !isComponentIdInternal(existing) && keyExistAndEqual('name', existing, cmptOption)) {
+          result[i].newOption = cmptOption;
+          newCmptOptions[index] = null;
+          return;
+        }
+      }
+    });
+  }
+
+  function mappingByIndex(result, newCmptOptions, brandNew) {
+    each(newCmptOptions, function (cmptOption) {
+      if (!cmptOption) {
+        return;
+      } // Find the first place that not mapped by id and not internal component (consider the "hole").
+
+
+      var resultItem;
+      var nextIdx = 0;
+
+      while ( // Be `!resultItem` only when `nextIdx >= result.length`.
+      (resultItem = result[nextIdx]) && ( // (1) Existing models that already have id should be able to mapped to. Because
+      // after mapping performed, model will always be assigned with an id if user not given.
+      // After that all models have id.
+      // (2) If new option has id, it can only set to a hole or append to the last. It should
+      // not be merged to the existings with different id. Because id should not be overwritten.
+      // (3) Name can be overwritten, because axis use name as 'show label text'.
+      resultItem.newOption || isComponentIdInternal(resultItem.existing) || // In mode "replaceMerge", here no not-mapped-non-internal-existing.
+      resultItem.existing && cmptOption.id != null && !keyExistAndEqual('id', cmptOption, resultItem.existing))) {
+        nextIdx++;
+      }
+
+      if (resultItem) {
+        resultItem.newOption = cmptOption;
+        resultItem.brandNew = brandNew;
+      } else {
+        result.push({
+          newOption: cmptOption,
+          brandNew: brandNew,
+          existing: null,
+          keyInfo: null
+        });
+      }
+
+      nextIdx++;
+    });
+  }
+
+  function mappingInReplaceAllMode(result, newCmptOptions) {
+    each(newCmptOptions, function (cmptOption) {
+      // The feature "reproduce" requires "hole" will also reproduced
+      // in case that compoennt index referring are broken.
+      result.push({
+        newOption: cmptOption,
+        brandNew: true,
+        existing: null,
+        keyInfo: null
+      });
+    });
+  }
+  /**
+   * Make id and name for mapping result (result of mappingToExists)
+   * into `keyInfo` field.
+   */
+
+
+  function makeIdAndName(mapResult) {
+    // We use this id to hash component models and view instances
+    // in echarts. id can be specified by user, or auto generated.
+    // The id generation rule ensures new view instance are able
+    // to mapped to old instance when setOption are called in
+    // no-merge mode. So we generate model id by name and plus
+    // type in view id.
+    // name can be duplicated among components, which is convenient
+    // to specify multi components (like series) by one name.
+    // Ensure that each id is distinct.
+    var idMap = createHashMap();
+    each(mapResult, function (item) {
+      var existing = item.existing;
+      existing && idMap.set(existing.id, item);
+    });
+    each(mapResult, function (item) {
+      var opt = item.newOption; // Force ensure id not duplicated.
+
+      assert(!opt || opt.id == null || !idMap.get(opt.id) || idMap.get(opt.id) === item, 'id duplicates: ' + (opt && opt.id));
+      opt && opt.id != null && idMap.set(opt.id, item);
+      !item.keyInfo && (item.keyInfo = {});
+    }); // Make name and id.
+
+    each(mapResult, function (item, index) {
+      var existing = item.existing;
+      var opt = item.newOption;
+      var keyInfo = item.keyInfo;
+
+      if (!isObject(opt)) {
+        return;
+      } // name can be overwitten. Consider case: axis.name = '20km'.
+      // But id generated by name will not be changed, which affect
+      // only in that case: setOption with 'not merge mode' and view
+      // instance will be recreated, which can be accepted.
+
+
+      keyInfo.name = opt.name != null ? makeComparableKey(opt.name) : existing ? existing.name // Avoid diffferent series has the same name,
+      // because name may be used like in color pallet.
+      : DUMMY_COMPONENT_NAME_PREFIX + index;
+
+      if (existing) {
+        keyInfo.id = makeComparableKey(existing.id);
+      } else if (opt.id != null) {
+        keyInfo.id = makeComparableKey(opt.id);
+      } else {
+        // Consider this situatoin:
+        //  optionA: [{name: 'a'}, {name: 'a'}, {..}]
+        //  optionB [{..}, {name: 'a'}, {name: 'a'}]
+        // Series with the same name between optionA and optionB
+        // should be mapped.
+        var idNum = 0;
+
+        do {
+          keyInfo.id = '\0' + keyInfo.name + '\0' + idNum++;
+        } while (idMap.get(keyInfo.id));
+      }
+
+      idMap.set(keyInfo.id, item);
+    });
+  }
+
+  function keyExistAndEqual(attr, obj1, obj2) {
+    var key1 = convertOptionIdName(obj1[attr], null);
+    var key2 = convertOptionIdName(obj2[attr], null); // See `MappingExistingItem`. `id` and `name` trade string equals to number.
+
+    return key1 != null && key2 != null && key1 === key2;
+  }
+  /**
+   * @return return null if not exist.
+   */
+
+
+  function makeComparableKey(val) {
+    {
+      if (val == null) {
+        throw new Error();
+      }
+    }
+    return convertOptionIdName(val, '');
+  }
+
+  function convertOptionIdName(idOrName, defaultValue) {
+    if (idOrName == null) {
+      return defaultValue;
+    }
+
+    return isString(idOrName) ? idOrName : isNumber(idOrName) || isStringSafe(idOrName) ? idOrName + '' : defaultValue;
+  }
+
+  function warnInvalidateIdOrName(idOrName) {
+    {
+      warn('`' + idOrName + '` is invalid id or name. Must be a string or number.');
+    }
+  }
+
+  function isValidIdOrName(idOrName) {
+    return isStringSafe(idOrName) || isNumeric(idOrName);
+  }
+
+  function isNameSpecified(componentModel) {
+    var name = componentModel.name; // Is specified when `indexOf` get -1 or > 0.
+
+    return !!(name && name.indexOf(DUMMY_COMPONENT_NAME_PREFIX));
+  }
+  /**
+   * @public
+   * @param {Object} cmptOption
+   * @return {boolean}
+   */
+
+
+  function isComponentIdInternal(cmptOption) {
+    return cmptOption && cmptOption.id != null && makeComparableKey(cmptOption.id).indexOf(INTERNAL_COMPONENT_ID_PREFIX) === 0;
+  }
+
+  function setComponentTypeToKeyInfo(mappingResult, mainType, componentModelCtor) {
+    // Set mainType and complete subType.
+    each(mappingResult, function (item) {
+      var newOption = item.newOption;
+
+      if (isObject(newOption)) {
+        item.keyInfo.mainType = mainType;
+        item.keyInfo.subType = determineSubType(mainType, newOption, item.existing, componentModelCtor);
+      }
+    });
+  }
+
+  function determineSubType(mainType, newCmptOption, existComponent, componentModelCtor) {
+    var subType = newCmptOption.type ? newCmptOption.type : existComponent ? existComponent.subType // Use determineSubType only when there is no existComponent.
+    : componentModelCtor.determineSubType(mainType, newCmptOption); // tooltip, markline, markpoint may always has no subType
+
+    return subType;
+  }
+  /**
+   * A helper for removing duplicate items between batchA and batchB,
+   * and in themselves, and categorize by series.
+   *
+   * @param batchA Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
+   * @param batchB Like: [{seriesId: 2, dataIndex: [32, 4, 5]}, ...]
+   * @return result: [resultBatchA, resultBatchB]
+   */
+
+  /**
+   * @param payload Contains dataIndex (means rawIndex) / dataIndexInside / name
+   *                         each of which can be Array or primary type.
+   * @return dataIndex If not found, return undefined/null.
+   */
+
+
+  function queryDataIndex(data, payload) {
+    if (payload.dataIndexInside != null) {
+      return payload.dataIndexInside;
+    } else if (payload.dataIndex != null) {
+      return isArray(payload.dataIndex) ? map(payload.dataIndex, function (value) {
+        return data.indexOfRawIndex(value);
+      }) : data.indexOfRawIndex(payload.dataIndex);
+    } else if (payload.name != null) {
+      return isArray(payload.name) ? map(payload.name, function (value) {
+        return data.indexOfName(value);
+      }) : data.indexOfName(payload.name);
+    }
+  }
+  /**
+   * Enable property storage to any host object.
+   * Notice: Serialization is not supported.
+   *
+   * For example:
+   * let inner = zrUitl.makeInner();
+   *
+   * function some1(hostObj) {
+   *      inner(hostObj).someProperty = 1212;
+   *      ...
+   * }
+   * function some2() {
+   *      let fields = inner(this);
+   *      fields.someProperty1 = 1212;
+   *      fields.someProperty2 = 'xx';
+   *      ...
+   * }
+   *
+   * @return {Function}
+   */
+
+
+  function makeInner() {
+    var key = '__ec_inner_' + innerUniqueIndex++;
+    return function (hostObj) {
+      return hostObj[key] || (hostObj[key] = {});
+    };
+  }
+
+  var innerUniqueIndex = getRandomIdBase();
+  /**
+   * The same behavior as `component.getReferringComponents`.
+   */
+
+  function parseFinder(ecModel, finderInput, opt) {
+    var _a = preParseFinder(finderInput, opt),
+        mainTypeSpecified = _a.mainTypeSpecified,
+        queryOptionMap = _a.queryOptionMap,
+        others = _a.others;
+
+    var result = others;
+    var defaultMainType = opt ? opt.defaultMainType : null;
+
+    if (!mainTypeSpecified && defaultMainType) {
+      queryOptionMap.set(defaultMainType, {});
+    }
+
+    queryOptionMap.each(function (queryOption, mainType) {
+      var queryResult = queryReferringComponents(ecModel, mainType, queryOption, {
+        useDefault: defaultMainType === mainType,
+        enableAll: opt && opt.enableAll != null ? opt.enableAll : true,
+        enableNone: opt && opt.enableNone != null ? opt.enableNone : true
+      });
+      result[mainType + 'Models'] = queryResult.models;
+      result[mainType + 'Model'] = queryResult.models[0];
+    });
+    return result;
+  }
+
+  function preParseFinder(finderInput, opt) {
+    var finder;
+
+    if (isString(finderInput)) {
+      var obj = {};
+      obj[finderInput + 'Index'] = 0;
+      finder = obj;
+    } else {
+      finder = finderInput;
+    }
+
+    var queryOptionMap = createHashMap();
+    var others = {};
+    var mainTypeSpecified = false;
+    each(finder, function (value, key) {
+      // Exclude 'dataIndex' and other illgal keys.
+      if (key === 'dataIndex' || key === 'dataIndexInside') {
+        others[key] = value;
+        return;
+      }
+
+      var parsedKey = key.match(/^(\w+)(Index|Id|Name)$/) || [];
+      var mainType = parsedKey[1];
+      var queryType = (parsedKey[2] || '').toLowerCase();
+
+      if (!mainType || !queryType || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) {
+        return;
+      }
+
+      mainTypeSpecified = mainTypeSpecified || !!mainType;
+      var queryOption = queryOptionMap.get(mainType) || queryOptionMap.set(mainType, {});
+      queryOption[queryType] = value;
+    });
+    return {
+      mainTypeSpecified: mainTypeSpecified,
+      queryOptionMap: queryOptionMap,
+      others: others
+    };
+  }
+
+  var SINGLE_REFERRING = {
+    useDefault: true,
+    enableAll: false,
+    enableNone: false
+  };
+
+  function queryReferringComponents(ecModel, mainType, userOption, opt) {
+    opt = opt || SINGLE_REFERRING;
+    var indexOption = userOption.index;
+    var idOption = userOption.id;
+    var nameOption = userOption.name;
+    var result = {
+      models: null,
+      specified: indexOption != null || idOption != null || nameOption != null
+    };
+
+    if (!result.specified) {
+      // Use the first as default if `useDefault`.
+      var firstCmpt = void 0;
+      result.models = opt.useDefault && (firstCmpt = ecModel.getComponent(mainType)) ? [firstCmpt] : [];
+      return result;
+    }
+
+    if (indexOption === 'none' || indexOption === false) {
+      assert(opt.enableNone, '`"none"` or `false` is not a valid value on index option.');
+      result.models = [];
+      return result;
+    } // `queryComponents` will return all components if
+    // both all of index/id/name are null/undefined.
+
+
+    if (indexOption === 'all') {
+      assert(opt.enableAll, '`"all"` is not a valid value on index option.');
+      indexOption = idOption = nameOption = null;
+    }
+
+    result.models = ecModel.queryComponents({
+      mainType: mainType,
+      index: indexOption,
+      id: idOption,
+      name: nameOption
+    });
+    return result;
+  }
+
+  function setAttribute(dom, key, value) {
+    dom.setAttribute ? dom.setAttribute(key, value) : dom[key] = value;
+  }
+
+  function getAttribute(dom, key) {
+    return dom.getAttribute ? dom.getAttribute(key) : dom[key];
+  }
+
+  function getTooltipRenderMode(renderModeOption) {
+    if (renderModeOption === 'auto') {
+      // Using html when `document` exists, use richText otherwise
+      return env.domSupported ? 'html' : 'richText';
+    } else {
+      return renderModeOption || 'html';
+    }
+  }
+  /**
+   * Group a list by key.
+   */
+
+  /**
+   * Interpolate raw values of a series with percent
+   *
+   * @param data         data
+   * @param labelModel   label model of the text element
+   * @param sourceValue  start value. May be null/undefined when init.
+   * @param targetValue  end value
+   * @param percent      0~1 percentage; 0 uses start value while 1 uses end value
+   * @return             interpolated values
+   *                     If `sourceValue` and `targetValue` are `number`, return `number`.
+   *                     If `sourceValue` and `targetValue` are `string`, return `string`.
+   *                     If `sourceValue` and `targetValue` are `(string | number)[]`, return `(string | number)[]`.
+   *                     Other cases do not supported.
+   */
+
+
+  function interpolateRawValues(data, precision, sourceValue, targetValue, percent) {
+    var isAutoPrecision = precision == null || precision === 'auto';
+
+    if (targetValue == null) {
+      return targetValue;
+    }
+
+    if (isNumber(targetValue)) {
+      var value = interpolateNumber$1(sourceValue || 0, targetValue, percent);
+      return round(value, isAutoPrecision ? Math.max(getPrecision(sourceValue || 0), getPrecision(targetValue)) : precision);
+    } else if (isString(targetValue)) {
+      return percent < 1 ? sourceValue : targetValue;
+    } else {
+      var interpolated = [];
+      var leftArr = sourceValue;
+      var rightArr = targetValue;
+      var length_1 = Math.max(leftArr ? leftArr.length : 0, rightArr.length);
+
+      for (var i = 0; i < length_1; ++i) {
+        var info = data.getDimensionInfo(i); // Don't interpolate ordinal dims
+
+        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 {
+          var leftVal = leftArr && leftArr[i] ? leftArr[i] : 0;
+          var rightVal = rightArr[i];
+          var value = interpolateNumber$1(leftVal, rightVal, percent);
+          interpolated[i] = round(value, isAutoPrecision ? Math.max(getPrecision(leftVal), getPrecision(rightVal)) : precision);
+        }
+      }
+
+      return interpolated;
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 TYPE_DELIMITER = '.';
+  var IS_CONTAINER = '___EC__COMPONENT__CONTAINER___';
+  var IS_EXTENDED_CLASS = '___EC__EXTENDED_CLASS___';
+  /**
+   * Notice, parseClassType('') should returns {main: '', sub: ''}
+   * @public
+   */
+
+  function parseClassType(componentType) {
+    var ret = {
+      main: '',
+      sub: ''
+    };
+
+    if (componentType) {
+      var typeArr = componentType.split(TYPE_DELIMITER);
+      ret.main = typeArr[0] || '';
+      ret.sub = typeArr[1] || '';
+    }
+
+    return ret;
+  }
+  /**
+   * @public
+   */
+
+
+  function checkClassType(componentType) {
+    assert(/^[a-zA-Z0-9_]+([.][a-zA-Z0-9_]+)?$/.test(componentType), 'componentType "' + componentType + '" illegal');
+  }
+
+  function isExtendedClass(clz) {
+    return !!(clz && clz[IS_EXTENDED_CLASS]);
+  }
+  /**
+   * Implements `ExtendableConstructor` for `rootClz`.
+   *
+   * @usage
+   * ```ts
+   * class Xxx {}
+   * type XxxConstructor = typeof Xxx & ExtendableConstructor
+   * enableClassExtend(Xxx as XxxConstructor);
+   * ```
+   */
+
+
+  function enableClassExtend(rootClz, mandatoryMethods) {
+    rootClz.$constructor = rootClz; // FIXME: not necessary?
+
+    rootClz.extend = function (proto) {
+      {
+        each(mandatoryMethods, function (method) {
+          if (!proto[method]) {
+            console.warn('Method `' + method + '` should be implemented' + (proto.type ? ' in ' + proto.type : '') + '.');
+          }
+        });
+      }
+      var superClass = this;
+      var ExtendedClass;
+
+      if (isESClass(superClass)) {
+        ExtendedClass =
+        /** @class */
+        function (_super) {
+          __extends(class_1, _super);
+
+          function class_1() {
+            return _super.apply(this, arguments) || this;
+          }
+
+          return class_1;
+        }(superClass);
+      } else {
+        // For backward compat, we both support ts class inheritance and this
+        // "extend" approach.
+        // The constructor should keep the same behavior as ts class inheritance:
+        // If this constructor/$constructor is not declared, auto invoke the super
+        // constructor.
+        // If this constructor/$constructor is declared, it is responsible for
+        // calling the super constructor.
+        ExtendedClass = function () {
+          (proto.$constructor || superClass).apply(this, arguments);
+        };
+
+        inherits(ExtendedClass, this);
+      }
+
+      extend(ExtendedClass.prototype, proto);
+      ExtendedClass[IS_EXTENDED_CLASS] = true;
+      ExtendedClass.extend = this.extend;
+      ExtendedClass.superCall = superCall;
+      ExtendedClass.superApply = superApply;
+      ExtendedClass.superClass = superClass;
+      return ExtendedClass;
+    };
+  }
+
+  function isESClass(fn) {
+    return isFunction(fn) && /^class\s/.test(Function.prototype.toString.call(fn));
+  }
+  /**
+   * A work around to both support ts extend and this extend mechanism.
+   * on sub-class.
+   * @usage
+   * ```ts
+   * class Component { ... }
+   * classUtil.enableClassExtend(Component);
+   * classUtil.enableClassManagement(Component, {registerWhenExtend: true});
+   *
+   * class Series extends Component { ... }
+   * // Without calling `markExtend`, `registerWhenExtend` will not work.
+   * Component.markExtend(Series);
+   * ```
+   */
+
+
+  function mountExtend(SubClz, SupperClz) {
+    SubClz.extend = SupperClz.extend;
+  } // A random offset.
+
+
+  var classBase = Math.round(Math.random() * 10);
+  /**
+   * Implements `CheckableConstructor` for `target`.
+   * Can not use instanceof, consider different scope by
+   * cross domain or es module import in ec extensions.
+   * Mount a method "isInstance()" to Clz.
+   *
+   * @usage
+   * ```ts
+   * class Xxx {}
+   * type XxxConstructor = typeof Xxx & CheckableConstructor;
+   * enableClassCheck(Xxx as XxxConstructor)
+   * ```
+   */
+
+  function enableClassCheck(target) {
+    var classAttr = ['__\0is_clz', classBase++].join('_');
+    target.prototype[classAttr] = true;
+    {
+      assert(!target.isInstance, 'The method "is" can not be defined.');
+    }
+
+    target.isInstance = function (obj) {
+      return !!(obj && obj[classAttr]);
+    };
+  } // superCall should have class info, which can not be fetch from 'this'.
+  // Consider this case:
+  // class A has method f,
+  // class B inherits class A, overrides method f, f call superApply('f'),
+  // class C inherits class B, do not overrides method f,
+  // then when method of class C is called, dead loop occured.
+
+
+  function superCall(context, methodName) {
+    var args = [];
+
+    for (var _i = 2; _i < arguments.length; _i++) {
+      args[_i - 2] = arguments[_i];
+    }
+
+    return this.superClass.prototype[methodName].apply(context, args);
+  }
+
+  function superApply(context, methodName, args) {
+    return this.superClass.prototype[methodName].apply(context, args);
+  }
+  /**
+   * Implements `ClassManager` for `target`
+   *
+   * @usage
+   * ```ts
+   * class Xxx {}
+   * type XxxConstructor = typeof Xxx & ClassManager
+   * enableClassManagement(Xxx as XxxConstructor);
+   * ```
+   */
+
+
+  function enableClassManagement(target) {
+    /**
+     * Component model classes
+     * key: componentType,
+     * value:
+     *     componentClass, when componentType is 'a'
+     *     or Object.<subKey, componentClass>, when componentType is 'a.b'
+     */
+    var storage = {};
+
+    target.registerClass = function (clz) {
+      // `type` should not be a "instance memeber".
+      // If using TS class, should better declared as `static type = 'series.pie'`.
+      // otherwise users have to mount `type` on prototype manually.
+      // For backward compat and enable instance visit type via `this.type`,
+      // we stil support fetch `type` from prototype.
+      var componentFullType = clz.type || clz.prototype.type;
+
+      if (componentFullType) {
+        checkClassType(componentFullType); // If only static type declared, we assign it to prototype mandatorily.
+
+        clz.prototype.type = componentFullType;
+        var componentTypeInfo = parseClassType(componentFullType);
+
+        if (!componentTypeInfo.sub) {
+          {
+            if (storage[componentTypeInfo.main]) {
+              console.warn(componentTypeInfo.main + ' exists.');
+            }
+          }
+          storage[componentTypeInfo.main] = clz;
+        } else if (componentTypeInfo.sub !== IS_CONTAINER) {
+          var container = makeContainer(componentTypeInfo);
+          container[componentTypeInfo.sub] = clz;
+        }
+      }
+
+      return clz;
+    };
+
+    target.getClass = function (mainType, subType, throwWhenNotFound) {
+      var clz = storage[mainType];
+
+      if (clz && clz[IS_CONTAINER]) {
+        clz = subType ? clz[subType] : null;
+      }
+
+      if (throwWhenNotFound && !clz) {
+        throw new Error(!subType ? mainType + '.' + 'type should be specified.' : 'Component ' + mainType + '.' + (subType || '') + ' is used but not imported.');
+      }
+
+      return clz;
+    };
+
+    target.getClassesByMainType = function (componentType) {
+      var componentTypeInfo = parseClassType(componentType);
+      var result = [];
+      var obj = storage[componentTypeInfo.main];
+
+      if (obj && obj[IS_CONTAINER]) {
+        each(obj, function (o, type) {
+          type !== IS_CONTAINER && result.push(o);
+        });
+      } else {
+        result.push(obj);
+      }
+
+      return result;
+    };
+
+    target.hasClass = function (componentType) {
+      // Just consider componentType.main.
+      var componentTypeInfo = parseClassType(componentType);
+      return !!storage[componentTypeInfo.main];
+    };
+    /**
+     * @return Like ['aa', 'bb'], but can not be ['aa.xx']
+     */
+
+
+    target.getAllClassMainTypes = function () {
+      var types = [];
+      each(storage, function (obj, type) {
+        types.push(type);
+      });
+      return types;
+    };
+    /**
+     * If a main type is container and has sub types
+     */
+
+
+    target.hasSubTypes = function (componentType) {
+      var componentTypeInfo = parseClassType(componentType);
+      var obj = storage[componentTypeInfo.main];
+      return obj && obj[IS_CONTAINER];
+    };
+
+    function makeContainer(componentTypeInfo) {
+      var container = storage[componentTypeInfo.main];
+
+      if (!container || !container[IS_CONTAINER]) {
+        container = storage[componentTypeInfo.main] = {};
+        container[IS_CONTAINER] = true;
+      }
+
+      return container;
+    }
+  } // /**
+  //  * @param {string|Array.<string>} properties
+  //  */
+  // export function setReadOnly(obj, properties) {
+  // FIXME It seems broken in IE8 simulation of IE11
+  // if (!zrUtil.isArray(properties)) {
+  //     properties = properties != null ? [properties] : [];
+  // }
+  // zrUtil.each(properties, function (prop) {
+  //     let value = obj[prop];
+  //     Object.defineProperty
+  //         && Object.defineProperty(obj, prop, {
+  //             value: value, writable: false
+  //         });
+  //     zrUtil.isArray(obj[prop])
+  //         && Object.freeze
+  //         && Object.freeze(obj[prop]);
+  // });
+  // }
+
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // TODO Parse shadow style
+  // TODO Only shallow path support
+
+
+  function makeStyleMapper(properties, ignoreParent) {
+    // Normalize
+    for (var i = 0; i < properties.length; i++) {
+      if (!properties[i][1]) {
+        properties[i][1] = properties[i][0];
+      }
+    }
+
+    ignoreParent = ignoreParent || false;
+    return function (model, excludes, includes) {
+      var style = {};
+
+      for (var i = 0; i < properties.length; i++) {
+        var propName = properties[i][1];
+
+        if (excludes && indexOf(excludes, propName) >= 0 || includes && indexOf(includes, propName) < 0) {
+          continue;
+        }
+
+        var val = model.getShallow(propName, ignoreParent);
+
+        if (val != null) {
+          style[properties[i][0]] = val;
+        }
+      } // TODO Text or image?
+
+
+      return style;
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`.
+  // So do not transfer decal directly.
+  ];
+  var getAreaStyle = makeStyleMapper(AREA_STYLE_KEY_MAP);
+
+  var AreaStyleMixin =
+  /** @class */
+  function () {
+    function AreaStyleMixin() {}
+
+    AreaStyleMixin.prototype.getAreaStyle = function (excludes, includes) {
+      return getAreaStyle(this, excludes, includes);
+    };
+
+    return AreaStyleMixin;
+  }();
+
+  var globalImageCache = new LRU(50);
+
+  function findExistImage(newImageOrSrc) {
+    if (typeof newImageOrSrc === 'string') {
+      var cachedImgObj = globalImageCache.get(newImageOrSrc);
+      return cachedImgObj && cachedImgObj.image;
+    } else {
+      return newImageOrSrc;
+    }
+  }
+
+  function createOrUpdateImage(newImageOrSrc, image, hostEl, onload, cbPayload) {
+    if (!newImageOrSrc) {
+      return image;
+    } else if (typeof newImageOrSrc === 'string') {
+      if (image && image.__zrImageSrc === newImageOrSrc || !hostEl) {
+        return image;
+      }
+
+      var cachedImgObj = globalImageCache.get(newImageOrSrc);
+      var pendingWrap = {
+        hostEl: hostEl,
+        cb: onload,
+        cbPayload: cbPayload
+      };
+
+      if (cachedImgObj) {
+        image = cachedImgObj.image;
+        !isImageReady(image) && cachedImgObj.pending.push(pendingWrap);
+      } else {
+        image = platformApi.loadImage(newImageOrSrc, imageOnLoad, imageOnLoad);
+        image.__zrImageSrc = newImageOrSrc;
+        globalImageCache.put(newImageOrSrc, image.__cachedImgObj = {
+          image: image,
+          pending: [pendingWrap]
+        });
+      }
+
+      return image;
+    } else {
+      return newImageOrSrc;
+    }
+  }
+
+  function imageOnLoad() {
+    var cachedImgObj = this.__cachedImgObj;
+    this.onload = this.onerror = this.__cachedImgObj = null;
+
+    for (var i = 0; i < cachedImgObj.pending.length; i++) {
+      var pendingWrap = cachedImgObj.pending[i];
+      var cb = pendingWrap.cb;
+      cb && cb(this, pendingWrap.cbPayload);
+      pendingWrap.hostEl.dirty();
+    }
+
+    cachedImgObj.pending.length = 0;
+  }
+
+  function isImageReady(image) {
+    return image && image.width && image.height;
+  }
+
+  var STYLE_REG = /\{([a-zA-Z0-9_]+)\|([^}]*)\}/g;
+
+  function truncateText(text, containerWidth, font, ellipsis, options) {
+    if (!containerWidth) {
+      return '';
+    }
+
+    var textLines = (text + '').split('\n');
+    options = prepareTruncateOptions(containerWidth, font, ellipsis, options);
+
+    for (var i = 0, len = textLines.length; i < len; i++) {
+      textLines[i] = truncateSingleLine(textLines[i], options);
+    }
+
+    return textLines.join('\n');
+  }
+
+  function prepareTruncateOptions(containerWidth, font, ellipsis, options) {
+    options = options || {};
+    var preparedOpts = extend({}, options);
+    preparedOpts.font = font;
+    ellipsis = retrieve2(ellipsis, '...');
+    preparedOpts.maxIterations = retrieve2(options.maxIterations, 2);
+    var minChar = preparedOpts.minChar = retrieve2(options.minChar, 0);
+    preparedOpts.cnCharWidth = getWidth('国', font);
+    var ascCharWidth = preparedOpts.ascCharWidth = getWidth('a', font);
+    preparedOpts.placeholder = retrieve2(options.placeholder, '');
+    var contentWidth = containerWidth = Math.max(0, containerWidth - 1);
+
+    for (var i = 0; i < minChar && contentWidth >= ascCharWidth; i++) {
+      contentWidth -= ascCharWidth;
+    }
+
+    var ellipsisWidth = getWidth(ellipsis, font);
+
+    if (ellipsisWidth > contentWidth) {
+      ellipsis = '';
+      ellipsisWidth = 0;
+    }
+
+    contentWidth = containerWidth - ellipsisWidth;
+    preparedOpts.ellipsis = ellipsis;
+    preparedOpts.ellipsisWidth = ellipsisWidth;
+    preparedOpts.contentWidth = contentWidth;
+    preparedOpts.containerWidth = containerWidth;
+    return preparedOpts;
+  }
+
+  function truncateSingleLine(textLine, options) {
+    var containerWidth = options.containerWidth;
+    var font = options.font;
+    var contentWidth = options.contentWidth;
+
+    if (!containerWidth) {
+      return '';
+    }
+
+    var lineWidth = getWidth(textLine, font);
+
+    if (lineWidth <= containerWidth) {
+      return textLine;
+    }
+
+    for (var j = 0;; j++) {
+      if (lineWidth <= contentWidth || j >= options.maxIterations) {
+        textLine += options.ellipsis;
+        break;
+      }
+
+      var subLength = j === 0 ? estimateLength(textLine, contentWidth, options.ascCharWidth, options.cnCharWidth) : lineWidth > 0 ? Math.floor(textLine.length * contentWidth / lineWidth) : 0;
+      textLine = textLine.substr(0, subLength);
+      lineWidth = getWidth(textLine, font);
+    }
+
+    if (textLine === '') {
+      textLine = options.placeholder;
+    }
+
+    return textLine;
+  }
+
+  function estimateLength(text, contentWidth, ascCharWidth, cnCharWidth) {
+    var width = 0;
+    var i = 0;
+
+    for (var len = text.length; i < len && width < contentWidth; i++) {
+      var charCode = text.charCodeAt(i);
+      width += 0 <= charCode && charCode <= 127 ? ascCharWidth : cnCharWidth;
+    }
+
+    return i;
+  }
+
+  function parsePlainText(text, style) {
+    text != null && (text += '');
+    var overflow = style.overflow;
+    var padding = style.padding;
+    var font = style.font;
+    var truncate = overflow === 'truncate';
+    var calculatedLineHeight = getLineHeight(font);
+    var lineHeight = retrieve2(style.lineHeight, calculatedLineHeight);
+    var bgColorDrawn = !!style.backgroundColor;
+    var truncateLineOverflow = style.lineOverflow === 'truncate';
+    var width = style.width;
+    var lines;
+
+    if (width != null && (overflow === 'break' || overflow === 'breakAll')) {
+      lines = text ? wrapText(text, style.font, width, overflow === 'breakAll', 0).lines : [];
+    } else {
+      lines = text ? text.split('\n') : [];
+    }
+
+    var contentHeight = lines.length * lineHeight;
+    var height = retrieve2(style.height, contentHeight);
+
+    if (contentHeight > height && truncateLineOverflow) {
+      var lineCount = Math.floor(height / lineHeight);
+      lines = lines.slice(0, lineCount);
+    }
+
+    if (text && truncate && width != null) {
+      var options = prepareTruncateOptions(width, font, style.ellipsis, {
+        minChar: style.truncateMinChar,
+        placeholder: style.placeholder
+      });
+
+      for (var i = 0; i < lines.length; i++) {
+        lines[i] = truncateSingleLine(lines[i], options);
+      }
+    }
+
+    var outerHeight = height;
+    var contentWidth = 0;
+
+    for (var i = 0; i < lines.length; i++) {
+      contentWidth = Math.max(getWidth(lines[i], font), contentWidth);
+    }
+
+    if (width == null) {
+      width = contentWidth;
+    }
+
+    var outerWidth = contentWidth;
+
+    if (padding) {
+      outerHeight += padding[0] + padding[2];
+      outerWidth += padding[1] + padding[3];
+      width += padding[1] + padding[3];
+    }
+
+    if (bgColorDrawn) {
+      outerWidth = width;
+    }
+
+    return {
+      lines: lines,
+      height: height,
+      outerWidth: outerWidth,
+      outerHeight: outerHeight,
+      lineHeight: lineHeight,
+      calculatedLineHeight: calculatedLineHeight,
+      contentWidth: contentWidth,
+      contentHeight: contentHeight,
+      width: width
+    };
+  }
+
+  var RichTextToken = function () {
+    function RichTextToken() {}
+
+    return RichTextToken;
+  }();
+
+  var RichTextLine = function () {
+    function RichTextLine(tokens) {
+      this.tokens = [];
+
+      if (tokens) {
+        this.tokens = tokens;
+      }
+    }
+
+    return RichTextLine;
+  }();
+
+  var RichTextContentBlock = function () {
+    function RichTextContentBlock() {
+      this.width = 0;
+      this.height = 0;
+      this.contentWidth = 0;
+      this.contentHeight = 0;
+      this.outerWidth = 0;
+      this.outerHeight = 0;
+      this.lines = [];
+    }
+
+    return RichTextContentBlock;
+  }();
+
+  function parseRichText(text, style) {
+    var contentBlock = new RichTextContentBlock();
+    text != null && (text += '');
+
+    if (!text) {
+      return contentBlock;
+    }
+
+    var topWidth = style.width;
+    var topHeight = style.height;
+    var overflow = style.overflow;
+    var wrapInfo = (overflow === 'break' || overflow === 'breakAll') && topWidth != null ? {
+      width: topWidth,
+      accumWidth: 0,
+      breakAll: overflow === 'breakAll'
+    } : null;
+    var lastIndex = STYLE_REG.lastIndex = 0;
+    var result;
+
+    while ((result = STYLE_REG.exec(text)) != null) {
+      var matchedIndex = result.index;
+
+      if (matchedIndex > lastIndex) {
+        pushTokens(contentBlock, text.substring(lastIndex, matchedIndex), style, wrapInfo);
+      }
+
+      pushTokens(contentBlock, result[2], style, wrapInfo, result[1]);
+      lastIndex = STYLE_REG.lastIndex;
+    }
+
+    if (lastIndex < text.length) {
+      pushTokens(contentBlock, text.substring(lastIndex, text.length), style, wrapInfo);
+    }
+
+    var pendingList = [];
+    var calculatedHeight = 0;
+    var calculatedWidth = 0;
+    var stlPadding = style.padding;
+    var truncate = overflow === 'truncate';
+    var truncateLine = style.lineOverflow === 'truncate';
+
+    function finishLine(line, lineWidth, lineHeight) {
+      line.width = lineWidth;
+      line.lineHeight = lineHeight;
+      calculatedHeight += lineHeight;
+      calculatedWidth = Math.max(calculatedWidth, lineWidth);
+    }
+
+    outer: for (var i = 0; i < contentBlock.lines.length; i++) {
+      var line = contentBlock.lines[i];
+      var lineHeight = 0;
+      var lineWidth = 0;
+
+      for (var j = 0; j < line.tokens.length; j++) {
+        var token = line.tokens[j];
+        var tokenStyle = token.styleName && style.rich[token.styleName] || {};
+        var textPadding = token.textPadding = tokenStyle.padding;
+        var paddingH = textPadding ? textPadding[1] + textPadding[3] : 0;
+        var font = token.font = tokenStyle.font || style.font;
+        token.contentHeight = getLineHeight(font);
+        var tokenHeight = retrieve2(tokenStyle.height, token.contentHeight);
+        token.innerHeight = tokenHeight;
+        textPadding && (tokenHeight += textPadding[0] + textPadding[2]);
+        token.height = tokenHeight;
+        token.lineHeight = retrieve3(tokenStyle.lineHeight, style.lineHeight, tokenHeight);
+        token.align = tokenStyle && tokenStyle.align || style.align;
+        token.verticalAlign = tokenStyle && tokenStyle.verticalAlign || 'middle';
+
+        if (truncateLine && topHeight != null && calculatedHeight + token.lineHeight > topHeight) {
+          if (j > 0) {
+            line.tokens = line.tokens.slice(0, j);
+            finishLine(line, lineWidth, lineHeight);
+            contentBlock.lines = contentBlock.lines.slice(0, i + 1);
+          } else {
+            contentBlock.lines = contentBlock.lines.slice(0, i);
+          }
+
+          break outer;
+        }
+
+        var styleTokenWidth = tokenStyle.width;
+        var tokenWidthNotSpecified = styleTokenWidth == null || styleTokenWidth === 'auto';
+
+        if (typeof styleTokenWidth === 'string' && styleTokenWidth.charAt(styleTokenWidth.length - 1) === '%') {
+          token.percentWidth = styleTokenWidth;
+          pendingList.push(token);
+          token.contentWidth = getWidth(token.text, font);
+        } else {
+          if (tokenWidthNotSpecified) {
+            var textBackgroundColor = tokenStyle.backgroundColor;
+            var bgImg = textBackgroundColor && textBackgroundColor.image;
+
+            if (bgImg) {
+              bgImg = findExistImage(bgImg);
+
+              if (isImageReady(bgImg)) {
+                token.width = Math.max(token.width, bgImg.width * tokenHeight / bgImg.height);
+              }
+            }
+          }
+
+          var remainTruncWidth = truncate && topWidth != null ? topWidth - lineWidth : null;
+
+          if (remainTruncWidth != null && remainTruncWidth < token.width) {
+            if (!tokenWidthNotSpecified || remainTruncWidth < paddingH) {
+              token.text = '';
+              token.width = token.contentWidth = 0;
+            } else {
+              token.text = truncateText(token.text, remainTruncWidth - paddingH, font, style.ellipsis, {
+                minChar: style.truncateMinChar
+              });
+              token.width = token.contentWidth = getWidth(token.text, font);
+            }
+          } else {
+            token.contentWidth = getWidth(token.text, font);
+          }
+        }
+
+        token.width += paddingH;
+        lineWidth += token.width;
+        tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));
+      }
+
+      finishLine(line, lineWidth, lineHeight);
+    }
+
+    contentBlock.outerWidth = contentBlock.width = retrieve2(topWidth, calculatedWidth);
+    contentBlock.outerHeight = contentBlock.height = retrieve2(topHeight, calculatedHeight);
+    contentBlock.contentHeight = calculatedHeight;
+    contentBlock.contentWidth = calculatedWidth;
+
+    if (stlPadding) {
+      contentBlock.outerWidth += stlPadding[1] + stlPadding[3];
+      contentBlock.outerHeight += stlPadding[0] + stlPadding[2];
+    }
+
+    for (var i = 0; i < pendingList.length; i++) {
+      var token = pendingList[i];
+      var percentWidth = token.percentWidth;
+      token.width = parseInt(percentWidth, 10) / 100 * contentBlock.width;
+    }
+
+    return contentBlock;
+  }
+
+  function pushTokens(block, str, style, wrapInfo, styleName) {
+    var isEmptyStr = str === '';
+    var tokenStyle = styleName && style.rich[styleName] || {};
+    var lines = block.lines;
+    var font = tokenStyle.font || style.font;
+    var newLine = false;
+    var strLines;
+    var linesWidths;
+
+    if (wrapInfo) {
+      var tokenPadding = tokenStyle.padding;
+      var tokenPaddingH = tokenPadding ? tokenPadding[1] + tokenPadding[3] : 0;
+
+      if (tokenStyle.width != null && tokenStyle.width !== 'auto') {
+        var outerWidth_1 = parsePercent(tokenStyle.width, wrapInfo.width) + tokenPaddingH;
+
+        if (lines.length > 0) {
+          if (outerWidth_1 + wrapInfo.accumWidth > wrapInfo.width) {
+            strLines = str.split('\n');
+            newLine = true;
+          }
+        }
+
+        wrapInfo.accumWidth = outerWidth_1;
+      } else {
+        var res = wrapText(str, font, wrapInfo.width, wrapInfo.breakAll, wrapInfo.accumWidth);
+        wrapInfo.accumWidth = res.accumWidth + tokenPaddingH;
+        linesWidths = res.linesWidths;
+        strLines = res.lines;
+      }
+    } else {
+      strLines = str.split('\n');
+    }
+
+    for (var i = 0; i < strLines.length; i++) {
+      var text = strLines[i];
+      var token = new RichTextToken();
+      token.styleName = styleName;
+      token.text = text;
+      token.isLineHolder = !text && !isEmptyStr;
+
+      if (typeof tokenStyle.width === 'number') {
+        token.width = tokenStyle.width;
+      } else {
+        token.width = linesWidths ? linesWidths[i] : getWidth(text, font);
+      }
+
+      if (!i && !newLine) {
+        var tokens = (lines[lines.length - 1] || (lines[0] = new RichTextLine())).tokens;
+        var tokensLen = tokens.length;
+        tokensLen === 1 && tokens[0].isLineHolder ? tokens[0] = token : (text || !tokensLen || isEmptyStr) && tokens.push(token);
+      } else {
+        lines.push(new RichTextLine([token]));
+      }
+    }
+  }
+
+  function isLatin(ch) {
+    var code = ch.charCodeAt(0);
+    return code >= 0x21 && code <= 0x17F;
+  }
+
+  var breakCharMap = reduce(',&?/;] '.split(''), function (obj, ch) {
+    obj[ch] = true;
+    return obj;
+  }, {});
+
+  function isWordBreakChar(ch) {
+    if (isLatin(ch)) {
+      if (breakCharMap[ch]) {
+        return true;
+      }
+
+      return false;
+    }
+
+    return true;
+  }
+
+  function wrapText(text, font, lineWidth, isBreakAll, lastAccumWidth) {
+    var lines = [];
+    var linesWidths = [];
+    var line = '';
+    var currentWord = '';
+    var currentWordWidth = 0;
+    var accumWidth = 0;
+
+    for (var i = 0; i < text.length; i++) {
+      var ch = text.charAt(i);
+
+      if (ch === '\n') {
+        if (currentWord) {
+          line += currentWord;
+          accumWidth += currentWordWidth;
+        }
+
+        lines.push(line);
+        linesWidths.push(accumWidth);
+        line = '';
+        currentWord = '';
+        currentWordWidth = 0;
+        accumWidth = 0;
+        continue;
+      }
+
+      var chWidth = getWidth(ch, font);
+      var inWord = isBreakAll ? false : !isWordBreakChar(ch);
+
+      if (!lines.length ? lastAccumWidth + accumWidth + chWidth > lineWidth : accumWidth + chWidth > lineWidth) {
+        if (!accumWidth) {
+          if (inWord) {
+            lines.push(currentWord);
+            linesWidths.push(currentWordWidth);
+            currentWord = ch;
+            currentWordWidth = chWidth;
+          } else {
+            lines.push(ch);
+            linesWidths.push(chWidth);
+          }
+        } else if (line || currentWord) {
+          if (inWord) {
+            if (!line) {
+              line = currentWord;
+              currentWord = '';
+              currentWordWidth = 0;
+              accumWidth = currentWordWidth;
+            }
+
+            lines.push(line);
+            linesWidths.push(accumWidth - currentWordWidth);
+            currentWord += ch;
+            currentWordWidth += chWidth;
+            line = '';
+            accumWidth = currentWordWidth;
+          } else {
+            if (currentWord) {
+              line += currentWord;
+              currentWord = '';
+              currentWordWidth = 0;
+            }
+
+            lines.push(line);
+            linesWidths.push(accumWidth);
+            line = ch;
+            accumWidth = chWidth;
+          }
+        }
+
+        continue;
+      }
+
+      accumWidth += chWidth;
+
+      if (inWord) {
+        currentWord += ch;
+        currentWordWidth += chWidth;
+      } else {
+        if (currentWord) {
+          line += currentWord;
+          currentWord = '';
+          currentWordWidth = 0;
+        }
+
+        line += ch;
+      }
+    }
+
+    if (!lines.length && !line) {
+      line = text;
+      currentWord = '';
+      currentWordWidth = 0;
+    }
+
+    if (currentWord) {
+      line += currentWord;
+    }
+
+    if (line) {
+      lines.push(line);
+      linesWidths.push(accumWidth);
+    }
+
+    if (lines.length === 1) {
+      accumWidth += lastAccumWidth;
+    }
+
+    return {
+      accumWidth: accumWidth,
+      lines: lines,
+      linesWidths: linesWidths
+    };
+  }
+
+  var STYLE_MAGIC_KEY = '__zr_style_' + Math.round(Math.random() * 10);
+  var DEFAULT_COMMON_STYLE = {
+    shadowBlur: 0,
+    shadowOffsetX: 0,
+    shadowOffsetY: 0,
+    shadowColor: '#000',
+    opacity: 1,
+    blend: 'source-over'
+  };
+  var DEFAULT_COMMON_ANIMATION_PROPS = {
+    style: {
+      shadowBlur: true,
+      shadowOffsetX: true,
+      shadowOffsetY: true,
+      shadowColor: true,
+      opacity: true
+    }
+  };
+  DEFAULT_COMMON_STYLE[STYLE_MAGIC_KEY] = true;
+  var PRIMARY_STATES_KEYS$1 = ['z', 'z2', 'invisible'];
+  var PRIMARY_STATES_KEYS_IN_HOVER_LAYER = ['invisible'];
+
+  var Displayable = function (_super) {
+    __extends(Displayable, _super);
+
+    function Displayable(props) {
+      return _super.call(this, props) || this;
+    }
+
+    Displayable.prototype._init = function (props) {
+      var keysArr = keys(props);
+
+      for (var i = 0; i < keysArr.length; i++) {
+        var key = keysArr[i];
+
+        if (key === 'style') {
+          this.useStyle(props[key]);
+        } else {
+          _super.prototype.attrKV.call(this, key, props[key]);
+        }
+      }
+
+      if (!this.style) {
+        this.useStyle({});
+      }
+    };
+
+    Displayable.prototype.beforeBrush = function () {};
+
+    Displayable.prototype.afterBrush = function () {};
+
+    Displayable.prototype.innerBeforeBrush = function () {};
+
+    Displayable.prototype.innerAfterBrush = function () {};
+
+    Displayable.prototype.shouldBePainted = function (viewWidth, viewHeight, considerClipPath, considerAncestors) {
+      var m = this.transform;
+
+      if (this.ignore || this.invisible || this.style.opacity === 0 || this.culling && isDisplayableCulled(this, viewWidth, viewHeight) || m && !m[0] && !m[3]) {
+        return false;
+      }
+
+      if (considerClipPath && this.__clipPaths) {
+        for (var i = 0; i < this.__clipPaths.length; ++i) {
+          if (this.__clipPaths[i].isZeroArea()) {
+            return false;
+          }
+        }
+      }
+
+      if (considerAncestors && this.parent) {
+        var parent_1 = this.parent;
+
+        while (parent_1) {
+          if (parent_1.ignore) {
+            return false;
+          }
+
+          parent_1 = parent_1.parent;
+        }
+      }
+
+      return true;
+    };
+
+    Displayable.prototype.contain = function (x, y) {
+      return this.rectContain(x, y);
+    };
+
+    Displayable.prototype.traverse = function (cb, context) {
+      cb.call(context, this);
+    };
+
+    Displayable.prototype.rectContain = function (x, y) {
+      var coord = this.transformCoordToLocal(x, y);
+      var rect = this.getBoundingRect();
+      return rect.contain(coord[0], coord[1]);
+    };
+
+    Displayable.prototype.getPaintRect = function () {
+      var rect = this._paintRect;
+
+      if (!this._paintRect || this.__dirty) {
+        var transform = this.transform;
+        var elRect = this.getBoundingRect();
+        var style = this.style;
+        var shadowSize = style.shadowBlur || 0;
+        var shadowOffsetX = style.shadowOffsetX || 0;
+        var shadowOffsetY = style.shadowOffsetY || 0;
+        rect = this._paintRect || (this._paintRect = new BoundingRect(0, 0, 0, 0));
+
+        if (transform) {
+          BoundingRect.applyTransform(rect, elRect, transform);
+        } else {
+          rect.copy(elRect);
+        }
+
+        if (shadowSize || shadowOffsetX || shadowOffsetY) {
+          rect.width += shadowSize * 2 + Math.abs(shadowOffsetX);
+          rect.height += shadowSize * 2 + Math.abs(shadowOffsetY);
+          rect.x = Math.min(rect.x, rect.x + shadowOffsetX - shadowSize);
+          rect.y = Math.min(rect.y, rect.y + shadowOffsetY - shadowSize);
+        }
+
+        var tolerance = this.dirtyRectTolerance;
+
+        if (!rect.isZero()) {
+          rect.x = Math.floor(rect.x - tolerance);
+          rect.y = Math.floor(rect.y - tolerance);
+          rect.width = Math.ceil(rect.width + 1 + tolerance * 2);
+          rect.height = Math.ceil(rect.height + 1 + tolerance * 2);
+        }
+      }
+
+      return rect;
+    };
+
+    Displayable.prototype.setPrevPaintRect = function (paintRect) {
+      if (paintRect) {
+        this._prevPaintRect = this._prevPaintRect || new BoundingRect(0, 0, 0, 0);
+
+        this._prevPaintRect.copy(paintRect);
+      } else {
+        this._prevPaintRect = null;
+      }
+    };
+
+    Displayable.prototype.getPrevPaintRect = function () {
+      return this._prevPaintRect;
+    };
+
+    Displayable.prototype.animateStyle = function (loop) {
+      return this.animate('style', loop);
+    };
+
+    Displayable.prototype.updateDuringAnimation = function (targetKey) {
+      if (targetKey === 'style') {
+        this.dirtyStyle();
+      } else {
+        this.markRedraw();
+      }
+    };
+
+    Displayable.prototype.attrKV = function (key, value) {
+      if (key !== 'style') {
+        _super.prototype.attrKV.call(this, key, value);
+      } else {
+        if (!this.style) {
+          this.useStyle(value);
+        } else {
+          this.setStyle(value);
+        }
+      }
+    };
+
+    Displayable.prototype.setStyle = function (keyOrObj, value) {
+      if (typeof keyOrObj === 'string') {
+        this.style[keyOrObj] = value;
+      } else {
+        extend(this.style, keyOrObj);
+      }
+
+      this.dirtyStyle();
+      return this;
+    };
+
+    Displayable.prototype.dirtyStyle = function (notRedraw) {
+      if (!notRedraw) {
+        this.markRedraw();
+      }
+
+      this.__dirty |= STYLE_CHANGED_BIT;
+
+      if (this._rect) {
+        this._rect = null;
+      }
+    };
+
+    Displayable.prototype.dirty = function () {
+      this.dirtyStyle();
+    };
+
+    Displayable.prototype.styleChanged = function () {
+      return !!(this.__dirty & STYLE_CHANGED_BIT);
+    };
+
+    Displayable.prototype.styleUpdated = function () {
+      this.__dirty &= ~STYLE_CHANGED_BIT;
+    };
+
+    Displayable.prototype.createStyle = function (obj) {
+      return createObject(DEFAULT_COMMON_STYLE, obj);
+    };
+
+    Displayable.prototype.useStyle = function (obj) {
+      if (!obj[STYLE_MAGIC_KEY]) {
+        obj = this.createStyle(obj);
+      }
+
+      if (this.__inHover) {
+        this.__hoverStyle = obj;
+      } else {
+        this.style = obj;
+      }
+
+      this.dirtyStyle();
+    };
+
+    Displayable.prototype.isStyleObject = function (obj) {
+      return obj[STYLE_MAGIC_KEY];
+    };
+
+    Displayable.prototype._innerSaveToNormal = function (toState) {
+      _super.prototype._innerSaveToNormal.call(this, toState);
+
+      var normalState = this._normalState;
+
+      if (toState.style && !normalState.style) {
+        normalState.style = this._mergeStyle(this.createStyle(), this.style);
+      }
+
+      this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS$1);
+    };
+
+    Displayable.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
+      _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg);
+
+      var needsRestoreToNormal = !(state && keepCurrentStates);
+      var targetStyle;
+
+      if (state && state.style) {
+        if (transition) {
+          if (keepCurrentStates) {
+            targetStyle = state.style;
+          } else {
+            targetStyle = this._mergeStyle(this.createStyle(), normalState.style);
+
+            this._mergeStyle(targetStyle, state.style);
+          }
+        } else {
+          targetStyle = this._mergeStyle(this.createStyle(), keepCurrentStates ? this.style : normalState.style);
+
+          this._mergeStyle(targetStyle, state.style);
+        }
+      } else if (needsRestoreToNormal) {
+        targetStyle = normalState.style;
+      }
+
+      if (targetStyle) {
+        if (transition) {
+          var sourceStyle = this.style;
+          this.style = this.createStyle(needsRestoreToNormal ? {} : sourceStyle);
+
+          if (needsRestoreToNormal) {
+            var changedKeys = keys(sourceStyle);
+
+            for (var i = 0; i < changedKeys.length; i++) {
+              var key = changedKeys[i];
+
+              if (key in targetStyle) {
+                targetStyle[key] = targetStyle[key];
+                this.style[key] = sourceStyle[key];
+              }
+            }
+          }
+
+          var targetKeys = keys(targetStyle);
+
+          for (var i = 0; i < targetKeys.length; i++) {
+            var key = targetKeys[i];
+            this.style[key] = this.style[key];
+          }
+
+          this._transitionState(stateName, {
+            style: targetStyle
+          }, animationCfg, this.getAnimationStyleProps());
+        } else {
+          this.useStyle(targetStyle);
+        }
+      }
+
+      var statesKeys = this.__inHover ? PRIMARY_STATES_KEYS_IN_HOVER_LAYER : PRIMARY_STATES_KEYS$1;
+
+      for (var i = 0; i < statesKeys.length; i++) {
+        var key = statesKeys[i];
+
+        if (state && state[key] != null) {
+          this[key] = state[key];
+        } else if (needsRestoreToNormal) {
+          if (normalState[key] != null) {
+            this[key] = normalState[key];
+          }
+        }
+      }
+    };
+
+    Displayable.prototype._mergeStates = function (states) {
+      var mergedState = _super.prototype._mergeStates.call(this, states);
+
+      var mergedStyle;
+
+      for (var i = 0; i < states.length; i++) {
+        var state = states[i];
+
+        if (state.style) {
+          mergedStyle = mergedStyle || {};
+
+          this._mergeStyle(mergedStyle, state.style);
+        }
+      }
+
+      if (mergedStyle) {
+        mergedState.style = mergedStyle;
+      }
+
+      return mergedState;
+    };
+
+    Displayable.prototype._mergeStyle = function (targetStyle, sourceStyle) {
+      extend(targetStyle, sourceStyle);
+      return targetStyle;
+    };
+
+    Displayable.prototype.getAnimationStyleProps = function () {
+      return DEFAULT_COMMON_ANIMATION_PROPS;
+    };
+
+    Displayable.initDefaultProps = function () {
+      var dispProto = Displayable.prototype;
+      dispProto.type = 'displayable';
+      dispProto.invisible = false;
+      dispProto.z = 0;
+      dispProto.z2 = 0;
+      dispProto.zlevel = 0;
+      dispProto.culling = false;
+      dispProto.cursor = 'pointer';
+      dispProto.rectHover = false;
+      dispProto.incremental = false;
+      dispProto._rect = null;
+      dispProto.dirtyRectTolerance = 0;
+      dispProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT;
+    }();
+
+    return Displayable;
+  }(Element);
+
+  var tmpRect = new BoundingRect(0, 0, 0, 0);
+  var viewRect = new BoundingRect(0, 0, 0, 0);
+
+  function isDisplayableCulled(el, width, height) {
+    tmpRect.copy(el.getBoundingRect());
+
+    if (el.transform) {
+      tmpRect.applyTransform(el.transform);
+    }
+
+    viewRect.width = width;
+    viewRect.height = height;
+    return !tmpRect.intersect(viewRect);
+  }
+
+  var mathMin$2 = Math.min;
+  var mathMax$2 = Math.max;
+  var mathSin$1 = Math.sin;
+  var mathCos$1 = Math.cos;
+  var PI2$1 = Math.PI * 2;
+  var start = create();
+  var end = create();
+  var extremity = create();
+
+  function fromLine(x0, y0, x1, y1, min$$1, max$$1) {
+    min$$1[0] = mathMin$2(x0, x1);
+    min$$1[1] = mathMin$2(y0, y1);
+    max$$1[0] = mathMax$2(x0, x1);
+    max$$1[1] = mathMax$2(y0, y1);
+  }
+
+  var xDim = [];
+  var yDim = [];
+
+  function fromCubic(x0, y0, x1, y1, x2, y2, x3, y3, min$$1, max$$1) {
+    var cubicExtrema$$1 = cubicExtrema;
+    var cubicAt$$1 = cubicAt;
+    var n = cubicExtrema$$1(x0, x1, x2, x3, xDim);
+    min$$1[0] = Infinity;
+    min$$1[1] = Infinity;
+    max$$1[0] = -Infinity;
+    max$$1[1] = -Infinity;
+
+    for (var i = 0; i < n; i++) {
+      var x = cubicAt$$1(x0, x1, x2, x3, xDim[i]);
+      min$$1[0] = mathMin$2(x, min$$1[0]);
+      max$$1[0] = mathMax$2(x, max$$1[0]);
+    }
+
+    n = cubicExtrema$$1(y0, y1, y2, y3, yDim);
+
+    for (var i = 0; i < n; i++) {
+      var y = cubicAt$$1(y0, y1, y2, y3, yDim[i]);
+      min$$1[1] = mathMin$2(y, min$$1[1]);
+      max$$1[1] = mathMax$2(y, max$$1[1]);
+    }
+
+    min$$1[0] = mathMin$2(x0, min$$1[0]);
+    max$$1[0] = mathMax$2(x0, max$$1[0]);
+    min$$1[0] = mathMin$2(x3, min$$1[0]);
+    max$$1[0] = mathMax$2(x3, max$$1[0]);
+    min$$1[1] = mathMin$2(y0, min$$1[1]);
+    max$$1[1] = mathMax$2(y0, max$$1[1]);
+    min$$1[1] = mathMin$2(y3, min$$1[1]);
+    max$$1[1] = mathMax$2(y3, max$$1[1]);
+  }
+
+  function fromQuadratic(x0, y0, x1, y1, x2, y2, min$$1, max$$1) {
+    var quadraticExtremum$$1 = quadraticExtremum;
+    var quadraticAt$$1 = quadraticAt;
+    var tx = mathMax$2(mathMin$2(quadraticExtremum$$1(x0, x1, x2), 1), 0);
+    var ty = mathMax$2(mathMin$2(quadraticExtremum$$1(y0, y1, y2), 1), 0);
+    var x = quadraticAt$$1(x0, x1, x2, tx);
+    var y = quadraticAt$$1(y0, y1, y2, ty);
+    min$$1[0] = mathMin$2(x0, x2, x);
+    min$$1[1] = mathMin$2(y0, y2, y);
+    max$$1[0] = mathMax$2(x0, x2, x);
+    max$$1[1] = mathMax$2(y0, y2, y);
+  }
+
+  function fromArc(x, y, rx, ry, startAngle, endAngle, anticlockwise, min$$1, max$$1) {
+    var vec2Min = min;
+    var vec2Max = max;
+    var diff = Math.abs(startAngle - endAngle);
+
+    if (diff % PI2$1 < 1e-4 && diff > 1e-4) {
+      min$$1[0] = x - rx;
+      min$$1[1] = y - ry;
+      max$$1[0] = x + rx;
+      max$$1[1] = y + ry;
+      return;
+    }
+
+    start[0] = mathCos$1(startAngle) * rx + x;
+    start[1] = mathSin$1(startAngle) * ry + y;
+    end[0] = mathCos$1(endAngle) * rx + x;
+    end[1] = mathSin$1(endAngle) * ry + y;
+    vec2Min(min$$1, start, end);
+    vec2Max(max$$1, start, end);
+    startAngle = startAngle % PI2$1;
+
+    if (startAngle < 0) {
+      startAngle = startAngle + PI2$1;
+    }
+
+    endAngle = endAngle % PI2$1;
+
+    if (endAngle < 0) {
+      endAngle = endAngle + PI2$1;
+    }
+
+    if (startAngle > endAngle && !anticlockwise) {
+      endAngle += PI2$1;
+    } else if (startAngle < endAngle && anticlockwise) {
+      startAngle += PI2$1;
+    }
+
+    if (anticlockwise) {
+      var tmp = endAngle;
+      endAngle = startAngle;
+      startAngle = tmp;
+    }
+
+    for (var angle = 0; angle < endAngle; angle += Math.PI / 2) {
+      if (angle > startAngle) {
+        extremity[0] = mathCos$1(angle) * rx + x;
+        extremity[1] = mathSin$1(angle) * ry + y;
+        vec2Min(min$$1, extremity, min$$1);
+        vec2Max(max$$1, extremity, max$$1);
+      }
+    }
+  }
+
+  var CMD = {
+    M: 1,
+    L: 2,
+    C: 3,
+    Q: 4,
+    A: 5,
+    Z: 6,
+    R: 7
+  };
+  var tmpOutX = [];
+  var tmpOutY = [];
+  var min$1 = [];
+  var max$1 = [];
+  var min2 = [];
+  var max2 = [];
+  var mathMin$1 = Math.min;
+  var mathMax$1 = Math.max;
+  var mathCos = Math.cos;
+  var mathSin = Math.sin;
+  var mathAbs = Math.abs;
+  var PI = Math.PI;
+  var PI2 = PI * 2;
+  var hasTypedArray = typeof Float32Array !== 'undefined';
+  var tmpAngles = [];
+
+  function modPI2(radian) {
+    var n = Math.round(radian / PI * 1e8) / 1e8;
+    return n % 2 * PI;
+  }
+
+  function normalizeArcAngles(angles, anticlockwise) {
+    var newStartAngle = modPI2(angles[0]);
+
+    if (newStartAngle < 0) {
+      newStartAngle += PI2;
+    }
+
+    var delta = newStartAngle - angles[0];
+    var newEndAngle = angles[1];
+    newEndAngle += delta;
+
+    if (!anticlockwise && newEndAngle - newStartAngle >= PI2) {
+      newEndAngle = newStartAngle + PI2;
+    } else if (anticlockwise && newStartAngle - newEndAngle >= PI2) {
+      newEndAngle = newStartAngle - PI2;
+    } else if (!anticlockwise && newStartAngle > newEndAngle) {
+      newEndAngle = newStartAngle + (PI2 - modPI2(newStartAngle - newEndAngle));
+    } else if (anticlockwise && newStartAngle < newEndAngle) {
+      newEndAngle = newStartAngle - (PI2 - modPI2(newEndAngle - newStartAngle));
+    }
+
+    angles[0] = newStartAngle;
+    angles[1] = newEndAngle;
+  }
+
+  var PathProxy = function () {
+    function PathProxy(notSaveData) {
+      this.dpr = 1;
+      this._xi = 0;
+      this._yi = 0;
+      this._x0 = 0;
+      this._y0 = 0;
+      this._len = 0;
+
+      if (notSaveData) {
+        this._saveData = false;
+      }
+
+      if (this._saveData) {
+        this.data = [];
+      }
+    }
+
+    PathProxy.prototype.increaseVersion = function () {
+      this._version++;
+    };
+
+    PathProxy.prototype.getVersion = function () {
+      return this._version;
+    };
+
+    PathProxy.prototype.setScale = function (sx, sy, segmentIgnoreThreshold) {
+      segmentIgnoreThreshold = segmentIgnoreThreshold || 0;
+
+      if (segmentIgnoreThreshold > 0) {
+        this._ux = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sx) || 0;
+        this._uy = mathAbs(segmentIgnoreThreshold / devicePixelRatio / sy) || 0;
+      }
+    };
+
+    PathProxy.prototype.setDPR = function (dpr) {
+      this.dpr = dpr;
+    };
+
+    PathProxy.prototype.setContext = function (ctx) {
+      this._ctx = ctx;
+    };
+
+    PathProxy.prototype.getContext = function () {
+      return this._ctx;
+    };
+
+    PathProxy.prototype.beginPath = function () {
+      this._ctx && this._ctx.beginPath();
+      this.reset();
+      return this;
+    };
+
+    PathProxy.prototype.reset = function () {
+      if (this._saveData) {
+        this._len = 0;
+      }
+
+      if (this._pathSegLen) {
+        this._pathSegLen = null;
+        this._pathLen = 0;
+      }
+
+      this._version++;
+    };
+
+    PathProxy.prototype.moveTo = function (x, y) {
+      this._drawPendingPt();
+
+      this.addData(CMD.M, x, y);
+      this._ctx && this._ctx.moveTo(x, y);
+      this._x0 = x;
+      this._y0 = y;
+      this._xi = x;
+      this._yi = y;
+      return this;
+    };
+
+    PathProxy.prototype.lineTo = function (x, y) {
+      var dx = mathAbs(x - this._xi);
+      var dy = mathAbs(y - this._yi);
+      var exceedUnit = dx > this._ux || dy > this._uy;
+      this.addData(CMD.L, x, y);
+
+      if (this._ctx && exceedUnit) {
+        this._ctx.lineTo(x, y);
+      }
+
+      if (exceedUnit) {
+        this._xi = x;
+        this._yi = y;
+        this._pendingPtDist = 0;
+      } else {
+        var d2 = dx * dx + dy * dy;
+
+        if (d2 > this._pendingPtDist) {
+          this._pendingPtX = x;
+          this._pendingPtY = y;
+          this._pendingPtDist = d2;
+        }
+      }
+
+      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._ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
+      }
+
+      this._xi = x3;
+      this._yi = y3;
+      return this;
+    };
+
+    PathProxy.prototype.quadraticCurveTo = function (x1, y1, x2, y2) {
+      this._drawPendingPt();
+
+      this.addData(CMD.Q, x1, y1, x2, y2);
+
+      if (this._ctx) {
+        this._ctx.quadraticCurveTo(x1, y1, x2, y2);
+      }
+
+      this._xi = x2;
+      this._yi = y2;
+      return this;
+    };
+
+    PathProxy.prototype.arc = function (cx, cy, r, startAngle, endAngle, anticlockwise) {
+      this._drawPendingPt();
+
+      tmpAngles[0] = startAngle;
+      tmpAngles[1] = endAngle;
+      normalizeArcAngles(tmpAngles, anticlockwise);
+      startAngle = tmpAngles[0];
+      endAngle = tmpAngles[1];
+      var delta = endAngle - startAngle;
+      this.addData(CMD.A, cx, cy, r, r, startAngle, delta, 0, anticlockwise ? 0 : 1);
+      this._ctx && this._ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
+      this._xi = mathCos(endAngle) * r + cx;
+      this._yi = mathSin(endAngle) * r + cy;
+      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;
+    };
+
+    PathProxy.prototype.closePath = function () {
+      this._drawPendingPt();
+
+      this.addData(CMD.Z);
+      var ctx = this._ctx;
+      var x0 = this._x0;
+      var y0 = this._y0;
+
+      if (ctx) {
+        ctx.closePath();
+      }
+
+      this._xi = x0;
+      this._yi = y0;
+      return this;
+    };
+
+    PathProxy.prototype.fill = function (ctx) {
+      ctx && ctx.fill();
+      this.toStatic();
+    };
+
+    PathProxy.prototype.stroke = function (ctx) {
+      ctx && ctx.stroke();
+      this.toStatic();
+    };
+
+    PathProxy.prototype.len = function () {
+      return this._len;
+    };
+
+    PathProxy.prototype.setData = function (data) {
+      var len$$1 = data.length;
+
+      if (!(this.data && this.data.length === len$$1) && hasTypedArray) {
+        this.data = new Float32Array(len$$1);
+      }
+
+      for (var i = 0; i < len$$1; i++) {
+        this.data[i] = data[i];
+      }
+
+      this._len = len$$1;
+    };
+
+    PathProxy.prototype.appendPath = function (path) {
+      if (!(path instanceof Array)) {
+        path = [path];
+      }
+
+      var len$$1 = path.length;
+      var appendSize = 0;
+      var offset = this._len;
+
+      for (var i = 0; i < len$$1; i++) {
+        appendSize += path[i].len();
+      }
+
+      if (hasTypedArray && this.data instanceof Float32Array) {
+        this.data = new Float32Array(offset + appendSize);
+      }
+
+      for (var i = 0; i < len$$1; i++) {
+        var appendPathData = path[i].data;
+
+        for (var k = 0; k < appendPathData.length; k++) {
+          this.data[offset++] = appendPathData[k];
+        }
+      }
+
+      this._len = offset;
+    };
+
+    PathProxy.prototype.addData = function (cmd, a, b, c, d, e, f, g, h) {
+      if (!this._saveData) {
+        return;
+      }
+
+      var data = this.data;
+
+      if (this._len + arguments.length > data.length) {
+        this._expandData();
+
+        data = this.data;
+      }
+
+      for (var i = 0; i < arguments.length; i++) {
+        data[this._len++] = arguments[i];
+      }
+    };
+
+    PathProxy.prototype._drawPendingPt = function () {
+      if (this._pendingPtDist > 0) {
+        this._ctx && this._ctx.lineTo(this._pendingPtX, this._pendingPtY);
+        this._pendingPtDist = 0;
+      }
+    };
+
+    PathProxy.prototype._expandData = function () {
+      if (!(this.data instanceof Array)) {
+        var newData = [];
+
+        for (var i = 0; i < this._len; i++) {
+          newData[i] = this.data[i];
+        }
+
+        this.data = newData;
+      }
+    };
+
+    PathProxy.prototype.toStatic = function () {
+      if (!this._saveData) {
+        return;
+      }
+
+      this._drawPendingPt();
+
+      var data = this.data;
+
+      if (data instanceof Array) {
+        data.length = this._len;
+
+        if (hasTypedArray && this._len > 11) {
+          this.data = new Float32Array(data);
+        }
+      }
+    };
+
+    PathProxy.prototype.getBoundingRect = function () {
+      min$1[0] = min$1[1] = min2[0] = min2[1] = Number.MAX_VALUE;
+      max$1[0] = max$1[1] = max2[0] = max2[1] = -Number.MAX_VALUE;
+      var data = this.data;
+      var xi = 0;
+      var yi = 0;
+      var x0 = 0;
+      var y0 = 0;
+      var i;
+
+      for (i = 0; i < this._len;) {
+        var cmd = data[i++];
+        var isFirst = i === 1;
+
+        if (isFirst) {
+          xi = data[i];
+          yi = data[i + 1];
+          x0 = xi;
+          y0 = yi;
+        }
+
+        switch (cmd) {
+          case CMD.M:
+            xi = x0 = data[i++];
+            yi = y0 = data[i++];
+            min2[0] = x0;
+            min2[1] = y0;
+            max2[0] = x0;
+            max2[1] = y0;
+            break;
+
+          case CMD.L:
+            fromLine(xi, yi, data[i], data[i + 1], min2, max2);
+            xi = data[i++];
+            yi = data[i++];
+            break;
+
+          case CMD.C:
+            fromCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], min2, max2);
+            xi = data[i++];
+            yi = data[i++];
+            break;
+
+          case CMD.Q:
+            fromQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], min2, max2);
+            xi = data[i++];
+            yi = data[i++];
+            break;
+
+          case CMD.A:
+            var cx = data[i++];
+            var cy = data[i++];
+            var rx = data[i++];
+            var ry = data[i++];
+            var startAngle = data[i++];
+            var endAngle = data[i++] + startAngle;
+            i += 1;
+            var anticlockwise = !data[i++];
+
+            if (isFirst) {
+              x0 = mathCos(startAngle) * rx + cx;
+              y0 = mathSin(startAngle) * ry + cy;
+            }
+
+            fromArc(cx, cy, rx, ry, startAngle, endAngle, anticlockwise, min2, max2);
+            xi = mathCos(endAngle) * rx + cx;
+            yi = mathSin(endAngle) * ry + cy;
+            break;
+
+          case CMD.R:
+            x0 = xi = data[i++];
+            y0 = yi = data[i++];
+            var width = data[i++];
+            var height = data[i++];
+            fromLine(x0, y0, x0 + width, y0 + height, min2, max2);
+            break;
+
+          case CMD.Z:
+            xi = x0;
+            yi = y0;
+            break;
+        }
+
+        min(min$1, min$1, min2);
+        max(max$1, max$1, max2);
+      }
+
+      if (i === 0) {
+        min$1[0] = min$1[1] = max$1[0] = max$1[1] = 0;
+      }
+
+      return new BoundingRect(min$1[0], min$1[1], max$1[0] - min$1[0], max$1[1] - min$1[1]);
+    };
+
+    PathProxy.prototype._calculateLength = function () {
+      var data = this.data;
+      var len$$1 = this._len;
+      var ux = this._ux;
+      var uy = this._uy;
+      var xi = 0;
+      var yi = 0;
+      var x0 = 0;
+      var y0 = 0;
+
+      if (!this._pathSegLen) {
+        this._pathSegLen = [];
+      }
+
+      var pathSegLen = this._pathSegLen;
+      var pathTotalLen = 0;
+      var segCount = 0;
+
+      for (var i = 0; i < len$$1;) {
+        var cmd = data[i++];
+        var isFirst = i === 1;
+
+        if (isFirst) {
+          xi = data[i];
+          yi = data[i + 1];
+          x0 = xi;
+          y0 = yi;
+        }
+
+        var l = -1;
+
+        switch (cmd) {
+          case CMD.M:
+            xi = x0 = data[i++];
+            yi = y0 = data[i++];
+            break;
+
+          case CMD.L:
+            {
+              var x2 = data[i++];
+              var y2 = data[i++];
+              var dx = x2 - xi;
+              var dy = y2 - yi;
+
+              if (mathAbs(dx) > ux || mathAbs(dy) > uy || i === len$$1 - 1) {
+                l = Math.sqrt(dx * dx + dy * dy);
+                xi = x2;
+                yi = y2;
+              }
+
+              break;
+            }
+
+          case CMD.C:
+            {
+              var x1 = data[i++];
+              var y1 = data[i++];
+              var x2 = data[i++];
+              var y2 = data[i++];
+              var x3 = data[i++];
+              var y3 = data[i++];
+              l = cubicLength(xi, yi, x1, y1, x2, y2, x3, y3, 10);
+              xi = x3;
+              yi = y3;
+              break;
+            }
+
+          case CMD.Q:
+            {
+              var x1 = data[i++];
+              var y1 = data[i++];
+              var x2 = data[i++];
+              var y2 = data[i++];
+              l = quadraticLength(xi, yi, x1, y1, x2, y2, 10);
+              xi = x2;
+              yi = y2;
+              break;
+            }
+
+          case CMD.A:
+            var cx = data[i++];
+            var cy = data[i++];
+            var rx = data[i++];
+            var ry = data[i++];
+            var startAngle = data[i++];
+            var delta = data[i++];
+            var endAngle = delta + startAngle;
+            i += 1;
+            var anticlockwise = !data[i++];
+
+            if (isFirst) {
+              x0 = mathCos(startAngle) * rx + cx;
+              y0 = mathSin(startAngle) * ry + cy;
+            }
+
+            l = mathMax$1(rx, ry) * mathMin$1(PI2, Math.abs(delta));
+            xi = mathCos(endAngle) * rx + cx;
+            yi = mathSin(endAngle) * ry + cy;
+            break;
+
+          case CMD.R:
+            {
+              x0 = xi = data[i++];
+              y0 = yi = data[i++];
+              var width = data[i++];
+              var height = data[i++];
+              l = width * 2 + height * 2;
+              break;
+            }
+
+          case CMD.Z:
+            {
+              var dx = x0 - xi;
+              var dy = y0 - yi;
+              l = Math.sqrt(dx * dx + dy * dy);
+              xi = x0;
+              yi = y0;
+              break;
+            }
+        }
+
+        if (l >= 0) {
+          pathSegLen[segCount++] = l;
+          pathTotalLen += l;
+        }
+      }
+
+      this._pathLen = pathTotalLen;
+      return pathTotalLen;
+    };
+
+    PathProxy.prototype.rebuildPath = function (ctx, percent) {
+      var d = this.data;
+      var ux = this._ux;
+      var uy = this._uy;
+      var len$$1 = this._len;
+      var x0;
+      var y0;
+      var xi;
+      var yi;
+      var x;
+      var y;
+      var drawPart = percent < 1;
+      var pathSegLen;
+      var pathTotalLen;
+      var accumLength = 0;
+      var segCount = 0;
+      var displayedLength;
+      var pendingPtDist = 0;
+      var pendingPtX;
+      var pendingPtY;
+
+      if (drawPart) {
+        if (!this._pathSegLen) {
+          this._calculateLength();
+        }
+
+        pathSegLen = this._pathSegLen;
+        pathTotalLen = this._pathLen;
+        displayedLength = percent * pathTotalLen;
+
+        if (!displayedLength) {
+          return;
+        }
+      }
+
+      lo: for (var i = 0; i < len$$1;) {
+        var cmd = d[i++];
+        var isFirst = i === 1;
+
+        if (isFirst) {
+          xi = d[i];
+          yi = d[i + 1];
+          x0 = xi;
+          y0 = yi;
+        }
+
+        if (cmd !== CMD.L && pendingPtDist > 0) {
+          ctx.lineTo(pendingPtX, pendingPtY);
+          pendingPtDist = 0;
+        }
+
+        switch (cmd) {
+          case CMD.M:
+            x0 = xi = d[i++];
+            y0 = yi = d[i++];
+            ctx.moveTo(xi, yi);
+            break;
+
+          case CMD.L:
+            {
+              x = d[i++];
+              y = d[i++];
+              var dx = mathAbs(x - xi);
+              var dy = mathAbs(y - yi);
+
+              if (dx > ux || dy > uy) {
+                if (drawPart) {
+                  var l = pathSegLen[segCount++];
+
+                  if (accumLength + l > displayedLength) {
+                    var t = (displayedLength - accumLength) / l;
+                    ctx.lineTo(xi * (1 - t) + x * t, yi * (1 - t) + y * t);
+                    break lo;
+                  }
+
+                  accumLength += l;
+                }
+
+                ctx.lineTo(x, y);
+                xi = x;
+                yi = y;
+                pendingPtDist = 0;
+              } else {
+                var d2 = dx * dx + dy * dy;
+
+                if (d2 > pendingPtDist) {
+                  pendingPtX = x;
+                  pendingPtY = y;
+                  pendingPtDist = d2;
+                }
+              }
+
+              break;
+            }
+
+          case CMD.C:
+            {
+              var x1 = d[i++];
+              var y1 = d[i++];
+              var x2 = d[i++];
+              var y2 = d[i++];
+              var x3 = d[i++];
+              var y3 = d[i++];
+
+              if (drawPart) {
+                var l = pathSegLen[segCount++];
+
+                if (accumLength + l > displayedLength) {
+                  var t = (displayedLength - accumLength) / l;
+                  cubicSubdivide(xi, x1, x2, x3, t, tmpOutX);
+                  cubicSubdivide(yi, y1, y2, y3, t, tmpOutY);
+                  ctx.bezierCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2], tmpOutX[3], tmpOutY[3]);
+                  break lo;
+                }
+
+                accumLength += l;
+              }
+
+              ctx.bezierCurveTo(x1, y1, x2, y2, x3, y3);
+              xi = x3;
+              yi = y3;
+              break;
+            }
+
+          case CMD.Q:
+            {
+              var x1 = d[i++];
+              var y1 = d[i++];
+              var x2 = d[i++];
+              var y2 = d[i++];
+
+              if (drawPart) {
+                var l = pathSegLen[segCount++];
+
+                if (accumLength + l > displayedLength) {
+                  var t = (displayedLength - accumLength) / l;
+                  quadraticSubdivide(xi, x1, x2, t, tmpOutX);
+                  quadraticSubdivide(yi, y1, y2, t, tmpOutY);
+                  ctx.quadraticCurveTo(tmpOutX[1], tmpOutY[1], tmpOutX[2], tmpOutY[2]);
+                  break lo;
+                }
+
+                accumLength += l;
+              }
+
+              ctx.quadraticCurveTo(x1, y1, x2, y2);
+              xi = x2;
+              yi = y2;
+              break;
+            }
+
+          case CMD.A:
+            var cx = d[i++];
+            var cy = d[i++];
+            var rx = d[i++];
+            var ry = d[i++];
+            var startAngle = d[i++];
+            var delta = d[i++];
+            var psi = d[i++];
+            var anticlockwise = !d[i++];
+            var r = rx > ry ? rx : ry;
+            var isEllipse = mathAbs(rx - ry) > 1e-3;
+            var endAngle = startAngle + delta;
+            var breakBuild = false;
+
+            if (drawPart) {
+              var l = pathSegLen[segCount++];
+
+              if (accumLength + l > displayedLength) {
+                endAngle = startAngle + delta * (displayedLength - accumLength) / l;
+                breakBuild = true;
+              }
+
+              accumLength += l;
+            }
+
+            if (isEllipse && ctx.ellipse) {
+              ctx.ellipse(cx, cy, rx, ry, psi, startAngle, endAngle, anticlockwise);
+            } else {
+              ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise);
+            }
+
+            if (breakBuild) {
+              break lo;
+            }
+
+            if (isFirst) {
+              x0 = mathCos(startAngle) * rx + cx;
+              y0 = mathSin(startAngle) * ry + cy;
+            }
+
+            xi = mathCos(endAngle) * rx + cx;
+            yi = mathSin(endAngle) * ry + cy;
+            break;
+
+          case CMD.R:
+            x0 = xi = d[i];
+            y0 = yi = d[i + 1];
+            x = d[i++];
+            y = d[i++];
+            var width = d[i++];
+            var height = d[i++];
+
+            if (drawPart) {
+              var l = pathSegLen[segCount++];
+
+              if (accumLength + l > displayedLength) {
+                var d_1 = displayedLength - accumLength;
+                ctx.moveTo(x, y);
+                ctx.lineTo(x + mathMin$1(d_1, width), y);
+                d_1 -= width;
+
+                if (d_1 > 0) {
+                  ctx.lineTo(x + width, y + mathMin$1(d_1, height));
+                }
+
+                d_1 -= height;
+
+                if (d_1 > 0) {
+                  ctx.lineTo(x + mathMax$1(width - d_1, 0), y + height);
+                }
+
+                d_1 -= width;
+
+                if (d_1 > 0) {
+                  ctx.lineTo(x, y + mathMax$1(height - d_1, 0));
+                }
+
+                break lo;
+              }
+
+              accumLength += l;
+            }
+
+            ctx.rect(x, y, width, height);
+            break;
+
+          case CMD.Z:
+            if (drawPart) {
+              var l = pathSegLen[segCount++];
+
+              if (accumLength + l > displayedLength) {
+                var t = (displayedLength - accumLength) / l;
+                ctx.lineTo(xi * (1 - t) + x0 * t, yi * (1 - t) + y0 * t);
+                break lo;
+              }
+
+              accumLength += l;
+            }
+
+            ctx.closePath();
+            xi = x0;
+            yi = y0;
+        }
+      }
+    };
+
+    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;
+      proto._saveData = true;
+      proto._ux = 0;
+      proto._uy = 0;
+      proto._pendingPtDist = 0;
+      proto._version = 0;
+    }();
+
+    return PathProxy;
+  }();
+
+  function containStroke$1(x0, y0, x1, y1, lineWidth, x, y) {
+    if (lineWidth === 0) {
+      return false;
+    }
+
+    var _l = lineWidth;
+    var _a = 0;
+    var _b = x0;
+
+    if (y > y0 + _l && y > y1 + _l || y < y0 - _l && y < y1 - _l || x > x0 + _l && x > x1 + _l || x < x0 - _l && x < x1 - _l) {
+      return false;
+    }
+
+    if (x0 !== x1) {
+      _a = (y0 - y1) / (x0 - x1);
+      _b = (x0 * y1 - x1 * y0) / (x0 - x1);
+    } else {
+      return Math.abs(x - x0) <= _l / 2;
+    }
+
+    var tmp = _a * x - y + _b;
+
+    var _s = tmp * tmp / (_a * _a + 1);
+
+    return _s <= _l / 2 * _l / 2;
+  }
+
+  function containStroke$2(x0, y0, x1, y1, x2, y2, x3, y3, lineWidth, x, y) {
+    if (lineWidth === 0) {
+      return false;
+    }
+
+    var _l = lineWidth;
+
+    if (y > y0 + _l && y > y1 + _l && y > y2 + _l && y > y3 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l && y < y3 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l && x > x3 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l && x < x3 - _l) {
+      return false;
+    }
+
+    var d = cubicProjectPoint(x0, y0, x1, y1, x2, y2, x3, y3, x, y, null);
+    return d <= _l / 2;
+  }
+
+  function containStroke$3(x0, y0, x1, y1, x2, y2, lineWidth, x, y) {
+    if (lineWidth === 0) {
+      return false;
+    }
+
+    var _l = lineWidth;
+
+    if (y > y0 + _l && y > y1 + _l && y > y2 + _l || y < y0 - _l && y < y1 - _l && y < y2 - _l || x > x0 + _l && x > x1 + _l && x > x2 + _l || x < x0 - _l && x < x1 - _l && x < x2 - _l) {
+      return false;
+    }
+
+    var d = quadraticProjectPoint(x0, y0, x1, y1, x2, y2, x, y, null);
+    return d <= _l / 2;
+  }
+
+  var PI2$4 = Math.PI * 2;
+
+  function normalizeRadian(angle) {
+    angle %= PI2$4;
+
+    if (angle < 0) {
+      angle += PI2$4;
+    }
+
+    return angle;
+  }
+
+  var PI2$3 = Math.PI * 2;
+
+  function containStroke$4(cx, cy, r, startAngle, endAngle, anticlockwise, lineWidth, x, y) {
+    if (lineWidth === 0) {
+      return false;
+    }
+
+    var _l = lineWidth;
+    x -= cx;
+    y -= cy;
+    var d = Math.sqrt(x * x + y * y);
+
+    if (d - _l > r || d + _l < r) {
+      return false;
+    }
+
+    if (Math.abs(startAngle - endAngle) % PI2$3 < 1e-4) {
+      return true;
+    }
+
+    if (anticlockwise) {
+      var tmp = startAngle;
+      startAngle = normalizeRadian(endAngle);
+      endAngle = normalizeRadian(tmp);
+    } else {
+      startAngle = normalizeRadian(startAngle);
+      endAngle = normalizeRadian(endAngle);
+    }
+
+    if (startAngle > endAngle) {
+      endAngle += PI2$3;
+    }
+
+    var angle = Math.atan2(y, x);
+
+    if (angle < 0) {
+      angle += PI2$3;
+    }
+
+    return angle >= startAngle && angle <= endAngle || angle + PI2$3 >= startAngle && angle + PI2$3 <= endAngle;
+  }
+
+  function windingLine(x0, y0, x1, y1, x, y) {
+    if (y > y0 && y > y1 || y < y0 && y < y1) {
+      return 0;
+    }
+
+    if (y1 === y0) {
+      return 0;
+    }
+
+    var t = (y - y0) / (y1 - y0);
+    var dir = y1 < y0 ? 1 : -1;
+
+    if (t === 1 || t === 0) {
+      dir = y1 < y0 ? 0.5 : -0.5;
+    }
+
+    var x_ = t * (x1 - x0) + x0;
+    return x_ === x ? Infinity : x_ > x ? dir : 0;
+  }
+
+  var CMD$1 = PathProxy.CMD;
+  var PI2$2 = Math.PI * 2;
+  var EPSILON$3 = 1e-4;
+
+  function isAroundEqual(a, b) {
+    return Math.abs(a - b) < EPSILON$3;
+  }
+
+  var roots = [-1, -1, -1];
+  var extrema = [-1, -1];
+
+  function swapExtrema() {
+    var tmp = extrema[0];
+    extrema[0] = extrema[1];
+    extrema[1] = tmp;
+  }
+
+  function windingCubic(x0, y0, x1, y1, x2, y2, x3, y3, x, y) {
+    if (y > y0 && y > y1 && y > y2 && y > y3 || y < y0 && y < y1 && y < y2 && y < y3) {
+      return 0;
+    }
+
+    var nRoots = cubicRootAt(y0, y1, y2, y3, y, roots);
+
+    if (nRoots === 0) {
+      return 0;
+    } else {
+      var w = 0;
+      var nExtrema = -1;
+      var y0_ = void 0;
+      var y1_ = void 0;
+
+      for (var i = 0; i < nRoots; i++) {
+        var t = roots[i];
+        var unit = t === 0 || t === 1 ? 0.5 : 1;
+        var x_ = cubicAt(x0, x1, x2, x3, t);
+
+        if (x_ < x) {
+          continue;
+        }
+
+        if (nExtrema < 0) {
+          nExtrema = cubicExtrema(y0, y1, y2, y3, extrema);
+
+          if (extrema[1] < extrema[0] && nExtrema > 1) {
+            swapExtrema();
+          }
+
+          y0_ = cubicAt(y0, y1, y2, y3, extrema[0]);
+
+          if (nExtrema > 1) {
+            y1_ = cubicAt(y0, y1, y2, y3, extrema[1]);
+          }
+        }
+
+        if (nExtrema === 2) {
+          if (t < extrema[0]) {
+            w += y0_ < y0 ? unit : -unit;
+          } else if (t < extrema[1]) {
+            w += y1_ < y0_ ? unit : -unit;
+          } else {
+            w += y3 < y1_ ? unit : -unit;
+          }
+        } else {
+          if (t < extrema[0]) {
+            w += y0_ < y0 ? unit : -unit;
+          } else {
+            w += y3 < y0_ ? unit : -unit;
+          }
+        }
+      }
+
+      return w;
+    }
+  }
+
+  function windingQuadratic(x0, y0, x1, y1, x2, y2, x, y) {
+    if (y > y0 && y > y1 && y > y2 || y < y0 && y < y1 && y < y2) {
+      return 0;
+    }
+
+    var nRoots = quadraticRootAt(y0, y1, y2, y, roots);
+
+    if (nRoots === 0) {
+      return 0;
+    } else {
+      var t = quadraticExtremum(y0, y1, y2);
+
+      if (t >= 0 && t <= 1) {
+        var w = 0;
+        var y_ = quadraticAt(y0, y1, y2, t);
+
+        for (var i = 0; i < nRoots; i++) {
+          var unit = roots[i] === 0 || roots[i] === 1 ? 0.5 : 1;
+          var x_ = quadraticAt(x0, x1, x2, roots[i]);
+
+          if (x_ < x) {
+            continue;
+          }
+
+          if (roots[i] < t) {
+            w += y_ < y0 ? unit : -unit;
+          } else {
+            w += y2 < y_ ? unit : -unit;
+          }
+        }
+
+        return w;
+      } else {
+        var unit = roots[0] === 0 || roots[0] === 1 ? 0.5 : 1;
+        var x_ = quadraticAt(x0, x1, x2, roots[0]);
+
+        if (x_ < x) {
+          return 0;
+        }
+
+        return y2 < y0 ? unit : -unit;
+      }
+    }
+  }
+
+  function windingArc(cx, cy, r, startAngle, endAngle, anticlockwise, x, y) {
+    y -= cy;
+
+    if (y > r || y < -r) {
+      return 0;
+    }
+
+    var tmp = Math.sqrt(r * r - y * y);
+    roots[0] = -tmp;
+    roots[1] = tmp;
+    var dTheta = Math.abs(startAngle - endAngle);
+
+    if (dTheta < 1e-4) {
+      return 0;
+    }
+
+    if (dTheta >= PI2$2 - 1e-4) {
+      startAngle = 0;
+      endAngle = PI2$2;
+      var dir = anticlockwise ? 1 : -1;
+
+      if (x >= roots[0] + cx && x <= roots[1] + cx) {
+        return dir;
+      } else {
+        return 0;
+      }
+    }
+
+    if (startAngle > endAngle) {
+      var tmp_1 = startAngle;
+      startAngle = endAngle;
+      endAngle = tmp_1;
+    }
+
+    if (startAngle < 0) {
+      startAngle += PI2$2;
+      endAngle += PI2$2;
+    }
+
+    var w = 0;
+
+    for (var i = 0; i < 2; i++) {
+      var x_ = roots[i];
+
+      if (x_ + cx > x) {
+        var angle = Math.atan2(y, x_);
+        var dir = anticlockwise ? 1 : -1;
+
+        if (angle < 0) {
+          angle = PI2$2 + angle;
+        }
+
+        if (angle >= startAngle && angle <= endAngle || angle + PI2$2 >= startAngle && angle + PI2$2 <= endAngle) {
+          if (angle > Math.PI / 2 && angle < Math.PI * 1.5) {
+            dir = -dir;
+          }
+
+          w += dir;
+        }
+      }
+    }
+
+    return w;
+  }
+
+  function containPath(path, lineWidth, isStroke, x, y) {
+    var data = path.data;
+    var len = path.len();
+    var w = 0;
+    var xi = 0;
+    var yi = 0;
+    var x0 = 0;
+    var y0 = 0;
+    var x1;
+    var y1;
+
+    for (var i = 0; i < len;) {
+      var cmd = data[i++];
+      var isFirst = i === 1;
+
+      if (cmd === CMD$1.M && i > 1) {
+        if (!isStroke) {
+          w += windingLine(xi, yi, x0, y0, x, y);
+        }
+      }
+
+      if (isFirst) {
+        xi = data[i];
+        yi = data[i + 1];
+        x0 = xi;
+        y0 = yi;
+      }
+
+      switch (cmd) {
+        case CMD$1.M:
+          x0 = data[i++];
+          y0 = data[i++];
+          xi = x0;
+          yi = y0;
+          break;
+
+        case CMD$1.L:
+          if (isStroke) {
+            if (containStroke$1(xi, yi, data[i], data[i + 1], lineWidth, x, y)) {
+              return true;
+            }
+          } else {
+            w += windingLine(xi, yi, data[i], data[i + 1], x, y) || 0;
+          }
+
+          xi = data[i++];
+          yi = data[i++];
+          break;
+
+        case CMD$1.C:
+          if (isStroke) {
+            if (containStroke$2(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
+              return true;
+            }
+          } else {
+            w += windingCubic(xi, yi, data[i++], data[i++], data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
+          }
+
+          xi = data[i++];
+          yi = data[i++];
+          break;
+
+        case CMD$1.Q:
+          if (isStroke) {
+            if (containStroke$3(xi, yi, data[i++], data[i++], data[i], data[i + 1], lineWidth, x, y)) {
+              return true;
+            }
+          } else {
+            w += windingQuadratic(xi, yi, data[i++], data[i++], data[i], data[i + 1], x, y) || 0;
+          }
+
+          xi = data[i++];
+          yi = data[i++];
+          break;
+
+        case CMD$1.A:
+          var cx = data[i++];
+          var cy = data[i++];
+          var rx = data[i++];
+          var ry = data[i++];
+          var theta = data[i++];
+          var dTheta = data[i++];
+          i += 1;
+          var anticlockwise = !!(1 - data[i++]);
+          x1 = Math.cos(theta) * rx + cx;
+          y1 = Math.sin(theta) * ry + cy;
+
+          if (!isFirst) {
+            w += windingLine(xi, yi, x1, y1, x, y);
+          } else {
+            x0 = x1;
+            y0 = y1;
+          }
+
+          var _x = (x - cx) * ry / rx + cx;
+
+          if (isStroke) {
+            if (containStroke$4(cx, cy, ry, theta, theta + dTheta, anticlockwise, lineWidth, _x, y)) {
+              return true;
+            }
+          } else {
+            w += windingArc(cx, cy, ry, theta, theta + dTheta, anticlockwise, _x, y);
+          }
+
+          xi = Math.cos(theta + dTheta) * rx + cx;
+          yi = Math.sin(theta + dTheta) * ry + cy;
+          break;
+
+        case CMD$1.R:
+          x0 = xi = data[i++];
+          y0 = yi = data[i++];
+          var width = data[i++];
+          var height = data[i++];
+          x1 = x0 + width;
+          y1 = y0 + height;
+
+          if (isStroke) {
+            if (containStroke$1(x0, y0, x1, y0, lineWidth, x, y) || containStroke$1(x1, y0, x1, y1, lineWidth, x, y) || containStroke$1(x1, y1, x0, y1, lineWidth, x, y) || containStroke$1(x0, y1, x0, y0, lineWidth, x, y)) {
+              return true;
+            }
+          } else {
+            w += windingLine(x1, y0, x1, y1, x, y);
+            w += windingLine(x0, y1, x0, y0, x, y);
+          }
+
+          break;
+
+        case CMD$1.Z:
+          if (isStroke) {
+            if (containStroke$1(xi, yi, x0, y0, lineWidth, x, y)) {
+              return true;
+            }
+          } else {
+            w += windingLine(xi, yi, x0, y0, x, y);
+          }
+
+          xi = x0;
+          yi = y0;
+          break;
+      }
+    }
+
+    if (!isStroke && !isAroundEqual(yi, y0)) {
+      w += windingLine(xi, yi, x0, y0, x, y) || 0;
+    }
+
+    return w !== 0;
+  }
+
+  function contain(pathProxy, x, y) {
+    return containPath(pathProxy, 0, false, x, y);
+  }
+
+  function containStroke(pathProxy, lineWidth, x, y) {
+    return containPath(pathProxy, lineWidth, true, x, y);
+  }
+
+  var DEFAULT_PATH_STYLE = defaults({
+    fill: '#000',
+    stroke: null,
+    strokePercent: 1,
+    fillOpacity: 1,
+    strokeOpacity: 1,
+    lineDashOffset: 0,
+    lineWidth: 1,
+    lineCap: 'butt',
+    miterLimit: 10,
+    strokeNoScale: false,
+    strokeFirst: false
+  }, DEFAULT_COMMON_STYLE);
+  var DEFAULT_PATH_ANIMATION_PROPS = {
+    style: defaults({
+      fill: true,
+      stroke: true,
+      strokePercent: true,
+      fillOpacity: true,
+      strokeOpacity: true,
+      lineDashOffset: true,
+      lineWidth: true,
+      miterLimit: true
+    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
+  };
+  var pathCopyParams = TRANSFORMABLE_PROPS.concat(['invisible', 'culling', 'z', 'z2', 'zlevel', 'parent']);
+
+  var Path = function (_super) {
+    __extends(Path, _super);
+
+    function Path(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Path.prototype.update = function () {
+      var _this = this;
+
+      _super.prototype.update.call(this);
+
+      var style = this.style;
+
+      if (style.decal) {
+        var decalEl = this._decalEl = this._decalEl || new Path();
+
+        if (decalEl.buildPath === Path.prototype.buildPath) {
+          decalEl.buildPath = function (ctx) {
+            _this.buildPath(ctx, _this.shape);
+          };
+        }
+
+        decalEl.silent = true;
+        var decalElStyle = decalEl.style;
+
+        for (var key in style) {
+          if (decalElStyle[key] !== style[key]) {
+            decalElStyle[key] = style[key];
+          }
+        }
+
+        decalElStyle.fill = style.fill ? style.decal : null;
+        decalElStyle.decal = null;
+        decalElStyle.shadowColor = null;
+        style.strokeFirst && (decalElStyle.stroke = null);
+
+        for (var i = 0; i < pathCopyParams.length; ++i) {
+          decalEl[pathCopyParams[i]] = this[pathCopyParams[i]];
+        }
+
+        decalEl.__dirty |= REDRAW_BIT;
+      } else if (this._decalEl) {
+        this._decalEl = null;
+      }
+    };
+
+    Path.prototype.getDecalElement = function () {
+      return this._decalEl;
+    };
+
+    Path.prototype._init = function (props) {
+      var keysArr = keys(props);
+      this.shape = this.getDefaultShape();
+      var defaultStyle = this.getDefaultStyle();
+
+      if (defaultStyle) {
+        this.useStyle(defaultStyle);
+      }
+
+      for (var i = 0; i < keysArr.length; i++) {
+        var key = keysArr[i];
+        var value = props[key];
+
+        if (key === 'style') {
+          if (!this.style) {
+            this.useStyle(value);
+          } else {
+            extend(this.style, value);
+          }
+        } else if (key === 'shape') {
+          extend(this.shape, value);
+        } else {
+          _super.prototype.attrKV.call(this, key, value);
+        }
+      }
+
+      if (!this.style) {
+        this.useStyle({});
+      }
+    };
+
+    Path.prototype.getDefaultStyle = function () {
+      return null;
+    };
+
+    Path.prototype.getDefaultShape = function () {
+      return {};
+    };
+
+    Path.prototype.canBeInsideText = function () {
+      return this.hasFill();
+    };
+
+    Path.prototype.getInsideTextFill = function () {
+      var pathFill = this.style.fill;
+
+      if (pathFill !== 'none') {
+        if (isString(pathFill)) {
+          var fillLum = lum(pathFill, 0);
+
+          if (fillLum > 0.5) {
+            return DARK_LABEL_COLOR;
+          } else if (fillLum > 0.2) {
+            return LIGHTER_LABEL_COLOR;
+          }
+
+          return LIGHT_LABEL_COLOR;
+        } else if (pathFill) {
+          return LIGHT_LABEL_COLOR;
+        }
+      }
+
+      return DARK_LABEL_COLOR;
+    };
+
+    Path.prototype.getInsideTextStroke = function (textFill) {
+      var pathFill = this.style.fill;
+
+      if (isString(pathFill)) {
+        var zr = this.__zr;
+        var isDarkMode = !!(zr && zr.isDarkMode());
+        var isDarkLabel = lum(textFill, 0) < DARK_MODE_THRESHOLD;
+
+        if (isDarkMode === isDarkLabel) {
+          return pathFill;
+        }
+      }
+    };
+
+    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);
+    };
+
+    Path.prototype.hasStroke = function () {
+      var style = this.style;
+      var stroke = style.stroke;
+      return !(stroke == null || stroke === 'none' || !(style.lineWidth > 0));
+    };
+
+    Path.prototype.hasFill = function () {
+      var style = this.style;
+      var fill = style.fill;
+      return fill != null && fill !== 'none';
+    };
+
+    Path.prototype.getBoundingRect = function () {
+      var rect = this._rect;
+      var style = this.style;
+      var needsUpdateRect = !rect;
+
+      if (needsUpdateRect) {
+        var firstInvoke = false;
+
+        if (!this.path) {
+          firstInvoke = true;
+          this.createPathProxy();
+        }
+
+        var path = this.path;
+
+        if (firstInvoke || this.__dirty & SHAPE_CHANGED_BIT) {
+          path.beginPath();
+          this.buildPath(path, this.shape, false);
+          this.pathUpdated();
+        }
+
+        rect = path.getBoundingRect();
+      }
+
+      this._rect = rect;
+
+      if (this.hasStroke() && this.path && this.path.len() > 0) {
+        var rectStroke = this._rectStroke || (this._rectStroke = rect.clone());
+
+        if (this.__dirty || needsUpdateRect) {
+          rectStroke.copy(rect);
+          var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
+          var w = style.lineWidth;
+
+          if (!this.hasFill()) {
+            var strokeContainThreshold = this.strokeContainThreshold;
+            w = Math.max(w, strokeContainThreshold == null ? 4 : strokeContainThreshold);
+          }
+
+          if (lineScale > 1e-10) {
+            rectStroke.width += w / lineScale;
+            rectStroke.height += w / lineScale;
+            rectStroke.x -= w / lineScale / 2;
+            rectStroke.y -= w / lineScale / 2;
+          }
+        }
+
+        return rectStroke;
+      }
+
+      return rect;
+    };
+
+    Path.prototype.contain = function (x, y) {
+      var localPos = this.transformCoordToLocal(x, y);
+      var rect = this.getBoundingRect();
+      var style = this.style;
+      x = localPos[0];
+      y = localPos[1];
+
+      if (rect.contain(x, y)) {
+        var pathProxy = this.path;
+
+        if (this.hasStroke()) {
+          var lineWidth = style.lineWidth;
+          var lineScale = style.strokeNoScale ? this.getLineScale() : 1;
+
+          if (lineScale > 1e-10) {
+            if (!this.hasFill()) {
+              lineWidth = Math.max(lineWidth, this.strokeContainThreshold);
+            }
+
+            if (containStroke(pathProxy, lineWidth / lineScale, x, y)) {
+              return true;
+            }
+          }
+        }
+
+        if (this.hasFill()) {
+          return contain(pathProxy, x, y);
+        }
+      }
+
+      return false;
+    };
+
+    Path.prototype.dirtyShape = function () {
+      this.__dirty |= SHAPE_CHANGED_BIT;
+
+      if (this._rect) {
+        this._rect = null;
+      }
+
+      if (this._decalEl) {
+        this._decalEl.dirtyShape();
+      }
+
+      this.markRedraw();
+    };
+
+    Path.prototype.dirty = function () {
+      this.dirtyStyle();
+      this.dirtyShape();
+    };
+
+    Path.prototype.animateShape = function (loop) {
+      return this.animate('shape', loop);
+    };
+
+    Path.prototype.updateDuringAnimation = function (targetKey) {
+      if (targetKey === 'style') {
+        this.dirtyStyle();
+      } else if (targetKey === 'shape') {
+        this.dirtyShape();
+      } else {
+        this.markRedraw();
+      }
+    };
+
+    Path.prototype.attrKV = function (key, value) {
+      if (key === 'shape') {
+        this.setShape(value);
+      } else {
+        _super.prototype.attrKV.call(this, key, value);
+      }
+    };
+
+    Path.prototype.setShape = function (keyOrObj, value) {
+      var shape = this.shape;
+
+      if (!shape) {
+        shape = this.shape = {};
+      }
+
+      if (typeof keyOrObj === 'string') {
+        shape[keyOrObj] = value;
+      } else {
+        extend(shape, keyOrObj);
+      }
+
+      this.dirtyShape();
+      return this;
+    };
+
+    Path.prototype.shapeChanged = function () {
+      return !!(this.__dirty & SHAPE_CHANGED_BIT);
+    };
+
+    Path.prototype.createStyle = function (obj) {
+      return createObject(DEFAULT_PATH_STYLE, obj);
+    };
+
+    Path.prototype._innerSaveToNormal = function (toState) {
+      _super.prototype._innerSaveToNormal.call(this, toState);
+
+      var normalState = this._normalState;
+
+      if (toState.shape && !normalState.shape) {
+        normalState.shape = extend({}, this.shape);
+      }
+    };
+
+    Path.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
+      _super.prototype._applyStateObj.call(this, stateName, state, normalState, keepCurrentStates, transition, animationCfg);
+
+      var needsRestoreToNormal = !(state && keepCurrentStates);
+      var targetShape;
+
+      if (state && state.shape) {
+        if (transition) {
+          if (keepCurrentStates) {
+            targetShape = state.shape;
+          } else {
+            targetShape = extend({}, normalState.shape);
+            extend(targetShape, state.shape);
+          }
+        } else {
+          targetShape = extend({}, keepCurrentStates ? this.shape : normalState.shape);
+          extend(targetShape, state.shape);
+        }
+      } else if (needsRestoreToNormal) {
+        targetShape = normalState.shape;
+      }
+
+      if (targetShape) {
+        if (transition) {
+          this.shape = extend({}, this.shape);
+          var targetShapePrimaryProps = {};
+          var shapeKeys = keys(targetShape);
+
+          for (var i = 0; i < shapeKeys.length; i++) {
+            var key = shapeKeys[i];
+
+            if (typeof targetShape[key] === 'object') {
+              this.shape[key] = targetShape[key];
+            } else {
+              targetShapePrimaryProps[key] = targetShape[key];
+            }
+          }
+
+          this._transitionState(stateName, {
+            shape: targetShapePrimaryProps
+          }, animationCfg);
+        } else {
+          this.shape = targetShape;
+          this.dirtyShape();
+        }
+      }
+    };
+
+    Path.prototype._mergeStates = function (states) {
+      var mergedState = _super.prototype._mergeStates.call(this, states);
+
+      var mergedShape;
+
+      for (var i = 0; i < states.length; i++) {
+        var state = states[i];
+
+        if (state.shape) {
+          mergedShape = mergedShape || {};
+
+          this._mergeStyle(mergedShape, state.shape);
+        }
+      }
+
+      if (mergedShape) {
+        mergedState.shape = mergedShape;
+      }
+
+      return mergedState;
+    };
+
+    Path.prototype.getAnimationStyleProps = function () {
+      return DEFAULT_PATH_ANIMATION_PROPS;
+    };
+
+    Path.prototype.isZeroArea = function () {
+      return false;
+    };
+
+    Path.extend = function (defaultProps) {
+      var Sub = function (_super) {
+        __extends(Sub, _super);
+
+        function Sub(opts) {
+          var _this = _super.call(this, opts) || this;
+
+          defaultProps.init && defaultProps.init.call(_this, opts);
+          return _this;
+        }
+
+        Sub.prototype.getDefaultStyle = function () {
+          return clone(defaultProps.style);
+        };
+
+        Sub.prototype.getDefaultShape = function () {
+          return clone(defaultProps.shape);
+        };
+
+        return Sub;
+      }(Path);
+
+      for (var key in defaultProps) {
+        if (typeof defaultProps[key] === 'function') {
+          Sub.prototype[key] = defaultProps[key];
+        }
+      }
+
+      return Sub;
+    };
+
+    Path.initDefaultProps = function () {
+      var pathProto = Path.prototype;
+      pathProto.type = 'path';
+      pathProto.strokeContainThreshold = 5;
+      pathProto.segmentIgnoreThreshold = 0;
+      pathProto.subPixelOptimize = false;
+      pathProto.autoBatch = false;
+      pathProto.__dirty = REDRAW_BIT | STYLE_CHANGED_BIT | SHAPE_CHANGED_BIT;
+    }();
+
+    return Path;
+  }(Displayable);
+
+  var DEFAULT_TSPAN_STYLE = defaults({
+    strokeFirst: true,
+    font: DEFAULT_FONT,
+    x: 0,
+    y: 0,
+    textAlign: 'left',
+    textBaseline: 'top',
+    miterLimit: 2
+  }, DEFAULT_PATH_STYLE);
+
+  var TSpan = function (_super) {
+    __extends(TSpan, _super);
+
+    function TSpan() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    TSpan.prototype.hasStroke = function () {
+      var style = this.style;
+      var stroke = style.stroke;
+      return stroke != null && stroke !== 'none' && style.lineWidth > 0;
+    };
+
+    TSpan.prototype.hasFill = function () {
+      var style = this.style;
+      var fill = style.fill;
+      return fill != null && fill !== 'none';
+    };
+
+    TSpan.prototype.createStyle = function (obj) {
+      return createObject(DEFAULT_TSPAN_STYLE, obj);
+    };
+
+    TSpan.prototype.setBoundingRect = function (rect) {
+      this._rect = rect;
+    };
+
+    TSpan.prototype.getBoundingRect = function () {
+      var style = this.style;
+
+      if (!this._rect) {
+        var text = style.text;
+        text != null ? text += '' : text = '';
+        var rect = getBoundingRect(text, style.font, style.textAlign, style.textBaseline);
+        rect.x += style.x || 0;
+        rect.y += style.y || 0;
+
+        if (this.hasStroke()) {
+          var w = style.lineWidth;
+          rect.x -= w / 2;
+          rect.y -= w / 2;
+          rect.width += w;
+          rect.height += w;
+        }
+
+        this._rect = rect;
+      }
+
+      return this._rect;
+    };
+
+    TSpan.initDefaultProps = function () {
+      var tspanProto = TSpan.prototype;
+      tspanProto.dirtyRectTolerance = 10;
+    }();
+
+    return TSpan;
+  }(Displayable);
+
+  TSpan.prototype.type = 'tspan';
+  var DEFAULT_IMAGE_STYLE = defaults({
+    x: 0,
+    y: 0
+  }, DEFAULT_COMMON_STYLE);
+  var DEFAULT_IMAGE_ANIMATION_PROPS = {
+    style: defaults({
+      x: true,
+      y: true,
+      width: true,
+      height: true,
+      sx: true,
+      sy: true,
+      sWidth: true,
+      sHeight: true
+    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
+  };
+
+  function isImageLike(source) {
+    return !!(source && typeof source !== 'string' && source.width && source.height);
+  }
+
+  var ZRImage = function (_super) {
+    __extends(ZRImage, _super);
+
+    function ZRImage() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    ZRImage.prototype.createStyle = function (obj) {
+      return createObject(DEFAULT_IMAGE_STYLE, obj);
+    };
+
+    ZRImage.prototype._getSize = function (dim) {
+      var style = this.style;
+      var size = style[dim];
+
+      if (size != null) {
+        return size;
+      }
+
+      var imageSource = isImageLike(style.image) ? style.image : this.__image;
+
+      if (!imageSource) {
+        return 0;
+      }
+
+      var otherDim = dim === 'width' ? 'height' : 'width';
+      var otherDimSize = style[otherDim];
+
+      if (otherDimSize == null) {
+        return imageSource[dim];
+      } else {
+        return imageSource[dim] / imageSource[otherDim] * otherDimSize;
+      }
+    };
+
+    ZRImage.prototype.getWidth = function () {
+      return this._getSize('width');
+    };
+
+    ZRImage.prototype.getHeight = function () {
+      return this._getSize('height');
+    };
+
+    ZRImage.prototype.getAnimationStyleProps = function () {
+      return DEFAULT_IMAGE_ANIMATION_PROPS;
+    };
+
+    ZRImage.prototype.getBoundingRect = function () {
+      var style = this.style;
+
+      if (!this._rect) {
+        this._rect = new BoundingRect(style.x || 0, style.y || 0, this.getWidth(), this.getHeight());
+      }
+
+      return this._rect;
+    };
+
+    return ZRImage;
+  }(Displayable);
+
+  ZRImage.prototype.type = 'image';
+
+  function buildPath(ctx, shape) {
+    var x = shape.x;
+    var y = shape.y;
+    var width = shape.width;
+    var height = shape.height;
+    var r = shape.r;
+    var r1;
+    var r2;
+    var r3;
+    var r4;
+
+    if (width < 0) {
+      x = x + width;
+      width = -width;
+    }
+
+    if (height < 0) {
+      y = y + height;
+      height = -height;
+    }
+
+    if (typeof r === 'number') {
+      r1 = r2 = r3 = r4 = r;
+    } else if (r instanceof Array) {
+      if (r.length === 1) {
+        r1 = r2 = r3 = r4 = r[0];
+      } else if (r.length === 2) {
+        r1 = r3 = r[0];
+        r2 = r4 = r[1];
+      } else if (r.length === 3) {
+        r1 = r[0];
+        r2 = r4 = r[1];
+        r3 = r[2];
+      } else {
+        r1 = r[0];
+        r2 = r[1];
+        r3 = r[2];
+        r4 = r[3];
+      }
+    } else {
+      r1 = r2 = r3 = r4 = 0;
+    }
+
+    var total;
+
+    if (r1 + r2 > width) {
+      total = r1 + r2;
+      r1 *= width / total;
+      r2 *= width / total;
+    }
+
+    if (r3 + r4 > width) {
+      total = r3 + r4;
+      r3 *= width / total;
+      r4 *= width / total;
+    }
+
+    if (r2 + r3 > height) {
+      total = r2 + r3;
+      r2 *= height / total;
+      r3 *= height / total;
+    }
+
+    if (r1 + r4 > height) {
+      total = r1 + r4;
+      r1 *= height / total;
+      r4 *= height / total;
+    }
+
+    ctx.moveTo(x + r1, y);
+    ctx.lineTo(x + width - r2, y);
+    r2 !== 0 && ctx.arc(x + width - r2, y + r2, r2, -Math.PI / 2, 0);
+    ctx.lineTo(x + width, y + height - r3);
+    r3 !== 0 && ctx.arc(x + width - r3, y + height - r3, r3, 0, Math.PI / 2);
+    ctx.lineTo(x + r4, y + height);
+    r4 !== 0 && ctx.arc(x + r4, y + height - r4, r4, Math.PI / 2, Math.PI);
+    ctx.lineTo(x, y + r1);
+    r1 !== 0 && ctx.arc(x + r1, y + r1, r1, Math.PI, Math.PI * 1.5);
+  }
+
+  var round$1 = Math.round;
+
+  function subPixelOptimizeLine(outputShape, inputShape, style) {
+    if (!inputShape) {
+      return;
+    }
+
+    var x1 = inputShape.x1;
+    var x2 = inputShape.x2;
+    var y1 = inputShape.y1;
+    var y2 = inputShape.y2;
+    outputShape.x1 = x1;
+    outputShape.x2 = x2;
+    outputShape.y1 = y1;
+    outputShape.y2 = y2;
+    var lineWidth = style && style.lineWidth;
+
+    if (!lineWidth) {
+      return outputShape;
+    }
+
+    if (round$1(x1 * 2) === round$1(x2 * 2)) {
+      outputShape.x1 = outputShape.x2 = subPixelOptimize(x1, lineWidth, true);
+    }
+
+    if (round$1(y1 * 2) === round$1(y2 * 2)) {
+      outputShape.y1 = outputShape.y2 = subPixelOptimize(y1, lineWidth, true);
+    }
+
+    return outputShape;
+  }
+
+  function subPixelOptimizeRect(outputShape, inputShape, style) {
+    if (!inputShape) {
+      return;
+    }
+
+    var originX = inputShape.x;
+    var originY = inputShape.y;
+    var originWidth = inputShape.width;
+    var originHeight = inputShape.height;
+    outputShape.x = originX;
+    outputShape.y = originY;
+    outputShape.width = originWidth;
+    outputShape.height = originHeight;
+    var lineWidth = style && style.lineWidth;
+
+    if (!lineWidth) {
+      return outputShape;
+    }
+
+    outputShape.x = subPixelOptimize(originX, lineWidth, true);
+    outputShape.y = subPixelOptimize(originY, lineWidth, true);
+    outputShape.width = Math.max(subPixelOptimize(originX + originWidth, lineWidth, false) - outputShape.x, originWidth === 0 ? 0 : 1);
+    outputShape.height = Math.max(subPixelOptimize(originY + originHeight, lineWidth, false) - outputShape.y, originHeight === 0 ? 0 : 1);
+    return outputShape;
+  }
+
+  function subPixelOptimize(position, lineWidth, positiveOrNegative) {
+    if (!lineWidth) {
+      return position;
+    }
+
+    var doubledPosition = round$1(position * 2);
+    return (doubledPosition + round$1(lineWidth)) % 2 === 0 ? doubledPosition / 2 : (doubledPosition + (positiveOrNegative ? 1 : -1)) / 2;
+  }
+
+  var RectShape = function () {
+    function RectShape() {
+      this.x = 0;
+      this.y = 0;
+      this.width = 0;
+      this.height = 0;
+    }
+
+    return RectShape;
+  }();
+
+  var subPixelOptimizeOutputShape = {};
+
+  var Rect = function (_super) {
+    __extends(Rect, _super);
+
+    function Rect(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Rect.prototype.getDefaultShape = function () {
+      return new RectShape();
+    };
+
+    Rect.prototype.buildPath = function (ctx, shape) {
+      var x;
+      var y;
+      var width;
+      var height;
+
+      if (this.subPixelOptimize) {
+        var optimizedShape = subPixelOptimizeRect(subPixelOptimizeOutputShape, shape, this.style);
+        x = optimizedShape.x;
+        y = optimizedShape.y;
+        width = optimizedShape.width;
+        height = optimizedShape.height;
+        optimizedShape.r = shape.r;
+        shape = optimizedShape;
+      } else {
+        x = shape.x;
+        y = shape.y;
+        width = shape.width;
+        height = shape.height;
+      }
+
+      if (!shape.r) {
+        ctx.rect(x, y, width, height);
+      } else {
+        buildPath(ctx, shape);
+      }
+    };
+
+    Rect.prototype.isZeroArea = function () {
+      return !this.shape.width || !this.shape.height;
+    };
+
+    return Rect;
+  }(Path);
+
+  Rect.prototype.type = 'rect';
+  var DEFAULT_RICH_TEXT_COLOR = {
+    fill: '#000'
+  };
+  var DEFAULT_STROKE_LINE_WIDTH = 2;
+  var DEFAULT_TEXT_ANIMATION_PROPS = {
+    style: defaults({
+      fill: true,
+      stroke: true,
+      fillOpacity: true,
+      strokeOpacity: true,
+      lineWidth: true,
+      fontSize: true,
+      lineHeight: true,
+      width: true,
+      height: true,
+      textShadowColor: true,
+      textShadowBlur: true,
+      textShadowOffsetX: true,
+      textShadowOffsetY: true,
+      backgroundColor: true,
+      padding: true,
+      borderColor: true,
+      borderWidth: true,
+      borderRadius: true
+    }, DEFAULT_COMMON_ANIMATION_PROPS.style)
+  };
+
+  var ZRText = function (_super) {
+    __extends(ZRText, _super);
+
+    function ZRText(opts) {
+      var _this = _super.call(this) || this;
+
+      _this.type = 'text';
+      _this._children = [];
+      _this._defaultStyle = DEFAULT_RICH_TEXT_COLOR;
+
+      _this.attr(opts);
+
+      return _this;
+    }
+
+    ZRText.prototype.childrenRef = function () {
+      return this._children;
+    };
+
+    ZRText.prototype.update = function () {
+      _super.prototype.update.call(this);
+
+      if (this.styleChanged()) {
+        this._updateSubTexts();
+      }
+
+      for (var i = 0; i < this._children.length; i++) {
+        var child = this._children[i];
+        child.zlevel = this.zlevel;
+        child.z = this.z;
+        child.z2 = this.z2;
+        child.culling = this.culling;
+        child.cursor = this.cursor;
+        child.invisible = this.invisible;
+      }
+    };
+
+    ZRText.prototype.updateTransform = function () {
+      var innerTransformable = this.innerTransformable;
+
+      if (innerTransformable) {
+        innerTransformable.updateTransform();
+
+        if (innerTransformable.transform) {
+          this.transform = innerTransformable.transform;
+        }
+      } else {
+        _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 _super.prototype.getComputedTransform.call(this);
+    };
+
+    ZRText.prototype._updateSubTexts = function () {
+      this._childCursor = 0;
+      normalizeTextStyle(this.style);
+      this.style.rich ? this._updateRichTexts() : this._updatePlainTexts();
+      this._children.length = this._childCursor;
+      this.styleUpdated();
+    };
+
+    ZRText.prototype.addSelfToZr = function (zr) {
+      _super.prototype.addSelfToZr.call(this, zr);
+
+      for (var i = 0; i < this._children.length; i++) {
+        this._children[i].__zr = zr;
+      }
+    };
+
+    ZRText.prototype.removeSelfFromZr = function (zr) {
+      _super.prototype.removeSelfFromZr.call(this, zr);
+
+      for (var i = 0; i < this._children.length; i++) {
+        this._children[i].__zr = null;
+      }
+    };
+
+    ZRText.prototype.getBoundingRect = function () {
+      if (this.styleChanged()) {
+        this._updateSubTexts();
+      }
+
+      if (!this._rect) {
+        var tmpRect = new BoundingRect(0, 0, 0, 0);
+        var children = this._children;
+        var tmpMat = [];
+        var rect = null;
+
+        for (var i = 0; i < children.length; i++) {
+          var child = children[i];
+          var childRect = child.getBoundingRect();
+          var transform = child.getLocalTransform(tmpMat);
+
+          if (transform) {
+            tmpRect.copy(childRect);
+            tmpRect.applyTransform(transform);
+            rect = rect || tmpRect.clone();
+            rect.union(tmpRect);
+          } else {
+            rect = rect || childRect.clone();
+            rect.union(childRect);
+          }
+        }
+
+        this._rect = rect || tmpRect;
+      }
+
+      return this._rect;
+    };
+
+    ZRText.prototype.setDefaultTextStyle = function (defaultTextStyle) {
+      this._defaultStyle = defaultTextStyle || DEFAULT_RICH_TEXT_COLOR;
+    };
+
+    ZRText.prototype.setTextContent = function (textContent) {
+      {
+        throw new Error('Can\'t attach text on another text');
+      }
+    };
+
+    ZRText.prototype._mergeStyle = function (targetStyle, sourceStyle) {
+      if (!sourceStyle) {
+        return targetStyle;
+      }
+
+      var sourceRich = sourceStyle.rich;
+      var targetRich = targetStyle.rich || sourceRich && {};
+      extend(targetStyle, sourceStyle);
+
+      if (sourceRich && targetRich) {
+        this._mergeRich(targetRich, sourceRich);
+
+        targetStyle.rich = targetRich;
+      } else if (targetRich) {
+        targetStyle.rich = targetRich;
+      }
+
+      return targetStyle;
+    };
+
+    ZRText.prototype._mergeRich = function (targetRich, sourceRich) {
+      var richNames = keys(sourceRich);
+
+      for (var i = 0; i < richNames.length; i++) {
+        var richName = richNames[i];
+        targetRich[richName] = targetRich[richName] || {};
+        extend(targetRich[richName], sourceRich[richName]);
+      }
+    };
+
+    ZRText.prototype.getAnimationStyleProps = function () {
+      return DEFAULT_TEXT_ANIMATION_PROPS;
+    };
+
+    ZRText.prototype._getOrCreateChild = function (Ctor) {
+      var child = this._children[this._childCursor];
+
+      if (!child || !(child instanceof Ctor)) {
+        child = new Ctor();
+      }
+
+      this._children[this._childCursor++] = child;
+      child.__zr = this.__zr;
+      child.parent = this;
+      return child;
+    };
+
+    ZRText.prototype._updatePlainTexts = function () {
+      var style = this.style;
+      var textFont = style.font || DEFAULT_FONT;
+      var textPadding = style.padding;
+      var text = getStyleText(style);
+      var contentBlock = parsePlainText(text, style);
+      var needDrawBg = needDrawBackground(style);
+      var bgColorDrawn = !!style.backgroundColor;
+      var outerHeight = contentBlock.outerHeight;
+      var outerWidth = contentBlock.outerWidth;
+      var contentWidth = contentBlock.contentWidth;
+      var textLines = contentBlock.lines;
+      var lineHeight = contentBlock.lineHeight;
+      var defaultStyle = this._defaultStyle;
+      var baseX = style.x || 0;
+      var baseY = style.y || 0;
+      var textAlign = style.align || defaultStyle.align || 'left';
+      var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign || 'top';
+      var textX = baseX;
+      var textY = adjustTextY$1(baseY, contentBlock.contentHeight, verticalAlign);
+
+      if (needDrawBg || textPadding) {
+        var boxX = adjustTextX(baseX, outerWidth, textAlign);
+        var boxY = adjustTextY$1(baseY, outerHeight, verticalAlign);
+        needDrawBg && this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight);
+      }
+
+      textY += lineHeight / 2;
+
+      if (textPadding) {
+        textX = getTextXForPadding(baseX, textAlign, textPadding);
+
+        if (verticalAlign === 'top') {
+          textY += textPadding[0];
+        } else if (verticalAlign === 'bottom') {
+          textY -= textPadding[2];
+        }
+      }
+
+      var defaultLineWidth = 0;
+      var useDefaultFill = false;
+      var textFill = getFill('fill' in style ? style.fill : (useDefaultFill = true, defaultStyle.fill));
+      var textStroke = getStroke('stroke' in style ? style.stroke : !bgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke) : null);
+      var hasShadow = style.textShadowBlur > 0;
+      var fixedBoundingRect = style.width != null && (style.overflow === 'truncate' || style.overflow === 'break' || style.overflow === 'breakAll');
+      var calculatedLineHeight = contentBlock.calculatedLineHeight;
+
+      for (var i = 0; i < textLines.length; i++) {
+        var el = this._getOrCreateChild(TSpan);
+
+        var subElStyle = el.createStyle();
+        el.useStyle(subElStyle);
+        subElStyle.text = textLines[i];
+        subElStyle.x = textX;
+        subElStyle.y = textY;
+
+        if (textAlign) {
+          subElStyle.textAlign = textAlign;
+        }
+
+        subElStyle.textBaseline = 'middle';
+        subElStyle.opacity = style.opacity;
+        subElStyle.strokeFirst = true;
+
+        if (hasShadow) {
+          subElStyle.shadowBlur = style.textShadowBlur || 0;
+          subElStyle.shadowColor = style.textShadowColor || 'transparent';
+          subElStyle.shadowOffsetX = style.textShadowOffsetX || 0;
+          subElStyle.shadowOffsetY = style.textShadowOffsetY || 0;
+        }
+
+        subElStyle.stroke = textStroke;
+        subElStyle.fill = textFill;
+
+        if (textStroke) {
+          subElStyle.lineWidth = style.lineWidth || defaultLineWidth;
+          subElStyle.lineDash = style.lineDash;
+          subElStyle.lineDashOffset = style.lineDashOffset || 0;
+        }
+
+        subElStyle.font = textFont;
+        setSeparateFont(subElStyle, style);
+        textY += lineHeight;
+
+        if (fixedBoundingRect) {
+          el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, style.width, subElStyle.textAlign), adjustTextY$1(subElStyle.y, calculatedLineHeight, subElStyle.textBaseline), contentWidth, calculatedLineHeight));
+        }
+      }
+    };
+
+    ZRText.prototype._updateRichTexts = function () {
+      var style = this.style;
+      var text = getStyleText(style);
+      var contentBlock = parseRichText(text, style);
+      var contentWidth = contentBlock.width;
+      var outerWidth = contentBlock.outerWidth;
+      var outerHeight = contentBlock.outerHeight;
+      var textPadding = style.padding;
+      var baseX = style.x || 0;
+      var baseY = style.y || 0;
+      var defaultStyle = this._defaultStyle;
+      var textAlign = style.align || defaultStyle.align;
+      var verticalAlign = style.verticalAlign || defaultStyle.verticalAlign;
+      var boxX = adjustTextX(baseX, outerWidth, textAlign);
+      var boxY = adjustTextY$1(baseY, outerHeight, verticalAlign);
+      var xLeft = boxX;
+      var lineTop = boxY;
+
+      if (textPadding) {
+        xLeft += textPadding[3];
+        lineTop += textPadding[0];
+      }
+
+      var xRight = xLeft + contentWidth;
+
+      if (needDrawBackground(style)) {
+        this._renderBackground(style, style, boxX, boxY, outerWidth, outerHeight);
+      }
+
+      var bgColorDrawn = !!style.backgroundColor;
+
+      for (var i = 0; i < contentBlock.lines.length; i++) {
+        var line = contentBlock.lines[i];
+        var tokens = line.tokens;
+        var tokenCount = tokens.length;
+        var lineHeight = line.lineHeight;
+        var remainedWidth = line.width;
+        var leftIndex = 0;
+        var lineXLeft = xLeft;
+        var lineXRight = xRight;
+        var rightIndex = tokenCount - 1;
+        var token = void 0;
+
+        while (leftIndex < tokenCount && (token = tokens[leftIndex], !token.align || token.align === 'left')) {
+          this._placeToken(token, style, lineHeight, lineTop, lineXLeft, 'left', bgColorDrawn);
+
+          remainedWidth -= token.width;
+          lineXLeft += token.width;
+          leftIndex++;
+        }
+
+        while (rightIndex >= 0 && (token = tokens[rightIndex], token.align === 'right')) {
+          this._placeToken(token, style, lineHeight, lineTop, lineXRight, 'right', bgColorDrawn);
+
+          remainedWidth -= token.width;
+          lineXRight -= token.width;
+          rightIndex--;
+        }
+
+        lineXLeft += (contentWidth - (lineXLeft - xLeft) - (xRight - lineXRight) - remainedWidth) / 2;
+
+        while (leftIndex <= rightIndex) {
+          token = tokens[leftIndex];
+
+          this._placeToken(token, style, lineHeight, lineTop, lineXLeft + token.width / 2, 'center', bgColorDrawn);
+
+          lineXLeft += token.width;
+          leftIndex++;
+        }
+
+        lineTop += lineHeight;
+      }
+    };
+
+    ZRText.prototype._placeToken = function (token, style, lineHeight, lineTop, x, textAlign, parentBgColorDrawn) {
+      var tokenStyle = style.rich[token.styleName] || {};
+      tokenStyle.text = token.text;
+      var verticalAlign = token.verticalAlign;
+      var y = lineTop + lineHeight / 2;
+
+      if (verticalAlign === 'top') {
+        y = lineTop + token.height / 2;
+      } else if (verticalAlign === 'bottom') {
+        y = lineTop + lineHeight - token.height / 2;
+      }
+
+      var needDrawBg = !token.isLineHolder && needDrawBackground(tokenStyle);
+      needDrawBg && this._renderBackground(tokenStyle, style, textAlign === 'right' ? x - token.width : textAlign === 'center' ? x - token.width / 2 : x, y - token.height / 2, token.width, token.height);
+      var bgColorDrawn = !!tokenStyle.backgroundColor;
+      var textPadding = token.textPadding;
+
+      if (textPadding) {
+        x = getTextXForPadding(x, textAlign, textPadding);
+        y -= token.height / 2 - textPadding[0] - token.innerHeight / 2;
+      }
+
+      var el = this._getOrCreateChild(TSpan);
+
+      var subElStyle = el.createStyle();
+      el.useStyle(subElStyle);
+      var defaultStyle = this._defaultStyle;
+      var useDefaultFill = false;
+      var defaultLineWidth = 0;
+      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 : 'stroke' in style ? style.stroke : !bgColorDrawn && !parentBgColorDrawn && (!defaultStyle.autoStroke || useDefaultFill) ? (defaultLineWidth = DEFAULT_STROKE_LINE_WIDTH, defaultStyle.stroke) : null);
+      var hasShadow = tokenStyle.textShadowBlur > 0 || style.textShadowBlur > 0;
+      subElStyle.text = token.text;
+      subElStyle.x = x;
+      subElStyle.y = y;
+
+      if (hasShadow) {
+        subElStyle.shadowBlur = tokenStyle.textShadowBlur || style.textShadowBlur || 0;
+        subElStyle.shadowColor = tokenStyle.textShadowColor || style.textShadowColor || 'transparent';
+        subElStyle.shadowOffsetX = tokenStyle.textShadowOffsetX || style.textShadowOffsetX || 0;
+        subElStyle.shadowOffsetY = tokenStyle.textShadowOffsetY || style.textShadowOffsetY || 0;
+      }
+
+      subElStyle.textAlign = textAlign;
+      subElStyle.textBaseline = 'middle';
+      subElStyle.font = token.font || DEFAULT_FONT;
+      subElStyle.opacity = retrieve3(tokenStyle.opacity, style.opacity, 1);
+      setSeparateFont(subElStyle, tokenStyle);
+
+      if (textStroke) {
+        subElStyle.lineWidth = retrieve3(tokenStyle.lineWidth, style.lineWidth, defaultLineWidth);
+        subElStyle.lineDash = retrieve2(tokenStyle.lineDash, style.lineDash);
+        subElStyle.lineDashOffset = style.lineDashOffset || 0;
+        subElStyle.stroke = textStroke;
+      }
+
+      if (textFill) {
+        subElStyle.fill = textFill;
+      }
+
+      var textWidth = token.contentWidth;
+      var textHeight = token.contentHeight;
+      el.setBoundingRect(new BoundingRect(adjustTextX(subElStyle.x, textWidth, subElStyle.textAlign), adjustTextY$1(subElStyle.y, textHeight, subElStyle.textBaseline), textWidth, textHeight));
+    };
+
+    ZRText.prototype._renderBackground = function (style, topStyle, x, y, width, height) {
+      var textBackgroundColor = style.backgroundColor;
+      var textBorderWidth = style.borderWidth;
+      var textBorderColor = style.borderColor;
+      var isImageBg = textBackgroundColor && textBackgroundColor.image;
+      var isPlainOrGradientBg = textBackgroundColor && !isImageBg;
+      var textBorderRadius = style.borderRadius;
+      var self = this;
+      var rectEl;
+      var imgEl;
+
+      if (isPlainOrGradientBg || style.lineHeight || textBorderWidth && textBorderColor) {
+        rectEl = this._getOrCreateChild(Rect);
+        rectEl.useStyle(rectEl.createStyle());
+        rectEl.style.fill = null;
+        var rectShape = rectEl.shape;
+        rectShape.x = x;
+        rectShape.y = y;
+        rectShape.width = width;
+        rectShape.height = height;
+        rectShape.r = textBorderRadius;
+        rectEl.dirtyShape();
+      }
+
+      if (isPlainOrGradientBg) {
+        var rectStyle = rectEl.style;
+        rectStyle.fill = textBackgroundColor || null;
+        rectStyle.fillOpacity = retrieve2(style.fillOpacity, 1);
+      } else if (isImageBg) {
+        imgEl = this._getOrCreateChild(ZRImage);
+
+        imgEl.onload = function () {
+          self.dirtyStyle();
+        };
+
+        var imgStyle = imgEl.style;
+        imgStyle.image = textBackgroundColor.image;
+        imgStyle.x = x;
+        imgStyle.y = y;
+        imgStyle.width = width;
+        imgStyle.height = height;
+      }
+
+      if (textBorderWidth && textBorderColor) {
+        var rectStyle = rectEl.style;
+        rectStyle.lineWidth = textBorderWidth;
+        rectStyle.stroke = textBorderColor;
+        rectStyle.strokeOpacity = retrieve2(style.strokeOpacity, 1);
+        rectStyle.lineDash = style.borderDash;
+        rectStyle.lineDashOffset = style.borderDashOffset || 0;
+        rectEl.strokeContainThreshold = 0;
+
+        if (rectEl.hasFill() && rectEl.hasStroke()) {
+          rectStyle.strokeFirst = true;
+          rectStyle.lineWidth *= 2;
+        }
+      }
+
+      var commonStyle = (rectEl || imgEl).style;
+      commonStyle.shadowBlur = style.shadowBlur || 0;
+      commonStyle.shadowColor = style.shadowColor || 'transparent';
+      commonStyle.shadowOffsetX = style.shadowOffsetX || 0;
+      commonStyle.shadowOffsetY = style.shadowOffsetY || 0;
+      commonStyle.opacity = retrieve3(style.opacity, topStyle.opacity, 1);
+    };
+
+    ZRText.makeFont = function (style) {
+      var font = '';
+
+      if (hasSeparateFont(style)) {
+        font = [style.fontStyle, style.fontWeight, parseFontSize(style.fontSize), style.fontFamily || 'sans-serif'].join(' ');
+      }
+
+      return font && trim(font) || style.textFont || style.font;
+    };
+
+    return ZRText;
+  }(Displayable);
+
+  var VALID_TEXT_ALIGN = {
+    left: true,
+    right: 1,
+    center: 1
+  };
+  var VALID_TEXT_VERTICAL_ALIGN = {
+    top: 1,
+    bottom: 1,
+    middle: 1
+  };
+  var FONT_PARTS = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily'];
+
+  function parseFontSize(fontSize) {
+    if (typeof fontSize === 'string' && (fontSize.indexOf('px') !== -1 || fontSize.indexOf('rem') !== -1 || fontSize.indexOf('em') !== -1)) {
+      return fontSize;
+    } else if (!isNaN(+fontSize)) {
+      return fontSize + 'px';
+    } else {
+      return DEFAULT_FONT_SIZE + 'px';
+    }
+  }
+
+  function setSeparateFont(targetStyle, sourceStyle) {
+    for (var i = 0; i < FONT_PARTS.length; i++) {
+      var fontProp = FONT_PARTS[i];
+      var val = sourceStyle[fontProp];
+
+      if (val != null) {
+        targetStyle[fontProp] = val;
+      }
+    }
+  }
+
+  function hasSeparateFont(style) {
+    return style.fontSize != null || style.fontFamily || style.fontWeight;
+  }
+
+  function normalizeTextStyle(style) {
+    normalizeStyle(style);
+    each(style.rich, normalizeStyle);
+    return style;
+  }
+
+  function normalizeStyle(style) {
+    if (style) {
+      style.font = ZRText.makeFont(style);
+      var textAlign = style.align;
+      textAlign === 'middle' && (textAlign = 'center');
+      style.align = textAlign == null || VALID_TEXT_ALIGN[textAlign] ? textAlign : 'left';
+      var verticalAlign = style.verticalAlign;
+      verticalAlign === 'center' && (verticalAlign = 'middle');
+      style.verticalAlign = verticalAlign == null || VALID_TEXT_VERTICAL_ALIGN[verticalAlign] ? verticalAlign : 'top';
+      var textPadding = style.padding;
+
+      if (textPadding) {
+        style.padding = normalizeCssArray(style.padding);
+      }
+    }
+  }
+
+  function getStroke(stroke, lineWidth) {
+    return stroke == null || lineWidth <= 0 || stroke === 'transparent' || stroke === 'none' ? null : stroke.image || stroke.colorStops ? '#000' : stroke;
+  }
+
+  function getFill(fill) {
+    return fill == null || fill === 'none' ? null : fill.image || fill.colorStops ? '#000' : fill;
+  }
+
+  function getTextXForPadding(x, textAlign, textPadding) {
+    return textAlign === 'right' ? x - textPadding[1] : textAlign === 'center' ? x + textPadding[3] / 2 - textPadding[1] / 2 : x + textPadding[3];
+  }
+
+  function getStyleText(style) {
+    var text = style.text;
+    text != null && (text += '');
+    return text;
+  }
+
+  function needDrawBackground(style) {
+    return !!(style.backgroundColor || style.lineHeight || style.borderWidth && style.borderColor);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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;
+        });
+      }
+    }
+  };
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 _highlightNextDigit = 1;
+  var _highlightKeyMap = {};
+  var getSavedStates = makeInner();
+  var getComponentStates = makeInner();
+  var HOVER_STATE_NORMAL = 0;
+  var HOVER_STATE_BLUR = 1;
+  var HOVER_STATE_EMPHASIS = 2;
+  var SPECIAL_STATES = ['emphasis', 'blur', 'select'];
+  var DISPLAY_STATES = ['normal', 'emphasis', 'blur', 'select'];
+  var Z2_EMPHASIS_LIFT = 10;
+  var Z2_SELECT_LIFT = 9;
+  var HIGHLIGHT_ACTION_TYPE = 'highlight';
+  var DOWNPLAY_ACTION_TYPE = 'downplay';
+  var SELECT_ACTION_TYPE = 'select';
+  var UNSELECT_ACTION_TYPE = 'unselect';
+  var TOGGLE_SELECT_ACTION_TYPE = 'toggleSelect';
+
+  function hasFillOrStroke(fillOrStroke) {
+    return fillOrStroke != null && fillOrStroke !== 'none';
+  } // Most lifted color are duplicated.
+
+
+  var liftedColorCache = new LRU(100);
+
+  function liftColor(color) {
+    if (isString(color)) {
+      var liftedColor = liftedColorCache.get(color);
+
+      if (!liftedColor) {
+        liftedColor = lift(color, -0.1);
+        liftedColorCache.put(color, liftedColor);
+      }
+
+      return liftedColor;
+    } else if (isGradientObject(color)) {
+      var ret = extend({}, color);
+      ret.colorStops = map(color.colorStops, function (stop) {
+        return {
+          offset: stop.offset,
+          color: lift(stop.color, -0.1)
+        };
+      });
+      return ret;
+    } // Change nothing.
+
+
+    return color;
+  }
+
+  function doChangeHoverState(el, stateName, hoverStateEnum) {
+    if (el.onHoverStateChange && (el.hoverState || 0) !== hoverStateEnum) {
+      el.onHoverStateChange(stateName);
+    }
+
+    el.hoverState = hoverStateEnum;
+  }
+
+  function singleEnterEmphasis(el) {
+    // Only mark the flag.
+    // States will be applied in the echarts.ts in next frame.
+    doChangeHoverState(el, 'emphasis', HOVER_STATE_EMPHASIS);
+  }
+
+  function singleLeaveEmphasis(el) {
+    // Only mark the flag.
+    // States will be applied in the echarts.ts in next frame.
+    if (el.hoverState === HOVER_STATE_EMPHASIS) {
+      doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
+    }
+  }
+
+  function singleEnterBlur(el) {
+    doChangeHoverState(el, 'blur', HOVER_STATE_BLUR);
+  }
+
+  function singleLeaveBlur(el) {
+    if (el.hoverState === HOVER_STATE_BLUR) {
+      doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
+    }
+  }
+
+  function singleEnterSelect(el) {
+    el.selected = true;
+  }
+
+  function singleLeaveSelect(el) {
+    el.selected = false;
+  }
+
+  function updateElementState(el, updater, commonParam) {
+    updater(el, commonParam);
+  }
+
+  function traverseUpdateState(el, updater, commonParam) {
+    updateElementState(el, updater, commonParam);
+    el.isGroup && el.traverse(function (child) {
+      updateElementState(child, updater, commonParam);
+    });
+  }
+
+  function setStatesFlag(el, stateName) {
+    switch (stateName) {
+      case 'emphasis':
+        el.hoverState = HOVER_STATE_EMPHASIS;
+        break;
+
+      case 'normal':
+        el.hoverState = HOVER_STATE_NORMAL;
+        break;
+
+      case 'blur':
+        el.hoverState = HOVER_STATE_BLUR;
+        break;
+
+      case 'select':
+        el.selected = true;
+    }
+  }
+  /**
+   * If we reuse elements when rerender.
+   * DONT forget to clearStates before we update the style and shape.
+   * Or we may update on the wrong state instead of normal state.
+   */
+
+
+  function getFromStateStyle(el, props, toStateName, defaultValue) {
+    var style = el.style;
+    var fromState = {};
+
+    for (var i = 0; i < props.length; i++) {
+      var propName = props[i];
+      var val = style[propName];
+      fromState[propName] = val == null ? defaultValue && defaultValue[propName] : val;
+    }
+
+    for (var i = 0; i < el.animators.length; i++) {
+      var animator = el.animators[i];
+
+      if (animator.__fromStateTransition // Dont consider the animation to emphasis state.
+      && animator.__fromStateTransition.indexOf(toStateName) < 0 && animator.targetName === 'style') {
+        animator.saveTo(fromState, props);
+      }
+    }
+
+    return fromState;
+  }
+
+  function createEmphasisDefaultState(el, stateName, targetStates, state) {
+    var hasSelect = targetStates && indexOf(targetStates, 'select') >= 0;
+    var cloned = false;
+
+    if (el instanceof Path) {
+      var store = getSavedStates(el);
+      var fromFill = hasSelect ? store.selectFill || store.normalFill : store.normalFill;
+      var fromStroke = hasSelect ? store.selectStroke || store.normalStroke : store.normalStroke;
+
+      if (hasFillOrStroke(fromFill) || hasFillOrStroke(fromStroke)) {
+        state = state || {};
+        var emphasisStyle = state.style || {}; // inherit case
+
+        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.
+
+            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.stroke = liftColor(fromStroke);
+            }
+
+        state.style = emphasisStyle;
+      }
+    }
+
+    if (state) {
+      // TODO Share with textContent?
+      if (state.z2 == null) {
+        if (!cloned) {
+          state = extend({}, state);
+        }
+
+        var z2EmphasisLift = el.z2EmphasisLift;
+        state.z2 = el.z2 + (z2EmphasisLift != null ? z2EmphasisLift : Z2_EMPHASIS_LIFT);
+      }
+    }
+
+    return state;
+  }
+
+  function createSelectDefaultState(el, stateName, state) {
+    // const hasSelect = indexOf(el.currentStates, stateName) >= 0;
+    if (state) {
+      // TODO Share with textContent?
+      if (state.z2 == null) {
+        state = extend({}, state);
+        var z2SelectLift = el.z2SelectLift;
+        state.z2 = el.z2 + (z2SelectLift != null ? z2SelectLift : Z2_SELECT_LIFT);
+      }
+    }
+
+    return state;
+  }
+
+  function createBlurDefaultState(el, stateName, state) {
+    var hasBlur = indexOf(el.currentStates, stateName) >= 0;
+    var currentOpacity = el.style.opacity;
+    var fromState = !hasBlur ? getFromStateStyle(el, ['opacity'], stateName, {
+      opacity: 1
+    }) : null;
+    state = state || {};
+    var blurStyle = state.style || {};
+
+    if (blurStyle.opacity == null) {
+      // clone state
+      state = extend({}, state);
+      blurStyle = extend({
+        // Already being applied 'emphasis'. DON'T mul opacity multiple times.
+        opacity: hasBlur ? currentOpacity : fromState.opacity * 0.1
+      }, blurStyle);
+      state.style = blurStyle;
+    }
+
+    return state;
+  }
+
+  function elementStateProxy(stateName, targetStates) {
+    var state = this.states[stateName];
+
+    if (this.style) {
+      if (stateName === 'emphasis') {
+        return createEmphasisDefaultState(this, stateName, targetStates, state);
+      } else if (stateName === 'blur') {
+        return createBlurDefaultState(this, stateName, state);
+      } else if (stateName === 'select') {
+        return createSelectDefaultState(this, stateName, state);
+      }
+    }
+
+    return state;
+  }
+  /**FI
+   * Set hover style (namely "emphasis style") of element.
+   * @param el Should not be `zrender/graphic/Group`.
+   * @param focus 'self' | 'selfInSeries' | 'series'
+   */
+
+
+  function setDefaultStateProxy(el) {
+    el.stateProxy = elementStateProxy;
+    var textContent = el.getTextContent();
+    var textGuide = el.getTextGuideLine();
+
+    if (textContent) {
+      textContent.stateProxy = elementStateProxy;
+    }
+
+    if (textGuide) {
+      textGuide.stateProxy = elementStateProxy;
+    }
+  }
+
+  function enterEmphasisWhenMouseOver(el, e) {
+    !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight.
+    && !el.__highByOuter && traverseUpdateState(el, singleEnterEmphasis);
+  }
+
+  function leaveEmphasisWhenMouseOut(el, e) {
+    !shouldSilent(el, e) // "emphasis" event highlight has higher priority than mouse highlight.
+    && !el.__highByOuter && traverseUpdateState(el, singleLeaveEmphasis);
+  }
+
+  function enterEmphasis(el, highlightDigit) {
+    el.__highByOuter |= 1 << (highlightDigit || 0);
+    traverseUpdateState(el, singleEnterEmphasis);
+  }
+
+  function leaveEmphasis(el, highlightDigit) {
+    !(el.__highByOuter &= ~(1 << (highlightDigit || 0))) && traverseUpdateState(el, singleLeaveEmphasis);
+  }
+
+  function enterBlur(el) {
+    traverseUpdateState(el, singleEnterBlur);
+  }
+
+  function leaveBlur(el) {
+    traverseUpdateState(el, singleLeaveBlur);
+  }
+
+  function enterSelect(el) {
+    traverseUpdateState(el, singleEnterSelect);
+  }
+
+  function leaveSelect(el) {
+    traverseUpdateState(el, singleLeaveSelect);
+  }
+
+  function shouldSilent(el, e) {
+    return el.__highDownSilentOnTouch && e.zrByTouch;
+  }
+
+  function allLeaveBlur(api) {
+    var model = api.getModel();
+    var leaveBlurredSeries = [];
+    var allComponentViews = [];
+    model.eachComponent(function (componentType, componentModel) {
+      var componentStates = getComponentStates(componentModel);
+      var isSeries = componentType === 'series';
+      var view = isSeries ? api.getViewOfSeriesModel(componentModel) : api.getViewOfComponentModel(componentModel);
+      !isSeries && allComponentViews.push(view);
+
+      if (componentStates.isBlured) {
+        // Leave blur anyway
+        view.group.traverse(function (child) {
+          singleLeaveBlur(child);
+        });
+        isSeries && leaveBlurredSeries.push(componentModel);
+      }
+
+      componentStates.isBlured = false;
+    });
+    each(allComponentViews, function (view) {
+      if (view && view.toggleBlurSeries) {
+        view.toggleBlurSeries(leaveBlurredSeries, false, model);
+      }
+    });
+  }
+
+  function blurSeries(targetSeriesIndex, focus, blurScope, api) {
+    var ecModel = api.getModel();
+    blurScope = blurScope || 'coordinateSystem';
+
+    function leaveBlurOfIndices(data, dataIndices) {
+      for (var i = 0; i < dataIndices.length; i++) {
+        var itemEl = data.getItemGraphicEl(dataIndices[i]);
+        itemEl && leaveBlur(itemEl);
+      }
+    }
+
+    if (targetSeriesIndex == null) {
+      return;
+    }
+
+    if (!focus || focus === 'none') {
+      return;
+    }
+
+    var targetSeriesModel = ecModel.getSeriesByIndex(targetSeriesIndex);
+    var targetCoordSys = targetSeriesModel.coordinateSystem;
+
+    if (targetCoordSys && targetCoordSys.master) {
+      targetCoordSys = targetCoordSys.master;
+    }
+
+    var blurredSeries = [];
+    ecModel.eachSeries(function (seriesModel) {
+      var sameSeries = targetSeriesModel === seriesModel;
+      var coordSys = seriesModel.coordinateSystem;
+
+      if (coordSys && coordSys.master) {
+        coordSys = coordSys.master;
+      }
+
+      var sameCoordSys = coordSys && targetCoordSys ? coordSys === targetCoordSys : sameSeries; // If there is no coordinate system. use sameSeries instead.
+
+      if (!( // Not blur other series if blurScope series
+      blurScope === 'series' && !sameSeries // Not blur other coordinate system if blurScope is coordinateSystem
+      || blurScope === 'coordinateSystem' && !sameCoordSys // Not blur self series if focus is series.
+      || focus === 'series' && sameSeries // TODO blurScope: coordinate system
+      )) {
+        var view = api.getViewOfSeriesModel(seriesModel);
+        view.group.traverse(function (child) {
+          singleEnterBlur(child);
+        });
+
+        if (isArrayLike(focus)) {
+          leaveBlurOfIndices(seriesModel.getData(), focus);
+        } else if (isObject(focus)) {
+          var dataTypes = keys(focus);
+
+          for (var d = 0; d < dataTypes.length; d++) {
+            leaveBlurOfIndices(seriesModel.getData(dataTypes[d]), focus[dataTypes[d]]);
+          }
+        }
+
+        blurredSeries.push(seriesModel);
+        getComponentStates(seriesModel).isBlured = true;
+      }
+    });
+    ecModel.eachComponent(function (componentType, componentModel) {
+      if (componentType === 'series') {
+        return;
+      }
+
+      var view = api.getViewOfComponentModel(componentModel);
+
+      if (view && view.toggleBlurSeries) {
+        view.toggleBlurSeries(blurredSeries, true, ecModel);
+      }
+    });
+  }
+
+  function blurComponent(componentMainType, componentIndex, api) {
+    if (componentMainType == null || componentIndex == null) {
+      return;
+    }
+
+    var componentModel = api.getModel().getComponent(componentMainType, componentIndex);
+
+    if (!componentModel) {
+      return;
+    }
+
+    getComponentStates(componentModel).isBlured = true;
+    var view = api.getViewOfComponentModel(componentModel);
+
+    if (!view || !view.focusBlurEnabled) {
+      return;
+    }
+
+    view.group.traverse(function (child) {
+      singleEnterBlur(child);
+    });
+  }
+
+  function blurSeriesFromHighlightPayload(seriesModel, payload, api) {
+    var seriesIndex = seriesModel.seriesIndex;
+    var data = seriesModel.getData(payload.dataType);
+
+    if (!data) {
+      {
+        error("Unknown dataType " + payload.dataType);
+      }
+      return;
+    }
+
+    var dataIndex = queryDataIndex(data, payload); // Pick the first one if there is multiple/none exists.
+
+    dataIndex = (isArray(dataIndex) ? dataIndex[0] : dataIndex) || 0;
+    var el = data.getItemGraphicEl(dataIndex);
+
+    if (!el) {
+      var count = data.count();
+      var current = 0; // If data on dataIndex is NaN.
+
+      while (!el && current < count) {
+        el = data.getItemGraphicEl(current++);
+      }
+    }
+
+    if (el) {
+      var ecData = getECData(el);
+      blurSeries(seriesIndex, ecData.focus, ecData.blurScope, api);
+    } else {
+      // If there is no element put on the data. Try getting it from raw option
+      // TODO Should put it on seriesModel?
+      var focus_1 = seriesModel.get(['emphasis', 'focus']);
+      var blurScope = seriesModel.get(['emphasis', 'blurScope']);
+
+      if (focus_1 != null) {
+        blurSeries(seriesIndex, focus_1, blurScope, api);
+      }
+    }
+  }
+
+  function findComponentHighDownDispatchers(componentMainType, componentIndex, name, api) {
+    var ret = {
+      focusSelf: false,
+      dispatchers: null
+    };
+
+    if (componentMainType == null || componentMainType === 'series' || componentIndex == null || name == null) {
+      return ret;
+    }
+
+    var componentModel = api.getModel().getComponent(componentMainType, componentIndex);
+
+    if (!componentModel) {
+      return ret;
+    }
+
+    var view = api.getViewOfComponentModel(componentModel);
+
+    if (!view || !view.findHighDownDispatchers) {
+      return ret;
+    }
+
+    var dispatchers = view.findHighDownDispatchers(name); // At presnet, the component (like Geo) only blur inside itself.
+    // So we do not use `blurScope` in component.
+
+    var focusSelf;
+
+    for (var i = 0; i < dispatchers.length; i++) {
+      if ("development" !== 'production' && !isHighDownDispatcher(dispatchers[i])) {
+        error('param should be highDownDispatcher');
+      }
+
+      if (getECData(dispatchers[i]).focus === 'self') {
+        focusSelf = true;
+        break;
+      }
+    }
+
+    return {
+      focusSelf: focusSelf,
+      dispatchers: dispatchers
+    };
+  }
+
+  function handleGlobalMouseOverForHighDown(dispatcher, e, api) {
+    if ("development" !== 'production' && !isHighDownDispatcher(dispatcher)) {
+      error('param should be highDownDispatcher');
+    }
+
+    var ecData = getECData(dispatcher);
+
+    var _a = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api),
+        dispatchers = _a.dispatchers,
+        focusSelf = _a.focusSelf; // If `findHighDownDispatchers` is supported on the component,
+    // highlight/downplay elements with the same name.
+
+
+    if (dispatchers) {
+      if (focusSelf) {
+        blurComponent(ecData.componentMainType, ecData.componentIndex, api);
+      }
+
+      each(dispatchers, function (dispatcher) {
+        return enterEmphasisWhenMouseOver(dispatcher, e);
+      });
+    } else {
+      // Try blur all in the related series. Then emphasis the hoverred.
+      // TODO. progressive mode.
+      blurSeries(ecData.seriesIndex, ecData.focus, ecData.blurScope, api);
+
+      if (ecData.focus === 'self') {
+        blurComponent(ecData.componentMainType, ecData.componentIndex, api);
+      } // Other than series, component that not support `findHighDownDispatcher` will
+      // also use it. But in this case, highlight/downplay are only supported in
+      // mouse hover but not in dispatchAction.
+
+
+      enterEmphasisWhenMouseOver(dispatcher, e);
+    }
+  }
+
+  function handleGlobalMouseOutForHighDown(dispatcher, e, api) {
+    if ("development" !== 'production' && !isHighDownDispatcher(dispatcher)) {
+      error('param should be highDownDispatcher');
+    }
+
+    allLeaveBlur(api);
+    var ecData = getECData(dispatcher);
+    var dispatchers = findComponentHighDownDispatchers(ecData.componentMainType, ecData.componentIndex, ecData.componentHighDownName, api).dispatchers;
+
+    if (dispatchers) {
+      each(dispatchers, function (dispatcher) {
+        return leaveEmphasisWhenMouseOut(dispatcher, e);
+      });
+    } else {
+      leaveEmphasisWhenMouseOut(dispatcher, e);
+    }
+  }
+
+  function toggleSelectionFromPayload(seriesModel, payload, api) {
+    if (!isSelectChangePayload(payload)) {
+      return;
+    }
+
+    var dataType = payload.dataType;
+    var data = seriesModel.getData(dataType);
+    var dataIndex = queryDataIndex(data, payload);
+
+    if (!isArray(dataIndex)) {
+      dataIndex = [dataIndex];
+    }
+
+    seriesModel[payload.type === TOGGLE_SELECT_ACTION_TYPE ? 'toggleSelect' : payload.type === SELECT_ACTION_TYPE ? 'select' : 'unselect'](dataIndex, dataType);
+  }
+
+  function updateSeriesElementSelection(seriesModel) {
+    var allData = seriesModel.getAllData();
+    each(allData, function (_a) {
+      var data = _a.data,
+          type = _a.type;
+      data.eachItemGraphicEl(function (el, idx) {
+        seriesModel.isSelected(idx, type) ? enterSelect(el) : leaveSelect(el);
+      });
+    });
+  }
+
+  function getAllSelectedIndices(ecModel) {
+    var ret = [];
+    ecModel.eachSeries(function (seriesModel) {
+      var allData = seriesModel.getAllData();
+      each(allData, function (_a) {
+        var data = _a.data,
+            type = _a.type;
+        var dataIndices = seriesModel.getSelectedDataIndices();
+
+        if (dataIndices.length > 0) {
+          var item = {
+            dataIndex: dataIndices,
+            seriesIndex: seriesModel.seriesIndex
+          };
+
+          if (type != null) {
+            item.dataType = type;
+          }
+
+          ret.push(item);
+        }
+      });
+    });
+    return ret;
+  }
+  /**
+   * Enable the function that mouseover will trigger the emphasis state.
+   *
+   * NOTE:
+   * This function should be used on the element with dataIndex, seriesIndex.
+   *
+   */
+
+
+  function enableHoverEmphasis(el, focus, blurScope) {
+    setAsHighDownDispatcher(el, true);
+    traverseUpdateState(el, setDefaultStateProxy);
+    enableHoverFocus(el, focus, blurScope);
+  }
+
+  function disableHoverEmphasis(el) {
+    setAsHighDownDispatcher(el, false);
+  }
+
+  function toggleHoverEmphasis(el, focus, blurScope, isDisabled) {
+    isDisabled ? disableHoverEmphasis(el) : enableHoverEmphasis(el, focus, blurScope);
+  }
+
+  function enableHoverFocus(el, focus, blurScope) {
+    var ecData = getECData(el);
+
+    if (focus != null) {
+      // TODO dataIndex may be set after this function. This check is not useful.
+      // if (ecData.dataIndex == null) {
+      //     if (__DEV__) {
+      //         console.warn('focus can only been set on element with dataIndex');
+      //     }
+      // }
+      // else {
+      ecData.focus = focus;
+      ecData.blurScope = blurScope; // }
+    } else if (ecData.focus) {
+      ecData.focus = null;
+    }
+  }
+
+  var OTHER_STATES = ['emphasis', 'blur', 'select'];
+  var defaultStyleGetterMap = {
+    itemStyle: 'getItemStyle',
+    lineStyle: 'getLineStyle',
+    areaStyle: 'getAreaStyle'
+  };
+  /**
+   * Set emphasis/blur/selected states of element.
+   */
+
+  function setStatesStylesFromModel(el, itemModel, styleType, // default itemStyle
+  getter) {
+    styleType = styleType || 'itemStyle';
+
+    for (var i = 0; i < OTHER_STATES.length; i++) {
+      var stateName = OTHER_STATES[i];
+      var model = itemModel.getModel([stateName, styleType]);
+      var state = el.ensureState(stateName); // Let it throw error if getterType is not found.
+
+      state.style = getter ? getter(model) : model[defaultStyleGetterMap[styleType]]();
+    }
+  }
+  /**
+   *
+   * Set element as highlight / downplay dispatcher.
+   * It will be checked when element recieved mouseover event or from highlight action.
+   * It's in change of all highlight/downplay behavior of it's children.
+   *
+   * @param el
+   * @param el.highDownSilentOnTouch
+   *        In touch device, mouseover event will be trigger on touchstart event
+   *        (see module:zrender/dom/HandlerProxy). By this mechanism, we can
+   *        conveniently use hoverStyle when tap on touch screen without additional
+   *        code for compatibility.
+   *        But if the chart/component has select feature, which usually also use
+   *        hoverStyle, there might be conflict between 'select-highlight' and
+   *        'hover-highlight' especially when roam is enabled (see geo for example).
+   *        In this case, `highDownSilentOnTouch` should be used to disable
+   *        hover-highlight on touch device.
+   * @param asDispatcher If `false`, do not set as "highDownDispatcher".
+   */
+
+
+  function setAsHighDownDispatcher(el, asDispatcher) {
+    var disable = asDispatcher === false;
+    var extendedEl = el; // Make `highDownSilentOnTouch` and `onStateChange` only work after
+    // `setAsHighDownDispatcher` called. Avoid it is modified by user unexpectedly.
+
+    if (el.highDownSilentOnTouch) {
+      extendedEl.__highDownSilentOnTouch = el.highDownSilentOnTouch;
+    } // Simple optimize, since this method might be
+    // called for each elements of a group in some cases.
+
+
+    if (!disable || extendedEl.__highDownDispatcher) {
+      // Emphasis, normal can be triggered manually by API or other components like hover link.
+      // el[method]('emphasis', onElementEmphasisEvent)[method]('normal', onElementNormalEvent);
+      // Also keep previous record.
+      extendedEl.__highByOuter = extendedEl.__highByOuter || 0;
+      extendedEl.__highDownDispatcher = !disable;
+    }
+  }
+
+  function isHighDownDispatcher(el) {
+    return !!(el && el.__highDownDispatcher);
+  }
+  /**
+   * Enable component highlight/downplay features:
+   * + hover link (within the same name)
+   * + focus blur in component
+   */
+
+  /**
+   * Support hightlight/downplay record on each elements.
+   * For the case: hover highlight/downplay (legend, visualMap, ...) and
+   * user triggerred hightlight/downplay should not conflict.
+   * Only all of the highlightDigit cleared, return to normal.
+   * @param {string} highlightKey
+   * @return {number} highlightDigit
+   */
+
+
+  function getHighlightDigit(highlightKey) {
+    var highlightDigit = _highlightKeyMap[highlightKey];
+
+    if (highlightDigit == null && _highlightNextDigit <= 32) {
+      highlightDigit = _highlightKeyMap[highlightKey] = _highlightNextDigit++;
+    }
+
+    return highlightDigit;
+  }
+
+  function isSelectChangePayload(payload) {
+    var payloadType = payload.type;
+    return payloadType === SELECT_ACTION_TYPE || payloadType === UNSELECT_ACTION_TYPE || payloadType === TOGGLE_SELECT_ACTION_TYPE;
+  }
+
+  function isHighDownPayload(payload) {
+    var payloadType = payload.type;
+    return payloadType === HIGHLIGHT_ACTION_TYPE || payloadType === DOWNPLAY_ACTION_TYPE;
+  }
+
+  function savePathStates(el) {
+    var store = getSavedStates(el);
+    store.normalFill = el.style.fill;
+    store.normalStroke = el.style.stroke;
+    var selectState = el.states.select || {};
+    store.selectFill = selectState.style && selectState.style.fill || null;
+    store.selectStroke = selectState.style && selectState.style.stroke || null;
+  }
+
+  var CMD$2 = PathProxy.CMD;
+  var points = [[], [], []];
+  var mathSqrt$2 = Math.sqrt;
+  var mathAtan2 = Math.atan2;
+
+  function transformPath(path, m) {
+    if (!m) {
+      return;
+    }
+
+    var data = path.data;
+    var len$$1 = path.len();
+    var cmd;
+    var nPoint;
+    var i;
+    var j;
+    var k;
+    var p;
+    var M = CMD$2.M;
+    var C = CMD$2.C;
+    var L = CMD$2.L;
+    var R = CMD$2.R;
+    var A = CMD$2.A;
+    var Q = CMD$2.Q;
+
+    for (i = 0, j = 0; i < len$$1;) {
+      cmd = data[i++];
+      j = i;
+      nPoint = 0;
+
+      switch (cmd) {
+        case M:
+          nPoint = 1;
+          break;
+
+        case L:
+          nPoint = 1;
+          break;
+
+        case C:
+          nPoint = 3;
+          break;
+
+        case Q:
+          nPoint = 2;
+          break;
+
+        case A:
+          var x = m[4];
+          var y = m[5];
+          var sx = mathSqrt$2(m[0] * m[0] + m[1] * m[1]);
+          var sy = mathSqrt$2(m[2] * m[2] + m[3] * m[3]);
+          var angle = mathAtan2(-m[1] / sy, m[0] / sx);
+          data[i] *= sx;
+          data[i++] += x;
+          data[i] *= sy;
+          data[i++] += y;
+          data[i++] *= sx;
+          data[i++] *= sy;
+          data[i++] += angle;
+          data[i++] += angle;
+          i += 2;
+          j = i;
+          break;
+
+        case R:
+          p[0] = data[i++];
+          p[1] = data[i++];
+          applyTransform(p, p, m);
+          data[j++] = p[0];
+          data[j++] = p[1];
+          p[0] += data[i++];
+          p[1] += data[i++];
+          applyTransform(p, p, m);
+          data[j++] = p[0];
+          data[j++] = p[1];
+      }
+
+      for (k = 0; k < nPoint; k++) {
+        var p_1 = points[k];
+        p_1[0] = data[i++];
+        p_1[1] = data[i++];
+        applyTransform(p_1, p_1, m);
+        data[j++] = p_1[0];
+        data[j++] = p_1[1];
+      }
+    }
+
+    path.increaseVersion();
+  }
+
+  var mathSqrt$1 = Math.sqrt;
+  var mathSin$2 = Math.sin;
+  var mathCos$2 = Math.cos;
+  var PI$1 = Math.PI;
+
+  function vMag(v) {
+    return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
+  }
+
+  function vRatio(u, v) {
+    return (u[0] * v[0] + u[1] * v[1]) / (vMag(u) * vMag(v));
+  }
+
+  function vAngle(u, v) {
+    return (u[0] * v[1] < u[1] * v[0] ? -1 : 1) * Math.acos(vRatio(u, v));
+  }
+
+  function processArc(x1, y1, x2, y2, fa, fs, rx, ry, psiDeg, cmd, path) {
+    var psi = psiDeg * (PI$1 / 180.0);
+    var xp = mathCos$2(psi) * (x1 - x2) / 2.0 + mathSin$2(psi) * (y1 - y2) / 2.0;
+    var yp = -1 * mathSin$2(psi) * (x1 - x2) / 2.0 + mathCos$2(psi) * (y1 - y2) / 2.0;
+    var lambda = xp * xp / (rx * rx) + yp * yp / (ry * ry);
+
+    if (lambda > 1) {
+      rx *= mathSqrt$1(lambda);
+      ry *= mathSqrt$1(lambda);
+    }
+
+    var f = (fa === fs ? -1 : 1) * mathSqrt$1((rx * rx * (ry * ry) - rx * rx * (yp * yp) - ry * ry * (xp * xp)) / (rx * rx * (yp * yp) + ry * ry * (xp * xp))) || 0;
+    var cxp = f * rx * yp / ry;
+    var cyp = f * -ry * xp / rx;
+    var cx = (x1 + x2) / 2.0 + mathCos$2(psi) * cxp - mathSin$2(psi) * cyp;
+    var cy = (y1 + y2) / 2.0 + mathSin$2(psi) * cxp + mathCos$2(psi) * cyp;
+    var theta = vAngle([1, 0], [(xp - cxp) / rx, (yp - cyp) / ry]);
+    var u = [(xp - cxp) / rx, (yp - cyp) / ry];
+    var v = [(-1 * xp - cxp) / rx, (-1 * yp - cyp) / ry];
+    var dTheta = vAngle(u, v);
+
+    if (vRatio(u, v) <= -1) {
+      dTheta = PI$1;
+    }
+
+    if (vRatio(u, v) >= 1) {
+      dTheta = 0;
+    }
+
+    if (dTheta < 0) {
+      var n = Math.round(dTheta / PI$1 * 1e6) / 1e6;
+      dTheta = PI$1 * 2 + n % 2 * PI$1;
+    }
+
+    path.addData(cmd, cx, cy, rx, ry, theta, dTheta, psi, fs);
+  }
+
+  var commandReg = /([mlvhzcqtsa])([^mlvhzcqtsa]*)/ig;
+  var numberReg = /-?([0-9]*\.)?[0-9]+([eE]-?[0-9]+)?/g;
+
+  function createPathProxyFromString(data) {
+    var path = new PathProxy();
+
+    if (!data) {
+      return path;
+    }
+
+    var cpx = 0;
+    var cpy = 0;
+    var subpathX = cpx;
+    var subpathY = cpy;
+    var prevCmd;
+    var CMD = PathProxy.CMD;
+    var cmdList = data.match(commandReg);
+
+    if (!cmdList) {
+      return path;
+    }
+
+    for (var l = 0; l < cmdList.length; l++) {
+      var cmdText = cmdList[l];
+      var cmdStr = cmdText.charAt(0);
+      var cmd = void 0;
+      var p = cmdText.match(numberReg) || [];
+      var pLen = p.length;
+
+      for (var i = 0; i < pLen; i++) {
+        p[i] = parseFloat(p[i]);
+      }
+
+      var off = 0;
+
+      while (off < pLen) {
+        var ctlPtx = void 0;
+        var ctlPty = void 0;
+        var rx = void 0;
+        var ry = void 0;
+        var psi = void 0;
+        var fa = void 0;
+        var fs = void 0;
+        var x1 = cpx;
+        var y1 = cpy;
+        var len = void 0;
+        var pathData = void 0;
+
+        switch (cmdStr) {
+          case 'l':
+            cpx += p[off++];
+            cpy += p[off++];
+            cmd = CMD.L;
+            path.addData(cmd, cpx, cpy);
+            break;
+
+          case 'L':
+            cpx = p[off++];
+            cpy = p[off++];
+            cmd = CMD.L;
+            path.addData(cmd, cpx, cpy);
+            break;
+
+          case 'm':
+            cpx += p[off++];
+            cpy += p[off++];
+            cmd = CMD.M;
+            path.addData(cmd, cpx, cpy);
+            subpathX = cpx;
+            subpathY = cpy;
+            cmdStr = 'l';
+            break;
+
+          case 'M':
+            cpx = p[off++];
+            cpy = p[off++];
+            cmd = CMD.M;
+            path.addData(cmd, cpx, cpy);
+            subpathX = cpx;
+            subpathY = cpy;
+            cmdStr = 'L';
+            break;
+
+          case 'h':
+            cpx += p[off++];
+            cmd = CMD.L;
+            path.addData(cmd, cpx, cpy);
+            break;
+
+          case 'H':
+            cpx = p[off++];
+            cmd = CMD.L;
+            path.addData(cmd, cpx, cpy);
+            break;
+
+          case 'v':
+            cpy += p[off++];
+            cmd = CMD.L;
+            path.addData(cmd, cpx, cpy);
+            break;
+
+          case 'V':
+            cpy = p[off++];
+            cmd = CMD.L;
+            path.addData(cmd, cpx, cpy);
+            break;
+
+          case 'C':
+            cmd = CMD.C;
+            path.addData(cmd, p[off++], p[off++], p[off++], p[off++], p[off++], p[off++]);
+            cpx = p[off - 2];
+            cpy = p[off - 1];
+            break;
+
+          case 'c':
+            cmd = CMD.C;
+            path.addData(cmd, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy, p[off++] + cpx, p[off++] + cpy);
+            cpx += p[off - 2];
+            cpy += p[off - 1];
+            break;
+
+          case 'S':
+            ctlPtx = cpx;
+            ctlPty = cpy;
+            len = path.len();
+            pathData = path.data;
+
+            if (prevCmd === CMD.C) {
+              ctlPtx += cpx - pathData[len - 4];
+              ctlPty += cpy - pathData[len - 3];
+            }
+
+            cmd = CMD.C;
+            x1 = p[off++];
+            y1 = p[off++];
+            cpx = p[off++];
+            cpy = p[off++];
+            path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
+            break;
+
+          case 's':
+            ctlPtx = cpx;
+            ctlPty = cpy;
+            len = path.len();
+            pathData = path.data;
+
+            if (prevCmd === CMD.C) {
+              ctlPtx += cpx - pathData[len - 4];
+              ctlPty += cpy - pathData[len - 3];
+            }
+
+            cmd = CMD.C;
+            x1 = cpx + p[off++];
+            y1 = cpy + p[off++];
+            cpx += p[off++];
+            cpy += p[off++];
+            path.addData(cmd, ctlPtx, ctlPty, x1, y1, cpx, cpy);
+            break;
+
+          case 'Q':
+            x1 = p[off++];
+            y1 = p[off++];
+            cpx = p[off++];
+            cpy = p[off++];
+            cmd = CMD.Q;
+            path.addData(cmd, x1, y1, cpx, cpy);
+            break;
+
+          case 'q':
+            x1 = p[off++] + cpx;
+            y1 = p[off++] + cpy;
+            cpx += p[off++];
+            cpy += p[off++];
+            cmd = CMD.Q;
+            path.addData(cmd, x1, y1, cpx, cpy);
+            break;
+
+          case 'T':
+            ctlPtx = cpx;
+            ctlPty = cpy;
+            len = path.len();
+            pathData = path.data;
+
+            if (prevCmd === CMD.Q) {
+              ctlPtx += cpx - pathData[len - 4];
+              ctlPty += cpy - pathData[len - 3];
+            }
+
+            cpx = p[off++];
+            cpy = p[off++];
+            cmd = CMD.Q;
+            path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
+            break;
+
+          case 't':
+            ctlPtx = cpx;
+            ctlPty = cpy;
+            len = path.len();
+            pathData = path.data;
+
+            if (prevCmd === CMD.Q) {
+              ctlPtx += cpx - pathData[len - 4];
+              ctlPty += cpy - pathData[len - 3];
+            }
+
+            cpx += p[off++];
+            cpy += p[off++];
+            cmd = CMD.Q;
+            path.addData(cmd, ctlPtx, ctlPty, cpx, cpy);
+            break;
+
+          case 'A':
+            rx = p[off++];
+            ry = p[off++];
+            psi = p[off++];
+            fa = p[off++];
+            fs = p[off++];
+            x1 = cpx, y1 = cpy;
+            cpx = p[off++];
+            cpy = p[off++];
+            cmd = CMD.A;
+            processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
+            break;
+
+          case 'a':
+            rx = p[off++];
+            ry = p[off++];
+            psi = p[off++];
+            fa = p[off++];
+            fs = p[off++];
+            x1 = cpx, y1 = cpy;
+            cpx += p[off++];
+            cpy += p[off++];
+            cmd = CMD.A;
+            processArc(x1, y1, cpx, cpy, fa, fs, rx, ry, psi, cmd, path);
+            break;
+        }
+      }
+
+      if (cmdStr === 'z' || cmdStr === 'Z') {
+        cmd = CMD.Z;
+        path.addData(cmd);
+        cpx = subpathX;
+        cpy = subpathY;
+      }
+
+      prevCmd = cmd;
+    }
+
+    path.toStatic();
+    return path;
+  }
+
+  var SVGPath = function (_super) {
+    __extends(SVGPath, _super);
+
+    function SVGPath() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    SVGPath.prototype.applyTransform = function (m) {};
+
+    return SVGPath;
+  }(Path);
+
+  function isPathProxy(path) {
+    return path.setData != null;
+  }
+
+  function createPathOptions(str, opts) {
+    var pathProxy = createPathProxyFromString(str);
+    var innerOpts = extend({}, opts);
+
+    innerOpts.buildPath = function (path) {
+      if (isPathProxy(path)) {
+        path.setData(pathProxy.data);
+        var ctx = path.getContext();
+
+        if (ctx) {
+          path.rebuildPath(ctx, 1);
+        }
+      } else {
+        var ctx = path;
+        pathProxy.rebuildPath(ctx, 1);
+      }
+    };
+
+    innerOpts.applyTransform = function (m) {
+      transformPath(pathProxy, m);
+      this.dirtyShape();
+    };
+
+    return innerOpts;
+  }
+
+  function createFromString(str, opts) {
+    return new SVGPath(createPathOptions(str, opts));
+  }
+
+  function extendFromString(str, defaultOpts) {
+    var innerOpts = createPathOptions(str, defaultOpts);
+
+    var Sub = function (_super) {
+      __extends(Sub, _super);
+
+      function Sub(opts) {
+        var _this = _super.call(this, opts) || this;
+
+        _this.applyTransform = innerOpts.applyTransform;
+        _this.buildPath = innerOpts.buildPath;
+        return _this;
+      }
+
+      return Sub;
+    }(SVGPath);
+
+    return Sub;
+  }
+
+  function mergePath$1(pathEls, opts) {
+    var pathList = [];
+    var len = pathEls.length;
+
+    for (var i = 0; i < len; i++) {
+      var pathEl = pathEls[i];
+      pathList.push(pathEl.getUpdatedPathProxy(true));
+    }
+
+    var pathBundle = new Path(opts);
+    pathBundle.createPathProxy();
+
+    pathBundle.buildPath = function (path) {
+      if (isPathProxy(path)) {
+        path.appendPath(pathList);
+        var ctx = path.getContext();
+
+        if (ctx) {
+          path.rebuildPath(ctx, 1);
+        }
+      }
+    };
+
+    return pathBundle;
+  }
+
+  var CircleShape = function () {
+    function CircleShape() {
+      this.cx = 0;
+      this.cy = 0;
+      this.r = 0;
+    }
+
+    return CircleShape;
+  }();
+
+  var Circle = function (_super) {
+    __extends(Circle, _super);
+
+    function Circle(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Circle.prototype.getDefaultShape = function () {
+      return new CircleShape();
+    };
+
+    Circle.prototype.buildPath = function (ctx, shape) {
+      ctx.moveTo(shape.cx + shape.r, shape.cy);
+      ctx.arc(shape.cx, shape.cy, shape.r, 0, Math.PI * 2);
+    };
+
+    return Circle;
+  }(Path);
+
+  Circle.prototype.type = 'circle';
+
+  var EllipseShape = function () {
+    function EllipseShape() {
+      this.cx = 0;
+      this.cy = 0;
+      this.rx = 0;
+      this.ry = 0;
+    }
+
+    return EllipseShape;
+  }();
+
+  var Ellipse = function (_super) {
+    __extends(Ellipse, _super);
+
+    function Ellipse(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Ellipse.prototype.getDefaultShape = function () {
+      return new EllipseShape();
+    };
+
+    Ellipse.prototype.buildPath = function (ctx, shape) {
+      var k = 0.5522848;
+      var x = shape.cx;
+      var y = shape.cy;
+      var a = shape.rx;
+      var b = shape.ry;
+      var ox = a * k;
+      var oy = b * k;
+      ctx.moveTo(x - a, y);
+      ctx.bezierCurveTo(x - a, y - oy, x - ox, y - b, x, y - b);
+      ctx.bezierCurveTo(x + ox, y - b, x + a, y - oy, x + a, y);
+      ctx.bezierCurveTo(x + a, y + oy, x + ox, y + b, x, y + b);
+      ctx.bezierCurveTo(x - ox, y + b, x - a, y + oy, x - a, y);
+      ctx.closePath();
+    };
+
+    return Ellipse;
+  }(Path);
+
+  Ellipse.prototype.type = 'ellipse';
+  var PI$2 = Math.PI;
+  var PI2$5 = PI$2 * 2;
+  var mathSin$3 = Math.sin;
+  var mathCos$3 = Math.cos;
+  var mathACos = Math.acos;
+  var mathATan2 = Math.atan2;
+  var mathAbs$1 = Math.abs;
+  var mathSqrt$3 = Math.sqrt;
+  var mathMax$4 = Math.max;
+  var mathMin$4 = Math.min;
+  var e = 1e-4;
+
+  function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
+    var dx10 = x1 - x0;
+    var dy10 = y1 - y0;
+    var dx32 = x3 - x2;
+    var dy32 = y3 - y2;
+    var t = dy32 * dx10 - dx32 * dy10;
+
+    if (t * t < e) {
+      return;
+    }
+
+    t = (dx32 * (y0 - y2) - dy32 * (x0 - x2)) / t;
+    return [x0 + t * dx10, y0 + t * dy10];
+  }
+
+  function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) {
+    var x01 = x0 - x1;
+    var y01 = y0 - y1;
+    var lo = (clockwise ? cr : -cr) / mathSqrt$3(x01 * x01 + y01 * y01);
+    var ox = lo * y01;
+    var oy = -lo * x01;
+    var x11 = x0 + ox;
+    var y11 = y0 + oy;
+    var x10 = x1 + ox;
+    var y10 = y1 + oy;
+    var x00 = (x11 + x10) / 2;
+    var y00 = (y11 + y10) / 2;
+    var dx = x10 - x11;
+    var dy = y10 - y11;
+    var d2 = dx * dx + dy * dy;
+    var r = radius - cr;
+    var s = x11 * y10 - x10 * y11;
+    var d = (dy < 0 ? -1 : 1) * mathSqrt$3(mathMax$4(0, r * r * d2 - s * s));
+    var cx0 = (s * dy - dx * d) / d2;
+    var cy0 = (-s * dx - dy * d) / d2;
+    var cx1 = (s * dy + dx * d) / d2;
+    var cy1 = (-s * dx + dy * d) / d2;
+    var dx0 = cx0 - x00;
+    var dy0 = cy0 - y00;
+    var dx1 = cx1 - x00;
+    var dy1 = cy1 - y00;
+
+    if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) {
+      cx0 = cx1;
+      cy0 = cy1;
+    }
+
+    return {
+      cx: cx0,
+      cy: cy0,
+      x0: -ox,
+      y0: -oy,
+      x1: cx0 * (radius / r - 1),
+      y1: cy0 * (radius / r - 1)
+    };
+  }
+
+  function normalizeCornerRadius(cr) {
+    var arr;
+
+    if (isArray(cr)) {
+      var len = cr.length;
+
+      if (!len) {
+        return cr;
+      }
+
+      if (len === 1) {
+        arr = [cr[0], cr[0], 0, 0];
+      } else if (len === 2) {
+        arr = [cr[0], cr[0], cr[1], cr[1]];
+      } else if (len === 3) {
+        arr = cr.concat(cr[2]);
+      } else {
+        arr = cr;
+      }
+    } else {
+      arr = [cr, cr, cr, cr];
+    }
+
+    return arr;
+  }
+
+  function buildPath$1(ctx, shape) {
+    var _a;
+
+    var radius = mathMax$4(shape.r, 0);
+    var innerRadius = mathMax$4(shape.r0 || 0, 0);
+    var hasRadius = radius > 0;
+    var hasInnerRadius = innerRadius > 0;
+
+    if (!hasRadius && !hasInnerRadius) {
+      return;
+    }
+
+    if (!hasRadius) {
+      radius = innerRadius;
+      innerRadius = 0;
+    }
+
+    if (innerRadius > radius) {
+      var tmp = radius;
+      radius = innerRadius;
+      innerRadius = tmp;
+    }
+
+    var startAngle = shape.startAngle,
+        endAngle = shape.endAngle;
+
+    if (isNaN(startAngle) || isNaN(endAngle)) {
+      return;
+    }
+
+    var cx = shape.cx,
+        cy = shape.cy;
+    var clockwise = !!shape.clockwise;
+    var arc = mathAbs$1(endAngle - startAngle);
+    var mod = arc > PI2$5 && arc % PI2$5;
+    mod > e && (arc = mod);
+
+    if (!(radius > e)) {
+      ctx.moveTo(cx, cy);
+    } else if (arc > PI2$5 - e) {
+      ctx.moveTo(cx + radius * mathCos$3(startAngle), cy + radius * mathSin$3(startAngle));
+      ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise);
+
+      if (innerRadius > e) {
+        ctx.moveTo(cx + innerRadius * mathCos$3(endAngle), cy + innerRadius * mathSin$3(endAngle));
+        ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise);
+      }
+    } else {
+      var icrStart = void 0;
+      var icrEnd = void 0;
+      var ocrStart = void 0;
+      var ocrEnd = void 0;
+      var ocrs = void 0;
+      var ocre = void 0;
+      var icrs = void 0;
+      var icre = void 0;
+      var ocrMax = void 0;
+      var icrMax = void 0;
+      var limitedOcrMax = void 0;
+      var limitedIcrMax = void 0;
+      var xre = void 0;
+      var yre = void 0;
+      var xirs = void 0;
+      var yirs = void 0;
+      var xrs = radius * mathCos$3(startAngle);
+      var yrs = radius * mathSin$3(startAngle);
+      var xire = innerRadius * mathCos$3(endAngle);
+      var yire = innerRadius * mathSin$3(endAngle);
+      var hasArc = arc > e;
+
+      if (hasArc) {
+        var cornerRadius = shape.cornerRadius;
+
+        if (cornerRadius) {
+          _a = normalizeCornerRadius(cornerRadius), icrStart = _a[0], icrEnd = _a[1], ocrStart = _a[2], ocrEnd = _a[3];
+        }
+
+        var halfRd = mathAbs$1(radius - innerRadius) / 2;
+        ocrs = mathMin$4(halfRd, ocrStart);
+        ocre = mathMin$4(halfRd, ocrEnd);
+        icrs = mathMin$4(halfRd, icrStart);
+        icre = mathMin$4(halfRd, icrEnd);
+        limitedOcrMax = ocrMax = mathMax$4(ocrs, ocre);
+        limitedIcrMax = icrMax = mathMax$4(icrs, icre);
+
+        if (ocrMax > e || icrMax > e) {
+          xre = radius * mathCos$3(endAngle);
+          yre = radius * mathSin$3(endAngle);
+          xirs = innerRadius * mathCos$3(startAngle);
+          yirs = innerRadius * mathSin$3(startAngle);
+
+          if (arc < PI$2) {
+            var it_1 = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire);
+
+            if (it_1) {
+              var x0 = xrs - it_1[0];
+              var y0 = yrs - it_1[1];
+              var x1 = xre - it_1[0];
+              var y1 = yre - it_1[1];
+              var a = 1 / mathSin$3(mathACos((x0 * x1 + y0 * y1) / (mathSqrt$3(x0 * x0 + y0 * y0) * mathSqrt$3(x1 * x1 + y1 * y1))) / 2);
+              var b = mathSqrt$3(it_1[0] * it_1[0] + it_1[1] * it_1[1]);
+              limitedOcrMax = mathMin$4(ocrMax, (radius - b) / (a + 1));
+              limitedIcrMax = mathMin$4(icrMax, (innerRadius - b) / (a - 1));
+            }
+          }
+        }
+      }
+
+      if (!hasArc) {
+        ctx.moveTo(cx + xrs, cy + yrs);
+      } else if (limitedOcrMax > e) {
+        var crStart = mathMin$4(ocrStart, limitedOcrMax);
+        var crEnd = mathMin$4(ocrEnd, limitedOcrMax);
+        var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, crStart, clockwise);
+        var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, crEnd, clockwise);
+        ctx.moveTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0);
+
+        if (limitedOcrMax < ocrMax && crStart === crEnd) {
+          ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedOcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise);
+        } else {
+          crStart > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crStart, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise);
+          ctx.arc(cx, cy, radius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), !clockwise);
+          crEnd > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crEnd, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise);
+        }
+      } else {
+        ctx.moveTo(cx + xrs, cy + yrs);
+        ctx.arc(cx, cy, radius, startAngle, endAngle, !clockwise);
+      }
+
+      if (!(innerRadius > e) || !hasArc) {
+        ctx.lineTo(cx + xire, cy + yire);
+      } else if (limitedIcrMax > e) {
+        var crStart = mathMin$4(icrStart, limitedIcrMax);
+        var crEnd = mathMin$4(icrEnd, limitedIcrMax);
+        var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -crEnd, clockwise);
+        var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -crStart, clockwise);
+        ctx.lineTo(cx + ct0.cx + ct0.x0, cy + ct0.cy + ct0.y0);
+
+        if (limitedIcrMax < icrMax && crStart === crEnd) {
+          ctx.arc(cx + ct0.cx, cy + ct0.cy, limitedIcrMax, mathATan2(ct0.y0, ct0.x0), mathATan2(ct1.y0, ct1.x0), !clockwise);
+        } else {
+          crEnd > 0 && ctx.arc(cx + ct0.cx, cy + ct0.cy, crEnd, mathATan2(ct0.y0, ct0.x0), mathATan2(ct0.y1, ct0.x1), !clockwise);
+          ctx.arc(cx, cy, innerRadius, mathATan2(ct0.cy + ct0.y1, ct0.cx + ct0.x1), mathATan2(ct1.cy + ct1.y1, ct1.cx + ct1.x1), clockwise);
+          crStart > 0 && ctx.arc(cx + ct1.cx, cy + ct1.cy, crStart, mathATan2(ct1.y1, ct1.x1), mathATan2(ct1.y0, ct1.x0), !clockwise);
+        }
+      } else {
+        ctx.lineTo(cx + xire, cy + yire);
+        ctx.arc(cx, cy, innerRadius, endAngle, startAngle, clockwise);
+      }
+    }
+
+    ctx.closePath();
+  }
+
+  var SectorShape = function () {
+    function SectorShape() {
+      this.cx = 0;
+      this.cy = 0;
+      this.r0 = 0;
+      this.r = 0;
+      this.startAngle = 0;
+      this.endAngle = Math.PI * 2;
+      this.clockwise = true;
+      this.cornerRadius = 0;
+    }
+
+    return SectorShape;
+  }();
+
+  var Sector = function (_super) {
+    __extends(Sector, _super);
+
+    function Sector(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Sector.prototype.getDefaultShape = function () {
+      return new SectorShape();
+    };
+
+    Sector.prototype.buildPath = function (ctx, shape) {
+      buildPath$1(ctx, shape);
+    };
+
+    Sector.prototype.isZeroArea = function () {
+      return this.shape.startAngle === this.shape.endAngle || this.shape.r === this.shape.r0;
+    };
+
+    return Sector;
+  }(Path);
+
+  Sector.prototype.type = 'sector';
+
+  var RingShape = function () {
+    function RingShape() {
+      this.cx = 0;
+      this.cy = 0;
+      this.r = 0;
+      this.r0 = 0;
+    }
+
+    return RingShape;
+  }();
+
+  var Ring = function (_super) {
+    __extends(Ring, _super);
+
+    function Ring(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Ring.prototype.getDefaultShape = function () {
+      return new RingShape();
+    };
+
+    Ring.prototype.buildPath = function (ctx, shape) {
+      var x = shape.cx;
+      var y = shape.cy;
+      var PI2 = Math.PI * 2;
+      ctx.moveTo(x + shape.r, y);
+      ctx.arc(x, y, shape.r, 0, PI2, false);
+      ctx.moveTo(x + shape.r0, y);
+      ctx.arc(x, y, shape.r0, 0, PI2, true);
+    };
+
+    return Ring;
+  }(Path);
+
+  Ring.prototype.type = 'ring';
+
+  function smoothBezier(points, smooth, isLoop, constraint) {
+    var cps = [];
+    var v = [];
+    var v1 = [];
+    var v2 = [];
+    var prevPoint;
+    var nextPoint;
+    var min$$1;
+    var max$$1;
+
+    if (constraint) {
+      min$$1 = [Infinity, Infinity];
+      max$$1 = [-Infinity, -Infinity];
+
+      for (var i = 0, len$$1 = points.length; i < len$$1; i++) {
+        min(min$$1, min$$1, points[i]);
+        max(max$$1, max$$1, points[i]);
+      }
+
+      min(min$$1, min$$1, constraint[0]);
+      max(max$$1, max$$1, constraint[1]);
+    }
+
+    for (var i = 0, len$$1 = points.length; i < len$$1; i++) {
+      var point = points[i];
+
+      if (isLoop) {
+        prevPoint = points[i ? i - 1 : len$$1 - 1];
+        nextPoint = points[(i + 1) % len$$1];
+      } else {
+        if (i === 0 || i === len$$1 - 1) {
+          cps.push(clone$1(points[i]));
+          continue;
+        } else {
+          prevPoint = points[i - 1];
+          nextPoint = points[i + 1];
+        }
+      }
+
+      sub(v, nextPoint, prevPoint);
+      scale(v, v, smooth);
+      var d0 = distance(point, prevPoint);
+      var d1 = distance(point, nextPoint);
+      var sum = d0 + d1;
+
+      if (sum !== 0) {
+        d0 /= sum;
+        d1 /= sum;
+      }
+
+      scale(v1, v, -d0);
+      scale(v2, v, d1);
+      var cp0 = add([], point, v1);
+      var cp1 = add([], point, v2);
+
+      if (constraint) {
+        max(cp0, cp0, min$$1);
+        min(cp0, cp0, max$$1);
+        max(cp1, cp1, min$$1);
+        min(cp1, cp1, max$$1);
+      }
+
+      cps.push(cp0);
+      cps.push(cp1);
+    }
+
+    if (isLoop) {
+      cps.push(cps.shift());
+    }
+
+    return cps;
+  }
+
+  function buildPath$2(ctx, shape, closePath) {
+    var smooth = shape.smooth;
+    var points = shape.points;
+
+    if (points && points.length >= 2) {
+      if (smooth) {
+        var controlPoints = smoothBezier(points, smooth, closePath, shape.smoothConstraint);
+        ctx.moveTo(points[0][0], points[0][1]);
+        var len = points.length;
+
+        for (var i = 0; i < (closePath ? len : len - 1); i++) {
+          var cp1 = controlPoints[i * 2];
+          var cp2 = controlPoints[i * 2 + 1];
+          var p = points[(i + 1) % len];
+          ctx.bezierCurveTo(cp1[0], cp1[1], cp2[0], cp2[1], p[0], p[1]);
+        }
+      } else {
+        ctx.moveTo(points[0][0], points[0][1]);
+
+        for (var i = 1, l = points.length; i < l; i++) {
+          ctx.lineTo(points[i][0], points[i][1]);
+        }
+      }
+
+      closePath && ctx.closePath();
+    }
+  }
+
+  var PolygonShape = function () {
+    function PolygonShape() {
+      this.points = null;
+      this.smooth = 0;
+      this.smoothConstraint = null;
+    }
+
+    return PolygonShape;
+  }();
+
+  var Polygon = function (_super) {
+    __extends(Polygon, _super);
+
+    function Polygon(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Polygon.prototype.getDefaultShape = function () {
+      return new PolygonShape();
+    };
+
+    Polygon.prototype.buildPath = function (ctx, shape) {
+      buildPath$2(ctx, shape, true);
+    };
+
+    return Polygon;
+  }(Path);
+
+  Polygon.prototype.type = 'polygon';
+
+  var PolylineShape = function () {
+    function PolylineShape() {
+      this.points = null;
+      this.percent = 1;
+      this.smooth = 0;
+      this.smoothConstraint = null;
+    }
+
+    return PolylineShape;
+  }();
+
+  var Polyline = function (_super) {
+    __extends(Polyline, _super);
+
+    function Polyline(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Polyline.prototype.getDefaultStyle = function () {
+      return {
+        stroke: '#000',
+        fill: null
+      };
+    };
+
+    Polyline.prototype.getDefaultShape = function () {
+      return new PolylineShape();
+    };
+
+    Polyline.prototype.buildPath = function (ctx, shape) {
+      buildPath$2(ctx, shape, false);
+    };
+
+    return Polyline;
+  }(Path);
+
+  Polyline.prototype.type = 'polyline';
+  var subPixelOptimizeOutputShape$1 = {};
+
+  var LineShape = function () {
+    function LineShape() {
+      this.x1 = 0;
+      this.y1 = 0;
+      this.x2 = 0;
+      this.y2 = 0;
+      this.percent = 1;
+    }
+
+    return LineShape;
+  }();
+
+  var Line = function (_super) {
+    __extends(Line, _super);
+
+    function Line(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Line.prototype.getDefaultStyle = function () {
+      return {
+        stroke: '#000',
+        fill: null
+      };
+    };
+
+    Line.prototype.getDefaultShape = function () {
+      return new LineShape();
+    };
+
+    Line.prototype.buildPath = function (ctx, shape) {
+      var x1;
+      var y1;
+      var x2;
+      var y2;
+
+      if (this.subPixelOptimize) {
+        var optimizedShape = subPixelOptimizeLine(subPixelOptimizeOutputShape$1, shape, this.style);
+        x1 = optimizedShape.x1;
+        y1 = optimizedShape.y1;
+        x2 = optimizedShape.x2;
+        y2 = optimizedShape.y2;
+      } else {
+        x1 = shape.x1;
+        y1 = shape.y1;
+        x2 = shape.x2;
+        y2 = shape.y2;
+      }
+
+      var percent = shape.percent;
+
+      if (percent === 0) {
+        return;
+      }
+
+      ctx.moveTo(x1, y1);
+
+      if (percent < 1) {
+        x2 = x1 * (1 - percent) + x2 * percent;
+        y2 = y1 * (1 - percent) + y2 * percent;
+      }
+
+      ctx.lineTo(x2, y2);
+    };
+
+    Line.prototype.pointAt = function (p) {
+      var shape = this.shape;
+      return [shape.x1 * (1 - p) + shape.x2 * p, shape.y1 * (1 - p) + shape.y2 * p];
+    };
+
+    return Line;
+  }(Path);
+
+  Line.prototype.type = 'line';
+  var out = [];
+
+  var BezierCurveShape = function () {
+    function BezierCurveShape() {
+      this.x1 = 0;
+      this.y1 = 0;
+      this.x2 = 0;
+      this.y2 = 0;
+      this.cpx1 = 0;
+      this.cpy1 = 0;
+      this.percent = 1;
+    }
+
+    return BezierCurveShape;
+  }();
+
+  function someVectorAt(shape, t, isTangent) {
+    var cpx2 = shape.cpx2;
+    var cpy2 = shape.cpy2;
+
+    if (cpx2 != null || cpy2 != null) {
+      return [(isTangent ? cubicDerivativeAt : cubicAt)(shape.x1, shape.cpx1, shape.cpx2, shape.x2, t), (isTangent ? cubicDerivativeAt : cubicAt)(shape.y1, shape.cpy1, shape.cpy2, shape.y2, t)];
+    } else {
+      return [(isTangent ? quadraticDerivativeAt : quadraticAt)(shape.x1, shape.cpx1, shape.x2, t), (isTangent ? quadraticDerivativeAt : quadraticAt)(shape.y1, shape.cpy1, shape.y2, t)];
+    }
+  }
+
+  var BezierCurve = function (_super) {
+    __extends(BezierCurve, _super);
+
+    function BezierCurve(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    BezierCurve.prototype.getDefaultStyle = function () {
+      return {
+        stroke: '#000',
+        fill: null
+      };
+    };
+
+    BezierCurve.prototype.getDefaultShape = function () {
+      return new BezierCurveShape();
+    };
+
+    BezierCurve.prototype.buildPath = function (ctx, shape) {
+      var x1 = shape.x1;
+      var y1 = shape.y1;
+      var x2 = shape.x2;
+      var y2 = shape.y2;
+      var cpx1 = shape.cpx1;
+      var cpy1 = shape.cpy1;
+      var cpx2 = shape.cpx2;
+      var cpy2 = shape.cpy2;
+      var percent = shape.percent;
+
+      if (percent === 0) {
+        return;
+      }
+
+      ctx.moveTo(x1, y1);
+
+      if (cpx2 == null || cpy2 == null) {
+        if (percent < 1) {
+          quadraticSubdivide(x1, cpx1, x2, percent, out);
+          cpx1 = out[1];
+          x2 = out[2];
+          quadraticSubdivide(y1, cpy1, y2, percent, out);
+          cpy1 = out[1];
+          y2 = out[2];
+        }
+
+        ctx.quadraticCurveTo(cpx1, cpy1, x2, y2);
+      } else {
+        if (percent < 1) {
+          cubicSubdivide(x1, cpx1, cpx2, x2, percent, out);
+          cpx1 = out[1];
+          cpx2 = out[2];
+          x2 = out[3];
+          cubicSubdivide(y1, cpy1, cpy2, y2, percent, out);
+          cpy1 = out[1];
+          cpy2 = out[2];
+          y2 = out[3];
+        }
+
+        ctx.bezierCurveTo(cpx1, cpy1, cpx2, cpy2, x2, y2);
+      }
+    };
+
+    BezierCurve.prototype.pointAt = function (t) {
+      return someVectorAt(this.shape, t, false);
+    };
+
+    BezierCurve.prototype.tangentAt = function (t) {
+      var p = someVectorAt(this.shape, t, true);
+      return normalize(p, p);
+    };
+
+    return BezierCurve;
+  }(Path);
+
+  BezierCurve.prototype.type = 'bezier-curve';
+
+  var ArcShape = function () {
+    function ArcShape() {
+      this.cx = 0;
+      this.cy = 0;
+      this.r = 0;
+      this.startAngle = 0;
+      this.endAngle = Math.PI * 2;
+      this.clockwise = true;
+    }
+
+    return ArcShape;
+  }();
+
+  var Arc = function (_super) {
+    __extends(Arc, _super);
+
+    function Arc(opts) {
+      return _super.call(this, opts) || this;
+    }
+
+    Arc.prototype.getDefaultStyle = function () {
+      return {
+        stroke: '#000',
+        fill: null
+      };
+    };
+
+    Arc.prototype.getDefaultShape = function () {
+      return new ArcShape();
+    };
+
+    Arc.prototype.buildPath = function (ctx, shape) {
+      var x = shape.cx;
+      var y = shape.cy;
+      var r = Math.max(shape.r, 0);
+      var startAngle = shape.startAngle;
+      var endAngle = shape.endAngle;
+      var clockwise = shape.clockwise;
+      var unitX = Math.cos(startAngle);
+      var unitY = Math.sin(startAngle);
+      ctx.moveTo(unitX * r + x, unitY * r + y);
+      ctx.arc(x, y, r, startAngle, endAngle, !clockwise);
+    };
+
+    return Arc;
+  }(Path);
+
+  Arc.prototype.type = 'arc';
+
+  var CompoundPath = function (_super) {
+    __extends(CompoundPath, _super);
+
+    function CompoundPath() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = 'compound';
+      return _this;
+    }
+
+    CompoundPath.prototype._updatePathDirty = function () {
+      var paths = this.shape.paths;
+      var dirtyPath = this.shapeChanged();
+
+      for (var i = 0; i < paths.length; i++) {
+        dirtyPath = dirtyPath || paths[i].shapeChanged();
+      }
+
+      if (dirtyPath) {
+        this.dirtyShape();
+      }
+    };
+
+    CompoundPath.prototype.beforeBrush = function () {
+      this._updatePathDirty();
+
+      var paths = this.shape.paths || [];
+      var scale = this.getGlobalScale();
+
+      for (var i = 0; i < paths.length; i++) {
+        if (!paths[i].path) {
+          paths[i].createPathProxy();
+        }
+
+        paths[i].path.setScale(scale[0], scale[1], paths[i].segmentIgnoreThreshold);
+      }
+    };
+
+    CompoundPath.prototype.buildPath = function (ctx, shape) {
+      var paths = shape.paths || [];
+
+      for (var i = 0; i < paths.length; i++) {
+        paths[i].buildPath(ctx, paths[i].shape, true);
+      }
+    };
+
+    CompoundPath.prototype.afterBrush = function () {
+      var paths = this.shape.paths || [];
+
+      for (var i = 0; i < paths.length; i++) {
+        paths[i].pathUpdated();
+      }
+    };
+
+    CompoundPath.prototype.getBoundingRect = function () {
+      this._updatePathDirty.call(this);
+
+      return Path.prototype.getBoundingRect.call(this);
+    };
+
+    return CompoundPath;
+  }(Path);
+
+  var Gradient = function () {
+    function Gradient(colorStops) {
+      this.colorStops = colorStops || [];
+    }
+
+    Gradient.prototype.addColorStop = function (offset, color) {
+      this.colorStops.push({
+        offset: offset,
+        color: color
+      });
+    };
+
+    return Gradient;
+  }();
+
+  var LinearGradient = function (_super) {
+    __extends(LinearGradient, _super);
+
+    function LinearGradient(x, y, x2, y2, colorStops, globalCoord) {
+      var _this = _super.call(this, colorStops) || this;
+
+      _this.x = x == null ? 0 : x;
+      _this.y = y == null ? 0 : y;
+      _this.x2 = x2 == null ? 1 : x2;
+      _this.y2 = y2 == null ? 0 : y2;
+      _this.type = 'linear';
+      _this.global = globalCoord || false;
+      return _this;
+    }
+
+    return LinearGradient;
+  }(Gradient);
+
+  var RadialGradient = function (_super) {
+    __extends(RadialGradient, _super);
+
+    function RadialGradient(x, y, r, colorStops, globalCoord) {
+      var _this = _super.call(this, colorStops) || this;
+
+      _this.x = x == null ? 0.5 : x;
+      _this.y = y == null ? 0.5 : y;
+      _this.r = r == null ? 0.5 : r;
+      _this.type = 'radial';
+      _this.global = globalCoord || false;
+      return _this;
+    }
+
+    return RadialGradient;
+  }(Gradient);
+
+  var extent = [0, 0];
+  var extent2 = [0, 0];
+  var minTv$1 = new Point();
+  var maxTv$1 = new Point();
+
+  var OrientedBoundingRect = function () {
+    function OrientedBoundingRect(rect, transform) {
+      this._corners = [];
+      this._axes = [];
+      this._origin = [0, 0];
+
+      for (var i = 0; i < 4; i++) {
+        this._corners[i] = new Point();
+      }
+
+      for (var i = 0; i < 2; i++) {
+        this._axes[i] = new Point();
+      }
+
+      if (rect) {
+        this.fromBoundingRect(rect, transform);
+      }
+    }
+
+    OrientedBoundingRect.prototype.fromBoundingRect = function (rect, transform) {
+      var corners = this._corners;
+      var axes = this._axes;
+      var x = rect.x;
+      var y = rect.y;
+      var x2 = x + rect.width;
+      var y2 = y + rect.height;
+      corners[0].set(x, y);
+      corners[1].set(x2, y);
+      corners[2].set(x2, y2);
+      corners[3].set(x, y2);
+
+      if (transform) {
+        for (var i = 0; i < 4; i++) {
+          corners[i].transform(transform);
+        }
+      }
+
+      Point.sub(axes[0], corners[1], corners[0]);
+      Point.sub(axes[1], corners[3], corners[0]);
+      axes[0].normalize();
+      axes[1].normalize();
+
+      for (var i = 0; i < 2; i++) {
+        this._origin[i] = axes[i].dot(corners[0]);
+      }
+    };
+
+    OrientedBoundingRect.prototype.intersect = function (other, mtv) {
+      var overlapped = true;
+      var noMtv = !mtv;
+      minTv$1.set(Infinity, Infinity);
+      maxTv$1.set(0, 0);
+
+      if (!this._intersectCheckOneSide(this, other, minTv$1, maxTv$1, noMtv, 1)) {
+        overlapped = false;
+
+        if (noMtv) {
+          return overlapped;
+        }
+      }
+
+      if (!this._intersectCheckOneSide(other, this, minTv$1, maxTv$1, noMtv, -1)) {
+        overlapped = false;
+
+        if (noMtv) {
+          return overlapped;
+        }
+      }
+
+      if (!noMtv) {
+        Point.copy(mtv, overlapped ? minTv$1 : maxTv$1);
+      }
+
+      return overlapped;
+    };
+
+    OrientedBoundingRect.prototype._intersectCheckOneSide = function (self, other, minTv, maxTv, noMtv, inverse) {
+      var overlapped = true;
+
+      for (var i = 0; i < 2; i++) {
+        var axis = this._axes[i];
+
+        this._getProjMinMaxOnAxis(i, self._corners, extent);
+
+        this._getProjMinMaxOnAxis(i, other._corners, extent2);
+
+        if (extent[1] < extent2[0] || extent[0] > extent2[1]) {
+          overlapped = false;
+
+          if (noMtv) {
+            return overlapped;
+          }
+
+          var dist0 = Math.abs(extent2[0] - extent[1]);
+          var dist1 = Math.abs(extent[0] - extent2[1]);
+
+          if (Math.min(dist0, dist1) > maxTv.len()) {
+            if (dist0 < dist1) {
+              Point.scale(maxTv, axis, -dist0 * inverse);
+            } else {
+              Point.scale(maxTv, axis, dist1 * inverse);
+            }
+          }
+        } else if (minTv) {
+          var dist0 = Math.abs(extent2[0] - extent[1]);
+          var dist1 = Math.abs(extent[0] - extent2[1]);
+
+          if (Math.min(dist0, dist1) < minTv.len()) {
+            if (dist0 < dist1) {
+              Point.scale(minTv, axis, dist0 * inverse);
+            } else {
+              Point.scale(minTv, axis, -dist1 * inverse);
+            }
+          }
+        }
+      }
+
+      return overlapped;
+    };
+
+    OrientedBoundingRect.prototype._getProjMinMaxOnAxis = function (dim, corners, out) {
+      var axis = this._axes[dim];
+      var origin = this._origin;
+      var proj = corners[0].dot(axis) + origin[dim];
+      var min = proj;
+      var max = proj;
+
+      for (var i = 1; i < corners.length; i++) {
+        var proj_1 = corners[i].dot(axis) + origin[dim];
+        min = Math.min(proj_1, min);
+        max = Math.max(proj_1, max);
+      }
+
+      out[0] = min;
+      out[1] = max;
+    };
+
+    return OrientedBoundingRect;
+  }();
+
+  var m = [];
+
+  var IncrementalDisplayable = function (_super) {
+    __extends(IncrementalDisplayable, _super);
+
+    function IncrementalDisplayable() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.notClear = true;
+      _this.incremental = true;
+      _this._displayables = [];
+      _this._temporaryDisplayables = [];
+      _this._cursor = 0;
+      return _this;
+    }
+
+    IncrementalDisplayable.prototype.traverse = function (cb, context) {
+      cb.call(context, this);
+    };
+
+    IncrementalDisplayable.prototype.useStyle = function () {
+      this.style = {};
+    };
+
+    IncrementalDisplayable.prototype.getCursor = function () {
+      return this._cursor;
+    };
+
+    IncrementalDisplayable.prototype.innerAfterBrush = function () {
+      this._cursor = this._displayables.length;
+    };
+
+    IncrementalDisplayable.prototype.clearDisplaybles = function () {
+      this._displayables = [];
+      this._temporaryDisplayables = [];
+      this._cursor = 0;
+      this.markRedraw();
+      this.notClear = false;
+    };
+
+    IncrementalDisplayable.prototype.clearTemporalDisplayables = function () {
+      this._temporaryDisplayables = [];
+    };
+
+    IncrementalDisplayable.prototype.addDisplayable = function (displayable, notPersistent) {
+      if (notPersistent) {
+        this._temporaryDisplayables.push(displayable);
+      } else {
+        this._displayables.push(displayable);
+      }
+
+      this.markRedraw();
+    };
+
+    IncrementalDisplayable.prototype.addDisplayables = function (displayables, notPersistent) {
+      notPersistent = notPersistent || false;
+
+      for (var i = 0; i < displayables.length; i++) {
+        this.addDisplayable(displayables[i], notPersistent);
+      }
+    };
+
+    IncrementalDisplayable.prototype.getDisplayables = function () {
+      return this._displayables;
+    };
+
+    IncrementalDisplayable.prototype.getTemporalDisplayables = function () {
+      return this._temporaryDisplayables;
+    };
+
+    IncrementalDisplayable.prototype.eachPendingDisplayable = function (cb) {
+      for (var i = this._cursor; i < this._displayables.length; i++) {
+        cb && cb(this._displayables[i]);
+      }
+
+      for (var i = 0; i < this._temporaryDisplayables.length; i++) {
+        cb && cb(this._temporaryDisplayables[i]);
+      }
+    };
+
+    IncrementalDisplayable.prototype.update = function () {
+      this.updateTransform();
+
+      for (var i = this._cursor; i < this._displayables.length; i++) {
+        var displayable = this._displayables[i];
+        displayable.parent = this;
+        displayable.update();
+        displayable.parent = null;
+      }
+
+      for (var i = 0; i < this._temporaryDisplayables.length; i++) {
+        var displayable = this._temporaryDisplayables[i];
+        displayable.parent = this;
+        displayable.update();
+        displayable.parent = null;
+      }
+    };
+
+    IncrementalDisplayable.prototype.getBoundingRect = function () {
+      if (!this._rect) {
+        var rect = new BoundingRect(Infinity, Infinity, -Infinity, -Infinity);
+
+        for (var i = 0; i < this._displayables.length; i++) {
+          var displayable = this._displayables[i];
+          var childRect = displayable.getBoundingRect().clone();
+
+          if (displayable.needLocalTransform()) {
+            childRect.applyTransform(displayable.getLocalTransform(m));
+          }
+
+          rect.union(childRect);
+        }
+
+        this._rect = rect;
+      }
+
+      return this._rect;
+    };
+
+    IncrementalDisplayable.prototype.contain = function (x, y) {
+      var localPos = this.transformCoordToLocal(x, y);
+      var rect = this.getBoundingRect();
+
+      if (rect.contain(localPos[0], localPos[1])) {
+        for (var i = 0; i < this._displayables.length; i++) {
+          var displayable = this._displayables[i];
+
+          if (displayable.contain(x, y)) {
+            return true;
+          }
+        }
+      }
+
+      return false;
+    };
+
+    return IncrementalDisplayable;
+  }(Displayable);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 transitionStore = makeInner();
+  /**
+   * Return null if animation is disabled.
+   */
+
+  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.
+
+    if (animatableModel && animatableModel.ecModel) {
+      var updatePayload = animatableModel.ecModel.getUpdatePayload();
+      animationPayload = updatePayload && updatePayload.animation;
+    }
+
+    var animationEnabled = animatableModel && animatableModel.isAnimationEnabled();
+    var isUpdate = animationType === 'update';
+
+    if (animationEnabled) {
+      var duration = void 0;
+      var easing = void 0;
+      var delay = void 0;
+
+      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.
+
+
+      if (animationPayload) {
+        animationPayload.duration != null && (duration = animationPayload.duration);
+        animationPayload.easing != null && (easing = animationPayload.easing);
+        animationPayload.delay != null && (delay = animationPayload.delay);
+      }
+
+      if (isFunction(delay)) {
+        delay = delay(dataIndex, extraDelayParams);
+      }
+
+      if (isFunction(duration)) {
+        duration = duration(dataIndex);
+      }
+
+      var config = {
+        duration: duration || 0,
+        delay: delay,
+        easing: easing
+      };
+      return config;
+    } else {
+      return null;
+    }
+  }
+
+  function animateOrSetProps(animationType, el, props, animatableModel, dataIndex, cb, during) {
+    var isFrom = false;
+    var removeOpt;
+
+    if (isFunction(dataIndex)) {
+      during = cb;
+      cb = dataIndex;
+      dataIndex = null;
+    } else if (isObject(dataIndex)) {
+      cb = dataIndex.cb;
+      during = dataIndex.during;
+      isFrom = dataIndex.isFrom;
+      removeOpt = dataIndex.removeOpt;
+      dataIndex = dataIndex.dataIndex;
+    }
+
+    var isRemove = animationType === 'leave';
+
+    if (!isRemove) {
+      // Must stop the remove animation.
+      el.stopAnimation('leave');
+    }
+
+    var animationConfig = getAnimationConfig(animationType, animatableModel, dataIndex, isRemove ? removeOpt || {} : null, animatableModel && animatableModel.getAnimationDelayParams ? animatableModel.getAnimationDelayParams(el, dataIndex) : null);
+
+    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
+      };
+      isFrom ? el.animateFrom(props, animateConfig) : el.animateTo(props, animateConfig);
+    } else {
+      el.stopAnimation(); // If `isFrom`, the props is the "from" props.
+
+      !isFrom && el.attr(props); // Call during at least once.
+
+      during && during(1);
+      cb && cb();
+    }
+  }
+  /**
+   * Update graphic element properties with or without animation according to the
+   * configuration in series.
+   *
+   * Caution: this method will stop previous animation.
+   * So do not use this method to one element twice before
+   * animation starts, unless you know what you are doing.
+   * @example
+   *     graphic.updateProps(el, {
+   *         position: [100, 100]
+   *     }, seriesModel, dataIndex, function () { console.log('Animation done!'); });
+   *     // Or
+   *     graphic.updateProps(el, {
+   *         position: [100, 100]
+   *     }, seriesModel, function () { console.log('Animation done!'); });
+   */
+
+
+  function updateProps(el, props, // TODO: TYPE AnimatableModel
+  animatableModel, dataIndex, cb, during) {
+    animateOrSetProps('update', el, props, animatableModel, dataIndex, cb, during);
+  }
+  /**
+   * Init graphic element properties with or without animation according to the
+   * configuration in series.
+   *
+   * Caution: this method will stop previous animation.
+   * So do not use this method to one element twice before
+   * animation starts, unless you know what you are doing.
+   */
+
+
+  function initProps(el, props, animatableModel, dataIndex, cb, during) {
+    animateOrSetProps('enter', 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 === 'leave') {
+        return true;
+      }
+    }
+
+    return false;
+  }
+  /**
+   * Remove graphic element
+   */
+
+
+  function removeElement(el, props, animatableModel, dataIndex, cb, during) {
+    // Don't do remove animation twice.
+    if (isElementRemoved(el)) {
+      return;
+    }
+
+    animateOrSetProps('leave', el, props, animatableModel, dataIndex, cb, during);
+  }
+
+  function fadeOutDisplayable(el, animatableModel, dataIndex, done) {
+    el.removeTextContent();
+    el.removeTextGuideLine();
+    removeElement(el, {
+      style: {
+        opacity: 0
+      }
+    }, animatableModel, dataIndex, done);
+  }
+
+  function removeElementWithFadeOut(el, animatableModel, dataIndex) {
+    function doRemove() {
+      el.parent && el.parent.remove(el);
+    } // Hide label and labelLine first
+    // TODO Also use fade out animation?
+
+
+    if (!el.isGroup) {
+      fadeOutDisplayable(el, animatableModel, dataIndex, doRemove);
+    } else {
+      el.traverse(function (disp) {
+        if (!disp.isGroup) {
+          // Can invoke doRemove multiple times.
+          fadeOutDisplayable(disp, animatableModel, dataIndex, doRemove);
+        }
+      });
+    }
+  }
+  /**
+   * 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 saveOldStyle(el) {
+    transitionStore(el).oldStyle = el.style;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 mathMax$3 = Math.max;
+  var mathMin$3 = 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
+   */
+
+
+  function makePath(pathData, opts, rect, layout) {
+    var path = createFromString(pathData, opts);
+
+    if (rect) {
+      if (layout === 'center') {
+        rect = centerGraphic(rect, path.getBoundingRect());
+      }
+
+      resizePath(path, rect);
+    }
+
+    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 = mergePath$1;
+  /**
+   * 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)
+   *
+   * @param target
+   * @param [ancestor]
+   */
+
+  function getTransform(target, ancestor) {
+    var mat = identity([]);
+
+    while (target && target !== ancestor) {
+      mul$1(mat, target.getLocalTransform(), mat);
+      target = target.parent;
+    }
+
+    return mat;
+  }
+  /**
+   * Apply transform to an vertex.
+   * @param target [x, y]
+   * @param transform Can be:
+   *      + Transform matrix: like [1, 0, 0, 1, 0, 0]
+   *      + {position, rotation, scale}, the same as `zrender/Transformable`.
+   * @param invert Whether use invert matrix.
+   * @return [x, y]
+   */
+
+
+  function applyTransform$1(target, transform, invert$$1) {
+    if (transform && !isArrayLike(transform)) {
+      transform = Transformable.getLocalTransform(transform);
+    }
+
+    if (invert$$1) {
+      transform = invert([], transform);
+    }
+
+    return applyTransform([], target, transform);
+  }
+  /**
+   * @param direction 'left' 'right' 'top' 'bottom'
+   * @param transform Transform matrix: like [1, 0, 0, 1, 0, 0]
+   * @param invert Whether use invert matrix.
+   * @return Transformed direction. 'left' 'right' 'top' 'bottom'
+   */
+
+
+  function transformDirection(direction, transform, invert$$1) {
+    // Pick a base, ensure that transform result will not be (0, 0).
+    var hBase = transform[4] === 0 || transform[5] === 0 || transform[0] === 0 ? 1 : Math.abs(2 * transform[4] / transform[0]);
+    var vBase = transform[4] === 0 || transform[5] === 0 || transform[2] === 0 ? 1 : Math.abs(2 * transform[4] / transform[2]);
+    var vertex = [direction === 'left' ? -hBase : direction === 'right' ? hBase : 0, direction === 'top' ? -vBase : direction === 'bottom' ? vBase : 0];
+    vertex = applyTransform$1(vertex, transform, invert$$1);
+    return Math.abs(vertex[0]) > Math.abs(vertex[1]) ? vertex[0] > 0 ? 'right' : 'left' : vertex[1] > 0 ? 'bottom' : 'top';
+  }
+
+  function isNotGroup(el) {
+    return !el.isGroup;
+  }
+
+  function isPath(el) {
+    return el.shape != null;
+  }
+  /**
+   * Apply group transition animation from g1 to g2.
+   * If no animatableModel, no animation.
+   */
+
+
+  function groupTransition(g1, g2, animatableModel) {
+    if (!g1 || !g2) {
+      return;
+    }
+
+    function getElMap(g) {
+      var elMap = {};
+      g.traverse(function (el) {
+        if (isNotGroup(el) && el.anid) {
+          elMap[el.anid] = el;
+        }
+      });
+      return elMap;
+    }
+
+    function getAnimatableProps(el) {
+      var obj = {
+        x: el.x,
+        y: el.y,
+        rotation: el.rotation
+      };
+
+      if (isPath(el)) {
+        obj.shape = extend({}, el.shape);
+      }
+
+      return obj;
+    }
+
+    var elMap1 = getElMap(g1);
+    g2.traverse(function (el) {
+      if (isNotGroup(el) && el.anid) {
+        var oldEl = elMap1[el.anid];
+
+        if (oldEl) {
+          var newProp = getAnimatableProps(el);
+          el.attr(getAnimatableProps(oldEl));
+          updateProps(el, newProp, animatableModel, getECData(el).dataIndex);
+        }
+      }
+    });
+  }
+
+  function clipPointsByRect(points, rect) {
+    // FIXME: this way migth be incorrect when grpahic clipped by a corner.
+    // and when element have border.
+    return map(points, function (point) {
+      var x = point[0];
+      x = mathMax$3(x, rect.x);
+      x = mathMin$3(x, rect.x + rect.width);
+      var y = point[1];
+      y = mathMax$3(y, rect.y);
+      y = mathMin$3(y, rect.y + rect.height);
+      return [x, y];
+    });
+  }
+  /**
+   * Return a new clipped rect. If rect size are negative, return undefined.
+   */
+
+
+  function clipRectByRect(targetRect, rect) {
+    var x = mathMax$3(targetRect.x, rect.x);
+    var x2 = mathMin$3(targetRect.x + targetRect.width, rect.x + rect.width);
+    var y = mathMax$3(targetRect.y, rect.y);
+    var y2 = mathMin$3(targetRect.y + targetRect.height, rect.y + rect.height); // If the total rect is cliped, nothing, including the border,
+    // should be painted. So return undefined.
+
+    if (x2 >= x && y2 >= y) {
+      return {
+        x: x,
+        y: y,
+        width: x2 - x,
+        height: y2 - y
+      };
+    }
+  }
+
+  function createIcon(iconStr, // Support 'image://' or 'path://' or direct svg path.
+  opt, rect) {
+    var innerOpts = extend({
+      rectHover: true
+    }, opt);
+    var style = innerOpts.style = {
+      strokeNoScale: true
+    };
+    rect = rect || {
+      x: -1,
+      y: -1,
+      width: 2,
+      height: 2
+    };
+
+    if (iconStr) {
+      return iconStr.indexOf('image://') === 0 ? (style.image = iconStr.slice(8), defaults(style, rect), new ZRImage(innerOpts)) : makePath(iconStr.replace('path://', ''), innerOpts, rect, 'center');
+    }
+  }
+  /**
+   * Return `true` if the given line (line `a`) and the given polygon
+   * are intersect.
+   * Note that we do not count colinear as intersect here because no
+   * requirement for that. We could do that if required in future.
+   */
+
+
+  function linePolygonIntersect(a1x, a1y, a2x, a2y, points) {
+    for (var i = 0, p2 = points[points.length - 1]; i < points.length; i++) {
+      var p = points[i];
+
+      if (lineLineIntersect(a1x, a1y, a2x, a2y, p[0], p[1], p2[0], p2[1])) {
+        return true;
+      }
+
+      p2 = p;
+    }
+  }
+  /**
+   * Return `true` if the given two lines (line `a` and line `b`)
+   * are intersect.
+   * Note that we do not count colinear as intersect here because no
+   * requirement for that. We could do that if required in future.
+   */
+
+
+  function lineLineIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y) {
+    // let `vec_m` to be `vec_a2 - vec_a1` and `vec_n` to be `vec_b2 - vec_b1`.
+    var mx = a2x - a1x;
+    var my = a2y - a1y;
+    var nx = b2x - b1x;
+    var ny = b2y - b1y; // `vec_m` and `vec_n` are parallel iff
+    //     exising `k` such that `vec_m = k · vec_n`, equivalent to `vec_m X vec_n = 0`.
+
+    var nmCrossProduct = crossProduct2d(nx, ny, mx, my);
+
+    if (nearZero(nmCrossProduct)) {
+      return false;
+    } // `vec_m` and `vec_n` are intersect iff
+    //     existing `p` and `q` in [0, 1] such that `vec_a1 + p * vec_m = vec_b1 + q * vec_n`,
+    //     such that `q = ((vec_a1 - vec_b1) X vec_m) / (vec_n X vec_m)`
+    //           and `p = ((vec_a1 - vec_b1) X vec_n) / (vec_n X vec_m)`.
+
+
+    var b1a1x = a1x - b1x;
+    var b1a1y = a1y - b1y;
+    var q = crossProduct2d(b1a1x, b1a1y, mx, my) / nmCrossProduct;
+
+    if (q < 0 || q > 1) {
+      return false;
+    }
+
+    var p = crossProduct2d(b1a1x, b1a1y, nx, ny) / nmCrossProduct;
+
+    if (p < 0 || p > 1) {
+      return false;
+    }
+
+    return true;
+  }
+  /**
+   * Cross product of 2-dimension vector.
+   */
+
+
+  function crossProduct2d(x1, y1, x2, y2) {
+    return x1 * y2 - x2 * y1;
+  }
+
+  function nearZero(val) {
+    return val <= 1e-6 && val >= -1e-6;
+  }
+
+  function setTooltipConfig(opt) {
+    var itemTooltipOption = opt.itemTooltipOption;
+    var componentModel = opt.componentModel;
+    var itemName = opt.itemName;
+    var itemTooltipOptionObj = isString(itemTooltipOption) ? {
+      formatter: itemTooltipOption
+    } : itemTooltipOption;
+    var mainType = componentModel.mainType;
+    var componentIndex = componentModel.componentIndex;
+    var formatterParams = {
+      componentType: mainType,
+      name: itemName,
+      $vars: ['name']
+    };
+    formatterParams[mainType + 'Index'] = componentIndex;
+    var formatterParamsExtra = opt.formatterParamsExtra;
+
+    if (formatterParamsExtra) {
+      each(keys(formatterParamsExtra), function (key) {
+        if (!hasOwn(formatterParams, key)) {
+          formatterParams[key] = formatterParamsExtra[key];
+          formatterParams.$vars.push(key);
+        }
+      });
+    }
+
+    var ecData = getECData(opt.el);
+    ecData.componentMainType = mainType;
+    ecData.componentIndex = componentIndex;
+    ecData.tooltipConfig = {
+      name: itemName,
+      option: defaults({
+        content: itemName,
+        formatterParams: formatterParams
+      }, itemTooltipOptionObj)
+    };
+  }
+
+  function traverseElement(el, cb) {
+    var stopped; // TODO
+    // Polyfill for fixing zrender group traverse don't visit it's root issue.
+
+    if (el.isGroup) {
+      stopped = cb(el);
+    }
+
+    if (!stopped) {
+      el.traverse(cb);
+    }
+  }
+
+  function traverseElements(els, cb) {
+    if (els) {
+      if (isArray(els)) {
+        for (var i = 0; i < els.length; i++) {
+          traverseElement(els[i], cb);
+        }
+      } else {
+        traverseElement(els, cb);
+      }
+    }
+  } // Register built-in shapes. These shapes might be overwirtten
+  // by users, although we do not recommend that.
+
+
+  registerShape('circle', Circle);
+  registerShape('ellipse', Ellipse);
+  registerShape('sector', Sector);
+  registerShape('ring', Ring);
+  registerShape('polygon', Polygon);
+  registerShape('polyline', Polyline);
+  registerShape('rect', Rect);
+  registerShape('line', Line);
+  registerShape('bezierCurve', BezierCurve);
+  registerShape('arc', Arc);
+  var graphic = (Object.freeze || Object)({
+    updateProps: updateProps,
+    initProps: initProps,
+    removeElement: removeElement,
+    removeElementWithFadeOut: removeElementWithFadeOut,
+    isElementRemoved: isElementRemoved,
+    extendShape: extendShape,
+    extendPath: extendPath,
+    registerShape: registerShape,
+    getShapeClass: getShapeClass,
+    makePath: makePath,
+    makeImage: makeImage,
+    mergePath: mergePath,
+    resizePath: resizePath,
+    subPixelOptimizeLine: subPixelOptimizeLine$1,
+    subPixelOptimizeRect: subPixelOptimizeRect$1,
+    subPixelOptimize: subPixelOptimize$1,
+    getTransform: getTransform,
+    applyTransform: applyTransform$1,
+    transformDirection: transformDirection,
+    groupTransition: groupTransition,
+    clipPointsByRect: clipPointsByRect,
+    clipRectByRect: clipRectByRect,
+    createIcon: createIcon,
+    linePolygonIntersect: linePolygonIntersect,
+    lineLineIntersect: lineLineIntersect,
+    setTooltipConfig: setTooltipConfig,
+    traverseElements: traverseElements,
+    Group: Group,
+    Image: ZRImage,
+    Text: ZRText,
+    Circle: Circle,
+    Ellipse: Ellipse,
+    Sector: Sector,
+    Ring: Ring,
+    Polygon: Polygon,
+    Polyline: Polyline,
+    Rect: Rect,
+    Line: Line,
+    BezierCurve: BezierCurve,
+    Arc: Arc,
+    IncrementalDisplayable: IncrementalDisplayable,
+    CompoundPath: CompoundPath,
+    LinearGradient: LinearGradient,
+    RadialGradient: RadialGradient,
+    BoundingRect: BoundingRect,
+    OrientedBoundingRect: OrientedBoundingRect,
+    Point: Point,
+    Path: Path
+  });
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 EMPTY_OBJ = {};
+
+  function setLabelText(label, labelTexts) {
+    for (var i = 0; i < SPECIAL_STATES.length; i++) {
+      var stateName = SPECIAL_STATES[i];
+      var text = labelTexts[stateName];
+      var state = label.ensureState(stateName);
+      state.style = state.style || {};
+      state.style.text = text;
+    }
+
+    var oldStates = label.currentStates.slice();
+    label.clearStates(true);
+    label.setStyle({
+      text: labelTexts.normal
+    });
+    label.useStates(oldStates, true);
+  }
+
+  function getLabelText(opt, stateModels, interpolatedValue) {
+    var labelFetcher = opt.labelFetcher;
+    var labelDataIndex = opt.labelDataIndex;
+    var labelDimIndex = opt.labelDimIndex;
+    var normalModel = stateModels.normal;
+    var baseText;
+
+    if (labelFetcher) {
+      baseText = labelFetcher.getFormattedLabel(labelDataIndex, 'normal', null, labelDimIndex, normalModel && normalModel.get('formatter'), interpolatedValue != null ? {
+        interpolatedValue: interpolatedValue
+      } : null);
+    }
+
+    if (baseText == null) {
+      baseText = isFunction(opt.defaultText) ? opt.defaultText(labelDataIndex, opt, interpolatedValue) : opt.defaultText;
+    }
+
+    var statesText = {
+      normal: baseText
+    };
+
+    for (var i = 0; i < SPECIAL_STATES.length; i++) {
+      var stateName = SPECIAL_STATES[i];
+      var stateModel = stateModels[stateName];
+      statesText[stateName] = retrieve2(labelFetcher ? labelFetcher.getFormattedLabel(labelDataIndex, stateName, null, labelDimIndex, stateModel && stateModel.get('formatter')) : null, baseText);
+    }
+
+    return statesText;
+  }
+
+  function setLabelStyle(targetEl, labelStatesModels, opt, stateSpecified // TODO specified position?
+  ) {
+    opt = opt || EMPTY_OBJ;
+    var isSetOnText = targetEl instanceof ZRText;
+    var needsCreateText = false;
+
+    for (var i = 0; i < DISPLAY_STATES.length; i++) {
+      var stateModel = labelStatesModels[DISPLAY_STATES[i]];
+
+      if (stateModel && stateModel.getShallow('show')) {
+        needsCreateText = true;
+        break;
+      }
+    }
+
+    var textContent = isSetOnText ? targetEl : targetEl.getTextContent();
+
+    if (needsCreateText) {
+      if (!isSetOnText) {
+        // Reuse the previous
+        if (!textContent) {
+          textContent = new ZRText();
+          targetEl.setTextContent(textContent);
+        } // Use same state proxy
+
+
+        if (targetEl.stateProxy) {
+          textContent.stateProxy = targetEl.stateProxy;
+        }
+      }
+
+      var labelStatesTexts = getLabelText(opt, labelStatesModels);
+      var normalModel = labelStatesModels.normal;
+      var showNormal = !!normalModel.getShallow('show');
+      var normalStyle = createTextStyle(normalModel, stateSpecified && stateSpecified.normal, opt, false, !isSetOnText);
+      normalStyle.text = labelStatesTexts.normal;
+
+      if (!isSetOnText) {
+        // Always create new
+        targetEl.setTextConfig(createTextConfig(normalModel, opt, false));
+      }
+
+      for (var i = 0; i < SPECIAL_STATES.length; i++) {
+        var stateName = SPECIAL_STATES[i];
+        var stateModel = labelStatesModels[stateName];
+
+        if (stateModel) {
+          var stateObj = textContent.ensureState(stateName);
+          var stateShow = !!retrieve2(stateModel.getShallow('show'), showNormal);
+
+          if (stateShow !== showNormal) {
+            stateObj.ignore = !stateShow;
+          }
+
+          stateObj.style = createTextStyle(stateModel, stateSpecified && stateSpecified[stateName], opt, true, !isSetOnText);
+          stateObj.style.text = labelStatesTexts[stateName];
+
+          if (!isSetOnText) {
+            var targetElEmphasisState = targetEl.ensureState(stateName);
+            targetElEmphasisState.textConfig = createTextConfig(stateModel, opt, true);
+          }
+        }
+      } // PENDING: if there is many requirements that emphasis position
+      // need to be different from normal position, we might consider
+      // auto slient is those cases.
+
+
+      textContent.silent = !!normalModel.getShallow('silent'); // Keep x and y
+
+      if (textContent.style.x != null) {
+        normalStyle.x = textContent.style.x;
+      }
+
+      if (textContent.style.y != null) {
+        normalStyle.y = textContent.style.y;
+      }
+
+      textContent.ignore = !showNormal; // Always create new style.
+
+      textContent.useStyle(normalStyle);
+      textContent.dirty();
+
+      if (opt.enableTextSetter) {
+        labelInner(textContent).setLabelText = function (interpolatedValue) {
+          var labelStatesTexts = getLabelText(opt, labelStatesModels, interpolatedValue);
+          setLabelText(textContent, labelStatesTexts);
+        };
+      }
+    } else if (textContent) {
+      // Not display rich text.
+      textContent.ignore = true;
+    }
+
+    targetEl.dirty();
+  }
+
+  function getLabelStatesModels(itemModel, labelName) {
+    labelName = labelName || 'label';
+    var statesModels = {
+      normal: itemModel.getModel(labelName)
+    };
+
+    for (var i = 0; i < SPECIAL_STATES.length; i++) {
+      var stateName = SPECIAL_STATES[i];
+      statesModels[stateName] = itemModel.getModel([stateName, labelName]);
+    }
+
+    return statesModels;
+  }
+  /**
+   * Set basic textStyle properties.
+   */
+
+
+  function createTextStyle(textStyleModel, specifiedTextStyle, // Fixed style in the code. Can't be set by model.
+  opt, isNotNormal, isAttached // If text is attached on an element. If so, auto color will handling in zrender.
+  ) {
+    var textStyle = {};
+    setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached);
+    specifiedTextStyle && extend(textStyle, specifiedTextStyle); // textStyle.host && textStyle.host.dirty && textStyle.host.dirty(false);
+
+    return textStyle;
+  }
+
+  function createTextConfig(textStyleModel, opt, isNotNormal) {
+    opt = opt || {};
+    var textConfig = {};
+    var labelPosition;
+    var labelRotate = textStyleModel.getShallow('rotate');
+    var labelDistance = retrieve2(textStyleModel.getShallow('distance'), isNotNormal ? null : 5);
+    var labelOffset = textStyleModel.getShallow('offset');
+    labelPosition = textStyleModel.getShallow('position') || (isNotNormal ? null : 'inside'); // 'outside' is not a valid zr textPostion value, but used
+    // in bar series, and magric type should be considered.
+
+    labelPosition === 'outside' && (labelPosition = opt.defaultOutsidePosition || 'top');
+
+    if (labelPosition != null) {
+      textConfig.position = labelPosition;
+    }
+
+    if (labelOffset != null) {
+      textConfig.offset = labelOffset;
+    }
+
+    if (labelRotate != null) {
+      labelRotate *= Math.PI / 180;
+      textConfig.rotation = labelRotate;
+    }
+
+    if (labelDistance != null) {
+      textConfig.distance = labelDistance;
+    } // fill and auto is determined by the color of path fill if it's not specified by developers.
+
+
+    textConfig.outsideFill = textStyleModel.get('color') === 'inherit' ? opt.inheritColor || null : 'auto';
+    return textConfig;
+  }
+  /**
+   * The uniform entry of set text style, that is, retrieve style definitions
+   * from `model` and set to `textStyle` object.
+   *
+   * Never in merge mode, but in overwrite mode, that is, all of the text style
+   * properties will be set. (Consider the states of normal and emphasis and
+   * default value can be adopted, merge would make the logic too complicated
+   * to manage.)
+   */
+
+
+  function setTextStyleCommon(textStyle, textStyleModel, opt, isNotNormal, isAttached) {
+    // Consider there will be abnormal when merge hover style to normal style if given default value.
+    opt = opt || EMPTY_OBJ;
+    var ecModel = textStyleModel.ecModel;
+    var globalTextStyle = ecModel && ecModel.option.textStyle; // Consider case:
+    // {
+    //     data: [{
+    //         value: 12,
+    //         label: {
+    //             rich: {
+    //                 // no 'a' here but using parent 'a'.
+    //             }
+    //         }
+    //     }],
+    //     rich: {
+    //         a: { ... }
+    //     }
+    // }
+
+    var richItemNames = getRichItemNames(textStyleModel);
+    var richResult;
+
+    if (richItemNames) {
+      richResult = {};
+
+      for (var name_1 in richItemNames) {
+        if (richItemNames.hasOwnProperty(name_1)) {
+          // Cascade is supported in rich.
+          var richTextStyle = textStyleModel.getModel(['rich', name_1]); // In rich, never `disableBox`.
+          // FIXME: consider `label: {formatter: '{a|xx}', color: 'blue', rich: {a: {}}}`,
+          // the default color `'blue'` will not be adopted if no color declared in `rich`.
+          // That might confuses users. So probably we should put `textStyleModel` as the
+          // root ancestor of the `richTextStyle`. But that would be a break change.
+
+          setTokenTextStyle(richResult[name_1] = {}, richTextStyle, globalTextStyle, opt, isNotNormal, isAttached, false, true);
+        }
+      }
+    }
+
+    if (richResult) {
+      textStyle.rich = richResult;
+    }
+
+    var overflow = textStyleModel.get('overflow');
+
+    if (overflow) {
+      textStyle.overflow = overflow;
+    }
+
+    var margin = textStyleModel.get('minMargin');
+
+    if (margin != null) {
+      textStyle.margin = margin;
+    }
+
+    setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, true, false);
+  } // Consider case:
+  // {
+  //     data: [{
+  //         value: 12,
+  //         label: {
+  //             rich: {
+  //                 // no 'a' here but using parent 'a'.
+  //             }
+  //         }
+  //     }],
+  //     rich: {
+  //         a: { ... }
+  //     }
+  // }
+  // TODO TextStyleModel
+
+
+  function getRichItemNames(textStyleModel) {
+    // Use object to remove duplicated names.
+    var richItemNameMap;
+
+    while (textStyleModel && textStyleModel !== textStyleModel.ecModel) {
+      var rich = (textStyleModel.option || EMPTY_OBJ).rich;
+
+      if (rich) {
+        richItemNameMap = richItemNameMap || {};
+        var richKeys = keys(rich);
+
+        for (var i = 0; i < richKeys.length; i++) {
+          var richKey = richKeys[i];
+          richItemNameMap[richKey] = 1;
+        }
+      }
+
+      textStyleModel = textStyleModel.parentModel;
+    }
+
+    return richItemNameMap;
+  }
+
+  var TEXT_PROPS_WITH_GLOBAL = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'textShadowColor', 'textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'];
+  var TEXT_PROPS_SELF = ['align', 'lineHeight', 'width', 'height', 'tag', 'verticalAlign'];
+  var TEXT_PROPS_BOX = ['padding', 'borderWidth', 'borderRadius', 'borderDashOffset', 'backgroundColor', 'borderColor', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'];
+
+  function setTokenTextStyle(textStyle, textStyleModel, globalTextStyle, opt, isNotNormal, isAttached, isBlock, inRich) {
+    // In merge mode, default value should not be given.
+    globalTextStyle = !isNotNormal && globalTextStyle || EMPTY_OBJ;
+    var inheritColor = opt && opt.inheritColor;
+    var fillColor = textStyleModel.getShallow('color');
+    var strokeColor = textStyleModel.getShallow('textBorderColor');
+    var opacity = retrieve2(textStyleModel.getShallow('opacity'), globalTextStyle.opacity);
+
+    if (fillColor === 'inherit' || fillColor === 'auto') {
+      {
+        if (fillColor === 'auto') {
+          deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
+        }
+      }
+
+      if (inheritColor) {
+        fillColor = inheritColor;
+      } else {
+        fillColor = null;
+      }
+    }
+
+    if (strokeColor === 'inherit' || strokeColor === 'auto') {
+      {
+        if (strokeColor === 'auto') {
+          deprecateReplaceLog('color: \'auto\'', 'color: \'inherit\'');
+        }
+      }
+
+      if (inheritColor) {
+        strokeColor = inheritColor;
+      } else {
+        strokeColor = null;
+      }
+    }
+
+    if (!isAttached) {
+      // Only use default global textStyle.color if text is individual.
+      // Otherwise it will use the strategy of attached text color because text may be on a path.
+      fillColor = fillColor || globalTextStyle.color;
+      strokeColor = strokeColor || globalTextStyle.textBorderColor;
+    }
+
+    if (fillColor != null) {
+      textStyle.fill = fillColor;
+    }
+
+    if (strokeColor != null) {
+      textStyle.stroke = strokeColor;
+    }
+
+    var textBorderWidth = retrieve2(textStyleModel.getShallow('textBorderWidth'), globalTextStyle.textBorderWidth);
+
+    if (textBorderWidth != null) {
+      textStyle.lineWidth = textBorderWidth;
+    }
+
+    var textBorderType = retrieve2(textStyleModel.getShallow('textBorderType'), globalTextStyle.textBorderType);
+
+    if (textBorderType != null) {
+      textStyle.lineDash = textBorderType;
+    }
+
+    var textBorderDashOffset = retrieve2(textStyleModel.getShallow('textBorderDashOffset'), globalTextStyle.textBorderDashOffset);
+
+    if (textBorderDashOffset != null) {
+      textStyle.lineDashOffset = textBorderDashOffset;
+    }
+
+    if (!isNotNormal && opacity == null && !inRich) {
+      opacity = opt && opt.defaultOpacity;
+    }
+
+    if (opacity != null) {
+      textStyle.opacity = opacity;
+    } // TODO
+
+
+    if (!isNotNormal && !isAttached) {
+      // Set default finally.
+      if (textStyle.fill == null && opt.inheritColor) {
+        textStyle.fill = opt.inheritColor;
+      }
+    } // Do not use `getFont` here, because merge should be supported, where
+    // part of these properties may be changed in emphasis style, and the
+    // others should remain their original value got from normal style.
+
+
+    for (var i = 0; i < TEXT_PROPS_WITH_GLOBAL.length; i++) {
+      var key = TEXT_PROPS_WITH_GLOBAL[i];
+      var val = retrieve2(textStyleModel.getShallow(key), globalTextStyle[key]);
+
+      if (val != null) {
+        textStyle[key] = val;
+      }
+    }
+
+    for (var i = 0; i < TEXT_PROPS_SELF.length; i++) {
+      var key = TEXT_PROPS_SELF[i];
+      var val = textStyleModel.getShallow(key);
+
+      if (val != null) {
+        textStyle[key] = val;
+      }
+    }
+
+    if (textStyle.verticalAlign == null) {
+      var baseline = textStyleModel.getShallow('baseline');
+
+      if (baseline != null) {
+        textStyle.verticalAlign = baseline;
+      }
+    }
+
+    if (!isBlock || !opt.disableBox) {
+      for (var i = 0; i < TEXT_PROPS_BOX.length; i++) {
+        var key = TEXT_PROPS_BOX[i];
+        var val = textStyleModel.getShallow(key);
+
+        if (val != null) {
+          textStyle[key] = val;
+        }
+      }
+
+      var borderType = textStyleModel.getShallow('borderType');
+
+      if (borderType != null) {
+        textStyle.borderDash = borderType;
+      }
+
+      if ((textStyle.backgroundColor === 'auto' || textStyle.backgroundColor === 'inherit') && inheritColor) {
+        {
+          if (textStyle.backgroundColor === 'auto') {
+            deprecateReplaceLog('backgroundColor: \'auto\'', 'backgroundColor: \'inherit\'');
+          }
+        }
+        textStyle.backgroundColor = inheritColor;
+      }
+
+      if ((textStyle.borderColor === 'auto' || textStyle.borderColor === 'inherit') && inheritColor) {
+        {
+          if (textStyle.borderColor === 'auto') {
+            deprecateReplaceLog('borderColor: \'auto\'', 'borderColor: \'inherit\'');
+          }
+        }
+        textStyle.borderColor = inheritColor;
+      }
+    }
+  }
+
+  function getFont(opt, ecModel) {
+    var gTextStyleModel = ecModel && ecModel.getModel('textStyle');
+    return trim([// FIXME in node-canvas fontWeight is before fontStyle
+    opt.fontStyle || gTextStyleModel && gTextStyleModel.getShallow('fontStyle') || '', opt.fontWeight || gTextStyleModel && gTextStyleModel.getShallow('fontWeight') || '', (opt.fontSize || gTextStyleModel && gTextStyleModel.getShallow('fontSize') || 12) + 'px', opt.fontFamily || gTextStyleModel && gTextStyleModel.getShallow('fontFamily') || 'sans-serif'].join(' '));
+  }
+
+  var labelInner = makeInner();
+
+  function setLabelValueAnimation(label, labelStatesModels, value, getDefaultText) {
+    if (!label) {
+      return;
+    }
+
+    var obj = labelInner(label);
+    obj.prevValue = obj.value;
+    obj.value = value;
+    var normalLabelModel = labelStatesModels.normal;
+    obj.valueAnimation = normalLabelModel.get('valueAnimation');
+
+    if (obj.valueAnimation) {
+      obj.precision = normalLabelModel.get('precision');
+      obj.defaultInterpolatedText = getDefaultText;
+      obj.statesModels = labelStatesModels;
+    }
+  }
+
+  function animateLabelValue(textEl, dataIndex, data, animatableModel, labelFetcher) {
+    var labelInnerStore = labelInner(textEl);
+
+    if (!labelInnerStore.valueAnimation || labelInnerStore.prevValue === labelInnerStore.value) {
+      // Value not changed, no new label animation
+      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);
+    }
+
+    textEl.percent = 0;
+    (labelInnerStore.prevValue == null ? initProps : updateProps)(textEl, {
+      // percent is used to prevent animation from being aborted #15916
+      percent: 1
+    }, animatableModel, dataIndex, null, during);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 PATH_COLOR = ['textStyle', 'color'];
+  var textStyleParams = ['fontStyle', 'fontWeight', 'fontSize', 'fontFamily', 'padding', 'lineHeight', 'rich', 'width', 'height', 'overflow']; // TODO Performance improvement?
+
+  var tmpText = new ZRText();
+
+  var TextStyleMixin =
+  /** @class */
+  function () {
+    function TextStyleMixin() {}
+    /**
+     * Get color property or get color from option.textStyle.color
+     */
+    // TODO Callback
+
+
+    TextStyleMixin.prototype.getTextColor = function (isEmphasis) {
+      var ecModel = this.ecModel;
+      return this.getShallow('color') || (!isEmphasis && ecModel ? ecModel.get(PATH_COLOR) : null);
+    };
+    /**
+     * Create font string from fontStyle, fontWeight, fontSize, fontFamily
+     * @return {string}
+     */
+
+
+    TextStyleMixin.prototype.getFont = function () {
+      return getFont({
+        fontStyle: this.getShallow('fontStyle'),
+        fontWeight: this.getShallow('fontWeight'),
+        fontSize: this.getShallow('fontSize'),
+        fontFamily: this.getShallow('fontFamily')
+      }, this.ecModel);
+    };
+
+    TextStyleMixin.prototype.getTextRect = function (text) {
+      var style = {
+        text: text,
+        verticalAlign: this.getShallow('verticalAlign') || this.getShallow('baseline')
+      };
+
+      for (var i = 0; i < textStyleParams.length; i++) {
+        style[textStyleParams[i]] = this.getShallow(textStyleParams[i]);
+      }
+
+      tmpText.useStyle(style);
+      tmpText.update();
+      return tmpText.getBoundingRect();
+    };
+
+    return TextStyleMixin;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 LINE_STYLE_KEY_MAP = [['lineWidth', 'width'], ['stroke', 'color'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'type'], ['lineDashOffset', 'dashOffset'], ['lineCap', 'cap'], ['lineJoin', 'join'], ['miterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`.
+  // So do not transfer decal directly.
+  ];
+  var getLineStyle = makeStyleMapper(LINE_STYLE_KEY_MAP);
+
+  var LineStyleMixin =
+  /** @class */
+  function () {
+    function LineStyleMixin() {}
+
+    LineStyleMixin.prototype.getLineStyle = function (excludes) {
+      return getLineStyle(this, excludes);
+    };
+
+    return LineStyleMixin;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 ITEM_STYLE_KEY_MAP = [['fill', 'color'], ['stroke', 'borderColor'], ['lineWidth', 'borderWidth'], ['opacity'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['shadowColor'], ['lineDash', 'borderType'], ['lineDashOffset', 'borderDashOffset'], ['lineCap', 'borderCap'], ['lineJoin', 'borderJoin'], ['miterLimit', 'borderMiterLimit'] // Option decal is in `DecalObject` but style.decal is in `PatternObject`.
+  // So do not transfer decal directly.
+  ];
+  var getItemStyle = makeStyleMapper(ITEM_STYLE_KEY_MAP);
+
+  var ItemStyleMixin =
+  /** @class */
+  function () {
+    function ItemStyleMixin() {}
+
+    ItemStyleMixin.prototype.getItemStyle = function (excludes, includes) {
+      return getItemStyle(this, excludes, includes);
+    };
+
+    return ItemStyleMixin;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 Model =
+  /** @class */
+  function () {
+    function Model(option, parentModel, ecModel) {
+      this.parentModel = parentModel;
+      this.ecModel = ecModel;
+      this.option = option; // Simple optimization
+      // if (this.init) {
+      //     if (arguments.length <= 4) {
+      //         this.init(option, parentModel, ecModel, extraOpt);
+      //     }
+      //     else {
+      //         this.init.apply(this, arguments);
+      //     }
+      // }
+    }
+
+    Model.prototype.init = function (option, parentModel, ecModel) {
+      var rest = [];
+
+      for (var _i = 3; _i < arguments.length; _i++) {
+        rest[_i - 3] = arguments[_i];
+      }
+    };
+    /**
+     * Merge the input option to me.
+     */
+
+
+    Model.prototype.mergeOption = function (option, ecModel) {
+      merge(this.option, option, true);
+    }; // `path` can be 'a.b.c', so the return value type have to be `ModelOption`
+    // TODO: TYPE strict key check?
+    // get(path: string | string[], ignoreParent?: boolean): ModelOption;
+
+
+    Model.prototype.get = function (path, ignoreParent) {
+      if (path == null) {
+        return this.option;
+      }
+
+      return this._doGet(this.parsePath(path), !ignoreParent && this.parentModel);
+    };
+
+    Model.prototype.getShallow = function (key, ignoreParent) {
+      var option = this.option;
+      var val = option == null ? option : option[key];
+
+      if (val == null && !ignoreParent) {
+        var parentModel = this.parentModel;
+
+        if (parentModel) {
+          // FIXME:TS do not know how to make it works
+          val = parentModel.getShallow(key);
+        }
+      }
+
+      return val;
+    }; // `path` can be 'a.b.c', so the return value type have to be `Model<ModelOption>`
+    // getModel(path: string | string[], parentModel?: Model): Model;
+    // TODO 'a.b.c' is deprecated
+
+
+    Model.prototype.getModel = function (path, parentModel) {
+      var hasPath = path != null;
+      var pathFinal = hasPath ? this.parsePath(path) : null;
+      var obj = hasPath ? this._doGet(pathFinal) : this.option;
+      parentModel = parentModel || this.parentModel && this.parentModel.getModel(this.resolveParentPath(pathFinal));
+      return new Model(obj, parentModel, this.ecModel);
+    };
+    /**
+     * If model has option
+     */
+
+
+    Model.prototype.isEmpty = function () {
+      return this.option == null;
+    };
+
+    Model.prototype.restoreData = function () {}; // Pending
+
+
+    Model.prototype.clone = function () {
+      var Ctor = this.constructor;
+      return new Ctor(clone(this.option));
+    }; // setReadOnly(properties): void {
+    // clazzUtil.setReadOnly(this, properties);
+    // }
+    // If path is null/undefined, return null/undefined.
+
+
+    Model.prototype.parsePath = function (path) {
+      if (typeof path === 'string') {
+        return path.split('.');
+      }
+
+      return path;
+    }; // Resolve path for parent. Perhaps useful when parent use a different property.
+    // Default to be a identity resolver.
+    // Can be modified to a different resolver.
+
+
+    Model.prototype.resolveParentPath = function (path) {
+      return path;
+    }; // FIXME:TS check whether put this method here
+
+
+    Model.prototype.isAnimationEnabled = function () {
+      if (!env.node && this.option) {
+        if (this.option.animation != null) {
+          return !!this.option.animation;
+        } else if (this.parentModel) {
+          return this.parentModel.isAnimationEnabled();
+        }
+      }
+    };
+
+    Model.prototype._doGet = function (pathArr, parentModel) {
+      var obj = this.option;
+
+      if (!pathArr) {
+        return obj;
+      }
+
+      for (var i = 0; i < pathArr.length; i++) {
+        // Ignore empty
+        if (!pathArr[i]) {
+          continue;
+        } // obj could be number/string/... (like 0)
+
+
+        obj = obj && typeof obj === 'object' ? obj[pathArr[i]] : null;
+
+        if (obj == null) {
+          break;
+        }
+      }
+
+      if (obj == null && parentModel) {
+        obj = parentModel._doGet(this.resolveParentPath(pathArr), parentModel.parentModel);
+      }
+
+      return obj;
+    };
+
+    return Model;
+  }(); // Enable Model.extend.
+
+
+  enableClassExtend(Model);
+  enableClassCheck(Model);
+  mixin(Model, LineStyleMixin);
+  mixin(Model, ItemStyleMixin);
+  mixin(Model, AreaStyleMixin);
+  mixin(Model, TextStyleMixin);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 base = Math.round(Math.random() * 10);
+  /**
+   * @public
+   * @param {string} type
+   * @return {string}
+   */
+
+  function getUID(type) {
+    // Considering the case of crossing js context,
+    // use Math.random to make id as unique as possible.
+    return [type || '', base++].join('_');
+  }
+  /**
+   * Implements `SubTypeDefaulterManager` for `target`.
+   */
+
+
+  function enableSubTypeDefaulter(target) {
+    var subTypeDefaulters = {};
+
+    target.registerSubTypeDefaulter = function (componentType, defaulter) {
+      var componentTypeInfo = parseClassType(componentType);
+      subTypeDefaulters[componentTypeInfo.main] = defaulter;
+    };
+
+    target.determineSubType = function (componentType, option) {
+      var type = option.type;
+
+      if (!type) {
+        var componentTypeMain = parseClassType(componentType).main;
+
+        if (target.hasSubTypes(componentType) && subTypeDefaulters[componentTypeMain]) {
+          type = subTypeDefaulters[componentTypeMain](option);
+        }
+      }
+
+      return type;
+    };
+  }
+  /**
+   * Implements `TopologicalTravelable<any>` for `entity`.
+   *
+   * Topological travel on Activity Network (Activity On Vertices).
+   * Dependencies is defined in Model.prototype.dependencies, like ['xAxis', 'yAxis'].
+   * If 'xAxis' or 'yAxis' is absent in componentTypeList, just ignore it in topology.
+   * If there is circular dependencey, Error will be thrown.
+   */
+
+
+  function enableTopologicalTravel(entity, dependencyGetter) {
+    /**
+     * @param targetNameList Target Component type list.
+     *                       Can be ['aa', 'bb', 'aa.xx']
+     * @param fullNameList By which we can build dependency graph.
+     * @param callback Params: componentType, dependencies.
+     * @param context Scope of callback.
+     */
+    entity.topologicalTravel = function (targetNameList, fullNameList, callback, context) {
+      if (!targetNameList.length) {
+        return;
+      }
+
+      var result = makeDepndencyGraph(fullNameList);
+      var graph = result.graph;
+      var noEntryList = result.noEntryList;
+      var targetNameSet = {};
+      each(targetNameList, function (name) {
+        targetNameSet[name] = true;
+      });
+
+      while (noEntryList.length) {
+        var currComponentType = noEntryList.pop();
+        var currVertex = graph[currComponentType];
+        var isInTargetNameSet = !!targetNameSet[currComponentType];
+
+        if (isInTargetNameSet) {
+          callback.call(context, currComponentType, currVertex.originalDeps.slice());
+          delete targetNameSet[currComponentType];
+        }
+
+        each(currVertex.successor, isInTargetNameSet ? removeEdgeAndAdd : removeEdge);
+      }
+
+      each(targetNameSet, function () {
+        var errMsg = '';
+        {
+          errMsg = makePrintable('Circular dependency may exists: ', targetNameSet, targetNameList, fullNameList);
+        }
+        throw new Error(errMsg);
+      });
+
+      function removeEdge(succComponentType) {
+        graph[succComponentType].entryCount--;
+
+        if (graph[succComponentType].entryCount === 0) {
+          noEntryList.push(succComponentType);
+        }
+      } // Consider this case: legend depends on series, and we call
+      // chart.setOption({series: [...]}), where only series is in option.
+      // If we do not have 'removeEdgeAndAdd', legendModel.mergeOption will
+      // not be called, but only sereis.mergeOption is called. Thus legend
+      // have no chance to update its local record about series (like which
+      // name of series is available in legend).
+
+
+      function removeEdgeAndAdd(succComponentType) {
+        targetNameSet[succComponentType] = true;
+        removeEdge(succComponentType);
+      }
+    };
+
+    function makeDepndencyGraph(fullNameList) {
+      var graph = {};
+      var noEntryList = [];
+      each(fullNameList, function (name) {
+        var thisItem = createDependencyGraphItem(graph, name);
+        var originalDeps = thisItem.originalDeps = dependencyGetter(name);
+        var availableDeps = getAvailableDependencies(originalDeps, fullNameList);
+        thisItem.entryCount = availableDeps.length;
+
+        if (thisItem.entryCount === 0) {
+          noEntryList.push(name);
+        }
+
+        each(availableDeps, function (dependentName) {
+          if (indexOf(thisItem.predecessor, dependentName) < 0) {
+            thisItem.predecessor.push(dependentName);
+          }
+
+          var thatItem = createDependencyGraphItem(graph, dependentName);
+
+          if (indexOf(thatItem.successor, dependentName) < 0) {
+            thatItem.successor.push(name);
+          }
+        });
+      });
+      return {
+        graph: graph,
+        noEntryList: noEntryList
+      };
+    }
+
+    function createDependencyGraphItem(graph, name) {
+      if (!graph[name]) {
+        graph[name] = {
+          predecessor: [],
+          successor: []
+        };
+      }
+
+      return graph[name];
+    }
+
+    function getAvailableDependencies(originalDeps, fullNameList) {
+      var availableDeps = [];
+      each(originalDeps, function (dep) {
+        indexOf(fullNameList, dep) >= 0 && availableDeps.push(dep);
+      });
+      return availableDeps;
+    }
+  }
+
+  function inheritDefaultOption(superOption, subOption) {
+    // See also `model/Component.ts#getDefaultOption`
+    return merge(merge({}, superOption, true), subOption, true);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Language: English.
+   */
+
+
+  var langEN = {
+    time: {
+      month: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
+      monthAbbr: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
+      dayOfWeek: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
+      dayOfWeekAbbr: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
+    },
+    legend: {
+      selector: {
+        all: 'All',
+        inverse: 'Inv'
+      }
+    },
+    toolbox: {
+      brush: {
+        title: {
+          rect: 'Box Select',
+          polygon: 'Lasso Select',
+          lineX: 'Horizontally Select',
+          lineY: 'Vertically Select',
+          keep: 'Keep Selections',
+          clear: 'Clear Selections'
+        }
+      },
+      dataView: {
+        title: 'Data View',
+        lang: ['Data View', 'Close', 'Refresh']
+      },
+      dataZoom: {
+        title: {
+          zoom: 'Zoom',
+          back: 'Zoom Reset'
+        }
+      },
+      magicType: {
+        title: {
+          line: 'Switch to Line Chart',
+          bar: 'Switch to Bar Chart',
+          stack: 'Stack',
+          tiled: 'Tile'
+        }
+      },
+      restore: {
+        title: 'Restore'
+      },
+      saveAsImage: {
+        title: 'Save as Image',
+        lang: ['Right Click to Save Image']
+      }
+    },
+    series: {
+      typeNames: {
+        pie: 'Pie chart',
+        bar: 'Bar chart',
+        line: 'Line chart',
+        scatter: 'Scatter plot',
+        effectScatter: 'Ripple scatter plot',
+        radar: 'Radar chart',
+        tree: 'Tree',
+        treemap: 'Treemap',
+        boxplot: 'Boxplot',
+        candlestick: 'Candlestick',
+        k: 'K line chart',
+        heatmap: 'Heat map',
+        map: 'Map',
+        parallel: 'Parallel coordinate map',
+        lines: 'Line graph',
+        graph: 'Relationship graph',
+        sankey: 'Sankey diagram',
+        funnel: 'Funnel chart',
+        gauge: 'Gauge',
+        pictorialBar: 'Pictorial bar',
+        themeRiver: 'Theme River Map',
+        sunburst: 'Sunburst'
+      }
+    },
+    aria: {
+      general: {
+        withTitle: 'This is a chart about "{title}"',
+        withoutTitle: 'This is a chart'
+      },
+      series: {
+        single: {
+          prefix: '',
+          withName: ' with type {seriesType} named {seriesName}.',
+          withoutName: ' with type {seriesType}.'
+        },
+        multiple: {
+          prefix: '. It consists of {seriesCount} series count.',
+          withName: ' The {seriesId} series is a {seriesType} representing {seriesName}.',
+          withoutName: ' The {seriesId} series is a {seriesType}.',
+          separator: {
+            middle: '',
+            end: ''
+          }
+        }
+      },
+      data: {
+        allData: 'The data is as follows: ',
+        partialData: 'The first {displayCnt} items are: ',
+        withName: 'the data for {name} is {value}',
+        withoutName: '{value}',
+        separator: {
+          middle: ', ',
+          end: '. '
+        }
+      }
+    }
+  };
+  /*
+  * 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.
+   */
+
+  /*
+   * 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 langZH = {
+    time: {
+      month: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
+      monthAbbr: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+      dayOfWeek: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
+      dayOfWeekAbbr: ['日', '一', '二', '三', '四', '五', '六']
+    },
+    legend: {
+      selector: {
+        all: '全选',
+        inverse: '反选'
+      }
+    },
+    toolbox: {
+      brush: {
+        title: {
+          rect: '矩形选择',
+          polygon: '圈选',
+          lineX: '横向选择',
+          lineY: '纵向选择',
+          keep: '保持选择',
+          clear: '清除选择'
+        }
+      },
+      dataView: {
+        title: '数据视图',
+        lang: ['数据视图', '关闭', '刷新']
+      },
+      dataZoom: {
+        title: {
+          zoom: '区域缩放',
+          back: '区域缩放还原'
+        }
+      },
+      magicType: {
+        title: {
+          line: '切换为折线图',
+          bar: '切换为柱状图',
+          stack: '切换为堆叠',
+          tiled: '切换为平铺'
+        }
+      },
+      restore: {
+        title: '还原'
+      },
+      saveAsImage: {
+        title: '保存为图片',
+        lang: ['右键另存为图片']
+      }
+    },
+    series: {
+      typeNames: {
+        pie: '饼图',
+        bar: '柱状图',
+        line: '折线图',
+        scatter: '散点图',
+        effectScatter: '涟漪散点图',
+        radar: '雷达图',
+        tree: '树图',
+        treemap: '矩形树图',
+        boxplot: '箱型图',
+        candlestick: 'K线图',
+        k: 'K线图',
+        heatmap: '热力图',
+        map: '地图',
+        parallel: '平行坐标图',
+        lines: '线图',
+        graph: '关系图',
+        sankey: '桑基图',
+        funnel: '漏斗图',
+        gauge: '仪表盘图',
+        pictorialBar: '象形柱图',
+        themeRiver: '主题河流图',
+        sunburst: '旭日图'
+      }
+    },
+    aria: {
+      general: {
+        withTitle: '这是一个关于“{title}”的图表。',
+        withoutTitle: '这是一个图表,'
+      },
+      series: {
+        single: {
+          prefix: '',
+          withName: '图表类型是{seriesType},表示{seriesName}。',
+          withoutName: '图表类型是{seriesType}。'
+        },
+        multiple: {
+          prefix: '它由{seriesCount}个图表系列组成。',
+          withName: '第{seriesId}个系列是一个表示{seriesName}的{seriesType},',
+          withoutName: '第{seriesId}个系列是一个{seriesType},',
+          separator: {
+            middle: ';',
+            end: '。'
+          }
+        }
+      },
+      data: {
+        allData: '其数据是——',
+        partialData: '其中,前{displayCnt}项是——',
+        withName: '{name}的数据是{value}',
+        withoutName: '{value}',
+        separator: {
+          middle: ',',
+          end: ''
+        }
+      }
+    }
+  };
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 LOCALE_ZH = 'ZH';
+  var LOCALE_EN = 'EN';
+  var DEFAULT_LOCALE = LOCALE_EN;
+  var localeStorage = {};
+  var localeModels = {};
+  var SYSTEM_LANG = !env.domSupported ? DEFAULT_LOCALE : function () {
+    var langStr = (
+    /* eslint-disable-next-line */
+    document.documentElement.lang || navigator.language || navigator.browserLanguage).toUpperCase();
+    return langStr.indexOf(LOCALE_ZH) > -1 ? LOCALE_ZH : DEFAULT_LOCALE;
+  }();
+
+  function registerLocale(locale, localeObj) {
+    locale = locale.toUpperCase();
+    localeModels[locale] = new Model(localeObj);
+    localeStorage[locale] = localeObj;
+  } // export function getLocale(locale: string) {
+  //     return localeStorage[locale];
+  // }
+
+
+  function createLocaleObject(locale) {
+    if (isString(locale)) {
+      var localeObj = localeStorage[locale.toUpperCase()] || {};
+
+      if (locale === LOCALE_ZH || locale === LOCALE_EN) {
+        return clone(localeObj);
+      } else {
+        return merge(clone(localeObj), clone(localeStorage[DEFAULT_LOCALE]), false);
+      }
+    } else {
+      return merge(clone(locale), clone(localeStorage[DEFAULT_LOCALE]), false);
+    }
+  }
+
+  function getLocaleModel(lang) {
+    return localeModels[lang];
+  }
+
+  function getDefaultLocaleModel() {
+    return localeModels[DEFAULT_LOCALE];
+  } // Default locale
+
+
+  registerLocale(LOCALE_EN, langEN);
+  registerLocale(LOCALE_ZH, langZH);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 ONE_SECOND = 1000;
+  var ONE_MINUTE = ONE_SECOND * 60;
+  var ONE_HOUR = ONE_MINUTE * 60;
+  var ONE_DAY = ONE_HOUR * 24;
+  var ONE_YEAR = ONE_DAY * 365;
+  var defaultLeveledFormatter = {
+    year: '{yyyy}',
+    month: '{MMM}',
+    day: '{d}',
+    hour: '{HH}:{mm}',
+    minute: '{HH}:{mm}',
+    second: '{HH}:{mm}:{ss}',
+    millisecond: '{HH}:{mm}:{ss} {SSS}',
+    none: '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss} {SSS}'
+  };
+  var fullDayFormatter = '{yyyy}-{MM}-{dd}';
+  var fullLeveledFormatter = {
+    year: '{yyyy}',
+    month: '{yyyy}-{MM}',
+    day: fullDayFormatter,
+    hour: fullDayFormatter + ' ' + defaultLeveledFormatter.hour,
+    minute: fullDayFormatter + ' ' + defaultLeveledFormatter.minute,
+    second: fullDayFormatter + ' ' + defaultLeveledFormatter.second,
+    millisecond: defaultLeveledFormatter.none
+  };
+  var primaryTimeUnits = ['year', 'month', 'day', 'hour', 'minute', 'second', 'millisecond'];
+  var timeUnits = ['year', 'half-year', 'quarter', 'month', 'week', 'half-week', 'day', 'half-day', 'quarter-day', 'hour', 'minute', 'second', 'millisecond'];
+
+  function pad(str, len) {
+    str += '';
+    return '0000'.substr(0, len - str.length) + str;
+  }
+
+  function getPrimaryTimeUnit(timeUnit) {
+    switch (timeUnit) {
+      case 'half-year':
+      case 'quarter':
+        return 'month';
+
+      case 'week':
+      case 'half-week':
+        return 'day';
+
+      case 'half-day':
+      case 'quarter-day':
+        return 'hour';
+
+      default:
+        // year, minutes, second, milliseconds
+        return timeUnit;
+    }
+  }
+
+  function isPrimaryTimeUnit(timeUnit) {
+    return timeUnit === getPrimaryTimeUnit(timeUnit);
+  }
+
+  function getDefaultFormatPrecisionOfInterval(timeUnit) {
+    switch (timeUnit) {
+      case 'year':
+      case 'month':
+        return 'day';
+
+      case 'millisecond':
+        return 'millisecond';
+
+      default:
+        // Also for day, hour, minute, second
+        return 'second';
+    }
+  }
+
+  function format( // Note: The result based on `isUTC` are totally different, which can not be just simply
+  // substituted by the result without `isUTC`. So we make the param `isUTC` mandatory.
+  time, template, isUTC, lang) {
+    var date = parseDate(time);
+    var y = date[fullYearGetterName(isUTC)]();
+    var M = date[monthGetterName(isUTC)]() + 1;
+    var q = Math.floor((M - 1) / 3) + 1;
+    var d = date[dateGetterName(isUTC)]();
+    var e = date['get' + (isUTC ? 'UTC' : '') + 'Day']();
+    var H = date[hoursGetterName(isUTC)]();
+    var h = (H - 1) % 12 + 1;
+    var m = date[minutesGetterName(isUTC)]();
+    var s = date[secondsGetterName(isUTC)]();
+    var S = date[millisecondsGetterName(isUTC)]();
+    var localeModel = lang instanceof Model ? lang : getLocaleModel(lang || SYSTEM_LANG) || getDefaultLocaleModel();
+    var timeModel = localeModel.getModel('time');
+    var month = timeModel.get('month');
+    var monthAbbr = timeModel.get('monthAbbr');
+    var dayOfWeek = timeModel.get('dayOfWeek');
+    var dayOfWeekAbbr = timeModel.get('dayOfWeekAbbr');
+    return (template || '').replace(/{yyyy}/g, y + '').replace(/{yy}/g, y % 100 + '').replace(/{Q}/g, q + '').replace(/{MMMM}/g, month[M - 1]).replace(/{MMM}/g, monthAbbr[M - 1]).replace(/{MM}/g, pad(M, 2)).replace(/{M}/g, M + '').replace(/{dd}/g, pad(d, 2)).replace(/{d}/g, d + '').replace(/{eeee}/g, dayOfWeek[e]).replace(/{ee}/g, dayOfWeekAbbr[e]).replace(/{e}/g, e + '').replace(/{HH}/g, pad(H, 2)).replace(/{H}/g, H + '').replace(/{hh}/g, pad(h + '', 2)).replace(/{h}/g, h + '').replace(/{mm}/g, pad(m, 2)).replace(/{m}/g, m + '').replace(/{ss}/g, pad(s, 2)).replace(/{s}/g, s + '').replace(/{SSS}/g, pad(S, 3)).replace(/{S}/g, S + '');
+  }
+
+  function leveledFormat(tick, idx, formatter, lang, isUTC) {
+    var template = null;
+
+    if (isString(formatter)) {
+      // Single formatter for all units at all levels
+      template = formatter;
+    } else if (isFunction(formatter)) {
+      // Callback formatter
+      template = formatter(tick.value, idx, {
+        level: tick.level
+      });
+    } else {
+      var defaults$$1 = extend({}, defaultLeveledFormatter);
+
+      if (tick.level > 0) {
+        for (var i = 0; i < primaryTimeUnits.length; ++i) {
+          defaults$$1[primaryTimeUnits[i]] = "{primary|" + defaults$$1[primaryTimeUnits[i]] + "}";
+        }
+      }
+
+      var mergedFormatter = formatter ? formatter.inherit === false ? formatter // Use formatter with bigger units
+      : defaults(formatter, defaults$$1) : defaults$$1;
+      var unit = getUnitFromValue(tick.value, isUTC);
+
+      if (mergedFormatter[unit]) {
+        template = mergedFormatter[unit];
+      } else if (mergedFormatter.inherit) {
+        // Unit formatter is not defined and should inherit from bigger units
+        var targetId = timeUnits.indexOf(unit);
+
+        for (var i = targetId - 1; i >= 0; --i) {
+          if (mergedFormatter[unit]) {
+            template = mergedFormatter[unit];
+            break;
+          }
+        }
+
+        template = template || defaults$$1.none;
+      }
+
+      if (isArray(template)) {
+        var levelId = tick.level == null ? 0 : tick.level >= 0 ? tick.level : template.length + tick.level;
+        levelId = Math.min(levelId, template.length - 1);
+        template = template[levelId];
+      }
+    }
+
+    return format(new Date(tick.value), template, isUTC, lang);
+  }
+
+  function getUnitFromValue(value, isUTC) {
+    var date = parseDate(value);
+    var M = date[monthGetterName(isUTC)]() + 1;
+    var d = date[dateGetterName(isUTC)]();
+    var h = date[hoursGetterName(isUTC)]();
+    var m = date[minutesGetterName(isUTC)]();
+    var s = date[secondsGetterName(isUTC)]();
+    var S = date[millisecondsGetterName(isUTC)]();
+    var isSecond = S === 0;
+    var isMinute = isSecond && s === 0;
+    var isHour = isMinute && m === 0;
+    var isDay = isHour && h === 0;
+    var isMonth = isDay && d === 1;
+    var isYear = isMonth && M === 1;
+
+    if (isYear) {
+      return 'year';
+    } else if (isMonth) {
+      return 'month';
+    } else if (isDay) {
+      return 'day';
+    } else if (isHour) {
+      return 'hour';
+    } else if (isMinute) {
+      return 'minute';
+    } else if (isSecond) {
+      return 'second';
+    } else {
+      return 'millisecond';
+    }
+  }
+
+  function getUnitValue(value, unit, isUTC) {
+    var date = isNumber(value) ? parseDate(value) : value;
+    unit = unit || getUnitFromValue(value, isUTC);
+
+    switch (unit) {
+      case 'year':
+        return date[fullYearGetterName(isUTC)]();
+
+      case 'half-year':
+        return date[monthGetterName(isUTC)]() >= 6 ? 1 : 0;
+
+      case 'quarter':
+        return Math.floor((date[monthGetterName(isUTC)]() + 1) / 4);
+
+      case 'month':
+        return date[monthGetterName(isUTC)]();
+
+      case 'day':
+        return date[dateGetterName(isUTC)]();
+
+      case 'half-day':
+        return date[hoursGetterName(isUTC)]() / 24;
+
+      case 'hour':
+        return date[hoursGetterName(isUTC)]();
+
+      case 'minute':
+        return date[minutesGetterName(isUTC)]();
+
+      case 'second':
+        return date[secondsGetterName(isUTC)]();
+
+      case 'millisecond':
+        return date[millisecondsGetterName(isUTC)]();
+    }
+  }
+
+  function fullYearGetterName(isUTC) {
+    return isUTC ? 'getUTCFullYear' : 'getFullYear';
+  }
+
+  function monthGetterName(isUTC) {
+    return isUTC ? 'getUTCMonth' : 'getMonth';
+  }
+
+  function dateGetterName(isUTC) {
+    return isUTC ? 'getUTCDate' : 'getDate';
+  }
+
+  function hoursGetterName(isUTC) {
+    return isUTC ? 'getUTCHours' : 'getHours';
+  }
+
+  function minutesGetterName(isUTC) {
+    return isUTC ? 'getUTCMinutes' : 'getMinutes';
+  }
+
+  function secondsGetterName(isUTC) {
+    return isUTC ? 'getUTCSeconds' : 'getSeconds';
+  }
+
+  function millisecondsGetterName(isUTC) {
+    return isUTC ? 'getUTCMilliseconds' : 'getMilliseconds';
+  }
+
+  function fullYearSetterName(isUTC) {
+    return isUTC ? 'setUTCFullYear' : 'setFullYear';
+  }
+
+  function monthSetterName(isUTC) {
+    return isUTC ? 'setUTCMonth' : 'setMonth';
+  }
+
+  function dateSetterName(isUTC) {
+    return isUTC ? 'setUTCDate' : 'setDate';
+  }
+
+  function hoursSetterName(isUTC) {
+    return isUTC ? 'setUTCHours' : 'setHours';
+  }
+
+  function minutesSetterName(isUTC) {
+    return isUTC ? 'setUTCMinutes' : 'setMinutes';
+  }
+
+  function secondsSetterName(isUTC) {
+    return isUTC ? 'setUTCSeconds' : 'setSeconds';
+  }
+
+  function millisecondsSetterName(isUTC) {
+    return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds';
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 getTextRect(text, font, align, verticalAlign, padding, rich, truncate, lineHeight) {
+    var textEl = new ZRText({
+      style: {
+        text: text,
+        font: font,
+        align: align,
+        verticalAlign: verticalAlign,
+        padding: padding,
+        rich: rich,
+        overflow: truncate ? 'truncate' : null,
+        lineHeight: lineHeight
+      }
+    });
+    return textEl.getBoundingRect();
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Add a comma each three digit.
+   */
+
+
+  function addCommas(x) {
+    if (!isNumeric(x)) {
+      return isString(x) ? x : '-';
+    }
+
+    var parts = (x + '').split('.');
+    return parts[0].replace(/(\d{1,3})(?=(?:\d{3})+(?!\d))/g, '$1,') + (parts.length > 1 ? '.' + parts[1] : '');
+  }
+
+  function toCamelCase(str, upperCaseFirst) {
+    str = (str || '').toLowerCase().replace(/-(.)/g, function (match, group1) {
+      return group1.toUpperCase();
+    });
+
+    if (upperCaseFirst && str) {
+      str = str.charAt(0).toUpperCase() + str.slice(1);
+    }
+
+    return str;
+  }
+
+  var normalizeCssArray$1 = normalizeCssArray;
+  var replaceReg = /([&<>"'])/g;
+  var replaceMap = {
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;',
+    '"': '&quot;',
+    '\'': '&#39;'
+  };
+
+  function encodeHTML(source) {
+    return source == null ? '' : (source + '').replace(replaceReg, function (str, c) {
+      return replaceMap[c];
+    });
+  }
+  /**
+   * Make value user readable for tooltip and label.
+   * "User readable":
+   *     Try to not print programmer-specific text like NaN, Infinity, null, undefined.
+   *     Avoid to display an empty string, which users can not recognize there is
+   *     a value and it might look like a bug.
+   */
+
+
+  function makeValueReadable(value, valueType, useUTC) {
+    var USER_READABLE_DEFUALT_TIME_PATTERN = '{yyyy}-{MM}-{dd} {HH}:{mm}:{ss}';
+
+    function stringToUserReadable(str) {
+      return str && trim(str) ? str : '-';
+    }
+
+    function isNumberUserReadable(num) {
+      return !!(num != null && !isNaN(num) && isFinite(num));
+    }
+
+    var isTypeTime = valueType === 'time';
+    var isValueDate = value instanceof Date;
+
+    if (isTypeTime || isValueDate) {
+      var date = isTypeTime ? parseDate(value) : value;
+
+      if (!isNaN(+date)) {
+        return format(date, USER_READABLE_DEFUALT_TIME_PATTERN, useUTC);
+      } else if (isValueDate) {
+        return '-';
+      } // In other cases, continue to try to display the value in the following code.
+
+    }
+
+    if (valueType === 'ordinal') {
+      return isStringSafe(value) ? stringToUserReadable(value) : isNumber(value) ? isNumberUserReadable(value) ? value + '' : '-' : '-';
+    } // By default.
+
+
+    var numericResult = numericToNumber(value);
+    return isNumberUserReadable(numericResult) ? addCommas(numericResult) : isStringSafe(value) ? stringToUserReadable(value) : typeof value === 'boolean' ? value + '' : '-';
+  }
+
+  var TPL_VAR_ALIAS = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
+
+  var wrapVar = function (varName, seriesIdx) {
+    return '{' + varName + (seriesIdx == null ? '' : seriesIdx) + '}';
+  };
+  /**
+   * Template formatter
+   * @param {Array.<Object>|Object} paramsList
+   */
+
+
+  function formatTpl(tpl, paramsList, encode) {
+    if (!isArray(paramsList)) {
+      paramsList = [paramsList];
+    }
+
+    var seriesLen = paramsList.length;
+
+    if (!seriesLen) {
+      return '';
+    }
+
+    var $vars = paramsList[0].$vars || [];
+
+    for (var i = 0; i < $vars.length; i++) {
+      var alias = TPL_VAR_ALIAS[i];
+      tpl = tpl.replace(wrapVar(alias), wrapVar(alias, 0));
+    }
+
+    for (var seriesIdx = 0; seriesIdx < seriesLen; seriesIdx++) {
+      for (var k = 0; k < $vars.length; k++) {
+        var val = paramsList[seriesIdx][$vars[k]];
+        tpl = tpl.replace(wrapVar(TPL_VAR_ALIAS[k], seriesIdx), encode ? encodeHTML(val) : val);
+      }
+    }
+
+    return tpl;
+  }
+  /**
+   * simple Template formatter
+   */
+
+
+  function getTooltipMarker(inOpt, extraCssText) {
+    var opt = isString(inOpt) ? {
+      color: inOpt,
+      extraCssText: extraCssText
+    } : inOpt || {};
+    var color = opt.color;
+    var type = opt.type;
+    extraCssText = opt.extraCssText;
+    var renderMode = opt.renderMode || 'html';
+
+    if (!color) {
+      return '';
+    }
+
+    if (renderMode === 'html') {
+      return type === 'subItem' ? '<span style="display:inline-block;vertical-align:middle;margin-right:8px;margin-left:3px;' + 'border-radius:4px;width:4px;height:4px;background-color:' // Only support string
+      + encodeHTML(color) + ';' + (extraCssText || '') + '"></span>' : '<span style="display:inline-block;margin-right:4px;' + 'border-radius:10px;width:10px;height:10px;background-color:' + encodeHTML(color) + ';' + (extraCssText || '') + '"></span>';
+    } else {
+      // Should better not to auto generate style name by auto-increment number here.
+      // Because this util is usually called in tooltip formatter, which is probably
+      // called repeatly when mouse move and the auto-increment number increases fast.
+      // Users can make their own style name by theirselves, make it unique and readable.
+      var markerId = opt.markerId || 'markerX';
+      return {
+        renderMode: renderMode,
+        content: '{' + markerId + '|}  ',
+        style: type === 'subItem' ? {
+          width: 4,
+          height: 4,
+          borderRadius: 2,
+          backgroundColor: color
+        } : {
+          width: 10,
+          height: 10,
+          borderRadius: 5,
+          backgroundColor: color
+        }
+      };
+    }
+  }
+  /**
+   * @deprecated Use `time/format` instead.
+   * ISO Date format
+   * @param {string} tpl
+   * @param {number} value
+   * @param {boolean} [isUTC=false] Default in local time.
+   *           see `module:echarts/scale/Time`
+   *           and `module:echarts/util/number#parseDate`.
+   * @inner
+   */
+
+
+  function formatTime(tpl, value, isUTC) {
+    {
+      deprecateReplaceLog('echarts.format.formatTime', 'echarts.time.format');
+    }
+
+    if (tpl === 'week' || tpl === 'month' || tpl === 'quarter' || tpl === 'half-year' || tpl === 'year') {
+      tpl = 'MM-dd\nyyyy';
+    }
+
+    var date = parseDate(value);
+    var getUTC = isUTC ? 'getUTC' : 'get';
+    var y = date[getUTC + 'FullYear']();
+    var M = date[getUTC + 'Month']() + 1;
+    var d = date[getUTC + 'Date']();
+    var h = date[getUTC + 'Hours']();
+    var m = date[getUTC + 'Minutes']();
+    var s = date[getUTC + 'Seconds']();
+    var S = date[getUTC + 'Milliseconds']();
+    tpl = tpl.replace('MM', pad(M, 2)).replace('M', M).replace('yyyy', y).replace('yy', pad(y % 100 + '', 2)).replace('dd', pad(d, 2)).replace('d', d).replace('hh', pad(h, 2)).replace('h', h).replace('mm', pad(m, 2)).replace('m', m).replace('ss', pad(s, 2)).replace('s', s).replace('SSS', pad(S, 3));
+    return tpl;
+  }
+  /**
+   * Capital first
+   * @param {string} str
+   * @return {string}
+   */
+
+
+  function capitalFirst(str) {
+    return str ? str.charAt(0).toUpperCase() + str.substr(1) : str;
+  }
+  /**
+   * @return Never be null/undefined.
+   */
+
+
+  function convertToColorString(color, defaultColor) {
+    defaultColor = defaultColor || 'transparent';
+    return isString(color) ? color : isObject(color) ? color.colorStops && (color.colorStops[0] || {}).color || defaultColor : defaultColor;
+  }
+  /**
+   * open new tab
+   * @param link url
+   * @param target blank or self
+   */
+
+
+  function windowOpen(link, target) {
+    /* global window */
+    if (target === '_blank' || target === 'blank') {
+      var blank = window.open();
+      blank.opener = null;
+      blank.location.href = link;
+    } else {
+      window.open(link, target);
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // Layout helpers for each component positioning
+
+
+  var each$1 = each;
+  /**
+   * @public
+   */
+
+  var LOCATION_PARAMS = ['left', 'right', 'top', 'bottom', 'width', 'height'];
+  /**
+   * @public
+   */
+
+  var HV_NAMES = [['width', 'left', 'right'], ['height', 'top', 'bottom']];
+
+  function boxLayout(orient, group, gap, maxWidth, maxHeight) {
+    var x = 0;
+    var y = 0;
+
+    if (maxWidth == null) {
+      maxWidth = Infinity;
+    }
+
+    if (maxHeight == null) {
+      maxHeight = Infinity;
+    }
+
+    var currentLineMaxSize = 0;
+    group.eachChild(function (child, idx) {
+      var rect = child.getBoundingRect();
+      var nextChild = group.childAt(idx + 1);
+      var nextChildRect = nextChild && nextChild.getBoundingRect();
+      var nextX;
+      var nextY;
+
+      if (orient === 'horizontal') {
+        var moveX = rect.width + (nextChildRect ? -nextChildRect.x + rect.x : 0);
+        nextX = x + moveX; // Wrap when width exceeds maxWidth or meet a `newline` group
+        // FIXME compare before adding gap?
+
+        if (nextX > maxWidth || child.newline) {
+          x = 0;
+          nextX = moveX;
+          y += currentLineMaxSize + gap;
+          currentLineMaxSize = rect.height;
+        } else {
+          // FIXME: consider rect.y is not `0`?
+          currentLineMaxSize = Math.max(currentLineMaxSize, rect.height);
+        }
+      } else {
+        var moveY = rect.height + (nextChildRect ? -nextChildRect.y + rect.y : 0);
+        nextY = y + moveY; // Wrap when width exceeds maxHeight or meet a `newline` group
+
+        if (nextY > maxHeight || child.newline) {
+          x += currentLineMaxSize + gap;
+          y = 0;
+          nextY = moveY;
+          currentLineMaxSize = rect.width;
+        } else {
+          currentLineMaxSize = Math.max(currentLineMaxSize, rect.width);
+        }
+      }
+
+      if (child.newline) {
+        return;
+      }
+
+      child.x = x;
+      child.y = y;
+      child.markRedraw();
+      orient === 'horizontal' ? x = nextX + gap : y = nextY + gap;
+    });
+  }
+  /**
+   * VBox or HBox layouting
+   * @param {string} orient
+   * @param {module:zrender/graphic/Group} group
+   * @param {number} gap
+   * @param {number} [width=Infinity]
+   * @param {number} [height=Infinity]
+   */
+
+
+  var box = boxLayout;
+  /**
+   * VBox layouting
+   * @param {module:zrender/graphic/Group} group
+   * @param {number} gap
+   * @param {number} [width=Infinity]
+   * @param {number} [height=Infinity]
+   */
+
+  var vbox = curry(boxLayout, 'vertical');
+  /**
+   * HBox layouting
+   * @param {module:zrender/graphic/Group} group
+   * @param {number} gap
+   * @param {number} [width=Infinity]
+   * @param {number} [height=Infinity]
+   */
+
+  var hbox = curry(boxLayout, 'horizontal');
+  /**
+   * If x or x2 is not specified or 'center' 'left' 'right',
+   * the width would be as long as possible.
+   * If y or y2 is not specified or 'middle' 'top' 'bottom',
+   * the height would be as long as possible.
+   */
+
+  /**
+   * Parse position info.
+   */
+
+  function getLayoutRect(positionInfo, containerRect, margin) {
+    margin = normalizeCssArray$1(margin || 0);
+    var containerWidth = containerRect.width;
+    var containerHeight = containerRect.height;
+    var left = parsePercent$1(positionInfo.left, containerWidth);
+    var top = parsePercent$1(positionInfo.top, containerHeight);
+    var right = parsePercent$1(positionInfo.right, containerWidth);
+    var bottom = parsePercent$1(positionInfo.bottom, containerHeight);
+    var width = parsePercent$1(positionInfo.width, containerWidth);
+    var height = parsePercent$1(positionInfo.height, containerHeight);
+    var verticalMargin = margin[2] + margin[0];
+    var horizontalMargin = margin[1] + margin[3];
+    var aspect = positionInfo.aspect; // If width is not specified, calculate width from left and right
+
+    if (isNaN(width)) {
+      width = containerWidth - right - horizontalMargin - left;
+    }
+
+    if (isNaN(height)) {
+      height = containerHeight - bottom - verticalMargin - top;
+    }
+
+    if (aspect != null) {
+      // If width and height are not given
+      // 1. Graph should not exceeds the container
+      // 2. Aspect must be keeped
+      // 3. Graph should take the space as more as possible
+      // FIXME
+      // Margin is not considered, because there is no case that both
+      // using margin and aspect so far.
+      if (isNaN(width) && isNaN(height)) {
+        if (aspect > containerWidth / containerHeight) {
+          width = containerWidth * 0.8;
+        } else {
+          height = containerHeight * 0.8;
+        }
+      } // Calculate width or height with given aspect
+
+
+      if (isNaN(width)) {
+        width = aspect * height;
+      }
+
+      if (isNaN(height)) {
+        height = width / aspect;
+      }
+    } // If left is not specified, calculate left from right and width
+
+
+    if (isNaN(left)) {
+      left = containerWidth - right - width - horizontalMargin;
+    }
+
+    if (isNaN(top)) {
+      top = containerHeight - bottom - height - verticalMargin;
+    } // Align left and top
+
+
+    switch (positionInfo.left || positionInfo.right) {
+      case 'center':
+        left = containerWidth / 2 - width / 2 - margin[3];
+        break;
+
+      case 'right':
+        left = containerWidth - width - horizontalMargin;
+        break;
+    }
+
+    switch (positionInfo.top || positionInfo.bottom) {
+      case 'middle':
+      case 'center':
+        top = containerHeight / 2 - height / 2 - margin[0];
+        break;
+
+      case 'bottom':
+        top = containerHeight - height - verticalMargin;
+        break;
+    } // If something is wrong and left, top, width, height are calculated as NaN
+
+
+    left = left || 0;
+    top = top || 0;
+
+    if (isNaN(width)) {
+      // Width may be NaN if only one value is given except width
+      width = containerWidth - horizontalMargin - left - (right || 0);
+    }
+
+    if (isNaN(height)) {
+      // Height may be NaN if only one value is given except height
+      height = containerHeight - verticalMargin - top - (bottom || 0);
+    }
+
+    var rect = new BoundingRect(left + margin[3], top + margin[0], width, height);
+    rect.margin = margin;
+    return rect;
+  }
+  /**
+   * Position a zr element in viewport
+   *  Group position is specified by either
+   *  {left, top}, {right, bottom}
+   *  If all properties exists, right and bottom will be igonred.
+   *
+   * Logic:
+   *     1. Scale (against origin point in parent coord)
+   *     2. Rotate (against origin point in parent coord)
+   *     3. Traslate (with el.position by this method)
+   * So this method only fixes the last step 'Traslate', which does not affect
+   * scaling and rotating.
+   *
+   * If be called repeatly with the same input el, the same result will be gotten.
+   *
+   * Return true if the layout happend.
+   *
+   * @param el Should have `getBoundingRect` method.
+   * @param positionInfo
+   * @param positionInfo.left
+   * @param positionInfo.top
+   * @param positionInfo.right
+   * @param positionInfo.bottom
+   * @param positionInfo.width Only for opt.boundingModel: 'raw'
+   * @param positionInfo.height Only for opt.boundingModel: 'raw'
+   * @param containerRect
+   * @param margin
+   * @param opt
+   * @param opt.hv Only horizontal or only vertical. Default to be [1, 1]
+   * @param opt.boundingMode
+   *        Specify how to calculate boundingRect when locating.
+   *        'all': Position the boundingRect that is transformed and uioned
+   *               both itself and its descendants.
+   *               This mode simplies confine the elements in the bounding
+   *               of their container (e.g., using 'right: 0').
+   *        'raw': Position the boundingRect that is not transformed and only itself.
+   *               This mode is useful when you want a element can overflow its
+   *               container. (Consider a rotated circle needs to be located in a corner.)
+   *               In this mode positionInfo.width/height can only be number.
+   */
+
+  /**
+   * @param option Contains some of the properties in HV_NAMES.
+   * @param hvIdx 0: horizontal; 1: vertical.
+   */
+
+
+  function fetchLayoutMode(ins) {
+    var layoutMode = ins.layoutMode || ins.constructor.layoutMode;
+    return isObject(layoutMode) ? layoutMode : layoutMode ? {
+      type: layoutMode
+    } : null;
+  }
+  /**
+   * Consider Case:
+   * When default option has {left: 0, width: 100}, and we set {right: 0}
+   * through setOption or media query, using normal zrUtil.merge will cause
+   * {right: 0} does not take effect.
+   *
+   * @example
+   * ComponentModel.extend({
+   *     init: function () {
+   *         ...
+   *         let inputPositionParams = layout.getLayoutParams(option);
+   *         this.mergeOption(inputPositionParams);
+   *     },
+   *     mergeOption: function (newOption) {
+   *         newOption && zrUtil.merge(thisOption, newOption, true);
+   *         layout.mergeLayoutParam(thisOption, newOption);
+   *     }
+   * });
+   *
+   * @param targetOption
+   * @param newOption
+   * @param opt
+   */
+
+
+  function mergeLayoutParam(targetOption, newOption, opt) {
+    var ignoreSize = opt && opt.ignoreSize;
+    !isArray(ignoreSize) && (ignoreSize = [ignoreSize, ignoreSize]);
+    var hResult = merge$$1(HV_NAMES[0], 0);
+    var vResult = merge$$1(HV_NAMES[1], 1);
+    copy(HV_NAMES[0], targetOption, hResult);
+    copy(HV_NAMES[1], targetOption, vResult);
+
+    function merge$$1(names, hvIdx) {
+      var newParams = {};
+      var newValueCount = 0;
+      var merged = {};
+      var mergedValueCount = 0;
+      var enoughParamNumber = 2;
+      each$1(names, function (name) {
+        merged[name] = targetOption[name];
+      });
+      each$1(names, function (name) {
+        // Consider case: newOption.width is null, which is
+        // set by user for removing width setting.
+        hasProp(newOption, name) && (newParams[name] = merged[name] = newOption[name]);
+        hasValue(newParams, name) && newValueCount++;
+        hasValue(merged, name) && mergedValueCount++;
+      });
+
+      if (ignoreSize[hvIdx]) {
+        // Only one of left/right is premitted to exist.
+        if (hasValue(newOption, names[1])) {
+          merged[names[2]] = null;
+        } else if (hasValue(newOption, names[2])) {
+          merged[names[1]] = null;
+        }
+
+        return merged;
+      } // Case: newOption: {width: ..., right: ...},
+      // or targetOption: {right: ...} and newOption: {width: ...},
+      // There is no conflict when merged only has params count
+      // little than enoughParamNumber.
+
+
+      if (mergedValueCount === enoughParamNumber || !newValueCount) {
+        return merged;
+      } // Case: newOption: {width: ..., right: ...},
+      // Than we can make sure user only want those two, and ignore
+      // all origin params in targetOption.
+      else if (newValueCount >= enoughParamNumber) {
+          return newParams;
+        } else {
+          // Chose another param from targetOption by priority.
+          for (var i = 0; i < names.length; i++) {
+            var name_1 = names[i];
+
+            if (!hasProp(newParams, name_1) && hasProp(targetOption, name_1)) {
+              newParams[name_1] = targetOption[name_1];
+              break;
+            }
+          }
+
+          return newParams;
+        }
+    }
+
+    function hasProp(obj, name) {
+      return obj.hasOwnProperty(name);
+    }
+
+    function hasValue(obj, name) {
+      return obj[name] != null && obj[name] !== 'auto';
+    }
+
+    function copy(names, target, source) {
+      each$1(names, function (name) {
+        target[name] = source[name];
+      });
+    }
+  }
+  /**
+   * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
+   */
+
+
+  function getLayoutParams(source) {
+    return copyLayoutParams({}, source);
+  }
+  /**
+   * Retrieve 'left', 'right', 'top', 'bottom', 'width', 'height' from object.
+   * @param {Object} source
+   * @return {Object} Result contains those props.
+   */
+
+
+  function copyLayoutParams(target, source) {
+    source && target && each$1(LOCATION_PARAMS, function (name) {
+      source.hasOwnProperty(name) && (target[name] = source[name]);
+    });
+    return target;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner = makeInner();
+
+  var ComponentModel =
+  /** @class */
+  function (_super) {
+    __extends(ComponentModel, _super);
+
+    function ComponentModel(option, parentModel, ecModel) {
+      var _this = _super.call(this, option, parentModel, ecModel) || this;
+
+      _this.uid = getUID('ec_cpt_model');
+      return _this;
+    }
+
+    ComponentModel.prototype.init = function (option, parentModel, ecModel) {
+      this.mergeDefaultAndTheme(option, ecModel);
+    };
+
+    ComponentModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
+      var layoutMode = fetchLayoutMode(this);
+      var inputPositionParams = layoutMode ? getLayoutParams(option) : {};
+      var themeModel = ecModel.getTheme();
+      merge(option, themeModel.get(this.mainType));
+      merge(option, this.getDefaultOption());
+
+      if (layoutMode) {
+        mergeLayoutParam(option, inputPositionParams, layoutMode);
+      }
+    };
+
+    ComponentModel.prototype.mergeOption = function (option, ecModel) {
+      merge(this.option, option, true);
+      var layoutMode = fetchLayoutMode(this);
+
+      if (layoutMode) {
+        mergeLayoutParam(this.option, option, layoutMode);
+      }
+    };
+    /**
+     * Called immediately after `init` or `mergeOption` of this instance called.
+     */
+
+
+    ComponentModel.prototype.optionUpdated = function (newCptOption, isInit) {};
+    /**
+     * [How to declare defaultOption]:
+     *
+     * (A) If using class declaration in typescript (since echarts 5):
+     * ```ts
+     * import {ComponentOption} from '../model/option.js';
+     * export interface XxxOption extends ComponentOption {
+     *     aaa: number
+     * }
+     * export class XxxModel extends Component {
+     *     static type = 'xxx';
+     *     static defaultOption: XxxOption = {
+     *         aaa: 123
+     *     }
+     * }
+     * Component.registerClass(XxxModel);
+     * ```
+     * ```ts
+     * import {inheritDefaultOption} from '../util/component.js';
+     * import {XxxModel, XxxOption} from './XxxModel.js';
+     * export interface XxxSubOption extends XxxOption {
+     *     bbb: number
+     * }
+     * class XxxSubModel extends XxxModel {
+     *     static defaultOption: XxxSubOption = inheritDefaultOption(XxxModel.defaultOption, {
+     *         bbb: 456
+     *     })
+     *     fn() {
+     *         let opt = this.getDefaultOption();
+     *         // opt is {aaa: 123, bbb: 456}
+     *     }
+     * }
+     * ```
+     *
+     * (B) If using class extend (previous approach in echarts 3 & 4):
+     * ```js
+     * let XxxComponent = Component.extend({
+     *     defaultOption: {
+     *         xx: 123
+     *     }
+     * })
+     * ```
+     * ```js
+     * let XxxSubComponent = XxxComponent.extend({
+     *     defaultOption: {
+     *         yy: 456
+     *     },
+     *     fn: function () {
+     *         let opt = this.getDefaultOption();
+     *         // opt is {xx: 123, yy: 456}
+     *     }
+     * })
+     * ```
+     */
+
+
+    ComponentModel.prototype.getDefaultOption = function () {
+      var ctor = this.constructor; // If using class declaration, it is different to travel super class
+      // in legacy env and auto merge defaultOption. So if using class
+      // declaration, defaultOption should be merged manually.
+
+      if (!isExtendedClass(ctor)) {
+        // When using ts class, defaultOption must be declared as static.
+        return ctor.defaultOption;
+      } // FIXME: remove this approach?
+
+
+      var fields = inner(this);
+
+      if (!fields.defaultOption) {
+        var optList = [];
+        var clz = ctor;
+
+        while (clz) {
+          var opt = clz.prototype.defaultOption;
+          opt && optList.push(opt);
+          clz = clz.superClass;
+        }
+
+        var defaultOption = {};
+
+        for (var i = optList.length - 1; i >= 0; i--) {
+          defaultOption = merge(defaultOption, optList[i], true);
+        }
+
+        fields.defaultOption = defaultOption;
+      }
+
+      return fields.defaultOption;
+    };
+    /**
+     * Notice: always force to input param `useDefault` in case that forget to consider it.
+     * The same behavior as `modelUtil.parseFinder`.
+     *
+     * @param useDefault In many cases like series refer axis and axis refer grid,
+     *        If axis index / axis id not specified, use the first target as default.
+     *        In other cases like dataZoom refer axis, if not specified, measn no refer.
+     */
+
+
+    ComponentModel.prototype.getReferringComponents = function (mainType, opt) {
+      var indexKey = mainType + 'Index';
+      var idKey = mainType + 'Id';
+      return queryReferringComponents(this.ecModel, mainType, {
+        index: this.get(indexKey, true),
+        id: this.get(idKey, true)
+      }, opt);
+    };
+
+    ComponentModel.prototype.getBoxLayoutParams = function () {
+      // Consider itself having box layout configs.
+      var boxLayoutModel = this;
+      return {
+        left: boxLayoutModel.get('left'),
+        top: boxLayoutModel.get('top'),
+        right: boxLayoutModel.get('right'),
+        bottom: boxLayoutModel.get('bottom'),
+        width: boxLayoutModel.get('width'),
+        height: boxLayoutModel.get('height')
+      };
+    };
+    /**
+     * Get key for zlevel.
+     * If developers don't configure zlevel. We will assign zlevel to series based on the key.
+     * For example, lines with trail effect and progressive series will in an individual zlevel.
+     */
+
+
+    ComponentModel.prototype.getZLevelKey = function () {
+      return '';
+    };
+
+    ComponentModel.prototype.setZLevel = function (zlevel) {
+      this.option.zlevel = zlevel;
+    };
+
+    ComponentModel.protoInitialize = function () {
+      var proto = ComponentModel.prototype;
+      proto.type = 'component';
+      proto.id = '';
+      proto.name = '';
+      proto.mainType = '';
+      proto.subType = '';
+      proto.componentIndex = 0;
+    }();
+
+    return ComponentModel;
+  }(Model);
+
+  mountExtend(ComponentModel, Model);
+  enableClassManagement(ComponentModel);
+  enableSubTypeDefaulter(ComponentModel);
+  enableTopologicalTravel(ComponentModel, getDependencies);
+
+  function getDependencies(componentType) {
+    var deps = [];
+    each(ComponentModel.getClassesByMainType(componentType), function (clz) {
+      deps = deps.concat(clz.dependencies || clz.prototype.dependencies || []);
+    }); // Ensure main type.
+
+    deps = map(deps, function (type) {
+      return parseClassType(type).main;
+    }); // Hack dataset for convenience.
+
+    if (componentType !== 'dataset' && indexOf(deps, 'dataset') <= 0) {
+      deps.unshift('dataset');
+    }
+
+    return deps;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 platform = ''; // Navigator not exists in node
+
+  if (typeof navigator !== 'undefined') {
+    /* global navigator */
+    platform = navigator.platform || '';
+  }
+
+  var decalColor = 'rgba(0, 0, 0, 0.2)';
+  var globalDefault = {
+    darkMode: 'auto',
+    // backgroundColor: 'rgba(0,0,0,0)',
+    colorBy: 'series',
+    color: ['#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de', '#3ba272', '#fc8452', '#9a60b4', '#ea7ccc'],
+    gradientColor: ['#f6efa6', '#d88273', '#bf444c'],
+    aria: {
+      decal: {
+        decals: [{
+          color: decalColor,
+          dashArrayX: [1, 0],
+          dashArrayY: [2, 5],
+          symbolSize: 1,
+          rotation: Math.PI / 6
+        }, {
+          color: decalColor,
+          symbol: 'circle',
+          dashArrayX: [[8, 8], [0, 8, 8, 0]],
+          dashArrayY: [6, 0],
+          symbolSize: 0.8
+        }, {
+          color: decalColor,
+          dashArrayX: [1, 0],
+          dashArrayY: [4, 3],
+          rotation: -Math.PI / 4
+        }, {
+          color: decalColor,
+          dashArrayX: [[6, 6], [0, 6, 6, 0]],
+          dashArrayY: [6, 0]
+        }, {
+          color: decalColor,
+          dashArrayX: [[1, 0], [1, 6]],
+          dashArrayY: [1, 0, 6, 0],
+          rotation: Math.PI / 4
+        }, {
+          color: decalColor,
+          symbol: 'triangle',
+          dashArrayX: [[9, 9], [0, 9, 9, 0]],
+          dashArrayY: [7, 2],
+          symbolSize: 0.75
+        }]
+      }
+    },
+    // If xAxis and yAxis declared, grid is created by default.
+    // grid: {},
+    textStyle: {
+      // color: '#000',
+      // decoration: 'none',
+      // PENDING
+      fontFamily: platform.match(/^Win/) ? 'Microsoft YaHei' : 'sans-serif',
+      // fontFamily: 'Arial, Verdana, sans-serif',
+      fontSize: 12,
+      fontStyle: 'normal',
+      fontWeight: 'normal'
+    },
+    // http://blogs.adobe.com/webplatform/2014/02/24/using-blend-modes-in-html-canvas/
+    // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation
+    // Default is source-over
+    blendMode: null,
+    stateAnimation: {
+      duration: 300,
+      easing: 'cubicOut'
+    },
+    animation: 'auto',
+    animationDuration: 1000,
+    animationDurationUpdate: 500,
+    animationEasing: 'cubicInOut',
+    animationEasingUpdate: 'cubicInOut',
+    animationThreshold: 2000,
+    // Configuration for progressive/incremental rendering
+    progressiveThreshold: 3000,
+    progressive: 400,
+    // Threshold of if use single hover layer to optimize.
+    // It is recommended that `hoverLayerThreshold` is equivalent to or less than
+    // `progressiveThreshold`, otherwise hover will cause restart of progressive,
+    // which is unexpected.
+    // see example <echarts/test/heatmap-large.html>.
+    hoverLayerThreshold: 3000,
+    // See: module:echarts/scale/Time
+    useUTC: false
+  };
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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';
+  var SOURCE_FORMAT_KEYED_COLUMNS = 'keyedColumns';
+  var SOURCE_FORMAT_TYPED_ARRAY = 'typedArray';
+  var SOURCE_FORMAT_UNKNOWN = 'unknown';
+  var SERIES_LAYOUT_BY_COLUMN = 'column';
+  var SERIES_LAYOUT_BY_ROW = 'row';
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 BE_ORDINAL = {
+    Must: 1,
+    Might: 2,
+    Not: 3 // Other cases
+
+  };
+  var innerGlobalModel = makeInner();
+  /**
+   * MUST be called before mergeOption of all series.
+   */
+
+  function resetSourceDefaulter(ecModel) {
+    // `datasetMap` is used to make default encode.
+    innerGlobalModel(ecModel).datasetMap = createHashMap();
+  }
+  /**
+   * [The strategy of the arrengment of data dimensions for dataset]:
+   * "value way": all axes are non-category axes. So series one by one take
+   *     several (the number is coordSysDims.length) dimensions from dataset.
+   *     The result of data arrengment of data dimensions like:
+   *     | ser0_x | ser0_y | ser1_x | ser1_y | ser2_x | ser2_y |
+   * "category way": at least one axis is category axis. So the the first data
+   *     dimension is always mapped to the first category axis and shared by
+   *     all of the series. The other data dimensions are taken by series like
+   *     "value way" does.
+   *     The result of data arrengment of data dimensions like:
+   *     | ser_shared_x | ser0_y | ser1_y | ser2_y |
+   *
+   * @return encode Never be `null/undefined`.
+   */
+
+
+  function makeSeriesEncodeForAxisCoordSys(coordDimensions, seriesModel, source) {
+    var encode = {};
+    var datasetModel = querySeriesUpstreamDatasetModel(seriesModel); // Currently only make default when using dataset, util more reqirements occur.
+
+    if (!datasetModel || !coordDimensions) {
+      return encode;
+    }
+
+    var encodeItemName = [];
+    var encodeSeriesName = [];
+    var ecModel = seriesModel.ecModel;
+    var datasetMap = innerGlobalModel(ecModel).datasetMap;
+    var key = datasetModel.uid + '_' + source.seriesLayoutBy;
+    var baseCategoryDimIndex;
+    var categoryWayValueDimStart;
+    coordDimensions = coordDimensions.slice();
+    each(coordDimensions, function (coordDimInfoLoose, coordDimIdx) {
+      var coordDimInfo = isObject(coordDimInfoLoose) ? coordDimInfoLoose : coordDimensions[coordDimIdx] = {
+        name: coordDimInfoLoose
+      };
+
+      if (coordDimInfo.type === 'ordinal' && baseCategoryDimIndex == null) {
+        baseCategoryDimIndex = coordDimIdx;
+        categoryWayValueDimStart = getDataDimCountOnCoordDim(coordDimInfo);
+      }
+
+      encode[coordDimInfo.name] = [];
+    });
+    var datasetRecord = datasetMap.get(key) || datasetMap.set(key, {
+      categoryWayDim: categoryWayValueDimStart,
+      valueWayDim: 0
+    }); // TODO
+    // Auto detect first time axis and do arrangement.
+
+    each(coordDimensions, function (coordDimInfo, coordDimIdx) {
+      var coordDimName = coordDimInfo.name;
+      var count = getDataDimCountOnCoordDim(coordDimInfo); // In value way.
+
+      if (baseCategoryDimIndex == null) {
+        var start = datasetRecord.valueWayDim;
+        pushDim(encode[coordDimName], start, count);
+        pushDim(encodeSeriesName, start, count);
+        datasetRecord.valueWayDim += count; // ??? TODO give a better default series name rule?
+        // especially when encode x y specified.
+        // consider: when mutiple series share one dimension
+        // category axis, series name should better use
+        // the other dimsion name. On the other hand, use
+        // both dimensions name.
+      } // In category way, the first category axis.
+      else if (baseCategoryDimIndex === coordDimIdx) {
+          pushDim(encode[coordDimName], 0, count);
+          pushDim(encodeItemName, 0, count);
+        } // In category way, the other axis.
+        else {
+            var start = datasetRecord.categoryWayDim;
+            pushDim(encode[coordDimName], start, count);
+            pushDim(encodeSeriesName, start, count);
+            datasetRecord.categoryWayDim += count;
+          }
+    });
+
+    function pushDim(dimIdxArr, idxFrom, idxCount) {
+      for (var i = 0; i < idxCount; i++) {
+        dimIdxArr.push(idxFrom + i);
+      }
+    }
+
+    function getDataDimCountOnCoordDim(coordDimInfo) {
+      var dimsDef = coordDimInfo.dimsDef;
+      return dimsDef ? dimsDef.length : 1;
+    }
+
+    encodeItemName.length && (encode.itemName = encodeItemName);
+    encodeSeriesName.length && (encode.seriesName = encodeSeriesName);
+    return encode;
+  }
+  /**
+   * Work for data like [{name: ..., value: ...}, ...].
+   *
+   * @return encode Never be `null/undefined`.
+   */
+
+
+  function makeSeriesEncodeForNameBased(seriesModel, source, dimCount) {
+    var encode = {};
+    var datasetModel = querySeriesUpstreamDatasetModel(seriesModel); // Currently only make default when using dataset, util more reqirements occur.
+
+    if (!datasetModel) {
+      return encode;
+    }
+
+    var sourceFormat = source.sourceFormat;
+    var dimensionsDefine = source.dimensionsDefine;
+    var potentialNameDimIndex;
+
+    if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS || sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
+      each(dimensionsDefine, function (dim, idx) {
+        if ((isObject(dim) ? dim.name : dim) === 'name') {
+          potentialNameDimIndex = idx;
+        }
+      });
+    }
+
+    var idxResult = function () {
+      var idxRes0 = {};
+      var idxRes1 = {};
+      var guessRecords = []; // 5 is an experience value.
+
+      for (var i = 0, len = Math.min(5, dimCount); i < len; i++) {
+        var guessResult = doGuessOrdinal(source.data, sourceFormat, source.seriesLayoutBy, dimensionsDefine, source.startIndex, i);
+        guessRecords.push(guessResult);
+        var isPureNumber = guessResult === BE_ORDINAL.Not; // [Strategy of idxRes0]: find the first BE_ORDINAL.Not as the value dim,
+        // and then find a name dim with the priority:
+        // "BE_ORDINAL.Might|BE_ORDINAL.Must" > "other dim" > "the value dim itself".
+
+        if (isPureNumber && idxRes0.v == null && i !== potentialNameDimIndex) {
+          idxRes0.v = i;
+        }
+
+        if (idxRes0.n == null || idxRes0.n === idxRes0.v || !isPureNumber && guessRecords[idxRes0.n] === BE_ORDINAL.Not) {
+          idxRes0.n = i;
+        }
+
+        if (fulfilled(idxRes0) && guessRecords[idxRes0.n] !== BE_ORDINAL.Not) {
+          return idxRes0;
+        } // [Strategy of idxRes1]: if idxRes0 not satisfied (that is, no BE_ORDINAL.Not),
+        // find the first BE_ORDINAL.Might as the value dim,
+        // and then find a name dim with the priority:
+        // "other dim" > "the value dim itself".
+        // That is for backward compat: number-like (e.g., `'3'`, `'55'`) can be
+        // treated as number.
+
+
+        if (!isPureNumber) {
+          if (guessResult === BE_ORDINAL.Might && idxRes1.v == null && i !== potentialNameDimIndex) {
+            idxRes1.v = i;
+          }
+
+          if (idxRes1.n == null || idxRes1.n === idxRes1.v) {
+            idxRes1.n = i;
+          }
+        }
+      }
+
+      function fulfilled(idxResult) {
+        return idxResult.v != null && idxResult.n != null;
+      }
+
+      return fulfilled(idxRes0) ? idxRes0 : fulfilled(idxRes1) ? idxRes1 : null;
+    }();
+
+    if (idxResult) {
+      encode.value = [idxResult.v]; // `potentialNameDimIndex` has highest priority.
+
+      var nameDimIndex = potentialNameDimIndex != null ? potentialNameDimIndex : idxResult.n; // By default, label use itemName in charts.
+      // So we dont set encodeLabel here.
+
+      encode.itemName = [nameDimIndex];
+      encode.seriesName = [nameDimIndex];
+    }
+
+    return encode;
+  }
+  /**
+   * @return If return null/undefined, indicate that should not use datasetModel.
+   */
+
+
+  function querySeriesUpstreamDatasetModel(seriesModel) {
+    // Caution: consider the scenario:
+    // A dataset is declared and a series is not expected to use the dataset,
+    // and at the beginning `setOption({series: { noData })` (just prepare other
+    // option but no data), then `setOption({series: {data: [...]}); In this case,
+    // the user should set an empty array to avoid that dataset is used by default.
+    var thisData = seriesModel.get('data', true);
+
+    if (!thisData) {
+      return queryReferringComponents(seriesModel.ecModel, 'dataset', {
+        index: seriesModel.get('datasetIndex', true),
+        id: seriesModel.get('datasetId', true)
+      }, SINGLE_REFERRING).models[0];
+    }
+  }
+  /**
+   * @return Always return an array event empty.
+   */
+
+
+  function queryDatasetUpstreamDatasetModels(datasetModel) {
+    // Only these attributes declared, we by defualt reference to `datasetIndex: 0`.
+    // Otherwise, no reference.
+    if (!datasetModel.get('transform', true) && !datasetModel.get('fromTransformResult', true)) {
+      return [];
+    }
+
+    return queryReferringComponents(datasetModel.ecModel, 'dataset', {
+      index: datasetModel.get('fromDatasetIndex', true),
+      id: datasetModel.get('fromDatasetId', true)
+    }, SINGLE_REFERRING).models;
+  }
+  /**
+   * The rule should not be complex, otherwise user might not
+   * be able to known where the data is wrong.
+   * The code is ugly, but how to make it neat?
+   */
+
+
+  function guessOrdinal(source, dimIndex) {
+    return doGuessOrdinal(source.data, source.sourceFormat, source.seriesLayoutBy, source.dimensionsDefine, source.startIndex, dimIndex);
+  } // dimIndex may be overflow source data.
+  // return {BE_ORDINAL}
+
+
+  function doGuessOrdinal(data, sourceFormat, seriesLayoutBy, dimensionsDefine, startIndex, dimIndex) {
+    var result; // Experience value.
+
+    var maxLoop = 5;
+
+    if (isTypedArray(data)) {
+      return BE_ORDINAL.Not;
+    } // When sourceType is 'objectRows' or 'keyedColumns', dimensionsDefine
+    // always exists in source.
+
+
+    var dimName;
+    var dimType;
+
+    if (dimensionsDefine) {
+      var dimDefItem = dimensionsDefine[dimIndex];
+
+      if (isObject(dimDefItem)) {
+        dimName = dimDefItem.name;
+        dimType = dimDefItem.type;
+      } else if (isString(dimDefItem)) {
+        dimName = dimDefItem;
+      }
+    }
+
+    if (dimType != null) {
+      return dimType === 'ordinal' ? BE_ORDINAL.Must : BE_ORDINAL.Not;
+    }
+
+    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
+      var dataArrayRows = data;
+
+      if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {
+        var sample = dataArrayRows[dimIndex];
+
+        for (var i = 0; i < (sample || []).length && i < maxLoop; i++) {
+          if ((result = detectValue(sample[startIndex + i])) != null) {
+            return result;
+          }
+        }
+      } else {
+        for (var i = 0; i < dataArrayRows.length && i < maxLoop; i++) {
+          var row = dataArrayRows[startIndex + i];
+
+          if (row && (result = detectValue(row[dimIndex])) != null) {
+            return result;
+          }
+        }
+      }
+    } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
+      var dataObjectRows = data;
+
+      if (!dimName) {
+        return BE_ORDINAL.Not;
+      }
+
+      for (var i = 0; i < dataObjectRows.length && i < maxLoop; i++) {
+        var item = dataObjectRows[i];
+
+        if (item && (result = detectValue(item[dimName])) != null) {
+          return result;
+        }
+      }
+    } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
+      var dataKeyedColumns = data;
+
+      if (!dimName) {
+        return BE_ORDINAL.Not;
+      }
+
+      var sample = dataKeyedColumns[dimName];
+
+      if (!sample || isTypedArray(sample)) {
+        return BE_ORDINAL.Not;
+      }
+
+      for (var i = 0; i < sample.length && i < maxLoop; i++) {
+        if ((result = detectValue(sample[i])) != null) {
+          return result;
+        }
+      }
+    } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
+      var dataOriginal = data;
+
+      for (var i = 0; i < dataOriginal.length && i < maxLoop; i++) {
+        var item = dataOriginal[i];
+        var val = getDataItemValue(item);
+
+        if (!isArray(val)) {
+          return BE_ORDINAL.Not;
+        }
+
+        if ((result = detectValue(val[dimIndex])) != null) {
+          return result;
+        }
+      }
+    }
+
+    function detectValue(val) {
+      var beStr = isString(val); // Consider usage convenience, '1', '2' will be treated as "number".
+      // `isFinit('')` get `true`.
+
+      if (val != null && isFinite(val) && val !== '') {
+        return beStr ? BE_ORDINAL.Might : BE_ORDINAL.Not;
+      } else if (beStr && val !== '-') {
+        return BE_ORDINAL.Must;
+      }
+    }
+
+    return BE_ORDINAL.Not;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 internalOptionCreatorMap = createHashMap();
+
+  function concatInternalOptions(ecModel, mainType, newCmptOptionList) {
+    var internalOptionCreator = internalOptionCreatorMap.get(mainType);
+
+    if (!internalOptionCreator) {
+      return newCmptOptionList;
+    }
+
+    var internalOptions = internalOptionCreator(ecModel);
+
+    if (!internalOptions) {
+      return newCmptOptionList;
+    }
+
+    {
+      for (var i = 0; i < internalOptions.length; i++) {
+        assert(isComponentIdInternal(internalOptions[i]));
+      }
+    }
+    return newCmptOptionList.concat(internalOptions);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 innerColor = makeInner();
+  var innerDecal = makeInner();
+
+  var PaletteMixin =
+  /** @class */
+  function () {
+    function PaletteMixin() {}
+
+    PaletteMixin.prototype.getColorFromPalette = function (name, scope, requestNum) {
+      var defaultPalette = normalizeToArray(this.get('color', true));
+      var layeredPalette = this.get('colorLayer', true);
+      return getFromPalette(this, innerColor, defaultPalette, layeredPalette, name, scope, requestNum);
+    };
+
+    PaletteMixin.prototype.clearColorPalette = function () {
+      clearPalette(this, innerColor);
+    };
+
+    return PaletteMixin;
+  }();
+
+  function getNearestPalette(palettes, requestColorNum) {
+    var paletteNum = palettes.length; // TODO palettes must be in order
+
+    for (var i = 0; i < paletteNum; i++) {
+      if (palettes[i].length > requestColorNum) {
+        return palettes[i];
+      }
+    }
+
+    return palettes[paletteNum - 1];
+  }
+  /**
+   * @param name MUST NOT be null/undefined. Otherwise call this function
+   *             twise with the same parameters will get different result.
+   * @param scope default this.
+   * @return Can be null/undefined
+   */
+
+
+  function getFromPalette(that, inner, defaultPalette, layeredPalette, name, scope, requestNum) {
+    scope = scope || that;
+    var scopeFields = inner(scope);
+    var paletteIdx = scopeFields.paletteIdx || 0;
+    var paletteNameMap = scopeFields.paletteNameMap = scopeFields.paletteNameMap || {}; // Use `hasOwnProperty` to avoid conflict with Object.prototype.
+
+    if (paletteNameMap.hasOwnProperty(name)) {
+      return paletteNameMap[name];
+    }
+
+    var palette = requestNum == null || !layeredPalette ? defaultPalette : getNearestPalette(layeredPalette, requestNum); // In case can't find in layered color palette.
+
+    palette = palette || defaultPalette;
+
+    if (!palette || !palette.length) {
+      return;
+    }
+
+    var pickedPaletteItem = palette[paletteIdx];
+
+    if (name) {
+      paletteNameMap[name] = pickedPaletteItem;
+    }
+
+    scopeFields.paletteIdx = (paletteIdx + 1) % palette.length;
+    return pickedPaletteItem;
+  }
+
+  function clearPalette(that, inner) {
+    inner(that).paletteIdx = 0;
+    inner(that).paletteNameMap = {};
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Caution: If the mechanism should be changed some day, these cases
+   * should be considered:
+   *
+   * (1) In `merge option` mode, if using the same option to call `setOption`
+   * many times, the result should be the same (try our best to ensure that).
+   * (2) In `merge option` mode, if a component has no id/name specified, it
+   * will be merged by index, and the result sequence of the components is
+   * consistent to the original sequence.
+   * (3) In `replaceMerge` mode, keep the result sequence of the components is
+   * consistent to the original sequence, even though there might result in "hole".
+   * (4) `reset` feature (in toolbox). Find detailed info in comments about
+   * `mergeOption` in module:echarts/model/OptionManager.
+   */
+  // Internal method names:
+  // -----------------------
+
+
+  var reCreateSeriesIndices;
+  var assertSeriesInitialized;
+  var initBase;
+  var OPTION_INNER_KEY = '\0_ec_inner';
+  var OPTION_INNER_VALUE = 1;
+  var BUITIN_COMPONENTS_MAP = {
+    grid: 'GridComponent',
+    polar: 'PolarComponent',
+    geo: 'GeoComponent',
+    singleAxis: 'SingleAxisComponent',
+    parallel: 'ParallelComponent',
+    calendar: 'CalendarComponent',
+    graphic: 'GraphicComponent',
+    toolbox: 'ToolboxComponent',
+    tooltip: 'TooltipComponent',
+    axisPointer: 'AxisPointerComponent',
+    brush: 'BrushComponent',
+    title: 'TitleComponent',
+    timeline: 'TimelineComponent',
+    markPoint: 'MarkPointComponent',
+    markLine: 'MarkLineComponent',
+    markArea: 'MarkAreaComponent',
+    legend: 'LegendComponent',
+    dataZoom: 'DataZoomComponent',
+    visualMap: 'VisualMapComponent',
+    // aria: 'AriaComponent',
+    // dataset: 'DatasetComponent',
+    // Dependencies
+    xAxis: 'GridComponent',
+    yAxis: 'GridComponent',
+    angleAxis: 'PolarComponent',
+    radiusAxis: 'PolarComponent'
+  };
+  var BUILTIN_CHARTS_MAP = {
+    line: 'LineChart',
+    bar: 'BarChart',
+    pie: 'PieChart',
+    scatter: 'ScatterChart',
+    radar: 'RadarChart',
+    map: 'MapChart',
+    tree: 'TreeChart',
+    treemap: 'TreemapChart',
+    graph: 'GraphChart',
+    gauge: 'GaugeChart',
+    funnel: 'FunnelChart',
+    parallel: 'ParallelChart',
+    sankey: 'SankeyChart',
+    boxplot: 'BoxplotChart',
+    candlestick: 'CandlestickChart',
+    effectScatter: 'EffectScatterChart',
+    lines: 'LinesChart',
+    heatmap: 'HeatmapChart',
+    pictorialBar: 'PictorialBarChart',
+    themeRiver: 'ThemeRiverChart',
+    sunburst: 'SunburstChart',
+    custom: 'CustomChart'
+  };
+  var componetsMissingLogPrinted = {};
+
+  function checkMissingComponents(option) {
+    each(option, function (componentOption, mainType) {
+      if (!ComponentModel.hasClass(mainType)) {
+        var componentImportName = BUITIN_COMPONENTS_MAP[mainType];
+
+        if (componentImportName && !componetsMissingLogPrinted[componentImportName]) {
+          error("Component " + mainType + " is used but not imported.\nimport { " + componentImportName + " } from 'echarts/components';\necharts.use([" + componentImportName + "]);");
+          componetsMissingLogPrinted[componentImportName] = true;
+        }
+      }
+    });
+  }
+
+  var GlobalModel =
+  /** @class */
+  function (_super) {
+    __extends(GlobalModel, _super);
+
+    function GlobalModel() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    GlobalModel.prototype.init = function (option, parentModel, ecModel, theme, locale, optionManager) {
+      theme = theme || {};
+      this.option = null; // Mark as not initialized.
+
+      this._theme = new Model(theme);
+      this._locale = new Model(locale);
+      this._optionManager = optionManager;
+    };
+
+    GlobalModel.prototype.setOption = function (option, opts, optionPreprocessorFuncs) {
+      {
+        assert(option != null, 'option is null/undefined');
+        assert(option[OPTION_INNER_KEY] !== OPTION_INNER_VALUE, 'please use chart.getOption()');
+      }
+      var innerOpt = normalizeSetOptionInput(opts);
+
+      this._optionManager.setOption(option, optionPreprocessorFuncs, innerOpt);
+
+      this._resetOption(null, innerOpt);
+    };
+    /**
+     * @param type null/undefined: reset all.
+     *        'recreate': force recreate all.
+     *        'timeline': only reset timeline option
+     *        'media': only reset media query option
+     * @return Whether option changed.
+     */
+
+
+    GlobalModel.prototype.resetOption = function (type, opt) {
+      return this._resetOption(type, normalizeSetOptionInput(opt));
+    };
+
+    GlobalModel.prototype._resetOption = function (type, opt) {
+      var optionChanged = false;
+      var optionManager = this._optionManager;
+
+      if (!type || type === 'recreate') {
+        var baseOption = optionManager.mountOption(type === 'recreate');
+        {
+          checkMissingComponents(baseOption);
+        }
+
+        if (!this.option || type === 'recreate') {
+          initBase(this, baseOption);
+        } else {
+          this.restoreData();
+
+          this._mergeOption(baseOption, opt);
+        }
+
+        optionChanged = true;
+      }
+
+      if (type === 'timeline' || type === 'media') {
+        this.restoreData();
+      } // By design, if `setOption(option2)` at the second time, and `option2` is a `ECUnitOption`,
+      // it should better not have the same props with `MediaUnit['option']`.
+      // Becuase either `option2` or `MediaUnit['option']` will be always merged to "current option"
+      // rather than original "baseOption". If they both override a prop, the result might be
+      // unexpected when media state changed after `setOption` called.
+      // If we really need to modify a props in each `MediaUnit['option']`, use the full version
+      // (`{baseOption, media}`) in `setOption`.
+      // For `timeline`, the case is the same.
+
+
+      if (!type || type === 'recreate' || type === 'timeline') {
+        var timelineOption = optionManager.getTimelineOption(this);
+
+        if (timelineOption) {
+          optionChanged = true;
+
+          this._mergeOption(timelineOption, opt);
+        }
+      }
+
+      if (!type || type === 'recreate' || type === 'media') {
+        var mediaOptions = optionManager.getMediaOption(this);
+
+        if (mediaOptions.length) {
+          each(mediaOptions, function (mediaOption) {
+            optionChanged = true;
+
+            this._mergeOption(mediaOption, opt);
+          }, this);
+        }
+      }
+
+      return optionChanged;
+    };
+
+    GlobalModel.prototype.mergeOption = function (option) {
+      this._mergeOption(option, null);
+    };
+
+    GlobalModel.prototype._mergeOption = function (newOption, opt) {
+      var option = this.option;
+      var componentsMap = this._componentsMap;
+      var componentsCount = this._componentsCount;
+      var newCmptTypes = [];
+      var newCmptTypeMap = createHashMap();
+      var replaceMergeMainTypeMap = opt && opt.replaceMergeMainTypeMap;
+      resetSourceDefaulter(this); // If no component class, merge directly.
+      // For example: color, animaiton options, etc.
+
+      each(newOption, function (componentOption, mainType) {
+        if (componentOption == null) {
+          return;
+        }
+
+        if (!ComponentModel.hasClass(mainType)) {
+          // globalSettingTask.dirty();
+          option[mainType] = option[mainType] == null ? clone(componentOption) : merge(option[mainType], componentOption, true);
+        } else if (mainType) {
+          newCmptTypes.push(mainType);
+          newCmptTypeMap.set(mainType, true);
+        }
+      });
+
+      if (replaceMergeMainTypeMap) {
+        // If there is a mainType `xxx` in `replaceMerge` but not declared in option,
+        // we trade it as it is declared in option as `{xxx: []}`. Because:
+        // (1) for normal merge, `{xxx: null/undefined}` are the same meaning as `{xxx: []}`.
+        // (2) some preprocessor may convert some of `{xxx: null/undefined}` to `{xxx: []}`.
+        replaceMergeMainTypeMap.each(function (val, mainTypeInReplaceMerge) {
+          if (ComponentModel.hasClass(mainTypeInReplaceMerge) && !newCmptTypeMap.get(mainTypeInReplaceMerge)) {
+            newCmptTypes.push(mainTypeInReplaceMerge);
+            newCmptTypeMap.set(mainTypeInReplaceMerge, true);
+          }
+        });
+      }
+
+      ComponentModel.topologicalTravel(newCmptTypes, ComponentModel.getAllClassMainTypes(), visitComponent, this);
+
+      function visitComponent(mainType) {
+        var newCmptOptionList = concatInternalOptions(this, mainType, normalizeToArray(newOption[mainType]));
+        var oldCmptList = componentsMap.get(mainType);
+        var mergeMode = // `!oldCmptList` means init. See the comment in `mappingToExists`
+        !oldCmptList ? 'replaceAll' : replaceMergeMainTypeMap && replaceMergeMainTypeMap.get(mainType) ? 'replaceMerge' : 'normalMerge';
+        var mappingResult = mappingToExists(oldCmptList, newCmptOptionList, mergeMode); // Set mainType and complete subType.
+
+        setComponentTypeToKeyInfo(mappingResult, mainType, ComponentModel); // Empty it before the travel, in order to prevent `this._componentsMap`
+        // from being used in the `init`/`mergeOption`/`optionUpdated` of some
+        // components, which is probably incorrect logic.
+
+        option[mainType] = null;
+        componentsMap.set(mainType, null);
+        componentsCount.set(mainType, 0);
+        var optionsByMainType = [];
+        var cmptsByMainType = [];
+        var cmptsCountByMainType = 0;
+        var tooltipExists;
+        var tooltipWarningLogged;
+        each(mappingResult, function (resultItem, index) {
+          var componentModel = resultItem.existing;
+          var newCmptOption = resultItem.newOption;
+
+          if (!newCmptOption) {
+            if (componentModel) {
+              // Consider where is no new option and should be merged using {},
+              // see removeEdgeAndAdd in topologicalTravel and
+              // ComponentModel.getAllClassMainTypes.
+              componentModel.mergeOption({}, this);
+              componentModel.optionUpdated({}, false);
+            } // If no both `resultItem.exist` and `resultItem.option`,
+            // either it is in `replaceMerge` and not matched by any id,
+            // or it has been removed in previous `replaceMerge` and left a "hole" in this component index.
+
+          } else {
+            var isSeriesType = mainType === 'series';
+            var ComponentModelClass = ComponentModel.getClass(mainType, resultItem.keyInfo.subType, !isSeriesType // Give a more detailed warn later if series don't exists
+            );
+
+            if (!ComponentModelClass) {
+              {
+                var subType = resultItem.keyInfo.subType;
+                var seriesImportName = BUILTIN_CHARTS_MAP[subType];
+
+                if (!componetsMissingLogPrinted[subType]) {
+                  componetsMissingLogPrinted[subType] = true;
+
+                  if (seriesImportName) {
+                    error("Series " + subType + " is used but not imported.\nimport { " + seriesImportName + " } from 'echarts/charts';\necharts.use([" + seriesImportName + "]);");
+                  } else {
+                    error("Unkown series " + subType);
+                  }
+                }
+              }
+              return;
+            } // TODO Before multiple tooltips get supported, we do this check to avoid unexpected exception.
+
+
+            if (mainType === 'tooltip') {
+              if (tooltipExists) {
+                {
+                  if (!tooltipWarningLogged) {
+                    warn('Currently only one tooltip component is allowed.');
+                    tooltipWarningLogged = true;
+                  }
+                }
+                return;
+              }
+
+              tooltipExists = true;
+            }
+
+            if (componentModel && componentModel.constructor === ComponentModelClass) {
+              componentModel.name = resultItem.keyInfo.name; // componentModel.settingTask && componentModel.settingTask.dirty();
+
+              componentModel.mergeOption(newCmptOption, this);
+              componentModel.optionUpdated(newCmptOption, false);
+            } else {
+              // PENDING Global as parent ?
+              var extraOpt = extend({
+                componentIndex: index
+              }, resultItem.keyInfo);
+              componentModel = new ComponentModelClass(newCmptOption, this, this, extraOpt); // Assign `keyInfo`
+
+              extend(componentModel, extraOpt);
+
+              if (resultItem.brandNew) {
+                componentModel.__requireNewView = true;
+              }
+
+              componentModel.init(newCmptOption, this, this); // Call optionUpdated after init.
+              // newCmptOption has been used as componentModel.option
+              // and may be merged with theme and default, so pass null
+              // to avoid confusion.
+
+              componentModel.optionUpdated(null, true);
+            }
+          }
+
+          if (componentModel) {
+            optionsByMainType.push(componentModel.option);
+            cmptsByMainType.push(componentModel);
+            cmptsCountByMainType++;
+          } else {
+            // Always do assign to avoid elided item in array.
+            optionsByMainType.push(void 0);
+            cmptsByMainType.push(void 0);
+          }
+        }, this);
+        option[mainType] = optionsByMainType;
+        componentsMap.set(mainType, cmptsByMainType);
+        componentsCount.set(mainType, cmptsCountByMainType); // Backup series for filtering.
+
+        if (mainType === 'series') {
+          reCreateSeriesIndices(this);
+        }
+      } // If no series declared, ensure `_seriesIndices` initialized.
+
+
+      if (!this._seriesIndices) {
+        reCreateSeriesIndices(this);
+      }
+    };
+    /**
+     * Get option for output (cloned option and inner info removed)
+     */
+
+
+    GlobalModel.prototype.getOption = function () {
+      var option = clone(this.option);
+      each(option, function (optInMainType, mainType) {
+        if (ComponentModel.hasClass(mainType)) {
+          var opts = normalizeToArray(optInMainType); // Inner cmpts need to be removed.
+          // Inner cmpts might not be at last since ec5.0, but still
+          // compatible for users: if inner cmpt at last, splice the returned array.
+
+          var realLen = opts.length;
+          var metNonInner = false;
+
+          for (var i = realLen - 1; i >= 0; i--) {
+            // Remove options with inner id.
+            if (opts[i] && !isComponentIdInternal(opts[i])) {
+              metNonInner = true;
+            } else {
+              opts[i] = null;
+              !metNonInner && realLen--;
+            }
+          }
+
+          opts.length = realLen;
+          option[mainType] = opts;
+        }
+      });
+      delete option[OPTION_INNER_KEY];
+      return option;
+    };
+
+    GlobalModel.prototype.getTheme = function () {
+      return this._theme;
+    };
+
+    GlobalModel.prototype.getLocaleModel = function () {
+      return this._locale;
+    };
+
+    GlobalModel.prototype.setUpdatePayload = function (payload) {
+      this._payload = payload;
+    };
+
+    GlobalModel.prototype.getUpdatePayload = function () {
+      return this._payload;
+    };
+    /**
+     * @param idx If not specified, return the first one.
+     */
+
+
+    GlobalModel.prototype.getComponent = function (mainType, idx) {
+      var list = this._componentsMap.get(mainType);
+
+      if (list) {
+        var cmpt = list[idx || 0];
+
+        if (cmpt) {
+          return cmpt;
+        } else if (idx == null) {
+          for (var i = 0; i < list.length; i++) {
+            if (list[i]) {
+              return list[i];
+            }
+          }
+        }
+      }
+    };
+    /**
+     * @return Never be null/undefined.
+     */
+
+
+    GlobalModel.prototype.queryComponents = function (condition) {
+      var mainType = condition.mainType;
+
+      if (!mainType) {
+        return [];
+      }
+
+      var index = condition.index;
+      var id = condition.id;
+      var name = condition.name;
+
+      var cmpts = this._componentsMap.get(mainType);
+
+      if (!cmpts || !cmpts.length) {
+        return [];
+      }
+
+      var result;
+
+      if (index != null) {
+        result = [];
+        each(normalizeToArray(index), function (idx) {
+          cmpts[idx] && result.push(cmpts[idx]);
+        });
+      } else if (id != null) {
+        result = queryByIdOrName('id', id, cmpts);
+      } else if (name != null) {
+        result = queryByIdOrName('name', name, cmpts);
+      } else {
+        // Return all non-empty components in that mainType
+        result = filter(cmpts, function (cmpt) {
+          return !!cmpt;
+        });
+      }
+
+      return filterBySubType(result, condition);
+    };
+    /**
+     * The interface is different from queryComponents,
+     * which is convenient for inner usage.
+     *
+     * @usage
+     * let result = findComponents(
+     *     {mainType: 'dataZoom', query: {dataZoomId: 'abc'}}
+     * );
+     * let result = findComponents(
+     *     {mainType: 'series', subType: 'pie', query: {seriesName: 'uio'}}
+     * );
+     * let result = findComponents(
+     *     {mainType: 'series',
+     *     filter: function (model, index) {...}}
+     * );
+     * // result like [component0, componnet1, ...]
+     */
+
+
+    GlobalModel.prototype.findComponents = function (condition) {
+      var query = condition.query;
+      var mainType = condition.mainType;
+      var queryCond = getQueryCond(query);
+      var result = queryCond ? this.queryComponents(queryCond) // Retrieve all non-empty components.
+      : filter(this._componentsMap.get(mainType), function (cmpt) {
+        return !!cmpt;
+      });
+      return doFilter(filterBySubType(result, condition));
+
+      function getQueryCond(q) {
+        var indexAttr = mainType + 'Index';
+        var idAttr = mainType + 'Id';
+        var nameAttr = mainType + 'Name';
+        return q && (q[indexAttr] != null || q[idAttr] != null || q[nameAttr] != null) ? {
+          mainType: mainType,
+          // subType will be filtered finally.
+          index: q[indexAttr],
+          id: q[idAttr],
+          name: q[nameAttr]
+        } : null;
+      }
+
+      function doFilter(res) {
+        return condition.filter ? filter(res, condition.filter) : res;
+      }
+    };
+
+    GlobalModel.prototype.eachComponent = function (mainType, cb, context) {
+      var componentsMap = this._componentsMap;
+
+      if (isFunction(mainType)) {
+        var ctxForAll_1 = cb;
+        var cbForAll_1 = mainType;
+        componentsMap.each(function (cmpts, componentType) {
+          for (var i = 0; cmpts && i < cmpts.length; i++) {
+            var cmpt = cmpts[i];
+            cmpt && cbForAll_1.call(ctxForAll_1, componentType, cmpt, cmpt.componentIndex);
+          }
+        });
+      } else {
+        var cmpts = isString(mainType) ? componentsMap.get(mainType) : isObject(mainType) ? this.findComponents(mainType) : null;
+
+        for (var i = 0; cmpts && i < cmpts.length; i++) {
+          var cmpt = cmpts[i];
+          cmpt && cb.call(context, cmpt, cmpt.componentIndex);
+        }
+      }
+    };
+    /**
+     * Get series list before filtered by name.
+     */
+
+
+    GlobalModel.prototype.getSeriesByName = function (name) {
+      var nameStr = convertOptionIdName(name, null);
+      return filter(this._componentsMap.get('series'), function (oneSeries) {
+        return !!oneSeries && nameStr != null && oneSeries.name === nameStr;
+      });
+    };
+    /**
+     * Get series list before filtered by index.
+     */
+
+
+    GlobalModel.prototype.getSeriesByIndex = function (seriesIndex) {
+      return this._componentsMap.get('series')[seriesIndex];
+    };
+    /**
+     * Get series list before filtered by type.
+     * FIXME: rename to getRawSeriesByType?
+     */
+
+
+    GlobalModel.prototype.getSeriesByType = function (subType) {
+      return filter(this._componentsMap.get('series'), function (oneSeries) {
+        return !!oneSeries && oneSeries.subType === subType;
+      });
+    };
+    /**
+     * Get all series before filtered.
+     */
+
+
+    GlobalModel.prototype.getSeries = function () {
+      return filter(this._componentsMap.get('series'), function (oneSeries) {
+        return !!oneSeries;
+      });
+    };
+    /**
+     * Count series before filtered.
+     */
+
+
+    GlobalModel.prototype.getSeriesCount = function () {
+      return this._componentsCount.get('series');
+    };
+    /**
+     * After filtering, series may be different
+     * frome raw series.
+     */
+
+
+    GlobalModel.prototype.eachSeries = function (cb, context) {
+      assertSeriesInitialized(this);
+      each(this._seriesIndices, function (rawSeriesIndex) {
+        var series = this._componentsMap.get('series')[rawSeriesIndex];
+
+        cb.call(context, series, rawSeriesIndex);
+      }, this);
+    };
+    /**
+     * Iterate raw series before filtered.
+     *
+     * @param {Function} cb
+     * @param {*} context
+     */
+
+
+    GlobalModel.prototype.eachRawSeries = function (cb, context) {
+      each(this._componentsMap.get('series'), function (series) {
+        series && cb.call(context, series, series.componentIndex);
+      });
+    };
+    /**
+     * After filtering, series may be different.
+     * frome raw series.
+     */
+
+
+    GlobalModel.prototype.eachSeriesByType = function (subType, cb, context) {
+      assertSeriesInitialized(this);
+      each(this._seriesIndices, function (rawSeriesIndex) {
+        var series = this._componentsMap.get('series')[rawSeriesIndex];
+
+        if (series.subType === subType) {
+          cb.call(context, series, rawSeriesIndex);
+        }
+      }, this);
+    };
+    /**
+     * Iterate raw series before filtered of given type.
+     */
+
+
+    GlobalModel.prototype.eachRawSeriesByType = function (subType, cb, context) {
+      return each(this.getSeriesByType(subType), cb, context);
+    };
+
+    GlobalModel.prototype.isSeriesFiltered = function (seriesModel) {
+      assertSeriesInitialized(this);
+      return this._seriesIndicesMap.get(seriesModel.componentIndex) == null;
+    };
+
+    GlobalModel.prototype.getCurrentSeriesIndices = function () {
+      return (this._seriesIndices || []).slice();
+    };
+
+    GlobalModel.prototype.filterSeries = function (cb, context) {
+      assertSeriesInitialized(this);
+      var newSeriesIndices = [];
+      each(this._seriesIndices, function (seriesRawIdx) {
+        var series = this._componentsMap.get('series')[seriesRawIdx];
+
+        cb.call(context, series, seriesRawIdx) && newSeriesIndices.push(seriesRawIdx);
+      }, this);
+      this._seriesIndices = newSeriesIndices;
+      this._seriesIndicesMap = createHashMap(newSeriesIndices);
+    };
+
+    GlobalModel.prototype.restoreData = function (payload) {
+      reCreateSeriesIndices(this);
+      var componentsMap = this._componentsMap;
+      var componentTypes = [];
+      componentsMap.each(function (components, componentType) {
+        if (ComponentModel.hasClass(componentType)) {
+          componentTypes.push(componentType);
+        }
+      });
+      ComponentModel.topologicalTravel(componentTypes, ComponentModel.getAllClassMainTypes(), function (componentType) {
+        each(componentsMap.get(componentType), function (component) {
+          if (component && (componentType !== 'series' || !isNotTargetSeries(component, payload))) {
+            component.restoreData();
+          }
+        });
+      });
+    };
+
+    GlobalModel.internalField = function () {
+      reCreateSeriesIndices = function (ecModel) {
+        var seriesIndices = ecModel._seriesIndices = [];
+        each(ecModel._componentsMap.get('series'), function (series) {
+          // series may have been removed by `replaceMerge`.
+          series && seriesIndices.push(series.componentIndex);
+        });
+        ecModel._seriesIndicesMap = createHashMap(seriesIndices);
+      };
+
+      assertSeriesInitialized = function (ecModel) {
+        // Components that use _seriesIndices should depends on series component,
+        // which make sure that their initialization is after series.
+        {
+          if (!ecModel._seriesIndices) {
+            throw new Error('Option should contains series.');
+          }
+        }
+      };
+
+      initBase = function (ecModel, baseOption) {
+        // Using OPTION_INNER_KEY to mark that this option can not be used outside,
+        // i.e. `chart.setOption(chart.getModel().option);` is forbiden.
+        ecModel.option = {};
+        ecModel.option[OPTION_INNER_KEY] = OPTION_INNER_VALUE; // Init with series: [], in case of calling findSeries method
+        // before series initialized.
+
+        ecModel._componentsMap = createHashMap({
+          series: []
+        });
+        ecModel._componentsCount = createHashMap(); // If user spefied `option.aria`, aria will be enable. This detection should be
+        // performed before theme and globalDefault merge.
+
+        var airaOption = baseOption.aria;
+
+        if (isObject(airaOption) && airaOption.enabled == null) {
+          airaOption.enabled = true;
+        }
+
+        mergeTheme(baseOption, ecModel._theme.option); // TODO Needs clone when merging to the unexisted property
+
+        merge(baseOption, globalDefault, false);
+
+        ecModel._mergeOption(baseOption, null);
+      };
+    }();
+
+    return GlobalModel;
+  }(Model);
+
+  function isNotTargetSeries(seriesModel, payload) {
+    if (payload) {
+      var index = payload.seriesIndex;
+      var id = payload.seriesId;
+      var name_1 = payload.seriesName;
+      return index != null && seriesModel.componentIndex !== index || id != null && seriesModel.id !== id || name_1 != null && seriesModel.name !== name_1;
+    }
+  }
+
+  function mergeTheme(option, theme) {
+    // PENDING
+    // NOT use `colorLayer` in theme if option has `color`
+    var notMergeColorLayer = option.color && !option.colorLayer;
+    each(theme, function (themeItem, name) {
+      if (name === 'colorLayer' && notMergeColorLayer) {
+        return;
+      } // If it is component model mainType, the model handles that merge later.
+      // otherwise, merge them here.
+
+
+      if (!ComponentModel.hasClass(name)) {
+        if (typeof themeItem === 'object') {
+          option[name] = !option[name] ? clone(themeItem) : merge(option[name], themeItem, false);
+        } else {
+          if (option[name] == null) {
+            option[name] = themeItem;
+          }
+        }
+      }
+    });
+  }
+
+  function queryByIdOrName(attr, idOrName, cmpts) {
+    // Here is a break from echarts4: string and number are
+    // treated as equal.
+    if (isArray(idOrName)) {
+      var keyMap_1 = createHashMap();
+      each(idOrName, function (idOrNameItem) {
+        if (idOrNameItem != null) {
+          var idName = convertOptionIdName(idOrNameItem, null);
+          idName != null && keyMap_1.set(idOrNameItem, true);
+        }
+      });
+      return filter(cmpts, function (cmpt) {
+        return cmpt && keyMap_1.get(cmpt[attr]);
+      });
+    } else {
+      var idName_1 = convertOptionIdName(idOrName, null);
+      return filter(cmpts, function (cmpt) {
+        return cmpt && idName_1 != null && cmpt[attr] === idName_1;
+      });
+    }
+  }
+
+  function filterBySubType(components, condition) {
+    // Using hasOwnProperty for restrict. Consider
+    // subType is undefined in user payload.
+    return condition.hasOwnProperty('subType') ? filter(components, function (cmpt) {
+      return cmpt && cmpt.subType === condition.subType;
+    }) : components;
+  }
+
+  function normalizeSetOptionInput(opts) {
+    var replaceMergeMainTypeMap = createHashMap();
+    opts && each(normalizeToArray(opts.replaceMerge), function (mainType) {
+      {
+        assert(ComponentModel.hasClass(mainType), '"' + mainType + '" is not valid component main type in "replaceMerge"');
+      }
+      replaceMergeMainTypeMap.set(mainType, true);
+    });
+    return {
+      replaceMergeMainTypeMap: replaceMergeMainTypeMap
+    };
+  }
+
+  mixin(GlobalModel, PaletteMixin);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 availableMethods = ['getDom', 'getZr', 'getWidth', 'getHeight', 'getDevicePixelRatio', 'dispatchAction', 'isSSR', 'isDisposed', 'on', 'off', 'getDataURL', 'getConnectedDataURL', // 'getModel',
+  'getOption', // 'getViewOfComponentModel',
+  // 'getViewOfSeriesModel',
+  'getId', 'updateLabelLayout'];
+
+  var ExtensionAPI =
+  /** @class */
+  function () {
+    function ExtensionAPI(ecInstance) {
+      each(availableMethods, function (methodName) {
+        this[methodName] = bind(ecInstance[methodName], ecInstance);
+      }, this);
+    }
+
+    return ExtensionAPI;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 coordinateSystemCreators = {};
+
+  var CoordinateSystemManager =
+  /** @class */
+  function () {
+    function CoordinateSystemManager() {
+      this._coordinateSystems = [];
+    }
+
+    CoordinateSystemManager.prototype.create = function (ecModel, api) {
+      var coordinateSystems = [];
+      each(coordinateSystemCreators, function (creater, type) {
+        var list = creater.create(ecModel, api);
+        coordinateSystems = coordinateSystems.concat(list || []);
+      });
+      this._coordinateSystems = coordinateSystems;
+    };
+
+    CoordinateSystemManager.prototype.update = function (ecModel, api) {
+      each(this._coordinateSystems, function (coordSys) {
+        coordSys.update && coordSys.update(ecModel, api);
+      });
+    };
+
+    CoordinateSystemManager.prototype.getCoordinateSystems = function () {
+      return this._coordinateSystems.slice();
+    };
+
+    CoordinateSystemManager.register = function (type, creator) {
+      coordinateSystemCreators[type] = creator;
+    };
+
+    CoordinateSystemManager.get = function (type) {
+      return coordinateSystemCreators[type];
+    };
+
+    return CoordinateSystemManager;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 QUERY_REG = /^(min|max)?(.+)$/; // Key: mainType
+  // type FakeComponentsMap = HashMap<(MappingExistingItem & { subType: string })[]>;
+
+  /**
+   * TERM EXPLANATIONS:
+   * See `ECOption` and `ECUnitOption` in `src/util/types.ts`.
+   */
+
+  var OptionManager =
+  /** @class */
+  function () {
+    // timeline.notMerge is not supported in ec3. Firstly there is rearly
+    // case that notMerge is needed. Secondly supporting 'notMerge' requires
+    // rawOption cloned and backuped when timeline changed, which does no
+    // good to performance. What's more, that both timeline and setOption
+    // method supply 'notMerge' brings complex and some problems.
+    // Consider this case:
+    // (step1) chart.setOption({timeline: {notMerge: false}, ...}, false);
+    // (step2) chart.setOption({timeline: {notMerge: true}, ...}, false);
+    function OptionManager(api) {
+      this._timelineOptions = [];
+      this._mediaList = [];
+      /**
+       * -1, means default.
+       * empty means no media.
+       */
+
+      this._currentMediaIndices = [];
+      this._api = api;
+    }
+
+    OptionManager.prototype.setOption = function (rawOption, optionPreprocessorFuncs, opt) {
+      if (rawOption) {
+        // That set dat primitive is dangerous if user reuse the data when setOption again.
+        each(normalizeToArray(rawOption.series), function (series) {
+          series && series.data && isTypedArray(series.data) && setAsPrimitive(series.data);
+        });
+        each(normalizeToArray(rawOption.dataset), function (dataset) {
+          dataset && dataset.source && isTypedArray(dataset.source) && setAsPrimitive(dataset.source);
+        });
+      } // Caution: some series modify option data, if do not clone,
+      // it should ensure that the repeat modify correctly
+      // (create a new object when modify itself).
+
+
+      rawOption = clone(rawOption); // FIXME
+      // If some property is set in timeline options or media option but
+      // not set in baseOption, a warning should be given.
+
+      var optionBackup = this._optionBackup;
+      var newParsedOption = parseRawOption(rawOption, optionPreprocessorFuncs, !optionBackup);
+      this._newBaseOption = newParsedOption.baseOption; // For setOption at second time (using merge mode);
+
+      if (optionBackup) {
+        // FIXME
+        // the restore merge solution is essentially incorrect.
+        // the mapping can not be 100% consistent with ecModel, which probably brings
+        // potential bug!
+        // The first merge is delayed, becuase in most cases, users do not call `setOption` twice.
+        // let fakeCmptsMap = this._fakeCmptsMap;
+        // if (!fakeCmptsMap) {
+        //     fakeCmptsMap = this._fakeCmptsMap = createHashMap();
+        //     mergeToBackupOption(fakeCmptsMap, null, optionBackup.baseOption, null);
+        // }
+        // mergeToBackupOption(
+        //     fakeCmptsMap, optionBackup.baseOption, newParsedOption.baseOption, opt
+        // );
+        // For simplicity, timeline options and media options do not support merge,
+        // that is, if you `setOption` twice and both has timeline options, the latter
+        // timeline opitons will not be merged to the formers, but just substitude them.
+        if (newParsedOption.timelineOptions.length) {
+          optionBackup.timelineOptions = newParsedOption.timelineOptions;
+        }
+
+        if (newParsedOption.mediaList.length) {
+          optionBackup.mediaList = newParsedOption.mediaList;
+        }
+
+        if (newParsedOption.mediaDefault) {
+          optionBackup.mediaDefault = newParsedOption.mediaDefault;
+        }
+      } else {
+        this._optionBackup = newParsedOption;
+      }
+    };
+
+    OptionManager.prototype.mountOption = function (isRecreate) {
+      var optionBackup = this._optionBackup;
+      this._timelineOptions = optionBackup.timelineOptions;
+      this._mediaList = optionBackup.mediaList;
+      this._mediaDefault = optionBackup.mediaDefault;
+      this._currentMediaIndices = [];
+      return clone(isRecreate // this._optionBackup.baseOption, which is created at the first `setOption`
+      // called, and is merged into every new option by inner method `mergeToBackupOption`
+      // each time `setOption` called, can be only used in `isRecreate`, because
+      // its reliability is under suspicion. In other cases option merge is
+      // performed by `model.mergeOption`.
+      ? optionBackup.baseOption : this._newBaseOption);
+    };
+
+    OptionManager.prototype.getTimelineOption = function (ecModel) {
+      var option;
+      var timelineOptions = this._timelineOptions;
+
+      if (timelineOptions.length) {
+        // getTimelineOption can only be called after ecModel inited,
+        // so we can get currentIndex from timelineModel.
+        var timelineModel = ecModel.getComponent('timeline');
+
+        if (timelineModel) {
+          option = clone( // FIXME:TS as TimelineModel or quivlant interface
+          timelineOptions[timelineModel.getCurrentIndex()]);
+        }
+      }
+
+      return option;
+    };
+
+    OptionManager.prototype.getMediaOption = function (ecModel) {
+      var ecWidth = this._api.getWidth();
+
+      var ecHeight = this._api.getHeight();
+
+      var mediaList = this._mediaList;
+      var mediaDefault = this._mediaDefault;
+      var indices = [];
+      var result = []; // No media defined.
+
+      if (!mediaList.length && !mediaDefault) {
+        return result;
+      } // Multi media may be applied, the latter defined media has higher priority.
+
+
+      for (var i = 0, len = mediaList.length; i < len; i++) {
+        if (applyMediaQuery(mediaList[i].query, ecWidth, ecHeight)) {
+          indices.push(i);
+        }
+      } // FIXME
+      // Whether mediaDefault should force users to provide? Otherwise
+      // the change by media query can not be recorvered.
+
+
+      if (!indices.length && mediaDefault) {
+        indices = [-1];
+      }
+
+      if (indices.length && !indicesEquals(indices, this._currentMediaIndices)) {
+        result = map(indices, function (index) {
+          return clone(index === -1 ? mediaDefault.option : mediaList[index].option);
+        });
+      } // Otherwise return nothing.
+
+
+      this._currentMediaIndices = indices;
+      return result;
+    };
+
+    return OptionManager;
+  }();
+  /**
+   * [RAW_OPTION_PATTERNS]
+   * (Note: "series: []" represents all other props in `ECUnitOption`)
+   *
+   * (1) No prop "baseOption" declared:
+   * Root option is used as "baseOption" (except prop "options" and "media").
+   * ```js
+   * option = {
+   *     series: [],
+   *     timeline: {},
+   *     options: [],
+   * };
+   * option = {
+   *     series: [],
+   *     media: {},
+   * };
+   * option = {
+   *     series: [],
+   *     timeline: {},
+   *     options: [],
+   *     media: {},
+   * }
+   * ```
+   *
+   * (2) Prop "baseOption" declared:
+   * If "baseOption" declared, `ECUnitOption` props can only be declared
+   * inside "baseOption" except prop "timeline" (compat ec2).
+   * ```js
+   * option = {
+   *     baseOption: {
+   *         timeline: {},
+   *         series: [],
+   *     },
+   *     options: []
+   * };
+   * option = {
+   *     baseOption: {
+   *         series: [],
+   *     },
+   *     media: []
+   * };
+   * option = {
+   *     baseOption: {
+   *         timeline: {},
+   *         series: [],
+   *     },
+   *     options: []
+   *     media: []
+   * };
+   * option = {
+   *     // ec3 compat ec2: allow (only) `timeline` declared
+   *     // outside baseOption. Keep this setting for compat.
+   *     timeline: {},
+   *     baseOption: {
+   *         series: [],
+   *     },
+   *     options: [],
+   *     media: []
+   * };
+   * ```
+   */
+
+
+  function parseRawOption( // `rawOption` May be modified
+  rawOption, optionPreprocessorFuncs, isNew) {
+    var mediaList = [];
+    var mediaDefault;
+    var baseOption;
+    var declaredBaseOption = rawOption.baseOption; // Compatible with ec2, [RAW_OPTION_PATTERNS] above.
+
+    var timelineOnRoot = rawOption.timeline;
+    var timelineOptionsOnRoot = rawOption.options;
+    var mediaOnRoot = rawOption.media;
+    var hasMedia = !!rawOption.media;
+    var hasTimeline = !!(timelineOptionsOnRoot || timelineOnRoot || declaredBaseOption && declaredBaseOption.timeline);
+
+    if (declaredBaseOption) {
+      baseOption = declaredBaseOption; // For merge option.
+
+      if (!baseOption.timeline) {
+        baseOption.timeline = timelineOnRoot;
+      }
+    } // For convenience, enable to use the root option as the `baseOption`:
+    // `{ ...normalOptionProps, media: [{ ... }, { ... }] }`
+    else {
+        if (hasTimeline || hasMedia) {
+          rawOption.options = rawOption.media = null;
+        }
+
+        baseOption = rawOption;
+      }
+
+    if (hasMedia) {
+      if (isArray(mediaOnRoot)) {
+        each(mediaOnRoot, function (singleMedia) {
+          {
+            // Real case of wrong config.
+            if (singleMedia && !singleMedia.option && isObject(singleMedia.query) && isObject(singleMedia.query.option)) {
+              error('Illegal media option. Must be like { media: [ { query: {}, option: {} } ] }');
+            }
+          }
+
+          if (singleMedia && singleMedia.option) {
+            if (singleMedia.query) {
+              mediaList.push(singleMedia);
+            } else if (!mediaDefault) {
+              // Use the first media default.
+              mediaDefault = singleMedia;
+            }
+          }
+        });
+      } else {
+        {
+          // Real case of wrong config.
+          error('Illegal media option. Must be an array. Like { media: [ {...}, {...} ] }');
+        }
+      }
+    }
+
+    doPreprocess(baseOption);
+    each(timelineOptionsOnRoot, function (option) {
+      return doPreprocess(option);
+    });
+    each(mediaList, function (media) {
+      return doPreprocess(media.option);
+    });
+
+    function doPreprocess(option) {
+      each(optionPreprocessorFuncs, function (preProcess) {
+        preProcess(option, isNew);
+      });
+    }
+
+    return {
+      baseOption: baseOption,
+      timelineOptions: timelineOptionsOnRoot || [],
+      mediaDefault: mediaDefault,
+      mediaList: mediaList
+    };
+  }
+  /**
+   * @see <http://www.w3.org/TR/css3-mediaqueries/#media1>
+   * Support: width, height, aspectRatio
+   * Can use max or min as prefix.
+   */
+
+
+  function applyMediaQuery(query, ecWidth, ecHeight) {
+    var realMap = {
+      width: ecWidth,
+      height: ecHeight,
+      aspectratio: ecWidth / ecHeight // lowser case for convenientce.
+
+    };
+    var applicatable = true;
+    each(query, function (value, attr) {
+      var matched = attr.match(QUERY_REG);
+
+      if (!matched || !matched[1] || !matched[2]) {
+        return;
+      }
+
+      var operator = matched[1];
+      var realAttr = matched[2].toLowerCase();
+
+      if (!compare(realMap[realAttr], value, operator)) {
+        applicatable = false;
+      }
+    });
+    return applicatable;
+  }
+
+  function compare(real, expect, operator) {
+    if (operator === 'min') {
+      return real >= expect;
+    } else if (operator === 'max') {
+      return real <= expect;
+    } else {
+      // Equals
+      return real === expect;
+    }
+  }
+
+  function indicesEquals(indices1, indices2) {
+    // indices is always order by asc and has only finite number.
+    return indices1.join(',') === indices2.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.
+  */
+
+  /**
+   * AUTO-GENERATED FILE. DO NOT MODIFY.
+   */
+
+  /*
+  * 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 each$2 = each;
+  var isObject$1 = isObject;
+  var POSSIBLE_STYLES = ['areaStyle', 'lineStyle', 'nodeStyle', 'linkStyle', 'chordStyle', 'label', 'labelLine'];
+
+  function compatEC2ItemStyle(opt) {
+    var itemStyleOpt = opt && opt.itemStyle;
+
+    if (!itemStyleOpt) {
+      return;
+    }
+
+    for (var i = 0, len = POSSIBLE_STYLES.length; i < len; i++) {
+      var styleName = POSSIBLE_STYLES[i];
+      var normalItemStyleOpt = itemStyleOpt.normal;
+      var emphasisItemStyleOpt = itemStyleOpt.emphasis;
+
+      if (normalItemStyleOpt && normalItemStyleOpt[styleName]) {
+        {
+          deprecateReplaceLog("itemStyle.normal." + styleName, styleName);
+        }
+        opt[styleName] = opt[styleName] || {};
+
+        if (!opt[styleName].normal) {
+          opt[styleName].normal = normalItemStyleOpt[styleName];
+        } else {
+          merge(opt[styleName].normal, normalItemStyleOpt[styleName]);
+        }
+
+        normalItemStyleOpt[styleName] = null;
+      }
+
+      if (emphasisItemStyleOpt && emphasisItemStyleOpt[styleName]) {
+        {
+          deprecateReplaceLog("itemStyle.emphasis." + styleName, "emphasis." + styleName);
+        }
+        opt[styleName] = opt[styleName] || {};
+
+        if (!opt[styleName].emphasis) {
+          opt[styleName].emphasis = emphasisItemStyleOpt[styleName];
+        } else {
+          merge(opt[styleName].emphasis, emphasisItemStyleOpt[styleName]);
+        }
+
+        emphasisItemStyleOpt[styleName] = null;
+      }
+    }
+  }
+
+  function convertNormalEmphasis(opt, optType, useExtend) {
+    if (opt && opt[optType] && (opt[optType].normal || opt[optType].emphasis)) {
+      var normalOpt = opt[optType].normal;
+      var emphasisOpt = opt[optType].emphasis;
+
+      if (normalOpt) {
+        {
+          // eslint-disable-next-line max-len
+          deprecateLog("'normal' hierarchy in " + optType + " has been removed since 4.0. All style properties are configured in " + optType + " directly now.");
+        } // Timeline controlStyle has other properties besides normal and emphasis
+
+        if (useExtend) {
+          opt[optType].normal = opt[optType].emphasis = null;
+          defaults(opt[optType], normalOpt);
+        } else {
+          opt[optType] = normalOpt;
+        }
+      }
+
+      if (emphasisOpt) {
+        {
+          deprecateLog(optType + ".emphasis has been changed to emphasis." + optType + " since 4.0");
+        }
+        opt.emphasis = opt.emphasis || {};
+        opt.emphasis[optType] = emphasisOpt; // Also compat the case user mix the style and focus together in ec3 style
+        // for example: { itemStyle: { normal: {}, emphasis: {focus, shadowBlur} } }
+
+        if (emphasisOpt.focus) {
+          opt.emphasis.focus = emphasisOpt.focus;
+        }
+
+        if (emphasisOpt.blurScope) {
+          opt.emphasis.blurScope = emphasisOpt.blurScope;
+        }
+      }
+    }
+  }
+
+  function removeEC3NormalStatus(opt) {
+    convertNormalEmphasis(opt, 'itemStyle');
+    convertNormalEmphasis(opt, 'lineStyle');
+    convertNormalEmphasis(opt, 'areaStyle');
+    convertNormalEmphasis(opt, 'label');
+    convertNormalEmphasis(opt, 'labelLine'); // treemap
+
+    convertNormalEmphasis(opt, 'upperLabel'); // graph
+
+    convertNormalEmphasis(opt, 'edgeLabel');
+  }
+
+  function compatTextStyle(opt, propName) {
+    // Check whether is not object (string\null\undefined ...)
+    var labelOptSingle = isObject$1(opt) && opt[propName];
+    var textStyle = isObject$1(labelOptSingle) && labelOptSingle.textStyle;
+
+    if (textStyle) {
+      {
+        // eslint-disable-next-line max-len
+        deprecateLog("textStyle hierarchy in " + propName + " has been removed since 4.0. All textStyle properties are configured in " + propName + " directly now.");
+      }
+
+      for (var i = 0, len = TEXT_STYLE_OPTIONS.length; i < len; i++) {
+        var textPropName = TEXT_STYLE_OPTIONS[i];
+
+        if (textStyle.hasOwnProperty(textPropName)) {
+          labelOptSingle[textPropName] = textStyle[textPropName];
+        }
+      }
+    }
+  }
+
+  function compatEC3CommonStyles(opt) {
+    if (opt) {
+      removeEC3NormalStatus(opt);
+      compatTextStyle(opt, 'label');
+      opt.emphasis && compatTextStyle(opt.emphasis, 'label');
+    }
+  }
+
+  function processSeries(seriesOpt) {
+    if (!isObject$1(seriesOpt)) {
+      return;
+    }
+
+    compatEC2ItemStyle(seriesOpt);
+    removeEC3NormalStatus(seriesOpt);
+    compatTextStyle(seriesOpt, 'label'); // treemap
+
+    compatTextStyle(seriesOpt, 'upperLabel'); // graph
+
+    compatTextStyle(seriesOpt, 'edgeLabel');
+
+    if (seriesOpt.emphasis) {
+      compatTextStyle(seriesOpt.emphasis, 'label'); // treemap
+
+      compatTextStyle(seriesOpt.emphasis, 'upperLabel'); // graph
+
+      compatTextStyle(seriesOpt.emphasis, 'edgeLabel');
+    }
+
+    var markPoint = seriesOpt.markPoint;
+
+    if (markPoint) {
+      compatEC2ItemStyle(markPoint);
+      compatEC3CommonStyles(markPoint);
+    }
+
+    var markLine = seriesOpt.markLine;
+
+    if (markLine) {
+      compatEC2ItemStyle(markLine);
+      compatEC3CommonStyles(markLine);
+    }
+
+    var markArea = seriesOpt.markArea;
+
+    if (markArea) {
+      compatEC3CommonStyles(markArea);
+    }
+
+    var data = seriesOpt.data; // Break with ec3: if `setOption` again, there may be no `type` in option,
+    // then the backward compat based on option type will not be performed.
+
+    if (seriesOpt.type === 'graph') {
+      data = data || seriesOpt.nodes;
+      var edgeData = seriesOpt.links || seriesOpt.edges;
+
+      if (edgeData && !isTypedArray(edgeData)) {
+        for (var i = 0; i < edgeData.length; i++) {
+          compatEC3CommonStyles(edgeData[i]);
+        }
+      }
+
+      each(seriesOpt.categories, function (opt) {
+        removeEC3NormalStatus(opt);
+      });
+    }
+
+    if (data && !isTypedArray(data)) {
+      for (var i = 0; i < data.length; i++) {
+        compatEC3CommonStyles(data[i]);
+      }
+    } // mark point data
+
+
+    markPoint = seriesOpt.markPoint;
+
+    if (markPoint && markPoint.data) {
+      var mpData = markPoint.data;
+
+      for (var i = 0; i < mpData.length; i++) {
+        compatEC3CommonStyles(mpData[i]);
+      }
+    } // mark line data
+
+
+    markLine = seriesOpt.markLine;
+
+    if (markLine && markLine.data) {
+      var mlData = markLine.data;
+
+      for (var i = 0; i < mlData.length; i++) {
+        if (isArray(mlData[i])) {
+          compatEC3CommonStyles(mlData[i][0]);
+          compatEC3CommonStyles(mlData[i][1]);
+        } else {
+          compatEC3CommonStyles(mlData[i]);
+        }
+      }
+    } // Series
+
+
+    if (seriesOpt.type === 'gauge') {
+      compatTextStyle(seriesOpt, 'axisLabel');
+      compatTextStyle(seriesOpt, 'title');
+      compatTextStyle(seriesOpt, 'detail');
+    } else if (seriesOpt.type === 'treemap') {
+      convertNormalEmphasis(seriesOpt.breadcrumb, 'itemStyle');
+      each(seriesOpt.levels, function (opt) {
+        removeEC3NormalStatus(opt);
+      });
+    } else if (seriesOpt.type === 'tree') {
+      removeEC3NormalStatus(seriesOpt.leaves);
+    } // sunburst starts from ec4, so it does not need to compat levels.
+
+  }
+
+  function toArr(o) {
+    return isArray(o) ? o : o ? [o] : [];
+  }
+
+  function toObj(o) {
+    return (isArray(o) ? o[0] : o) || {};
+  }
+
+  function globalCompatStyle(option, isTheme) {
+    each$2(toArr(option.series), function (seriesOpt) {
+      isObject$1(seriesOpt) && processSeries(seriesOpt);
+    });
+    var axes = ['xAxis', 'yAxis', 'radiusAxis', 'angleAxis', 'singleAxis', 'parallelAxis', 'radar'];
+    isTheme && axes.push('valueAxis', 'categoryAxis', 'logAxis', 'timeAxis');
+    each$2(axes, function (axisName) {
+      each$2(toArr(option[axisName]), function (axisOpt) {
+        if (axisOpt) {
+          compatTextStyle(axisOpt, 'axisLabel');
+          compatTextStyle(axisOpt.axisPointer, 'label');
+        }
+      });
+    });
+    each$2(toArr(option.parallel), function (parallelOpt) {
+      var parallelAxisDefault = parallelOpt && parallelOpt.parallelAxisDefault;
+      compatTextStyle(parallelAxisDefault, 'axisLabel');
+      compatTextStyle(parallelAxisDefault && parallelAxisDefault.axisPointer, 'label');
+    });
+    each$2(toArr(option.calendar), function (calendarOpt) {
+      convertNormalEmphasis(calendarOpt, 'itemStyle');
+      compatTextStyle(calendarOpt, 'dayLabel');
+      compatTextStyle(calendarOpt, 'monthLabel');
+      compatTextStyle(calendarOpt, 'yearLabel');
+    }); // radar.name.textStyle
+
+    each$2(toArr(option.radar), function (radarOpt) {
+      compatTextStyle(radarOpt, 'name'); // Use axisName instead of name because component has name property
+
+      if (radarOpt.name && radarOpt.axisName == null) {
+        radarOpt.axisName = radarOpt.name;
+        delete radarOpt.name;
+        {
+          deprecateLog('name property in radar component has been changed to axisName');
+        }
+      }
+
+      if (radarOpt.nameGap != null && radarOpt.axisNameGap == null) {
+        radarOpt.axisNameGap = radarOpt.nameGap;
+        delete radarOpt.nameGap;
+        {
+          deprecateLog('nameGap property in radar component has been changed to axisNameGap');
+        }
+      }
+
+      {
+        each$2(radarOpt.indicator, function (indicatorOpt) {
+          if (indicatorOpt.text) {
+            deprecateReplaceLog('text', 'name', 'radar.indicator');
+          }
+        });
+      }
+    });
+    each$2(toArr(option.geo), function (geoOpt) {
+      if (isObject$1(geoOpt)) {
+        compatEC3CommonStyles(geoOpt);
+        each$2(toArr(geoOpt.regions), function (regionObj) {
+          compatEC3CommonStyles(regionObj);
+        });
+      }
+    });
+    each$2(toArr(option.timeline), function (timelineOpt) {
+      compatEC3CommonStyles(timelineOpt);
+      convertNormalEmphasis(timelineOpt, 'label');
+      convertNormalEmphasis(timelineOpt, 'itemStyle');
+      convertNormalEmphasis(timelineOpt, 'controlStyle', true);
+      var data = timelineOpt.data;
+      isArray(data) && each(data, function (item) {
+        if (isObject(item)) {
+          convertNormalEmphasis(item, 'label');
+          convertNormalEmphasis(item, 'itemStyle');
+        }
+      });
+    });
+    each$2(toArr(option.toolbox), function (toolboxOpt) {
+      convertNormalEmphasis(toolboxOpt, 'iconStyle');
+      each$2(toolboxOpt.feature, function (featureOpt) {
+        convertNormalEmphasis(featureOpt, 'iconStyle');
+      });
+    });
+    compatTextStyle(toObj(option.axisPointer), 'label');
+    compatTextStyle(toObj(option.tooltip).axisPointer, 'label'); // Clean logs
+    // storedLogs = {};
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 get(opt, path) {
+    var pathArr = path.split(',');
+    var obj = opt;
+
+    for (var i = 0; i < pathArr.length; i++) {
+      obj = obj && obj[pathArr[i]];
+
+      if (obj == null) {
+        break;
+      }
+    }
+
+    return obj;
+  }
+
+  function set$1(opt, path, val, overwrite) {
+    var pathArr = path.split(',');
+    var obj = opt;
+    var key;
+    var i = 0;
+
+    for (; i < pathArr.length - 1; i++) {
+      key = pathArr[i];
+
+      if (obj[key] == null) {
+        obj[key] = {};
+      }
+
+      obj = obj[key];
+    }
+
+    if (overwrite || obj[pathArr[i]] == null) {
+      obj[pathArr[i]] = val;
+    }
+  }
+
+  function compatLayoutProperties(option) {
+    option && each(LAYOUT_PROPERTIES, function (prop) {
+      if (prop[0] in option && !(prop[1] in option)) {
+        option[prop[1]] = option[prop[0]];
+      }
+    });
+  }
+
+  var LAYOUT_PROPERTIES = [['x', 'left'], ['y', 'top'], ['x2', 'right'], ['y2', 'bottom']];
+  var COMPATITABLE_COMPONENTS = ['grid', 'geo', 'parallel', 'legend', 'toolbox', 'title', 'visualMap', 'dataZoom', 'timeline'];
+  var BAR_ITEM_STYLE_MAP = [['borderRadius', 'barBorderRadius'], ['borderColor', 'barBorderColor'], ['borderWidth', 'barBorderWidth']];
+
+  function compatBarItemStyle(option) {
+    var itemStyle = option && option.itemStyle;
+
+    if (itemStyle) {
+      for (var i = 0; i < BAR_ITEM_STYLE_MAP.length; i++) {
+        var oldName = BAR_ITEM_STYLE_MAP[i][1];
+        var newName = BAR_ITEM_STYLE_MAP[i][0];
+
+        if (itemStyle[oldName] != null) {
+          itemStyle[newName] = itemStyle[oldName];
+          {
+            deprecateReplaceLog(oldName, newName);
+          }
+        }
+      }
+    }
+  }
+
+  function compatPieLabel(option) {
+    if (!option) {
+      return;
+    }
+
+    if (option.alignTo === 'edge' && option.margin != null && option.edgeDistance == null) {
+      {
+        deprecateReplaceLog('label.margin', 'label.edgeDistance', 'pie');
+      }
+      option.edgeDistance = option.margin;
+    }
+  }
+
+  function compatSunburstState(option) {
+    if (!option) {
+      return;
+    }
+
+    if (option.downplay && !option.blur) {
+      option.blur = option.downplay;
+      {
+        deprecateReplaceLog('downplay', 'blur', 'sunburst');
+      }
+    }
+  }
+
+  function compatGraphFocus(option) {
+    if (!option) {
+      return;
+    }
+
+    if (option.focusNodeAdjacency != null) {
+      option.emphasis = option.emphasis || {};
+
+      if (option.emphasis.focus == null) {
+        {
+          deprecateReplaceLog('focusNodeAdjacency', 'emphasis: { focus: \'adjacency\'}', 'graph/sankey');
+        }
+        option.emphasis.focus = 'adjacency';
+      }
+    }
+  }
+
+  function traverseTree(data, cb) {
+    if (data) {
+      for (var i = 0; i < data.length; i++) {
+        cb(data[i]);
+        data[i] && traverseTree(data[i].children, cb);
+      }
+    }
+  }
+
+  function globalBackwardCompat(option, isTheme) {
+    globalCompatStyle(option, isTheme); // Make sure series array for model initialization.
+
+    option.series = normalizeToArray(option.series);
+    each(option.series, function (seriesOpt) {
+      if (!isObject(seriesOpt)) {
+        return;
+      }
+
+      var seriesType = seriesOpt.type;
+
+      if (seriesType === 'line') {
+        if (seriesOpt.clipOverflow != null) {
+          seriesOpt.clip = seriesOpt.clipOverflow;
+          {
+            deprecateReplaceLog('clipOverflow', 'clip', 'line');
+          }
+        }
+      } else if (seriesType === 'pie' || seriesType === 'gauge') {
+        if (seriesOpt.clockWise != null) {
+          seriesOpt.clockwise = seriesOpt.clockWise;
+          {
+            deprecateReplaceLog('clockWise', 'clockwise');
+          }
+        }
+
+        compatPieLabel(seriesOpt.label);
+        var data = seriesOpt.data;
+
+        if (data && !isTypedArray(data)) {
+          for (var i = 0; i < data.length; i++) {
+            compatPieLabel(data[i]);
+          }
+        }
+
+        if (seriesOpt.hoverOffset != null) {
+          seriesOpt.emphasis = seriesOpt.emphasis || {};
+
+          if (seriesOpt.emphasis.scaleSize = null) {
+            {
+              deprecateReplaceLog('hoverOffset', 'emphasis.scaleSize');
+            }
+            seriesOpt.emphasis.scaleSize = seriesOpt.hoverOffset;
+          }
+        }
+      } else if (seriesType === 'gauge') {
+        var pointerColor = get(seriesOpt, 'pointer.color');
+        pointerColor != null && set$1(seriesOpt, 'itemStyle.color', pointerColor);
+      } else if (seriesType === 'bar') {
+        compatBarItemStyle(seriesOpt);
+        compatBarItemStyle(seriesOpt.backgroundStyle);
+        compatBarItemStyle(seriesOpt.emphasis);
+        var data = seriesOpt.data;
+
+        if (data && !isTypedArray(data)) {
+          for (var i = 0; i < data.length; i++) {
+            if (typeof data[i] === 'object') {
+              compatBarItemStyle(data[i]);
+              compatBarItemStyle(data[i] && data[i].emphasis);
+            }
+          }
+        }
+      } else if (seriesType === 'sunburst') {
+        var highlightPolicy = seriesOpt.highlightPolicy;
+
+        if (highlightPolicy) {
+          seriesOpt.emphasis = seriesOpt.emphasis || {};
+
+          if (!seriesOpt.emphasis.focus) {
+            seriesOpt.emphasis.focus = highlightPolicy;
+            {
+              deprecateReplaceLog('highlightPolicy', 'emphasis.focus', 'sunburst');
+            }
+          }
+        }
+
+        compatSunburstState(seriesOpt);
+        traverseTree(seriesOpt.data, compatSunburstState);
+      } else if (seriesType === 'graph' || seriesType === 'sankey') {
+        compatGraphFocus(seriesOpt); // TODO nodes, edges?
+      } else if (seriesType === 'map') {
+        if (seriesOpt.mapType && !seriesOpt.map) {
+          {
+            deprecateReplaceLog('mapType', 'map', 'map');
+          }
+          seriesOpt.map = seriesOpt.mapType;
+        }
+
+        if (seriesOpt.mapLocation) {
+          {
+            deprecateLog('`mapLocation` is not used anymore.');
+          }
+          defaults(seriesOpt, seriesOpt.mapLocation);
+        }
+      }
+
+      if (seriesOpt.hoverAnimation != null) {
+        seriesOpt.emphasis = seriesOpt.emphasis || {};
+
+        if (seriesOpt.emphasis && seriesOpt.emphasis.scale == null) {
+          {
+            deprecateReplaceLog('hoverAnimation', 'emphasis.scale');
+          }
+          seriesOpt.emphasis.scale = seriesOpt.hoverAnimation;
+        }
+      }
+
+      compatLayoutProperties(seriesOpt);
+    }); // dataRange has changed to visualMap
+
+    if (option.dataRange) {
+      option.visualMap = option.dataRange;
+    }
+
+    each(COMPATITABLE_COMPONENTS, function (componentName) {
+      var options = option[componentName];
+
+      if (options) {
+        if (!isArray(options)) {
+          options = [options];
+        }
+
+        each(options, function (option) {
+          compatLayoutProperties(option);
+        });
+      }
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  //     data processing stage is blocked in stream.
+  //     See <module:echarts/stream/Scheduler#performDataProcessorTasks>
+  // (2) Only register once when import repeatedly.
+  //     Should be executed after series is filtered and before stack calculation.
+
+
+  function dataStack(ecModel) {
+    var stackInfoMap = createHashMap();
+    ecModel.eachSeries(function (seriesModel) {
+      var stack = seriesModel.get('stack'); // Compatible: when `stack` is set as '', do not stack.
+
+      if (stack) {
+        var stackInfoList = stackInfoMap.get(stack) || stackInfoMap.set(stack, []);
+        var data = seriesModel.getData();
+        var stackInfo = {
+          // Used for calculate axis extent automatically.
+          // TODO: Type getCalculationInfo return more specific type?
+          stackResultDimension: data.getCalculationInfo('stackResultDimension'),
+          stackedOverDimension: data.getCalculationInfo('stackedOverDimension'),
+          stackedDimension: data.getCalculationInfo('stackedDimension'),
+          stackedByDimension: data.getCalculationInfo('stackedByDimension'),
+          isStackedByIndex: data.getCalculationInfo('isStackedByIndex'),
+          data: data,
+          seriesModel: seriesModel
+        }; // If stacked on axis that do not support data stack.
+
+        if (!stackInfo.stackedDimension || !(stackInfo.isStackedByIndex || stackInfo.stackedByDimension)) {
+          return;
+        }
+
+        stackInfoList.length && data.setCalculationInfo('stackedOnSeries', stackInfoList[stackInfoList.length - 1].seriesModel);
+        stackInfoList.push(stackInfo);
+      }
+    });
+    stackInfoMap.each(calculateStack);
+  }
+
+  function calculateStack(stackInfoList) {
+    each(stackInfoList, function (targetStackInfo, idxInStack) {
+      var resultVal = [];
+      var resultNaN = [NaN, NaN];
+      var dims = [targetStackInfo.stackResultDimension, targetStackInfo.stackedOverDimension];
+      var targetData = targetStackInfo.data;
+      var isStackedByIndex = targetStackInfo.isStackedByIndex;
+      var stackStrategy = targetStackInfo.seriesModel.get('stackStrategy') || 'samesign'; // Should not write on raw data, because stack series model list changes
+      // depending on legend selection.
+
+      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.
+
+        if (isNaN(sum)) {
+          return resultNaN;
+        }
+
+        var byValue;
+        var stackedDataRawIndex;
+
+        if (isStackedByIndex) {
+          stackedDataRawIndex = targetData.getRawIndex(dataIndex);
+        } else {
+          byValue = targetData.get(targetStackInfo.stackedByDimension, dataIndex);
+        } // If stackOver is NaN, chart view will render point on value start.
+
+
+        var stackedOver = NaN;
+
+        for (var j = idxInStack - 1; j >= 0; j--) {
+          var stackInfo = stackInfoList[j]; // Has been optimized by inverted indices on `stackedByDimension`.
+
+          if (!isStackedByIndex) {
+            stackedDataRawIndex = stackInfo.data.rawIndexOf(stackInfo.stackedByDimension, byValue);
+          }
+
+          if (stackedDataRawIndex >= 0) {
+            var val = stackInfo.data.getByRawIndex(stackInfo.stackResultDimension, stackedDataRawIndex); // Considering positive stack, negative stack and empty data
+
+            if (stackStrategy === 'all' // single stack group
+            || stackStrategy === 'positive' && val > 0 || stackStrategy === 'negative' && val < 0 || stackStrategy === 'samesign' && sum >= 0 && val > 0 // All positive stack
+            || stackStrategy === 'samesign' && sum <= 0 && val < 0 // All negative stack
+            ) {
+                // The sum has to be very small to be affected by the
+                // floating arithmetic problem. An incorrect result will probably
+                // cause axis min/max to be filtered incorrectly.
+                sum = addSafe(sum, val);
+                stackedOver = val;
+                break;
+              }
+          }
+        }
+
+        resultVal[0] = sum;
+        resultVal[1] = stackedOver;
+        return resultVal;
+      });
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // @inner
+
+
+  var SourceImpl =
+  /** @class */
+  function () {
+    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.dimensionsDetectedCount = fields.dimensionsDetectedCount;
+      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;
+  }();
+
+  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) {
+    sourceFormat = sourceFormat || detectSourceFormat(sourceData);
+    var seriesLayoutBy = thisMetaRawOption.seriesLayoutBy;
+    var determined = determineSourceDimensions(sourceData, sourceFormat, seriesLayoutBy, thisMetaRawOption.sourceHeader, thisMetaRawOption.dimensions);
+    var source = new SourceImpl({
+      data: sourceData,
+      sourceFormat: sourceFormat,
+      seriesLayoutBy: seriesLayoutBy,
+      dimensionsDefine: determined.dimensionsDefine,
+      startIndex: determined.startIndex,
+      dimensionsDetectedCount: determined.dimensionsDetectedCount,
+      metaRawOption: clone(thisMetaRawOption)
+    });
+    return source;
+  }
+  /**
+   * Wrap original series data for some compatibility cases.
+   */
+
+
+  function createSourceFromSeriesDataOption(data) {
+    return new SourceImpl({
+      data: data,
+      sourceFormat: isTypedArray(data) ? SOURCE_FORMAT_TYPED_ARRAY : SOURCE_FORMAT_ORIGINAL
+    });
+  }
+  /**
+   * Clone source but excludes source data.
+   */
+
+
+  function cloneSourceShallow(source) {
+    return new SourceImpl({
+      data: source.data,
+      sourceFormat: source.sourceFormat,
+      seriesLayoutBy: source.seriesLayoutBy,
+      dimensionsDefine: clone(source.dimensionsDefine),
+      startIndex: source.startIndex,
+      dimensionsDetectedCount: source.dimensionsDetectedCount
+    });
+  }
+  /**
+   * Note: An empty array will be detected as `SOURCE_FORMAT_ARRAY_ROWS`.
+   */
+
+
+  function detectSourceFormat(data) {
+    var sourceFormat = SOURCE_FORMAT_UNKNOWN;
+
+    if (isTypedArray(data)) {
+      sourceFormat = SOURCE_FORMAT_TYPED_ARRAY;
+    } else if (isArray(data)) {
+      // FIXME Whether tolerate null in top level array?
+      if (data.length === 0) {
+        sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
+      }
+
+      for (var i = 0, len = data.length; i < len; i++) {
+        var item = data[i];
+
+        if (item == null) {
+          continue;
+        } else if (isArray(item)) {
+          sourceFormat = SOURCE_FORMAT_ARRAY_ROWS;
+          break;
+        } else if (isObject(item)) {
+          sourceFormat = SOURCE_FORMAT_OBJECT_ROWS;
+          break;
+        }
+      }
+    } else if (isObject(data)) {
+      for (var key in data) {
+        if (hasOwn(data, key) && isArrayLike(data[key])) {
+          sourceFormat = SOURCE_FORMAT_KEYED_COLUMNS;
+          break;
+        }
+      }
+    }
+
+    return sourceFormat;
+  }
+  /**
+   * Determine the source definitions from data standalone dimensions definitions
+   * are not specified.
+   */
+
+
+  function determineSourceDimensions(data, sourceFormat, seriesLayoutBy, sourceHeader, // standalone raw dimensions definition, like:
+  // {
+  //     dimensions: ['aa', 'bb', { name: 'cc', type: 'time' }]
+  // }
+  // in `dataset` or `series`
+  dimensionsDefine) {
+    var dimensionsDetectedCount;
+    var startIndex; // PEDING: could data be null/undefined here?
+    // currently, if `dataset.source` not specified, error thrown.
+    // if `series.data` not specified, nothing rendered without error thrown.
+    // Should test these cases.
+
+    if (!data) {
+      return {
+        dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
+        startIndex: startIndex,
+        dimensionsDetectedCount: dimensionsDetectedCount
+      };
+    }
+
+    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
+      var dataArrayRows = data; // Rule: Most of the first line are string: it is header.
+      // Caution: consider a line with 5 string and 1 number,
+      // it still can not be sure it is a head, because the
+      // 5 string may be 5 values of category columns.
+
+      if (sourceHeader === 'auto' || sourceHeader == null) {
+        arrayRowsTravelFirst(function (val) {
+          // '-' is regarded as null/undefined.
+          if (val != null && val !== '-') {
+            if (isString(val)) {
+              startIndex == null && (startIndex = 1);
+            } else {
+              startIndex = 0;
+            }
+          } // 10 is an experience number, avoid long loop.
+
+        }, seriesLayoutBy, dataArrayRows, 10);
+      } else {
+        startIndex = isNumber(sourceHeader) ? sourceHeader : sourceHeader ? 1 : 0;
+      }
+
+      if (!dimensionsDefine && startIndex === 1) {
+        dimensionsDefine = [];
+        arrayRowsTravelFirst(function (val, index) {
+          dimensionsDefine[index] = val != null ? val + '' : '';
+        }, seriesLayoutBy, dataArrayRows, Infinity);
+      }
+
+      dimensionsDetectedCount = dimensionsDefine ? dimensionsDefine.length : seriesLayoutBy === SERIES_LAYOUT_BY_ROW ? dataArrayRows.length : dataArrayRows[0] ? dataArrayRows[0].length : null;
+    } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
+      if (!dimensionsDefine) {
+        dimensionsDefine = objectRowsCollectDimensions(data);
+      }
+    } else if (sourceFormat === SOURCE_FORMAT_KEYED_COLUMNS) {
+      if (!dimensionsDefine) {
+        dimensionsDefine = [];
+        each(data, function (colArr, key) {
+          dimensionsDefine.push(key);
+        });
+      }
+    } else if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
+      var value0 = getDataItemValue(data[0]);
+      dimensionsDetectedCount = isArray(value0) && value0.length || 1;
+    } else if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
+      {
+        assert(!!dimensionsDefine, 'dimensions must be given if data is TypedArray.');
+      }
+    }
+
+    return {
+      startIndex: startIndex,
+      dimensionsDefine: normalizeDimensionsOption(dimensionsDefine),
+      dimensionsDetectedCount: dimensionsDetectedCount
+    };
+  }
+
+  function objectRowsCollectDimensions(data) {
+    var firstIndex = 0;
+    var obj;
+
+    while (firstIndex < data.length && !(obj = data[firstIndex++])) {} // jshint ignore: line
+
+
+    if (obj) {
+      var dimensions_1 = [];
+      each(obj, function (value, key) {
+        dimensions_1.push(key);
+      });
+      return dimensions_1;
+    }
+  } // Consider dimensions defined like ['A', 'price', 'B', 'price', 'C', 'price'],
+  // which is reasonable. But dimension name is duplicated.
+  // Returns undefined or an array contains only object without null/undefiend or string.
+
+
+  function normalizeDimensionsOption(dimensionsDefine) {
+    if (!dimensionsDefine) {
+      // The meaning of null/undefined is different from empty array.
+      return;
+    }
+
+    var nameMap = createHashMap();
+    return map(dimensionsDefine, function (rawItem, index) {
+      rawItem = isObject(rawItem) ? rawItem : {
+        name: rawItem
+      }; // Other fields will be discarded.
+
+      var item = {
+        name: rawItem.name,
+        displayName: rawItem.displayName,
+        type: rawItem.type
+      }; // User can set null in dimensions.
+      // We dont auto specify name, othewise a given name may
+      // cause it be refered unexpectedly.
+
+      if (item.name == null) {
+        return item;
+      } // Also consider number form like 2012.
+
+
+      item.name += ''; // User may also specify displayName.
+      // displayName will always exists except user not
+      // specified or dim name is not specified or detected.
+      // (A auto generated dim name will not be used as
+      // displayName).
+
+      if (item.displayName == null) {
+        item.displayName = item.name;
+      }
+
+      var exist = nameMap.get(item.name);
+
+      if (!exist) {
+        nameMap.set(item.name, {
+          count: 1
+        });
+      } else {
+        item.name += '-' + exist.count++;
+      }
+
+      return item;
+    });
+  }
+
+  function arrayRowsTravelFirst(cb, seriesLayoutBy, data, maxLoop) {
+    if (seriesLayoutBy === SERIES_LAYOUT_BY_ROW) {
+      for (var i = 0; i < data.length && i < maxLoop; i++) {
+        cb(data[i] ? data[i][0] : null, i);
+      }
+    } else {
+      var value0 = data[0] || [];
+
+      for (var i = 0; i < value0.length && i < maxLoop; i++) {
+        cb(value0[i], i);
+      }
+    }
+  }
+
+  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
+  * 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.
+   */
+
+  /*
+  * 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 _a;
+
+  var _b;
+
+  var _c; // TODO
+  // ??? refactor? check the outer usage of data provider.
+  // merge with defaultDimValueGetter?
+
+
+  var providerMethods;
+  var mountMethods;
+  /**
+   * If normal array used, mutable chunk size is supported.
+   * If typed array used, chunk size must be fixed.
+   */
+
+  var DefaultDataProvider =
+  /** @class */
+  function () {
+    function DefaultDataProvider(sourceParam, dimSize) {
+      // let source: Source;
+      var source = !isSourceInstance(sourceParam) ? createSourceFromSeriesDataOption(sourceParam) : sourceParam; // declare source is Source;
+
+      this._source = source;
+      var data = this._data = source.data; // Typed array. TODO IE10+?
+
+      if (source.sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
+        {
+          if (dimSize == null) {
+            throw new Error('Typed array data must specify dimension size');
+          }
+        }
+        this._offset = 0;
+        this._dimSize = dimSize;
+        this._data = data;
+      }
+
+      mountMethods(this, data, source);
+    }
+
+    DefaultDataProvider.prototype.getSource = function () {
+      return this._source;
+    };
+
+    DefaultDataProvider.prototype.count = function () {
+      return 0;
+    };
+
+    DefaultDataProvider.prototype.getItem = function (idx, out) {
+      return;
+    };
+
+    DefaultDataProvider.prototype.appendData = function (newData) {};
+
+    DefaultDataProvider.prototype.clean = function () {};
+
+    DefaultDataProvider.protoInitialize = function () {
+      // PENDING: To avoid potential incompat (e.g., prototype
+      // is visited somewhere), still init them on prototype.
+      var proto = DefaultDataProvider.prototype;
+      proto.pure = false;
+      proto.persistent = true;
+    }();
+
+    DefaultDataProvider.internalField = function () {
+      var _a;
+
+      mountMethods = function (provider, data, source) {
+        var sourceFormat = source.sourceFormat;
+        var seriesLayoutBy = source.seriesLayoutBy;
+        var startIndex = source.startIndex;
+        var dimsDef = source.dimensionsDefine;
+        var methods = providerMethods[getMethodMapKey(sourceFormat, seriesLayoutBy)];
+        {
+          assert(methods, 'Invalide sourceFormat: ' + sourceFormat);
+        }
+        extend(provider, methods);
+
+        if (sourceFormat === SOURCE_FORMAT_TYPED_ARRAY) {
+          provider.getItem = getItemForTypedArray;
+          provider.count = countForTypedArray;
+          provider.fillStorage = fillStorageForTypedArray;
+        } else {
+          var rawItemGetter = getRawSourceItemGetter(sourceFormat, seriesLayoutBy);
+          provider.getItem = bind(rawItemGetter, null, data, startIndex, dimsDef);
+          var rawCounter = getRawSourceDataCounter(sourceFormat, seriesLayoutBy);
+          provider.count = bind(rawCounter, null, data, startIndex, dimsDef);
+        }
+      };
+
+      var getItemForTypedArray = function (idx, out) {
+        idx = idx - this._offset;
+        out = out || [];
+        var data = this._data;
+        var dimSize = this._dimSize;
+        var offset = dimSize * idx;
+
+        for (var i = 0; i < dimSize; i++) {
+          out[i] = data[offset + i];
+        }
+
+        return out;
+      };
+
+      var fillStorageForTypedArray = function (start, end, storage, extent) {
+        var data = this._data;
+        var dimSize = this._dimSize;
+
+        for (var dim = 0; dim < dimSize; dim++) {
+          var dimExtent = extent[dim];
+          var min = dimExtent[0] == null ? Infinity : dimExtent[0];
+          var max = dimExtent[1] == null ? -Infinity : dimExtent[1];
+          var count = end - start;
+          var arr = storage[dim];
+
+          for (var i = 0; i < count; i++) {
+            // appendData with TypedArray will always do replace in provider.
+            var val = data[i * dimSize + dim];
+            arr[start + i] = val;
+            val < min && (min = val);
+            val > max && (max = val);
+          }
+
+          dimExtent[0] = min;
+          dimExtent[1] = max;
+        }
+      };
+
+      var countForTypedArray = function () {
+        return this._data ? this._data.length / this._dimSize : 0;
+      };
+
+      providerMethods = (_a = {}, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = {
+        pure: true,
+        appendData: appendDataSimply
+      }, _a[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = {
+        pure: true,
+        appendData: function () {
+          throw new Error('Do not support appendData when set seriesLayoutBy: "row".');
+        }
+      }, _a[SOURCE_FORMAT_OBJECT_ROWS] = {
+        pure: true,
+        appendData: appendDataSimply
+      }, _a[SOURCE_FORMAT_KEYED_COLUMNS] = {
+        pure: true,
+        appendData: function (newData) {
+          var data = this._data;
+          each(newData, function (newCol, key) {
+            var oldCol = data[key] || (data[key] = []);
+
+            for (var i = 0; i < (newCol || []).length; i++) {
+              oldCol.push(newCol[i]);
+            }
+          });
+        }
+      }, _a[SOURCE_FORMAT_ORIGINAL] = {
+        appendData: appendDataSimply
+      }, _a[SOURCE_FORMAT_TYPED_ARRAY] = {
+        persistent: false,
+        pure: true,
+        appendData: function (newData) {
+          {
+            assert(isTypedArray(newData), 'Added data must be TypedArray if data in initialization is TypedArray');
+          }
+          this._data = newData;
+        },
+        // Clean self if data is already used.
+        clean: function () {
+          // PENDING
+          this._offset += this.count();
+          this._data = null;
+        }
+      }, _a);
+
+      function appendDataSimply(newData) {
+        for (var i = 0; i < newData.length; i++) {
+          this._data.push(newData[i]);
+        }
+      }
+    }();
+
+    return DefaultDataProvider;
+  }();
+
+  var getItemSimply = function (rawData, startIndex, dimsDef, idx) {
+    return rawData[idx];
+  };
+
+  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, out) {
+    idx += startIndex;
+    var item = out || [];
+    var data = rawData;
+
+    for (var i = 0; i < data.length; i++) {
+      var row = data[i];
+      item[i] = row ? row[idx] : null;
+    }
+
+    return 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;
+      {
+        if (dimName == null) {
+          throw new Error();
+        }
+      }
+      var col = rawData[dimName];
+      item[i] = col ? col[idx] : null;
+    }
+
+    return item;
+  }, _a[SOURCE_FORMAT_ORIGINAL] = getItemSimply, _a);
+
+  function getRawSourceItemGetter(sourceFormat, seriesLayoutBy) {
+    var method = rawSourceItemGetterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)];
+    {
+      assert(method, 'Do not support get item on "' + sourceFormat + '", "' + seriesLayoutBy + '".');
+    }
+    return method;
+  }
+
+  var countSimply = function (rawData, startIndex, dimsDef) {
+    return rawData.length;
+  };
+
+  var rawSourceDataCounterMap = (_b = {}, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_COLUMN] = function (rawData, startIndex, dimsDef) {
+    return Math.max(0, rawData.length - startIndex);
+  }, _b[SOURCE_FORMAT_ARRAY_ROWS + '_' + SERIES_LAYOUT_BY_ROW] = function (rawData, startIndex, dimsDef) {
+    var row = rawData[0];
+    return row ? Math.max(0, row.length - startIndex) : 0;
+  }, _b[SOURCE_FORMAT_OBJECT_ROWS] = countSimply, _b[SOURCE_FORMAT_KEYED_COLUMNS] = function (rawData, startIndex, dimsDef) {
+    var dimName = dimsDef[0].name;
+    {
+      if (dimName == null) {
+        throw new Error();
+      }
+    }
+    var col = rawData[dimName];
+    return col ? col.length : 0;
+  }, _b[SOURCE_FORMAT_ORIGINAL] = countSimply, _b);
+
+  function getRawSourceDataCounter(sourceFormat, seriesLayoutBy) {
+    var method = rawSourceDataCounterMap[getMethodMapKey(sourceFormat, seriesLayoutBy)];
+    {
+      assert(method, 'Do not suppport count on "' + sourceFormat + '", "' + seriesLayoutBy + '".');
+    }
+    return method;
+  }
+
+  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, 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 !(value instanceof Array) ? value : value[dimIndex];
+  }, _c[SOURCE_FORMAT_TYPED_ARRAY] = getRawValueSimply, _c);
+
+  function getRawSourceValueGetter(sourceFormat) {
+    var method = rawSourceValueGetterMap[sourceFormat];
+    {
+      assert(method, 'Do not suppport get value on "' + sourceFormat + '".');
+    }
+    return method;
+  }
+
+  function getMethodMapKey(sourceFormat, seriesLayoutBy) {
+    return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS ? sourceFormat + '_' + seriesLayoutBy : sourceFormat;
+  } // ??? FIXME can these logic be more neat: getRawValue, getRawDataItem,
+  // Consider persistent.
+  // Caution: why use raw value to display on label or tooltip?
+  // A reason is to avoid format. For example time value we do not know
+  // how to format is expected. More over, if stack is used, calculated
+  // value may be 0.91000000001, which have brings trouble to display.
+  // TODO: consider how to treat null/undefined/NaN when display?
+
+
+  function retrieveRawValue(data, dataIndex, // If dimIndex is null/undefined, return OptionDataItem.
+  // Otherwise, return OptionDataValue.
+  dim) {
+    if (!data) {
+      return;
+    } // Consider data may be not persistent.
+
+
+    var dataItem = data.getRawDataItem(dataIndex);
+
+    if (dataItem == null) {
+      return;
+    }
+
+    var store = data.getStore();
+    var sourceFormat = store.getSource().sourceFormat;
+
+    if (dim != null) {
+      var dimIndex = data.getDimensionIndex(dim);
+      var property = store.getDimensionProperty(dimIndex);
+      return getRawSourceValueGetter(sourceFormat)(dataItem, dimIndex, property);
+    } else {
+      var result = dataItem;
+
+      if (sourceFormat === SOURCE_FORMAT_ORIGINAL) {
+        result = getDataItemValue(dataItem);
+      }
+
+      return result;
+    }
+  }
+  /**
+   * Compatible with some cases (in pie, map) like:
+   * data: [{name: 'xx', value: 5, selected: true}, ...]
+   * where only sourceFormat is 'original' and 'objectRows' supported.
+   *
+   * // TODO
+   * Supported detail options in data item when using 'arrayRows'.
+   *
+   * @param data
+   * @param dataIndex
+   * @param attr like 'selected'
+   */
+
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 DIMENSION_LABEL_REG = /\{@(.+?)\}/g;
+
+  var DataFormatMixin =
+  /** @class */
+  function () {
+    function DataFormatMixin() {}
+    /**
+     * Get params for formatter
+     */
+
+
+    DataFormatMixin.prototype.getDataParams = function (dataIndex, dataType) {
+      var data = this.getData(dataType);
+      var rawValue = this.getRawValue(dataIndex, dataType);
+      var rawDataIndex = data.getRawIndex(dataIndex);
+      var name = data.getName(dataIndex);
+      var itemOpt = data.getRawDataItem(dataIndex);
+      var style = data.getItemVisual(dataIndex, 'style');
+      var color = style && style[data.getItemVisual(dataIndex, 'drawType') || 'fill'];
+      var borderColor = style && style.stroke;
+      var mainType = this.mainType;
+      var isSeries = mainType === 'series';
+      var userOutput = data.userOutput && data.userOutput.get();
+      return {
+        componentType: mainType,
+        componentSubType: this.subType,
+        componentIndex: this.componentIndex,
+        seriesType: isSeries ? this.subType : null,
+        seriesIndex: this.seriesIndex,
+        seriesId: isSeries ? this.id : null,
+        seriesName: isSeries ? this.name : null,
+        name: name,
+        dataIndex: rawDataIndex,
+        data: itemOpt,
+        dataType: dataType,
+        value: rawValue,
+        color: color,
+        borderColor: borderColor,
+        dimensionNames: userOutput ? userOutput.fullDimensions : null,
+        encode: userOutput ? userOutput.encode : null,
+        // Param name list for mapping `a`, `b`, `c`, `d`, `e`
+        $vars: ['seriesName', 'name', 'value']
+      };
+    };
+    /**
+     * Format label
+     * @param dataIndex
+     * @param status 'normal' by default
+     * @param dataType
+     * @param labelDimIndex Only used in some chart that
+     *        use formatter in different dimensions, like radar.
+     * @param formatter Formatter given outside.
+     * @return return null/undefined if no formatter
+     */
+
+
+    DataFormatMixin.prototype.getFormattedLabel = function (dataIndex, status, dataType, labelDimIndex, formatter, extendParams) {
+      status = status || 'normal';
+      var data = this.getData(dataType);
+      var params = this.getDataParams(dataIndex, dataType);
+
+      if (extendParams) {
+        params.value = extendParams.interpolatedValue;
+      }
+
+      if (labelDimIndex != null && isArray(params.value)) {
+        params.value = params.value[labelDimIndex];
+      }
+
+      if (!formatter) {
+        var itemModel = data.getItemModel(dataIndex); // @ts-ignore
+
+        formatter = itemModel.get(status === 'normal' ? ['label', 'formatter'] : [status, 'label', 'formatter']);
+      }
+
+      if (isFunction(formatter)) {
+        params.status = status;
+        params.dimensionIndex = labelDimIndex;
+        return formatter(params);
+      } else if (isString(formatter)) {
+        var str = formatTpl(formatter, params); // Support 'aaa{@[3]}bbb{@product}ccc'.
+        // Do not support '}' in dim name util have to.
+
+        return str.replace(DIMENSION_LABEL_REG, function (origin, dimStr) {
+          var len = dimStr.length;
+          var dimLoose = dimStr;
+
+          if (dimLoose.charAt(0) === '[' && dimLoose.charAt(len - 1) === ']') {
+            dimLoose = +dimLoose.slice(1, len - 1); // Also support: '[]' => 0
+
+            {
+              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 dimIndex = data.getDimensionIndex(dimLoose);
+
+            if (dimIndex >= 0) {
+              val = extendParams.interpolatedValue[dimIndex];
+            }
+          }
+
+          return val != null ? val + '' : '';
+        });
+      }
+    };
+    /**
+     * Get raw value in option
+     */
+
+
+    DataFormatMixin.prototype.getRawValue = function (idx, dataType) {
+      return retrieveRawValue(this.getData(dataType), idx);
+    };
+    /**
+     * Should be implemented.
+     * @param {number} dataIndex
+     * @param {boolean} [multipleSeries=false]
+     * @param {string} [dataType]
+     */
+
+
+    DataFormatMixin.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) {
+      // Empty function
+      return;
+    };
+
+    return DataFormatMixin;
+  }(); // PENDING: previously we accept this type when calling `formatTooltip`,
+  // but guess little chance has been used outside. Do we need to backward
+  // compat it?
+  // type TooltipFormatResultLegacyObject = {
+  //     // `html` means the markup language text, either in 'html' or 'richText'.
+  //     // The name `html` is not appropriate becuase in 'richText' it is not a HTML
+  //     // string. But still support it for backward compat.
+  //     html: string;
+  //     markers: Dictionary<ColorString>;
+  // };
+
+  /**
+   * For backward compat, normalize the return from `formatTooltip`.
+   */
+
+
+  function normalizeTooltipFormatResult(result) {
+    var markupText; // let markers: Dictionary<ColorString>;
+
+    var markupFragment;
+
+    if (isObject(result)) {
+      if (result.type) {
+        markupFragment = result;
+      } else {
+        {
+          console.warn('The return type of `formatTooltip` is not supported: ' + makePrintable(result));
+        }
+      } // else {
+      //     markupText = (result as TooltipFormatResultLegacyObject).html;
+      //     markers = (result as TooltipFormatResultLegacyObject).markers;
+      //     if (markersExisting) {
+      //         markers = zrUtil.merge(markersExisting, markers);
+      //     }
+      // }
+
+    } else {
+      markupText = result;
+    }
+
+    return {
+      text: markupText,
+      // markers: markers || markersExisting,
+      frag: markupFragment
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * @param {Object} define
+   * @return See the return of `createTask`.
+   */
+
+
+  function createTask(define) {
+    return new Task(define);
+  }
+
+  var Task =
+  /** @class */
+  function () {
+    function Task(define) {
+      define = define || {};
+      this._reset = define.reset;
+      this._plan = define.plan;
+      this._count = define.count;
+      this._onDirty = define.onDirty;
+      this._dirty = true;
+    }
+    /**
+     * @param step Specified step.
+     * @param skip Skip customer perform call.
+     * @param modBy Sampling window size.
+     * @param modDataCount Sampling count.
+     * @return whether unfinished.
+     */
+
+
+    Task.prototype.perform = function (performArgs) {
+      var upTask = this._upstream;
+      var skip = performArgs && performArgs.skip; // TODO some refactor.
+      // Pull data. Must pull data each time, because context.data
+      // may be updated by Series.setData.
+
+      if (this._dirty && upTask) {
+        var context = this.context;
+        context.data = context.outputData = upTask.context.outputData;
+      }
+
+      if (this.__pipeline) {
+        this.__pipeline.currentTask = this;
+      }
+
+      var planResult;
+
+      if (this._plan && !skip) {
+        planResult = this._plan(this.context);
+      } // Support sharding by mod, which changes the render sequence and makes the rendered graphic
+      // elements uniformed distributed when progress, especially when moving or zooming.
+
+
+      var lastModBy = normalizeModBy(this._modBy);
+      var lastModDataCount = this._modDataCount || 0;
+      var modBy = normalizeModBy(performArgs && performArgs.modBy);
+      var modDataCount = performArgs && performArgs.modDataCount || 0;
+
+      if (lastModBy !== modBy || lastModDataCount !== modDataCount) {
+        planResult = 'reset';
+      }
+
+      function normalizeModBy(val) {
+        !(val >= 1) && (val = 1); // jshint ignore:line
+
+        return val;
+      }
+
+      var forceFirstProgress;
+
+      if (this._dirty || planResult === 'reset') {
+        this._dirty = false;
+        forceFirstProgress = this._doReset(skip);
+      }
+
+      this._modBy = modBy;
+      this._modDataCount = modDataCount;
+      var step = performArgs && performArgs.step;
+
+      if (upTask) {
+        {
+          assert(upTask._outputDueEnd != null);
+        }
+        this._dueEnd = upTask._outputDueEnd;
+      } // DataTask or overallTask
+      else {
+          {
+            assert(!this._progress || this._count);
+          }
+          this._dueEnd = this._count ? this._count(this.context) : Infinity;
+        } // Note: Stubs, that its host overall task let it has progress, has progress.
+      // If no progress, pass index from upstream to downstream each time plan called.
+
+
+      if (this._progress) {
+        var start = this._dueIndex;
+        var end = Math.min(step != null ? this._dueIndex + step : Infinity, this._dueEnd);
+
+        if (!skip && (forceFirstProgress || start < end)) {
+          var progress = this._progress;
+
+          if (isArray(progress)) {
+            for (var i = 0; i < progress.length; i++) {
+              this._doProgress(progress[i], start, end, modBy, modDataCount);
+            }
+          } else {
+            this._doProgress(progress, start, end, modBy, modDataCount);
+          }
+        }
+
+        this._dueIndex = end; // If no `outputDueEnd`, assume that output data and
+        // input data is the same, so use `dueIndex` as `outputDueEnd`.
+
+        var outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : end;
+        {
+          // ??? Can not rollback.
+          assert(outputDueEnd >= this._outputDueEnd);
+        }
+        this._outputDueEnd = outputDueEnd;
+      } else {
+        // (1) Some overall task has no progress.
+        // (2) Stubs, that its host overall task do not let it has progress, has no progress.
+        // This should always be performed so it can be passed to downstream.
+        this._dueIndex = this._outputDueEnd = this._settedOutputEnd != null ? this._settedOutputEnd : this._dueEnd;
+      }
+
+      return this.unfinished();
+    };
+
+    Task.prototype.dirty = function () {
+      this._dirty = true;
+      this._onDirty && this._onDirty(this.context);
+    };
+
+    Task.prototype._doProgress = function (progress, start, end, modBy, modDataCount) {
+      iterator.reset(start, end, modBy, modDataCount);
+      this._callingProgress = progress;
+
+      this._callingProgress({
+        start: start,
+        end: end,
+        count: end - start,
+        next: iterator.next
+      }, this.context);
+    };
+
+    Task.prototype._doReset = function (skip) {
+      this._dueIndex = this._outputDueEnd = this._dueEnd = 0;
+      this._settedOutputEnd = null;
+      var progress;
+      var forceFirstProgress;
+
+      if (!skip && this._reset) {
+        progress = this._reset(this.context);
+
+        if (progress && progress.progress) {
+          forceFirstProgress = progress.forceFirstProgress;
+          progress = progress.progress;
+        } // To simplify no progress checking, array must has item.
+
+
+        if (isArray(progress) && !progress.length) {
+          progress = null;
+        }
+      }
+
+      this._progress = progress;
+      this._modBy = this._modDataCount = null;
+      var downstream = this._downstream;
+      downstream && downstream.dirty();
+      return forceFirstProgress;
+    };
+
+    Task.prototype.unfinished = function () {
+      return this._progress && this._dueIndex < this._dueEnd;
+    };
+    /**
+     * @param downTask The downstream task.
+     * @return The downstream task.
+     */
+
+
+    Task.prototype.pipe = function (downTask) {
+      {
+        assert(downTask && !downTask._disposed && downTask !== this);
+      } // If already downstream, do not dirty downTask.
+
+      if (this._downstream !== downTask || this._dirty) {
+        this._downstream = downTask;
+        downTask._upstream = this;
+        downTask.dirty();
+      }
+    };
+
+    Task.prototype.dispose = function () {
+      if (this._disposed) {
+        return;
+      }
+
+      this._upstream && (this._upstream._downstream = null);
+      this._downstream && (this._downstream._upstream = null);
+      this._dirty = false;
+      this._disposed = true;
+    };
+
+    Task.prototype.getUpstream = function () {
+      return this._upstream;
+    };
+
+    Task.prototype.getDownstream = function () {
+      return this._downstream;
+    };
+
+    Task.prototype.setOutputEnd = function (end) {
+      // This only happend in dataTask, dataZoom, map, currently.
+      // where dataZoom do not set end each time, but only set
+      // when reset. So we should record the setted end, in case
+      // that the stub of dataZoom perform again and earse the
+      // setted end by upstream.
+      this._outputDueEnd = this._settedOutputEnd = end;
+    };
+
+    return Task;
+  }();
+
+  var iterator = function () {
+    var end;
+    var current;
+    var modBy;
+    var modDataCount;
+    var winCount;
+    var it = {
+      reset: function (s, e, sStep, sCount) {
+        current = s;
+        end = e;
+        modBy = sStep;
+        modDataCount = sCount;
+        winCount = Math.ceil(modDataCount / modBy);
+        it.next = modBy > 1 && modDataCount > 0 ? modNext : sequentialNext;
+      }
+    };
+    return it;
+
+    function sequentialNext() {
+      return current < end ? current++ : null;
+    }
+
+    function modNext() {
+      var dataIndex = current % winCount * modBy + Math.ceil(current / winCount);
+      var result = current >= end ? null : dataIndex < modDataCount ? dataIndex // If modDataCount is smaller than data.count() (consider `appendData` case),
+      // Use normal linear rendering mode.
+      : current;
+      current++;
+      return result;
+    }
+  }(); ///////////////////////////////////////////////////////////
+  // For stream debug (Should be commented out after used!)
+  // @usage: printTask(this, 'begin');
+  // @usage: printTask(this, null, {someExtraProp});
+  // @usage: Use `__idxInPipeline` as conditional breakpiont.
+  //
+  // window.printTask = function (task: any, prefix: string, extra: { [key: string]: unknown }): void {
+  //     window.ecTaskUID == null && (window.ecTaskUID = 0);
+  //     task.uidDebug == null && (task.uidDebug = `task_${window.ecTaskUID++}`);
+  //     task.agent && task.agent.uidDebug == null && (task.agent.uidDebug = `task_${window.ecTaskUID++}`);
+  //     let props = [];
+  //     if (task.__pipeline) {
+  //         let val = `${task.__idxInPipeline}/${task.__pipeline.tail.__idxInPipeline} ${task.agent ? '(stub)' : ''}`;
+  //         props.push({text: '__idxInPipeline/total', value: val});
+  //     } else {
+  //         let stubCount = 0;
+  //         task.agentStubMap.each(() => stubCount++);
+  //         props.push({text: 'idx', value: `overall (stubs: ${stubCount})`});
+  //     }
+  //     props.push({text: 'uid', value: task.uidDebug});
+  //     if (task.__pipeline) {
+  //         props.push({text: 'pipelineId', value: task.__pipeline.id});
+  //         task.agent && props.push(
+  //             {text: 'stubFor', value: task.agent.uidDebug}
+  //         );
+  //     }
+  //     props.push(
+  //         {text: 'dirty', value: task._dirty},
+  //         {text: 'dueIndex', value: task._dueIndex},
+  //         {text: 'dueEnd', value: task._dueEnd},
+  //         {text: 'outputDueEnd', value: task._outputDueEnd}
+  //     );
+  //     if (extra) {
+  //         Object.keys(extra).forEach(key => {
+  //             props.push({text: key, value: extra[key]});
+  //         });
+  //     }
+  //     let args = ['color: blue'];
+  //     let msg = `%c[${prefix || 'T'}] %c` + props.map(item => (
+  //         args.push('color: green', 'color: red'),
+  //         `${item.text}: %c${item.value}`
+  //     )).join('%c, ');
+  //     console.log.apply(console, [msg].concat(args));
+  //     // console.log(this);
+  // };
+  // window.printPipeline = function (task: any, prefix: string) {
+  //     const pipeline = task.__pipeline;
+  //     let currTask = pipeline.head;
+  //     while (currTask) {
+  //         window.printTask(currTask, prefix);
+  //         currTask = currTask._downstream;
+  //     }
+  // };
+  // window.showChain = function (chainHeadTask) {
+  //     var chain = [];
+  //     var task = chainHeadTask;
+  //     while (task) {
+  //         chain.push({
+  //             task: task,
+  //             up: task._upstream,
+  //             down: task._downstream,
+  //             idxInPipeline: task.__idxInPipeline
+  //         });
+  //         task = task._downstream;
+  //     }
+  //     return chain;
+  // };
+  // window.findTaskInChain = function (task, chainHeadTask) {
+  //     let chain = window.showChain(chainHeadTask);
+  //     let result = [];
+  //     for (let i = 0; i < chain.length; i++) {
+  //         let chainItem = chain[i];
+  //         if (chainItem.task === task) {
+  //             result.push(i);
+  //         }
+  //     }
+  //     return result;
+  // };
+  // window.printChainAEachInChainB = function (chainHeadTaskA, chainHeadTaskB) {
+  //     let chainA = window.showChain(chainHeadTaskA);
+  //     for (let i = 0; i < chainA.length; i++) {
+  //         console.log('chainAIdx:', i, 'inChainB:', window.findTaskInChain(chainA[i].task, chainHeadTaskB));
+  //     }
+  // };
+
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Convert raw the value in to inner value in List.
+   *
+   * [Performance sensitive]
+   *
+   * [Caution]: this is the key logic of user value parser.
+   * For backward compatibiliy, do not modify it until have to!
+   */
+
+
+  function parseDataValue(value, // For high performance, do not omit the second param.
+  opt) {
+    // Performance sensitive.
+    var dimType = opt && opt.type;
+
+    if (dimType === 'ordinal') {
+      // If given value is a category string
+      return value;
+    }
+
+    if (dimType === 'time' // spead up when using timestamp
+    && !isNumber(value) && value != null && value !== '-') {
+      value = +parseDate(value);
+    } // dimType defaults 'number'.
+    // If dimType is not ordinal and value is null or undefined or NaN or '-',
+    // parse to NaN.
+    // number-like string (like ' 123 ') can be converted to a number.
+    // where null/undefined or other string will be converted to NaN.
+
+
+    return value == null || value === '' ? NaN // If string (like '-'), using '+' parse to NaN
+    // If object, also parse to NaN
+    : +value;
+  }
+
+  var valueParserMap = createHashMap({
+    'number': function (val) {
+      // Do not use `numericToNumber` here. We have by defualt `numericToNumber`.
+      // Here the number parser can have loose rule:
+      // enable to cut suffix: "120px" => 120, "14%" => 14.
+      return parseFloat(val);
+    },
+    'time': function (val) {
+      // return timestamp.
+      return +parseDate(val);
+    },
+    'trim': function (val) {
+      return isString(val) ? trim(val) : val;
+    }
+  });
+  var ORDER_COMPARISON_OP_MAP = {
+    lt: function (lval, rval) {
+      return lval < rval;
+    },
+    lte: function (lval, rval) {
+      return lval <= rval;
+    },
+    gt: function (lval, rval) {
+      return lval > rval;
+    },
+    gte: function (lval, rval) {
+      return lval >= rval;
+    }
+  };
+
+  var FilterOrderComparator =
+  /** @class */
+  function () {
+    function FilterOrderComparator(op, rval) {
+      if (!isNumber(rval)) {
+        var errMsg = '';
+        {
+          errMsg = 'rvalue of "<", ">", "<=", ">=" can only be number in filter.';
+        }
+        throwError(errMsg);
+      }
+
+      this._opFn = ORDER_COMPARISON_OP_MAP[op];
+      this._rvalFloat = numericToNumber(rval);
+    } // Performance sensitive.
+
+
+    FilterOrderComparator.prototype.evaluate = function (lval) {
+      // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat.
+      return isNumber(lval) ? this._opFn(lval, this._rvalFloat) : this._opFn(numericToNumber(lval), this._rvalFloat);
+    };
+
+    return FilterOrderComparator;
+  }();
+
+  var SortOrderComparator =
+  /** @class */
+  function () {
+    /**
+     * @param order by defualt: 'asc'
+     * @param incomparable by defualt: Always on the tail.
+     *        That is, if 'asc' => 'max', if 'desc' => 'min'
+     *        See the definition of "incomparable" in [SORT_COMPARISON_RULE]
+     */
+    function SortOrderComparator(order, incomparable) {
+      var isDesc = order === 'desc';
+      this._resultLT = isDesc ? 1 : -1;
+
+      if (incomparable == null) {
+        incomparable = isDesc ? 'min' : 'max';
+      }
+
+      this._incomparable = incomparable === 'min' ? -Infinity : Infinity;
+    } // See [SORT_COMPARISON_RULE].
+    // Performance sensitive.
+
+
+    SortOrderComparator.prototype.evaluate = function (lval, rval) {
+      // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat.
+      var lvalFloat = isNumber(lval) ? lval : numericToNumber(lval);
+      var rvalFloat = isNumber(rval) ? rval : numericToNumber(rval);
+      var lvalNotNumeric = isNaN(lvalFloat);
+      var rvalNotNumeric = isNaN(rvalFloat);
+
+      if (lvalNotNumeric) {
+        lvalFloat = this._incomparable;
+      }
+
+      if (rvalNotNumeric) {
+        rvalFloat = this._incomparable;
+      }
+
+      if (lvalNotNumeric && rvalNotNumeric) {
+        var lvalIsStr = isString(lval);
+        var rvalIsStr = isString(rval);
+
+        if (lvalIsStr) {
+          lvalFloat = rvalIsStr ? lval : 0;
+        }
+
+        if (rvalIsStr) {
+          rvalFloat = lvalIsStr ? rval : 0;
+        }
+      }
+
+      return lvalFloat < rvalFloat ? this._resultLT : lvalFloat > rvalFloat ? -this._resultLT : 0;
+    };
+
+    return SortOrderComparator;
+  }();
+
+  var FilterEqualityComparator =
+  /** @class */
+  function () {
+    function FilterEqualityComparator(isEq, rval) {
+      this._rval = rval;
+      this._isEQ = isEq;
+      this._rvalTypeof = typeof rval;
+      this._rvalFloat = numericToNumber(rval);
+    } // Performance sensitive.
+
+
+    FilterEqualityComparator.prototype.evaluate = function (lval) {
+      var eqResult = lval === this._rval;
+
+      if (!eqResult) {
+        var lvalTypeof = typeof lval;
+
+        if (lvalTypeof !== this._rvalTypeof && (lvalTypeof === 'number' || this._rvalTypeof === 'number')) {
+          eqResult = numericToNumber(lval) === this._rvalFloat;
+        }
+      }
+
+      return this._isEQ ? eqResult : !eqResult;
+    };
+
+    return FilterEqualityComparator;
+  }();
+  /**
+   * [FILTER_COMPARISON_RULE]
+   * `lt`|`lte`|`gt`|`gte`:
+   * + rval must be a number. And lval will be converted to number (`numericToNumber`) to compare.
+   * `eq`:
+   * + If same type, compare with `===`.
+   * + If there is one number, convert to number (`numericToNumber`) to compare.
+   * + Else return `false`.
+   * `ne`:
+   * + Not `eq`.
+   *
+   *
+   * [SORT_COMPARISON_RULE]
+   * All the values are grouped into three categories:
+   * + "numeric" (number and numeric string)
+   * + "non-numeric-string" (string that excluding numeric string)
+   * + "others"
+   * "numeric" vs "numeric": values are ordered by number order.
+   * "non-numeric-string" vs "non-numeric-string": values are ordered by ES spec (#sec-abstract-relational-comparison).
+   * "others" vs "others": do not change order (always return 0).
+   * "numeric" vs "non-numeric-string": "non-numeric-string" is treated as "incomparable".
+   * "number" vs "others": "others" is treated as "incomparable".
+   * "non-numeric-string" vs "others": "others" is treated as "incomparable".
+   * "incomparable" will be seen as -Infinity or Infinity (depends on the settings).
+   * MEMO:
+   *   non-numeric string sort make sence when need to put the items with the same tag together.
+   *   But if we support string sort, we still need to avoid the misleading like `'2' > '12'`,
+   *   So we treat "numeric-string" sorted by number order rather than string comparison.
+   *
+   *
+   * [CHECK_LIST_OF_THE_RULE_DESIGN]
+   * + Do not support string comparison until required. And also need to
+   *   void the misleading of "2" > "12".
+   * + Should avoid the misleading case:
+   *   `" 22 " gte "22"` is `true` but `" 22 " eq "22"` is `false`.
+   * + JS bad case should be avoided: null <= 0, [] <= 0, ' ' <= 0, ...
+   * + Only "numeric" can be converted to comparable number, otherwise converted to NaN.
+   *   See `util/number.ts#numericToNumber`.
+   *
+   * @return If `op` is not `RelationalOperator`, return null;
+   */
+
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * TODO: disable writable.
+   * This structure will be exposed to users.
+   */
+
+
+  var ExternalSource =
+  /** @class */
+  function () {
+    function ExternalSource() {}
+
+    ExternalSource.prototype.getRawData = function () {
+      // Only built-in transform available.
+      throw new Error('not supported');
+    };
+
+    ExternalSource.prototype.getRawDataItem = function (dataIndex) {
+      // Only built-in transform available.
+      throw new Error('not supported');
+    };
+
+    ExternalSource.prototype.cloneRawData = function () {
+      return;
+    };
+    /**
+     * @return If dimension not found, return null/undefined.
+     */
+
+
+    ExternalSource.prototype.getDimensionInfo = function (dim) {
+      return;
+    };
+    /**
+     * dimensions defined if and only if either:
+     * (a) dataset.dimensions are declared.
+     * (b) dataset data include dimensions definitions in data (detected or via specified `sourceHeader`).
+     * If dimensions are defined, `dimensionInfoAll` is corresponding to
+     * the defined dimensions.
+     * Otherwise, `dimensionInfoAll` is determined by data columns.
+     * @return Always return an array (even empty array).
+     */
+
+
+    ExternalSource.prototype.cloneAllDimensionInfo = function () {
+      return;
+    };
+
+    ExternalSource.prototype.count = function () {
+      return;
+    };
+    /**
+     * Only support by dimension index.
+     * No need to support by dimension name in transform function,
+     * becuase transform function is not case-specific, no need to use name literally.
+     */
+
+
+    ExternalSource.prototype.retrieveValue = function (dataIndex, dimIndex) {
+      return;
+    };
+
+    ExternalSource.prototype.retrieveValueFromItem = function (dataItem, dimIndex) {
+      return;
+    };
+
+    ExternalSource.prototype.convertValue = function (rawVal, dimInfo) {
+      return parseDataValue(rawVal, dimInfo);
+    };
+
+    return ExternalSource;
+  }();
+
+  function createExternalSource(internalSource, externalTransform) {
+    var extSource = new ExternalSource();
+    var data = internalSource.data;
+    var sourceFormat = extSource.sourceFormat = internalSource.sourceFormat;
+    var sourceHeaderCount = internalSource.startIndex;
+    var errMsg = '';
+
+    if (internalSource.seriesLayoutBy !== SERIES_LAYOUT_BY_COLUMN) {
+      // For the logic simplicity in transformer, only 'culumn' is
+      // supported in data transform. Otherwise, the `dimensionsDefine`
+      // might be detected by 'row', which probably confuses users.
+      {
+        errMsg = '`seriesLayoutBy` of upstream dataset can only be "column" in data transform.';
+      }
+      throwError(errMsg);
+    } // [MEMO]
+    // Create a new dimensions structure for exposing.
+    // Do not expose all dimension info to users directly.
+    // Becuase the dimension is probably auto detected from data and not might reliable.
+    // Should not lead the transformers to think that is relialbe and return it.
+    // See [DIMENSION_INHERIT_RULE] in `sourceManager.ts`.
+
+
+    var dimensions = [];
+    var dimsByName = {};
+    var dimsDef = internalSource.dimensionsDefine;
+
+    if (dimsDef) {
+      each(dimsDef, function (dimDef, idx) {
+        var name = dimDef.name;
+        var dimDefExt = {
+          index: idx,
+          name: name,
+          displayName: dimDef.displayName
+        };
+        dimensions.push(dimDefExt); // Users probably not sepcify dimension name. For simplicity, data transform
+        // do not generate dimension name.
+
+        if (name != null) {
+          // Dimension name should not be duplicated.
+          // For simplicity, data transform forbid name duplication, do not generate
+          // new name like module `completeDimensions.ts` did, but just tell users.
+          var errMsg_1 = '';
+
+          if (hasOwn(dimsByName, name)) {
+            {
+              errMsg_1 = 'dimension name "' + name + '" duplicated.';
+            }
+            throwError(errMsg_1);
+          }
+
+          dimsByName[name] = dimDefExt;
+        }
+      });
+    } // If dimension definitions are not defined and can not be detected.
+    // e.g., pure data `[[11, 22], ...]`.
+    else {
+        for (var i = 0; i < internalSource.dimensionsDetectedCount || 0; i++) {
+          // Do not generete name or anything others. The consequence process in
+          // `transform` or `series` probably have there own name generation strategry.
+          dimensions.push({
+            index: i
+          });
+        }
+      } // Implement public methods:
+
+
+    var rawItemGetter = getRawSourceItemGetter(sourceFormat, SERIES_LAYOUT_BY_COLUMN);
+
+    if (externalTransform.__isBuiltIn) {
+      extSource.getRawDataItem = function (dataIndex) {
+        return rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex);
+      };
+
+      extSource.getRawData = bind(getRawData, null, internalSource);
+    }
+
+    extSource.cloneRawData = bind(cloneRawData, null, internalSource);
+    var rawCounter = getRawSourceDataCounter(sourceFormat, SERIES_LAYOUT_BY_COLUMN);
+    extSource.count = bind(rawCounter, null, data, sourceHeaderCount, dimensions);
+    var rawValueGetter = getRawSourceValueGetter(sourceFormat);
+
+    extSource.retrieveValue = function (dataIndex, dimIndex) {
+      var rawItem = rawItemGetter(data, sourceHeaderCount, dimensions, dataIndex);
+      return retrieveValueFromItem(rawItem, dimIndex);
+    };
+
+    var retrieveValueFromItem = extSource.retrieveValueFromItem = function (dataItem, dimIndex) {
+      if (dataItem == null) {
+        return;
+      }
+
+      var dimDef = dimensions[dimIndex]; // When `dimIndex` is `null`, `rawValueGetter` return the whole item.
+
+      if (dimDef) {
+        return rawValueGetter(dataItem, dimIndex, dimDef.name);
+      }
+    };
+
+    extSource.getDimensionInfo = bind(getDimensionInfo, null, dimensions, dimsByName);
+    extSource.cloneAllDimensionInfo = bind(cloneAllDimensionInfo, null, dimensions);
+    return extSource;
+  }
+
+  function getRawData(upstream) {
+    var sourceFormat = upstream.sourceFormat;
+
+    if (!isSupportedSourceFormat(sourceFormat)) {
+      var errMsg = '';
+      {
+        errMsg = '`getRawData` is not supported in source format ' + sourceFormat;
+      }
+      throwError(errMsg);
+    }
+
+    return upstream.data;
+  }
+
+  function cloneRawData(upstream) {
+    var sourceFormat = upstream.sourceFormat;
+    var data = upstream.data;
+
+    if (!isSupportedSourceFormat(sourceFormat)) {
+      var errMsg = '';
+      {
+        errMsg = '`cloneRawData` is not supported in source format ' + sourceFormat;
+      }
+      throwError(errMsg);
+    }
+
+    if (sourceFormat === SOURCE_FORMAT_ARRAY_ROWS) {
+      var result = [];
+
+      for (var i = 0, len = data.length; i < len; i++) {
+        // Not strictly clone for performance
+        result.push(data[i].slice());
+      }
+
+      return result;
+    } else if (sourceFormat === SOURCE_FORMAT_OBJECT_ROWS) {
+      var result = [];
+
+      for (var i = 0, len = data.length; i < len; i++) {
+        // Not strictly clone for performance
+        result.push(extend({}, data[i]));
+      }
+
+      return result;
+    }
+  }
+
+  function getDimensionInfo(dimensions, dimsByName, dim) {
+    if (dim == null) {
+      return;
+    } // Keep the same logic as `List::getDimension` did.
+
+
+    if (isNumber(dim) // If being a number-like string but not being defined a dimension name.
+    || !isNaN(dim) && !hasOwn(dimsByName, dim)) {
+      return dimensions[dim];
+    } else if (hasOwn(dimsByName, dim)) {
+      return dimsByName[dim];
+    }
+  }
+
+  function cloneAllDimensionInfo(dimensions) {
+    return clone(dimensions);
+  }
+
+  var externalTransformMap = createHashMap();
+
+  function registerExternalTransform(externalTransform) {
+    externalTransform = clone(externalTransform);
+    var type = externalTransform.type;
+    var errMsg = '';
+
+    if (!type) {
+      {
+        errMsg = 'Must have a `type` when `registerTransform`.';
+      }
+      throwError(errMsg);
+    }
+
+    var typeParsed = type.split(':');
+
+    if (typeParsed.length !== 2) {
+      {
+        errMsg = 'Name must include namespace like "ns:regression".';
+      }
+      throwError(errMsg);
+    } // Namespace 'echarts:xxx' is official namespace, where the transforms should
+    // be called directly via 'xxx' rather than 'echarts:xxx'.
+
+
+    var isBuiltIn = false;
+
+    if (typeParsed[0] === 'echarts') {
+      type = typeParsed[1];
+      isBuiltIn = true;
+    }
+
+    externalTransform.__isBuiltIn = isBuiltIn;
+    externalTransformMap.set(type, externalTransform);
+  }
+
+  function applyDataTransform(rawTransOption, sourceList, infoForPrint) {
+    var pipedTransOption = normalizeToArray(rawTransOption);
+    var pipeLen = pipedTransOption.length;
+    var errMsg = '';
+
+    if (!pipeLen) {
+      {
+        errMsg = 'If `transform` declared, it should at least contain one transform.';
+      }
+      throwError(errMsg);
+    }
+
+    for (var i = 0, len = pipeLen; i < len; i++) {
+      var transOption = pipedTransOption[i];
+      sourceList = applySingleDataTransform(transOption, sourceList, infoForPrint, pipeLen === 1 ? null : i); // piped transform only support single input, except the fist one.
+      // piped transform only support single output, except the last one.
+
+      if (i !== len - 1) {
+        sourceList.length = Math.max(sourceList.length, 1);
+      }
+    }
+
+    return sourceList;
+  }
+
+  function applySingleDataTransform(transOption, upSourceList, infoForPrint, // If `pipeIndex` is null/undefined, no piped transform.
+  pipeIndex) {
+    var errMsg = '';
+
+    if (!upSourceList.length) {
+      {
+        errMsg = 'Must have at least one upstream dataset.';
+      }
+      throwError(errMsg);
+    }
+
+    if (!isObject(transOption)) {
+      {
+        errMsg = 'transform declaration must be an object rather than ' + typeof transOption + '.';
+      }
+      throwError(errMsg);
+    }
+
+    var transType = transOption.type;
+    var externalTransform = externalTransformMap.get(transType);
+
+    if (!externalTransform) {
+      {
+        errMsg = 'Can not find transform on type "' + transType + '".';
+      }
+      throwError(errMsg);
+    } // Prepare source
+
+
+    var extUpSourceList = map(upSourceList, function (upSource) {
+      return createExternalSource(upSource, externalTransform);
+    });
+    var resultList = normalizeToArray(externalTransform.transform({
+      upstream: extUpSourceList[0],
+      upstreamList: extUpSourceList,
+      config: clone(transOption.config)
+    }));
+    {
+      if (transOption.print) {
+        var printStrArr = map(resultList, function (extSource) {
+          var pipeIndexStr = pipeIndex != null ? ' === pipe index: ' + pipeIndex : '';
+          return ['=== dataset index: ' + infoForPrint.datasetIndex + pipeIndexStr + ' ===', '- transform result data:', makePrintable(extSource.data), '- transform result dimensions:', makePrintable(extSource.dimensions)].join('\n');
+        }).join('\n');
+        log(printStrArr);
+      }
+    }
+    return map(resultList, function (result, resultIndex) {
+      var errMsg = '';
+
+      if (!isObject(result)) {
+        {
+          errMsg = 'A transform should not return some empty results.';
+        }
+        throwError(errMsg);
+      }
+
+      if (!result.data) {
+        {
+          errMsg = 'Transform result data should be not be null or undefined';
+        }
+        throwError(errMsg);
+      }
+
+      var sourceFormat = detectSourceFormat(result.data);
+
+      if (!isSupportedSourceFormat(sourceFormat)) {
+        {
+          errMsg = 'Transform result data should be array rows or object rows.';
+        }
+        throwError(errMsg);
+      }
+
+      var resultMetaRawOption;
+      var firstUpSource = upSourceList[0];
+      /**
+       * Intuitively, the end users known the content of the original `dataset.source`,
+       * calucating the transform result in mind.
+       * Suppose the original `dataset.source` is:
+       * ```js
+       * [
+       *     ['product', '2012', '2013', '2014', '2015'],
+       *     ['AAA', 41.1, 30.4, 65.1, 53.3],
+       *     ['BBB', 86.5, 92.1, 85.7, 83.1],
+       *     ['CCC', 24.1, 67.2, 79.5, 86.4]
+       * ]
+       * ```
+       * The dimension info have to be detected from the source data.
+       * Some of the transformers (like filter, sort) will follow the dimension info
+       * of upstream, while others use new dimensions (like aggregate).
+       * Transformer can output a field `dimensions` to define the its own output dimensions.
+       * We also allow transformers to ignore the output `dimensions` field, and
+       * inherit the upstream dimensions definition. It can reduce the burden of handling
+       * dimensions in transformers.
+       *
+       * See also [DIMENSION_INHERIT_RULE] in `sourceManager.ts`.
+       */
+
+      if (firstUpSource && resultIndex === 0 // If transformer returns `dimensions`, it means that the transformer has different
+      // dimensions definitions. We do not inherit anything from upstream.
+      && !result.dimensions) {
+        var startIndex = firstUpSource.startIndex; // We copy the header of upstream to the result becuase:
+        // (1) The returned data always does not contain header line and can not be used
+        // as dimension-detection. In this case we can not use "detected dimensions" of
+        // upstream directly, because it might be detected based on different `seriesLayoutBy`.
+        // (2) We should support that the series read the upstream source in `seriesLayoutBy: 'row'`.
+        // So the original detected header should be add to the result, otherwise they can not be read.
+
+        if (startIndex) {
+          result.data = firstUpSource.data.slice(0, startIndex).concat(result.data);
+        }
+
+        resultMetaRawOption = {
+          seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,
+          sourceHeader: startIndex,
+          dimensions: firstUpSource.metaRawOption.dimensions
+        };
+      } else {
+        resultMetaRawOption = {
+          seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN,
+          sourceHeader: 0,
+          dimensions: result.dimensions
+        };
+      }
+
+      return createSource(result.data, resultMetaRawOption, null);
+    });
+  }
+
+  function isSupportedSourceFormat(sourceFormat) {
+    return sourceFormat === SOURCE_FORMAT_ARRAY_ROWS || sourceFormat === SOURCE_FORMAT_OBJECT_ROWS;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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;
+  /**
+   * Multi dimensional data store
+   */
+
+  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 DataStore() {
+      this._chunks = []; // It will not be calculated util needed.
+
+      this._rawExtent = [];
+      this._extent = [];
+      this._count = 0;
+      this._rawCount = 0;
+      this._calcDimNameToIdx = createHashMap();
+    }
+    /**
+     * Initialize from data
+     */
+
+
+    DataStore.prototype.initData = function (provider, inputDimensions, dimValueGetter) {
+      {
+        assert(isFunction(provider.getItem) && isFunction(provider.count), 'Invalid data provider.');
+      }
+      this._provider = provider; // Clear
+
+      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 (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;
+    };
+    /**
+     * 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.
+     */
+
+
+    DataStore.prototype.getSource = function () {
+      return this._provider.getSource();
+    };
+    /**
+     * @caution Only used in dataStack.
+     */
+
+
+    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;
+      }
+
+      dimensions[calcDimIdx] = {
+        type: type
+      };
+      calcDimNameToIdx.set(dimName, calcDimIdx);
+      this._chunks[calcDimIdx] = new dataCtors[type || 'float'](this._rawCount);
+      this._rawExtent[calcDimIdx] = getInitialExtent();
+      return calcDimIdx;
+    };
+
+    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;
+
+      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 dimRawExtent = rawExtents[dimIdx]; // Parse from previous data offset. len may be changed after appendData
+
+      for (var i = offset; i < len; i++) {
+        var val = chunk[i] = ordinalMeta.parseAndCollect(chunk[i]);
+
+        if (!isNaN(val)) {
+          dimRawExtent[0] = Math.min(val, dimRawExtent[0]);
+          dimRawExtent[1] = Math.max(val, dimRawExtent[1]);
+        }
+      }
+
+      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;
+    };
+
+    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).
+     */
+
+
+    DataStore.prototype.appendData = function (data) {
+      {
+        assert(!this._indices, 'appendData can only be called on raw data.');
+      }
+      var provider = this._provider;
+      var start = this.count();
+      provider.appendData(data);
+      var end = provider.count();
+
+      if (!provider.persistent) {
+        end += start;
+      }
+
+      if (start < end) {
+        this._initDataFromProvider(start, end, true);
+      }
+
+      return [start, end];
+    };
+
+    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);
+
+      for (var i = 0; i < dimLen; i++) {
+        var dim = dimensions[i];
+        prepareStore(chunks, i, dim.type, end, true);
+      }
+
+      var emptyDataItem = [];
+
+      for (var idx = start; idx < end; idx++) {
+        var sourceIdx = idx - start; // Store the data by dimensions
+
+        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);
+        }
+      }
+
+      this._rawCount = this._count = end;
+      return {
+        start: start,
+        end: end
+      };
+    };
+
+    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;
+      });
+
+      for (var i = 0; i < dimLen; i++) {
+        var dim = dimensions[i];
+
+        if (!rawExtent[i]) {
+          rawExtent[i] = getInitialExtent();
+        }
+
+        prepareStore(chunks, i, dim.type, end, append);
+      }
+
+      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);
+          }
+        }
+      }
+
+      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 = [];
+    };
+
+    DataStore.prototype.count = function () {
+      return this._count;
+    };
+    /**
+     * Get value. Return NaN if idx is out of range.
+     */
+
+
+    DataStore.prototype.get = function (dim, idx) {
+      if (!(idx >= 0 && idx < this._count)) {
+        return NaN;
+      }
+
+      var dimStore = this._chunks[dim];
+      return dimStore ? dimStore[this.getRawIndex(idx)] : NaN;
+    };
+
+    DataStore.prototype.getValues = function (dimensions, idx) {
+      var values = [];
+      var dimArr = [];
+
+      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 dim concrete dim
+     */
+
+
+    DataStore.prototype.getByRawIndex = function (dim, rawIdx) {
+      if (!(rawIdx >= 0 && rawIdx < this._rawCount)) {
+        return NaN;
+      }
+
+      var dimStore = this._chunks[dim];
+      return dimStore ? dimStore[rawIdx] : NaN;
+    };
+    /**
+     * Get sum of data in one dimension
+     */
+
+
+    DataStore.prototype.getSum = function (dim) {
+      var dimData = this._chunks[dim];
+      var sum = 0;
+
+      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
+     */
+
+
+    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?
+
+      var sortedDimDataArray = dimDataArray.sort(function (a, b) {
+        return a - b;
+      });
+      var len = this.count(); // calculate median
+
+      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
+     */
+
+
+    DataStore.prototype.indexOfRawIndex = function (rawIndex) {
+      if (rawIndex >= this._rawCount || rawIndex < 0) {
+        return -1;
+      }
+
+      if (!this._indices) {
+        return rawIndex;
+      } // Indices are ascending
+
+
+      var indices = this._indices; // If rawIndex === dataIndex
+
+      var rawDataIndex = indices[rawIndex];
+
+      if (rawDataIndex != null && rawDataIndex < this._count && rawDataIndex === rawIndex) {
+        return rawIndex;
+      }
+
+      var left = 0;
+      var right = this._count - 1;
+
+      while (left <= right) {
+        var mid = (left + right) / 2 | 0;
+
+        if (indices[mid] < rawIndex) {
+          left = mid + 1;
+        } else if (indices[mid] > rawIndex) {
+          right = mid - 1;
+        } else {
+          return mid;
+        }
+      }
+
+      return -1;
+    };
+    /**
+     * 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.
+     */
+
+
+    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;
+          }
+
+          if (diff === minDiff) {
+            nearestIndices[nearestIndicesLen++] = i;
+          }
+        }
+      }
+
+      nearestIndices.length = nearestIndicesLen;
+      return nearestIndices;
+    };
+
+    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 {
+          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;
+    };
+    /**
+     * Data filter.
+     */
+
+
+    DataStore.prototype.filter = function (dims, cb) {
+      if (!this._count) {
+        return this;
+      }
+
+      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;
+
+      for (var i = 0; i < count; i++) {
+        var keep = void 0;
+        var rawIdx = newStore.getRawIndex(i); // Simple optimization
+
+        if (dimSize === 0) {
+          keep = cb(i);
+        } else if (dimSize === 1) {
+          var val = chunks[dim0][rawIdx];
+          keep = cb(val, i);
+        } else {
+          var k = 0;
+
+          for (; k < dimSize; k++) {
+            value[k] = chunks[dims[k]][rawIdx];
+          }
+
+          value[k] = i;
+          keep = cb.apply(null, value);
+        }
+
+        if (keep) {
+          newIndices[offset++] = rawIdx;
+        }
+      } // Set indices after filtered.
+
+
+      if (offset < count) {
+        newStore._indices = newIndices;
+      }
+
+      newStore._count = offset; // Reset data extent
+
+      newStore._extent = [];
+
+      newStore._updateGetRawIdx();
+
+      return newStore;
+    };
+    /**
+     * Select data in range. (For optimization of filter)
+     * (Manually inline code, support 5 million data filtering in data zoom.)
+     */
+
+
+    DataStore.prototype.selectRange = function (range) {
+      var newStore = this.clone();
+      var len = newStore._count;
+
+      if (!len) {
+        return this;
+      }
+
+      var dims = keys(range);
+      var dimSize = dims.length;
+
+      if (!dimSize) {
+        return this;
+      }
+
+      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;
+
+      if (!newStore._indices) {
+        // Extreme optimization for common case. About 2x faster in chrome.
+        var idx = 0;
+
+        if (dimSize === 1) {
+          var dimStorage = storeArr[dims[0]];
+
+          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.
+
+            if (val >= min && val <= max || isNaN(val)) {
+              newIndices[offset++] = idx;
+            }
+
+            idx++;
+          }
+
+          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];
+
+          for (var i = 0; i < len; i++) {
+            var val = dimStorage[i];
+            var val2 = dimStorage2[i]; // Do not filter NaN, see comment above.
+
+            if ((val >= min && val <= max || isNaN(val)) && (val2 >= min2 && val2 <= max2 || isNaN(val2))) {
+              newIndices[offset++] = idx;
+            }
+
+            idx++;
+          }
+
+          quickFinished = true;
+        }
+      }
+
+      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.
+
+            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);
+
+            for (var k = 0; k < dimSize; k++) {
+              var dimk = dims[k];
+              var val = storeArr[dimk][rawIndex]; // Do not filter NaN, see comment above.
+
+              if (val < range[dimk][0] || val > range[dimk][1]) {
+                keep = false;
+              }
+            }
+
+            if (keep) {
+              newIndices[offset++] = newStore.getRawIndex(i);
+            }
+          }
+        }
+      } // Set indices after filtered.
+
+
+      if (offset < originalCount) {
+        newStore._indices = newIndices;
+      }
+
+      newStore._count = offset; // Reset data extent
+
+      newStore._extent = [];
+
+      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;
+    // }
+
+    /**
+     * Data mapping to a new List with given dimensions
+     */
+
+
+    DataStore.prototype.map = function (dims, cb) {
+      // TODO only clone picked chunks.
+      var target = this.clone(dims);
+
+      this._updateDims(target, dims, cb);
+
+      return target;
+    };
+    /**
+     * @caution Danger!! Only used in dataStack.
+     */
+
+
+    DataStore.prototype.modify = function (dims, cb) {
+      this._updateDims(this, dims, cb);
+    };
+
+    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;
+
+      for (var i = 0; i < dims.length; i++) {
+        rawExtent[dims[i]] = getInitialExtent();
+      }
+
+      for (var dataIndex = 0; dataIndex < dataCount; dataIndex++) {
+        var rawIndex = target.getRawIndex(dataIndex);
+
+        for (var k = 0; k < dimSize; k++) {
+          values[k] = targetChunks[dims[k]][rawIndex];
+        }
+
+        values[dimSize] = dataIndex;
+        var retValue = cb && cb.apply(null, values);
+
+        if (retValue != null) {
+          // a number or string (in oridinal dimension)?
+          if (typeof retValue !== 'object') {
+            tmpRetValue[0] = retValue;
+            retValue = tmpRetValue;
+          }
+
+          for (var i = 0; i < retValue.length; i++) {
+            var dim = dims[i];
+            var val = retValue[i];
+            var rawExtentOnDim = rawExtent[dim];
+            var dimStore = targetChunks[dim];
+
+            if (dimStore) {
+              dimStore[rawIndex] = val;
+            }
+
+            if (val < rawExtentOnDim[0]) {
+              rawExtentOnDim[0] = val;
+            }
+
+            if (val > rawExtentOnDim[1]) {
+              rawExtentOnDim[1] = val;
+            }
+          }
+        }
+      }
+    };
+    /**
+     * Large data down sampling using largest-triangle-three-buckets
+     * @param {string} valueDimension
+     * @param {number} targetCount
+     */
+
+
+    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.min((Math.ceil(len / frameSize) + 2) * 2, len)); // First frame use the first data.
+
+      newIndices[sampledIndex++] = currentRawIndex;
+
+      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;
+
+        for (var idx = nextFrameStart; idx < nextFrameEnd; idx++) {
+          var rawIndex = this.getRawIndex(idx);
+          var y = dimStore[rawIndex];
+
+          if (isNaN(y)) {
+            continue;
+          }
+
+          avgY += y;
+        }
+
+        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;
+        var firstNaNIndex = -1;
+        var countNaN = 0; // Find a point from current frame that construct a triangel with largest area with previous selected point
+        // And the average of next frame.
+
+        for (var idx = frameStart; idx < frameEnd; idx++) {
+          var rawIndex = this.getRawIndex(idx);
+          var y = dimStore[rawIndex];
+
+          if (isNaN(y)) {
+            countNaN++;
+
+            if (firstNaNIndex < 0) {
+              firstNaNIndex = rawIndex;
+            }
+
+            continue;
+          } // Calculate triangle area over three buckets
+
+
+          area = Math.abs((pointAX - avgX) * (y - pointAY) - (pointAX - idx) * (avgY - pointAY));
+
+          if (area > maxArea) {
+            maxArea = area;
+            nextRawIndex = rawIndex; // Next a is this b
+          }
+        }
+
+        if (countNaN > 0 && countNaN < frameEnd - frameStart) {
+          // Append first NaN point in every bucket.
+          // It is necessary to ensure the correct order of indices.
+          newIndices[sampledIndex++] = Math.min(firstNaNIndex, nextRawIndex);
+          nextRawIndex = Math.max(firstNaNIndex, nextRawIndex);
+        }
+
+        newIndices[sampledIndex++] = nextRawIndex;
+        currentRawIndex = nextRawIndex; // This a is the next a (chosen b)
+      } // First frame use the last data.
+
+
+      newIndices[sampledIndex++] = this.getRawIndex(len - 1);
+      target._count = sampledIndex;
+      target._indices = newIndices;
+      target.getRawIndex = this._getRawIdx;
+      return target;
+    };
+    /**
+     * Large data down sampling on given dimension
+     * @param sampleIndex Sample index for name and id
+     */
+
+
+    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;
+
+      for (var i = 0; i < len; i += frameSize) {
+        // Last frame
+        if (frameSize > len - i) {
+          frameSize = len - i;
+          frameValues.length = frameSize;
+        }
+
+        for (var k = 0; k < frameSize; k++) {
+          var dataIdx = this.getRawIndex(i + k);
+          frameValues[k] = dimStore[dataIdx];
+        }
+
+        var value = sampleValue(frameValues);
+        var sampleFrameIdx = this.getRawIndex(Math.min(i + sampleIndex(frameValues, value) || 0, len - 1)); // Only write value on the filtered data
+
+        dimStore[sampleFrameIdx] = value;
+
+        if (value < rawExtentOnDim[0]) {
+          rawExtentOnDim[0] = value;
+        }
+
+        if (value > rawExtentOnDim[1]) {
+          rawExtentOnDim[1] = value;
+        }
+
+        newIndices[offset++] = sampleFrameIdx;
+      }
+
+      target._count = offset;
+      target._indices = newIndices;
+
+      target._updateGetRawIdx();
+
+      return target;
+    };
+    /**
+     * 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) {})
+     */
+
+
+    DataStore.prototype.each = function (dims, cb) {
+      if (!this._count) {
+        return;
+      }
+
+      var dimSize = dims.length;
+      var chunks = this._chunks;
+
+      for (var i = 0, len = this.count(); i < len; i++) {
+        var rawIdx = this.getRawIndex(i); // Simple optimization
+
+        switch (dimSize) {
+          case 0:
+            cb(i);
+            break;
+
+          case 1:
+            cb(chunks[dims[0]][rawIdx], i);
+            break;
+
+          case 2:
+            cb(chunks[dims[0]][rawIdx], chunks[dims[1]][rawIdx], i);
+            break;
+
+          default:
+            var k = 0;
+            var value = [];
+
+            for (; k < dimSize; k++) {
+              value[k] = chunks[dims[k]][rawIdx];
+            } // Index
+
+
+            value[k] = i;
+            cb.apply(null, value);
+        }
+      }
+    };
+    /**
+     * Get extent of data in one dimension
+     */
+
+
+    DataStore.prototype.getDataExtent = function (dim) {
+      // Make sure use concrete dim as cache name.
+      var dimData = this._chunks[dim];
+      var initialExtent = getInitialExtent();
+
+      if (!dimData) {
+        return initialExtent;
+      } // Make more strict checkings to ensure hitting cache.
+
+
+      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;
+
+      if (useRaw) {
+        return this._rawExtent[dim].slice();
+      }
+
+      dimExtent = this._extent[dim];
+
+      if (dimExtent) {
+        return dimExtent.slice();
+      }
+
+      dimExtent = initialExtent;
+      var min = dimExtent[0];
+      var max = dimExtent[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
+     */
+
+
+    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.
+     */
+
+
+    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 (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;
+      }
+
+      this._copyCommonProps(target);
+
+      if (!ignoreIndices) {
+        target._indices = this._cloneIndices();
+      }
+
+      target._updateGetRawIdx();
+
+      return target;
+    };
+
+    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);
+    };
+
+    DataStore.prototype._cloneIndices = function () {
+      if (this._indices) {
+        var Ctor = this._indices.constructor;
+        var indices = void 0;
+
+        if (Ctor === Array) {
+          var thisCount = this._indices.length;
+          indices = new Ctor(thisCount);
+
+          for (var i = 0; i < thisCount; i++) {
+            indices[i] = this._indices[i];
+          }
+        } else {
+          indices = new Ctor(this._indices);
+        }
+
+        return indices;
+      }
+
+      return null;
+    };
+
+    DataStore.prototype._getRawIdxIdentity = function (idx) {
+      return idx;
+    };
+
+    DataStore.prototype._getRawIdx = function (idx) {
+      if (idx < this._count && idx >= 0) {
+        return this._indices[idx];
+      }
+
+      return -1;
+    };
+
+    DataStore.prototype._updateGetRawIdx = function () {
+      this.getRawIndex = this._indices ? this._getRawIdx : this._getRawIdxIdentity;
+    };
+
+    DataStore.internalField = function () {
+      function getDimValueSimply(dataItem, property, dataIndex, dimIndex) {
+        return parseDataValue(dataItem[dimIndex], this._dimensions[dimIndex]);
+      }
+
+      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 DataStore;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * [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
+   * }]
+   * ```
+   */
+
+
+  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.
+
+      this._upstreamSignList = [];
+      this._versionSignBase = 0;
+      this._dirty = true;
+      this._sourceHost = sourceHost;
+    }
+    /**
+     * Mark dirty.
+     */
+
+
+    SourceManager.prototype.dirty = function () {
+      this._setLocalSource([], []);
+
+      this._storeList = [];
+      this._dirty = true;
+    };
+
+    SourceManager.prototype._setLocalSource = function (sourceList, upstreamSignList) {
+      this._sourceList = sourceList;
+      this._upstreamSignList = upstreamSignList;
+      this._versionSignBase++;
+
+      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.
+     */
+
+
+    SourceManager.prototype._getVersionSign = function () {
+      return this._sourceHost.uid + '_' + this._versionSignBase;
+    };
+    /**
+     * Always return a source instance. Otherwise throw error.
+     */
+
+
+    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;
+      }
+    };
+
+    SourceManager.prototype._createSource = function () {
+      this._setLocalSource([], []);
+
+      var sourceHost = this._sourceHost;
+
+      var upSourceMgrList = this._getUpstreamSourceManagers();
+
+      var hasUpstream = !!upSourceMgrList.length;
+      var resultSourceList;
+      var upstreamSignList;
+
+      if (isSeries(sourceHost)) {
+        var seriesModel = sourceHost;
+        var data = void 0;
+        var sourceFormat = void 0;
+        var upSource = void 0; // Has upstream dataset
+
+        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.
+
+
+        var newMetaRawOption = this._getSourceMetaRawOption() || {};
+        var upMetaRawOption = upSource && upSource.metaRawOption || {};
+        var seriesLayoutBy = retrieve2(newMetaRawOption.seriesLayoutBy, upMetaRawOption.seriesLayoutBy) || null;
+        var sourceHeader = retrieve2(newMetaRawOption.sourceHeader, upMetaRawOption.sourceHeader); // 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.
+
+        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.
+
+        if (hasUpstream) {
+          var result = this._applyTransform(upSourceMgrList);
+
+          resultSourceList = result.sourceList;
+          upstreamSignList = result.upstreamSignList;
+        } // Is root dataset.
+        else {
+            var sourceData = datasetModel.get('source', true);
+            resultSourceList = [createSource(sourceData, this._getSourceMetaRawOption(), null)];
+            upstreamSignList = [];
+          }
+      }
+
+      {
+        assert(resultSourceList && upstreamSignList);
+      }
+
+      this._setLocalSource(resultSourceList, upstreamSignList);
+    };
+
+    SourceManager.prototype._applyTransform = function (upMgrList) {
+      var datasetModel = this._sourceHost;
+      var transformOption = datasetModel.get('transform', true);
+      var fromTransformResult = datasetModel.get('fromTransformResult', true);
+      {
+        assert(fromTransformResult != null || transformOption != null);
+      }
+
+      if (fromTransformResult != null) {
+        var errMsg = '';
+
+        if (upMgrList.length !== 1) {
+          {
+            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) {
+          {
+            errMsg = 'Can not retrieve result by `fromTransformResult`: ' + fromTransformResult;
+          }
+          doThrow(errMsg);
+        }
+
+        upSourceList.push(upSource);
+        upstreamSignList.push(upMgr._getVersionSign());
+      });
+
+      if (transformOption) {
+        sourceList = applyDataTransform(transformOption, upSourceList, {
+          datasetIndex: datasetModel.componentIndex
+        });
+      } else if (fromTransformResult != null) {
+        sourceList = [cloneSourceShallow(upSourceList[0])];
+      }
+
+      return {
+        sourceList: sourceList,
+        upstreamSignList: upstreamSignList
+      };
+    };
+
+    SourceManager.prototype._isDirty = function () {
+      if (this._dirty) {
+        return true;
+      } // All sourceList is from the some upsteam.
+
+
+      var upSourceMgrList = this._getUpstreamSourceManagers();
+
+      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;
+        }
+      }
+    };
+    /**
+     * @param sourceIndex By defualt 0, means "main source".
+     *                    Most cases there is only one source.
+     */
+
+
+    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;
+    };
+    /**
+     *
+     * 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.
+     */
+
+
+    SourceManager.prototype.getSharedDataStore = function (seriesDimRequest) {
+      {
+        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);
+    };
+
+    SourceManager.prototype._innerGetDataStore = function (storeDims, seriesSource, sourceReadKey) {
+      // TODO Can use other sourceIndex?
+      var sourceIndex = 0;
+      var storeList = this._storeList;
+      var cachedStoreMap = storeList[sourceIndex];
+
+      if (!cachedStoreMap) {
+        cachedStoreMap = storeList[sourceIndex] = {};
+      }
+
+      var cachedStore = cachedStoreMap[sourceReadKey];
+
+      if (!cachedStore) {
+        var upSourceMgr = this._getUpstreamSourceManagers()[0];
+
+        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);
+        }
+
+        cachedStoreMap[sourceReadKey] = cachedStore;
+      }
+
+      return cachedStore;
+    };
+    /**
+     * PEDING: Is it fast enough?
+     * If no upstream, return empty array.
+     */
+
+
+    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();
+        });
+      }
+    };
+
+    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);
+        }
+
+      return {
+        seriesLayoutBy: seriesLayoutBy,
+        sourceHeader: sourceHeader,
+        dimensions: dimensions
+      };
+    };
+
+    return SourceManager;
+  }(); // disable the transform merge, but do not disable transfrom clone from rawOption.
+
+
+  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';
+  }
+
+  function doThrow(errMsg) {
+    throw new Error(errMsg);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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';
+
+    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 HTML_GAPS = [0, 10, 20, 30];
+  var RICH_TEXT_GAPS = ['', '\n', '\n\n', '\n\n\n']; // eslint-disable-next-line max-len
+
+  function createTooltipMarkup(type, option) {
+    option.type = type;
+    return option;
+  }
+
+  function isSectionFragment(frag) {
+    return frag.type === 'section';
+  }
+
+  function getBuilder(frag) {
+    return isSectionFragment(frag) ? buildSection : buildNameValue;
+  }
+
+  function getBlockGapLevel(frag) {
+    if (isSectionFragment(frag)) {
+      var gapLevel_1 = 0;
+      var subBlockLen = frag.blocks.length;
+      var hasInnerGap_1 = subBlockLen > 1 || subBlockLen > 0 && !frag.noHeader;
+      each(frag.blocks, function (subBlock) {
+        var subGapLevel = getBlockGapLevel(subBlock); // 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 >= gapLevel_1) {
+          gapLevel_1 = subGapLevel + +(hasInnerGap_1 && ( // 0 always can not be readable gap level.
+          !subGapLevel // If no header, always keep the sub gap level. Otherwise
+          // look weird in case `multipleSeries`.
+          || isSectionFragment(subBlock) && !subBlock.noHeader));
+        }
+      });
+      return gapLevel_1;
+    }
+
+    return 0;
+  }
+
+  function buildSection(ctx, fragment, topMarginForOuterGap, toolTipTextStyle) {
+    var noHeader = fragment.noHeader;
+    var gaps = getGap(getBlockGapLevel(fragment));
+    var subMarkupTextList = [];
+    var subBlocks = fragment.blocks || [];
+    assert(!subBlocks || isArray(subBlocks));
+    subBlocks = subBlocks || [];
+    var orderMode = ctx.orderMode;
+
+    if (fragment.sortBlocks && orderMode) {
+      subBlocks = subBlocks.slice();
+      var orderMap = {
+        valueAsc: 'asc',
+        valueDesc: 'desc'
+      };
+
+      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();
+        }
+    }
+
+    each(subBlocks, function (subBlock, idx) {
+      var valueFormatter = fragment.valueFormatter;
+      var subMarkupText = getBuilder(subBlock)( // Inherit valueFormatter
+      valueFormatter ? extend(extend({}, ctx), {
+        valueFormatter: valueFormatter
+      }) : ctx, subBlock, idx > 0 ? gaps.html : 0, toolTipTextStyle);
+      subMarkupText != null && subMarkupTextList.push(subMarkupText);
+    });
+    var subMarkupText = ctx.renderMode === 'richText' ? subMarkupTextList.join(gaps.richText) : wrapBlockHTML(subMarkupTextList.join(''), noHeader ? topMarginForOuterGap : gaps.html);
+
+    if (noHeader) {
+      return subMarkupText;
+    }
+
+    var displayableHeader = makeValueReadable(fragment.header, 'ordinal', ctx.useUTC);
+    var nameStyle = getTooltipTextStyle(toolTipTextStyle, ctx.renderMode).nameStyle;
+
+    if (ctx.renderMode === 'richText') {
+      return wrapInlineNameRichText(ctx, displayableHeader, nameStyle) + gaps.richText + subMarkupText;
+    } else {
+      return wrapBlockHTML("<div style=\"" + nameStyle + ";" + TOOLTIP_LINE_HEIGHT_CSS + ";\">" + encodeHTML(displayableHeader) + '</div>' + subMarkupText, topMarginForOuterGap);
+    }
+  }
+
+  function buildNameValue(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 useUTC = ctx.useUTC;
+
+    var valueFormatter = fragment.valueFormatter || ctx.valueFormatter || function (value) {
+      value = isArray(value) ? value : [value];
+      return map(value, function (val, idx) {
+        return makeValueReadable(val, isArray(valueTypeOption) ? valueTypeOption[idx] : valueTypeOption, 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 ? [] : valueFormatter(fragment.value);
+    var valueAlignRight = !noMarker || !noName; // It little weird if only value next to marker but far from marker.
+
+    var valueCloseToMarker = !noMarker && noName;
+
+    var _a = getTooltipTextStyle(toolTipTextStyle, renderMode),
+        nameStyle = _a.nameStyle,
+        valueStyle = _a.valueStyle;
+
+    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);
+  }
+  /**
+   * @return markupText. null/undefined means no content.
+   */
+
+
+  function buildTooltipMarkup(fragment, markupStyleCreator, renderMode, orderMode, useUTC, toolTipTextStyle) {
+    if (!fragment) {
+      return;
+    }
+
+    var builder = getBuilder(fragment);
+    var ctx = {
+      useUTC: useUTC,
+      renderMode: renderMode,
+      orderMode: orderMode,
+      markupStyleCreator: markupStyleCreator,
+      valueFormatter: fragment.valueFormatter
+    };
+    return builder(ctx, fragment, 0, toolTipTextStyle);
+  }
+
+  function getGap(gapLevel) {
+    return {
+      html: HTML_GAPS[gapLevel],
+      richText: RICH_TEXT_GAPS[gapLevel]
+    };
+  }
+
+  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 wrapInlineNameHTML(name, leftHasMarker, style) {
+    var marginCss = leftHasMarker ? 'margin-left:2px' : '';
+    return "<span style=\"" + style + ";" + marginCss + "\">" + encodeHTML(name) + '</span>';
+  }
+
+  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 : '';
+    valueList = isArray(valueList) ? valueList : [valueList];
+    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>';
+  }
+
+  function wrapInlineNameRichText(ctx, name, style) {
+    return ctx.markupStyleCreator.wrapRichTextStyle(name, style);
+  }
+
+  function wrapInlineValueRichText(ctx, values, 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.
+
+    return ctx.markupStyleCreator.wrapRichTextStyle(isArray(values) ? values.join('  ') : values, styles);
+  }
+
+  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).
+
+      this._nextStyleNameId = getRandomIdBase();
+    }
+
+    TooltipMarkupStyleCreator.prototype._generateStyleName = function () {
+      return '__EC_aUTo_' + this._nextStyleNameId++;
+    };
+
+    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 (isString(marker)) {
+        return marker;
+      } else {
+        {
+          assert(markerId);
+        }
+        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
+     *     }
+     * ]);
+     * ```
+     */
+
+
+    TooltipMarkupStyleCreator.prototype.wrapRichTextStyle = function (text, styles) {
+      var finalStl = {};
+
+      if (isArray(styles)) {
+        each(styles, function (stl) {
+          return extend(finalStl, stl);
+        });
+      } else {
+        extend(finalStl, styles);
+      }
+
+      var styleName = this._generateStyleName();
+
+      this.richTextStyles[styleName] = finalStl;
+      return "{" + styleName + "|" + text + "}";
+    };
+
+    return TooltipMarkupStyleCreator;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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.
+
+    var inlineValue;
+    var inlineValueType;
+    var subBlocks;
+    var sortParam;
+
+    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.
+
+      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.
+
+
+    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 || [])
+    });
+  }
+
+  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.
+
+      if (!dimInfo || dimInfo.otherDims.tooltip === false) {
+        return;
+      }
+
+      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 {
+      inlineValues: inlineValues,
+      inlineValueTypes: inlineValueTypes,
+      blocks: blocks
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$1 = makeInner();
+
+  function getSelectionKey(data, dataIndex) {
+    return data.getName(dataIndex) || data.getId(dataIndex);
+  }
+
+  var SERIES_UNIVERSAL_TRANSITION_PROP = '__universalTransitionEnabled';
+
+  var SeriesModel =
+  /** @class */
+  function (_super) {
+    __extends(SeriesModel, _super);
+
+    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
+      // ---------------------------------------
+
+
+      _this._selectedDataIndicesMap = {};
+      return _this;
+    }
+
+    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;
+      {
+        assert(data, 'getInitialData returned invalid data.');
+      }
+      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();
+
+      autoSeriesName(this);
+
+      this._initSelectedMapFromData(data);
+    };
+    /**
+     * Util for merge default and theme to option
+     */
+
+
+    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 themeSubType = this.subType;
+
+      if (ComponentModel.hasClass(themeSubType)) {
+        themeSubType += 'Series';
+      }
+
+      merge(option, ecModel.getTheme().get(this.subType));
+      merge(option, this.getDefaultOption()); // Default label emphasis `show`
+
+      defaultEmphasis(option, 'label', ['show']);
+      this.fillDataTextStyle(option.data);
+
+      if (layoutMode) {
+        mergeLayoutParam(option, inputPositionParams, layoutMode);
+      }
+    };
+
+    SeriesModel.prototype.mergeOption = function (newSeriesOption, ecModel) {
+      // this.settingTask.dirty();
+      newSeriesOption = merge(this.option, newSeriesOption, true);
+      this.fillDataTextStyle(newSeriesOption.data);
+      var layoutMode = fetchLayoutMode(this);
+
+      if (layoutMode) {
+        mergeLayoutParam(this.option, newSeriesOption, layoutMode);
+      }
+
+      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);
+    };
+
+    SeriesModel.prototype.fillDataTextStyle = function (data) {
+      // Default data label emphasis `show`
+      // FIXME Tree structure data ?
+      // FIXME Performance ?
+      if (data && !isTypedArray(data)) {
+        var props = ['show'];
+
+        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.
+     */
+
+
+    SeriesModel.prototype.getInitialData = function (option, ecModel) {
+      return;
+    };
+    /**
+     * Append data to list
+     */
+
+
+    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.
+     */
+
+
+    SeriesModel.prototype.getData = function (dataType) {
+      var task = getCurrentTask(this);
+
+      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;
+      }
+    };
+
+    SeriesModel.prototype.getAllData = function () {
+      var mainData = this.getData();
+      return mainData && mainData.getLinkedDataAll ? mainData.getLinkedDataAll() : [{
+        data: mainData
+      }];
+    };
+
+    SeriesModel.prototype.setData = function (data) {
+      var task = getCurrentTask(this);
+
+      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());
+        // }
+
+        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;
+        }
+      }
+
+      inner$1(this).data = data;
+    };
+
+    SeriesModel.prototype.getEncode = function () {
+      var encode = this.get('encode', true);
+
+      if (encode) {
+        return createHashMap(encode);
+      }
+    };
+
+    SeriesModel.prototype.getSourceManager = function () {
+      return inner$1(this).sourceManager;
+    };
+
+    SeriesModel.prototype.getSource = function () {
+      return this.getSourceManager().getSource();
+    };
+    /**
+     * Get data before processed
+     */
+
+
+    SeriesModel.prototype.getRawData = function () {
+      return inner$1(this).dataBeforeProcessed;
+    };
+
+    SeriesModel.prototype.getColorBy = function () {
+      var colorBy = this.get('colorBy');
+      return colorBy || 'series';
+    };
+
+    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
+     */
+
+
+    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
+     */
+
+
+    SeriesModel.prototype.formatTooltip = function (dataIndex, multipleSeries, dataType) {
+      return defaultSeriesFormatTooltip({
+        series: this,
+        dataIndex: dataIndex,
+        multipleSeries: multipleSeries
+      });
+    };
+
+    SeriesModel.prototype.isAnimationEnabled = function () {
+      var ecModel = this.ecModel; // Disable animation if using echarts in node but not give ssr flag.
+      // In ssr mode, renderToString will generate svg with css animation.
+
+      if (env.node && !(ecModel && ecModel.ssr)) {
+        return false;
+      }
+
+      var animationEnabled = this.getShallow('animation');
+
+      if (animationEnabled) {
+        if (this.getData().count() > this.getShallow('animationThreshold')) {
+          animationEnabled = false;
+        }
+      }
+
+      return !!animationEnabled;
+    };
+
+    SeriesModel.prototype.restoreData = function () {
+      this.dataTask.dirty();
+    };
+
+    SeriesModel.prototype.getColorFromPalette = function (name, scope, requestColorNum) {
+      var ecModel = this.ecModel; // PENDING
+
+      var color = PaletteMixin.prototype.getColorFromPalette.call(this, name, scope, requestColorNum);
+
+      if (!color) {
+        color = ecModel.getColorFromPalette(name, scope, requestColorNum);
+      }
+
+      return color;
+    };
+    /**
+     * Use `data.mapDimensionsAll(coordDim)` instead.
+     * @deprecated
+     */
+
+
+    SeriesModel.prototype.coordDimToDataDim = function (coordDim) {
+      return this.getRawData().mapDimensionsAll(coordDim);
+    };
+    /**
+     * Get progressive rendering count each step
+     */
+
+
+    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;
+      }
+
+      var selectedMode = this.option.selectedMode;
+      var data = this.getData(dataType);
+
+      if (selectedMode === 'series' || selectedMap === 'all') {
+        this.option.selectedMap = {};
+        this._selectedDataIndicesMap = {};
+        return;
+      }
+
+      for (var i = 0; i < innerDataIndices.length; i++) {
+        var dataIndex = innerDataIndices[i];
+        var nameOrId = getSelectionKey(data, dataIndex);
+        selectedMap[nameOrId] = false;
+        this._selectedDataIndicesMap[nameOrId] = -1;
+      }
+    };
+
+    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);
+      }
+    };
+
+    SeriesModel.prototype.getSelectedDataIndices = function () {
+      if (this.option.selectedMap === 'all') {
+        return [].slice.call(this.getData().getIndices());
+      }
+
+      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;
+    };
+
+    SeriesModel.prototype.isSelected = function (dataIndex, dataType) {
+      var selectedMap = this.option.selectedMap;
+
+      if (!selectedMap) {
+        return false;
+      }
+
+      var data = this.getData(dataType);
+      return (selectedMap === 'all' || selectedMap[getSelectionKey(data, dataIndex)]) && !data.getItemModel(dataIndex).get(['select', 'disabled']);
+    };
+
+    SeriesModel.prototype.isUniversalTransitionEnabled = function () {
+      if (this[SERIES_UNIVERSAL_TRANSITION_PROP]) {
+        return true;
+      }
+
+      var universalTransitionOpt = this.option.universalTransition; // Quick reject
+
+      if (!universalTransitionOpt) {
+        return false;
+      }
+
+      if (universalTransitionOpt === true) {
+        return true;
+      } // Can be simply 'universalTransition: true'
+
+
+      return universalTransitionOpt && universalTransitionOpt.enabled;
+    };
+
+    SeriesModel.prototype._innerSelect = function (data, innerDataIndices) {
+      var _a, _b;
+
+      var option = this.option;
+      var selectedMode = option.selectedMode;
+      var len = innerDataIndices.length;
+
+      if (!selectedMode || !len) {
+        return;
+      }
+
+      if (selectedMode === 'series') {
+        option.selectedMap = 'all';
+      } else if (selectedMode === 'multiple') {
+        if (!isObject(option.selectedMap)) {
+          option.selectedMap = {};
+        }
+
+        var selectedMap = 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 (selectedMode === 'single' || selectedMode === true) {
+        var lastDataIndex = innerDataIndices[len - 1];
+        var nameOrId = getSelectionKey(data, lastDataIndex);
+        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;
+      }
+
+      var dataIndices = [];
+
+      if (data.hasItemOption) {
+        data.each(function (idx) {
+          var rawItem = data.getRawDataItem(idx);
+
+          if (rawItem && rawItem.selected) {
+            dataIndices.push(idx);
+          }
+        });
+      }
+
+      if (dataIndices.length > 0) {
+        this._innerSelect(data, dataIndices);
+      }
+    }; // /**
+    //  * @see {module:echarts/stream/Scheduler}
+    //  */
+    // abstract pipeTask: null
+
+
+    SeriesModel.registerClass = function (clz) {
+      return ComponentModel.registerClass(clz);
+    };
+
+    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!
+
+      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;
+    }
+  }
+
+  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();
+  }
+
+  function dataTaskReset(context) {
+    var seriesModel = context.model;
+    seriesModel.setData(seriesModel.getRawData().cloneShallow());
+    return dataTaskProgress;
+  }
+
+  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
+
+
+  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);
+
+    if (task) {
+      // Consider case: filter, selectRange
+      task.setOutputEnd((newList || this).count());
+    }
+
+    return newList;
+  }
+
+  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;
+
+      if (task) {
+        var agentStubMap = task.agentStubMap;
+
+        if (agentStubMap) {
+          task = agentStubMap.get(seriesModel.uid);
+        }
+      }
+
+      return task;
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 ComponentView =
+  /** @class */
+  function () {
+    function ComponentView() {
+      this.group = new Group();
+      this.uid = getUID('viewComponent');
+    }
+
+    ComponentView.prototype.init = function (ecModel, api) {};
+
+    ComponentView.prototype.render = function (model, ecModel, api, payload) {};
+
+    ComponentView.prototype.dispose = function (ecModel, api) {};
+
+    ComponentView.prototype.updateView = function (model, ecModel, api, payload) {// Do nothing;
+    };
+
+    ComponentView.prototype.updateLayout = function (model, ecModel, api, payload) {// Do nothing;
+    };
+
+    ComponentView.prototype.updateVisual = function (model, ecModel, api, payload) {// Do nothing;
+    };
+    /**
+     * Hook for toggle blur target series.
+     * Can be used in marker for blur or leave blur the markers
+     */
+
+
+    ComponentView.prototype.toggleBlurSeries = function (seriesModels, isBlur, ecModel) {// Do nothing;
+    };
+    /**
+     * Traverse the new rendered elements.
+     *
+     * It will traverse the new added element in progressive rendering.
+     * And traverse all in normal rendering.
+     */
+
+
+    ComponentView.prototype.eachRendered = function (cb) {
+      var group = this.group;
+
+      if (group) {
+        group.traverse(cb);
+      }
+    };
+
+    return ComponentView;
+  }();
+
+  enableClassExtend(ComponentView);
+  enableClassManagement(ComponentView);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * @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';
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$2 = makeInner();
+  var renderPlanner = createRenderPlanner();
+
+  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
+      };
+    }
+
+    ChartView.prototype.init = function (ecModel, api) {};
+
+    ChartView.prototype.render = function (seriesModel, ecModel, api, payload) {
+      {
+        throw new Error('render method must been implemented');
+      }
+    };
+    /**
+     * Highlight series or specified data item.
+     */
+
+
+    ChartView.prototype.highlight = function (seriesModel, ecModel, api, payload) {
+      var data = seriesModel.getData(payload && payload.dataType);
+
+      if (!data) {
+        {
+          error("Unknown dataType " + payload.dataType);
+        }
+        return;
+      }
+
+      toggleHighlight(data, payload, 'emphasis');
+    };
+    /**
+     * Downplay series or specified data item.
+     */
+
+
+    ChartView.prototype.downplay = function (seriesModel, ecModel, api, payload) {
+      var data = seriesModel.getData(payload && payload.dataType);
+
+      if (!data) {
+        {
+          error("Unknown dataType " + payload.dataType);
+        }
+        return;
+      }
+
+      toggleHighlight(data, payload, 'normal');
+    };
+    /**
+     * Remove self.
+     */
+
+
+    ChartView.prototype.remove = function (ecModel, api) {
+      this.group.removeAll();
+    };
+    /**
+     * Dispose self.
+     */
+
+
+    ChartView.prototype.dispose = function (ecModel, api) {};
+
+    ChartView.prototype.updateView = function (seriesModel, ecModel, api, payload) {
+      this.render(seriesModel, ecModel, api, payload);
+    }; // FIXME never used?
+
+
+    ChartView.prototype.updateLayout = function (seriesModel, ecModel, api, payload) {
+      this.render(seriesModel, ecModel, api, payload);
+    }; // FIXME never used?
+
+
+    ChartView.prototype.updateVisual = function (seriesModel, ecModel, api, payload) {
+      this.render(seriesModel, ecModel, api, payload);
+    };
+    /**
+     * Traverse the new rendered elements.
+     *
+     * It will traverse the new added element in progressive rendering.
+     * And traverse all in normal rendering.
+     */
+
+
+    ChartView.prototype.eachRendered = function (cb) {
+      traverseElements(this.group, cb);
+    };
+
+    ChartView.markUpdateMethod = function (payload, methodName) {
+      inner$2(payload).updateMethod = methodName;
+    };
+
+    ChartView.protoInitialize = function () {
+      var proto = ChartView.prototype;
+      proto.type = 'chart';
+    }();
+
+    return ChartView;
+  }();
+  /**
+   * Set state of single element
+   */
+
+
+  function elSetState(el, state, highlightDigit) {
+    if (el && isHighDownDispatcher(el)) {
+      (state === 'emphasis' ? enterEmphasis : leaveEmphasis)(el, highlightDigit);
+    }
+  }
+
+  function toggleHighlight(data, payload, state) {
+    var dataIndex = queryDataIndex(data, payload);
+    var highlightDigit = payload && payload.highlightKey != null ? getHighlightDigit(payload.highlightKey) : null;
+
+    if (dataIndex != null) {
+      each(normalizeToArray(dataIndex), function (dataIdx) {
+        elSetState(data.getItemGraphicEl(dataIdx), state, highlightDigit);
+      });
+    } else {
+      data.eachItemGraphicEl(function (el) {
+        elSetState(el, state, highlightDigit);
+      });
+    }
+  }
+
+  enableClassExtend(ChartView, ['dispose']);
+  enableClassManagement(ChartView);
+
+  function renderTaskPlan(context) {
+    return renderPlanner(context.model);
+  }
+
+  function renderTaskReset(context) {
+    var seriesModel = context.model;
+    var ecModel = context.ecModel;
+    var api = context.api;
+    var payload = context.payload; // FIXME: remove updateView updateVisual
+
+    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 (methodName !== 'render') {
+      view[methodName](seriesModel, ecModel, api, payload);
+    }
+
+    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.
+   */
+
+  /*
+  * 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 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 || []);
+    }
+
+    var cb = function () {
+      var cbArgs = [];
+
+      for (var _i = 0; _i < arguments.length; _i++) {
+        cbArgs[_i] = arguments[_i];
+      }
+
+      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
+     */
+
+
+    cb.clear = function () {
+      if (timer) {
+        clearTimeout(timer);
+        timer = null;
+      }
+    };
+    /**
+     * Enable debounce once.
+     */
+
+
+    cb.debounceNextCall = function (debounceDelay) {
+      debounceNextCall = debounceDelay;
+    };
+
+    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');
+   * };
+   *
+   */
+
+
+  function createOrUpdate(obj, fnAttr, rate, throttleType) {
+    var fn = obj[fnAttr];
+
+    if (!fn) {
+      return;
+    }
+
+    var originFn = fn[ORIGIN_METHOD] || fn;
+    var lastThrottleType = fn[THROTTLE_TYPE];
+    var lastRate = fn[RATE];
+
+    if (lastRate !== rate || lastThrottleType !== throttleType) {
+      if (rate == null || !throttleType) {
+        return obj[fnAttr] = originFn;
+      }
+
+      fn = obj[fnAttr] = throttle(originFn, rate, throttleType === 'debounce');
+      fn[ORIGIN_METHOD] = originFn;
+      fn[THROTTLE_TYPE] = throttleType;
+      fn[RATE] = rate;
+    }
+
+    return fn;
+  }
+  /**
+   * Clear throttle. Example see throttle.createOrUpdate.
+   */
+
+
+  function clear(obj, fnAttr) {
+    var fn = obj[fnAttr];
+
+    if (fn && fn[ORIGIN_METHOD]) {
+      // Clear throttle
+      fn.clear && fn.clear();
+      obj[fnAttr] = fn[ORIGIN_METHOD];
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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];
+
+    if (!styleMapper) {
+      console.warn("Unkown style type '" + stylePath + "'.");
+      return defaultStyleMappers.itemStyle;
+    }
+
+    return styleMapper;
+  }
+
+  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;
+  }
+
+  var seriesStyleTask = {
+    createOnAllSeries: true,
+    performRawSeries: true,
+    reset: function (seriesModel, ecModel) {
+      var data = seriesModel.getData();
+      var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle
+
+      var styleModel = seriesModel.getModel(stylePath);
+      var getStyle = getStyleMapper(seriesModel, stylePath);
+      var globalStyle = getStyle(styleModel);
+      var decalOption = styleModel.getShallow('decal');
+
+      if (decalOption) {
+        data.setVisual('decal', decalOption);
+        decalOption.dirty = true;
+      } // TODO
+
+
+      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' || isFunction(globalStyle.fill) ? colorPalette : globalStyle.fill;
+        globalStyle.stroke = globalStyle.stroke === 'auto' || isFunction(globalStyle.stroke) ? colorPalette : globalStyle.stroke;
+      }
+
+      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;
+      }
+
+      var data = seriesModel.getData();
+      var stylePath = seriesModel.visualStyleAccessPath || 'itemStyle'; // Set in itemStyle
+
+      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);
+
+          if (rawItem && rawItem[stylePath]) {
+            sharedModel.option = rawItem[stylePath];
+            var style = getStyle(sharedModel);
+            var existsStyle = data.ensureUniqueItemVisual(idx, 'style');
+            extend(existsStyle, style);
+
+            if (sharedModel.option.decal) {
+              data.setItemVisual(idx, 'decal', sharedModel.option.decal);
+              sharedModel.option.decal.dirty = true;
+            }
+
+            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 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;
+        }
+
+        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;
+        }
+
+        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.
+
+        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);
+          }
+        });
+      });
+    }
+  };
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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}
+   */
+
+  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;
+
+    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
+
+
+    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 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;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 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);
+    }
+
+    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();
+      });
+    }; // If seriesModel provided, incremental threshold is check by series data.
+
+
+    Scheduler.prototype.getPerformArgs = function (task, isBlock) {
+      // For overall task
+      if (!task.__pipeline) {
+        return;
+      }
+
+      var pipeline = this._pipelineMap.get(task.__pipeline.id);
+
+      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
+      };
+    };
+
+    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()`.
+     */
+
+
+    Scheduler.prototype.updateStreamModes = function (seriesModel, view) {
+      var pipeline = this._pipelineMap.get(seriesModel.uid);
+
+      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 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`
+
+      var modDataCount = seriesModel.get('progressiveChunkMode') === 'mod' ? dataLen : null;
+      seriesModel.pipelineContext = pipeline.context = {
+        progressiveRender: progressiveRender,
+        modDataCount: modDataCount,
+        large: large
+      };
+    };
+
+    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
+        });
+
+        scheduler._pipe(seriesModel, seriesModel.dataTask);
+      });
+    };
+
+    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 = '';
+        {
+          // Currently do not need to support to sepecify them both.
+          errMsg = '"reset" and "overallReset" must not be both specified.';
+        }
+        assert(!(handler.reset && handler.overallReset), errMsg);
+        handler.reset && this._createSeriesStageTask(handler, record, ecModel, api);
+        handler.overallReset && this._createOverallStageTask(handler, record, ecModel, api);
+      }, this);
+    };
+
+    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;
+
+      this._pipe(model, renderTask);
+    };
+
+    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);
+    };
+
+    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);
+
+        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.
+
+          agentStubMap.each(function (stub) {
+            stub.perform(performArgs_1);
+          });
+
+          if (overallTask.perform(performArgs_1)) {
+            unfinished = true;
+          }
+        } else if (seriesTaskMap) {
+          seriesTaskMap.each(function (task, pipelineId) {
+            if (needSetDirty(opt, task)) {
+              task.dirty();
+            }
+
+            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.
+
+            performArgs.skip = !stageHandler.performRawSeries && ecModel.isSeriesFiltered(task.context.model);
+            scheduler.updatePayload(task, payload);
+
+            if (task.perform(performArgs)) {
+              unfinished = true;
+            }
+          });
+        }
+      });
+
+      function needSetDirty(opt, task) {
+        return opt.setDirty && (!opt.dirtyMap || opt.dirtyMap.get(task.__pipeline.id));
+      }
+
+      this.unfinished = unfinished || this.unfinished;
+    };
+
+    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;
+    };
+
+    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;
+          }
+
+          task = task.getUpstream();
+        } while (task);
+      });
+    };
+
+    Scheduler.prototype.updatePayload = function (task, payload) {
+      payload !== 'remain' && (task.context.payload = payload);
+    };
+
+    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.
+
+      if (stageHandler.createOnAllSeries) {
+        ecModel.eachRawSeries(create);
+      } else if (seriesType) {
+        ecModel.eachRawSeriesByType(seriesType, create);
+      } else if (getTargetSeries) {
+        getTargetSeries(ecModel, api).each(create);
+      }
+
+      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
+        };
+
+        scheduler._pipe(seriesModel, task);
+      }
+    };
+
+    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.
+
+      var errMsg = '';
+      {
+        errMsg = '"createOnAllSeries" do not supported for "overallReset", ' + 'becuase it will block all streams.';
+      }
+      assert(!stageHandler.createOnAllSeries, errMsg);
+
+      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
+
+        };
+        stub.agent = overallTask;
+        stub.__block = overallProgress;
+
+        scheduler._pipe(seriesModel, stub);
+      }
+
+      if (shouldOverallTaskDirty) {
+        overallTask.dirty();
+      }
+    };
+
+    Scheduler.prototype._pipe = function (seriesModel, task) {
+      var pipelineId = seriesModel.uid;
+
+      var pipeline = this._pipelineMap.get(pipelineId);
+
+      !pipeline.head && (pipeline.head = task);
+      pipeline.tail && pipeline.tail.pipe(task);
+      pipeline.tail = task;
+      task.__idxInPipeline = pipeline.count++;
+      task.__pipeline = pipeline;
+    };
+
+    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;
+  }();
+
+  function overallTaskReset(context) {
+    context.overallReset(context.ecModel, context.api, context.payload);
+  }
+
+  function stubReset(context) {
+    return context.overallProgress && stubProgress;
+  }
+
+  function stubProgress() {
+    this.agent.dirty();
+    this.getDownstream().dirty();
+  }
+
+  function stubOnDirty() {
+    this.agent && this.agent.dirty();
+  }
+
+  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();
+    }
+
+    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;
+  }
+
+  var singleSeriesTaskProgress = makeSeriesTaskProgress(0);
+
+  function makeSeriesTaskProgress(resetDefineIdx) {
+    return function (params, context) {
+      var data = context.data;
+      var resetDefine = context.resetDefines[resetDefineIdx];
+
+      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);
+      }
+    };
+  }
+
+  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 detectSeriseType(legacyFunc) {
+    seriesType = null;
+
+    try {
+      // Assume there is no async when calling `eachSeriesByType`.
+      legacyFunc(ecModelMock, apiMock);
+    } catch (e) {}
+
+    return seriesType;
+  }
+
+  var ecModelMock = {};
+  var apiMock = {};
+  var seriesType;
+  mockMethods(ecModelMock, GlobalModel);
+  mockMethods(apiMock, ExtensionAPI);
+
+  ecModelMock.eachSeriesByType = ecModelMock.eachRawSeriesByType = function (type) {
+    seriesType = type;
+  };
+
+  ecModelMock.eachComponent = function (cond) {
+    if (cond.mainType === 'series' && cond.subType) {
+      seriesType = cond.subType;
+    }
+  };
+
+  function mockMethods(target, Clz) {
+    /* eslint-disable */
+    for (var name_1 in Clz.prototype) {
+      // Do not use hasOwnProperty
+      target[name_1] = noop;
+    }
+    /* eslint-enable */
+
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * AUTO-GENERATED FILE. DO NOT MODIFY.
+   */
+
+  /*
+  * 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';
+
+  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'
+        }
+      }
+    };
+  };
+
+  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)']]
+        }
+      },
+      axisLabel: {
+        color: contrastColor
+      },
+      detail: {
+        color: '#EEF1FA'
+      }
+    },
+    candlestick: {
+      itemStyle: {
+        color: '#f64e56',
+        color0: '#54ea92',
+        borderColor: '#f64e56',
+        borderColor0: '#54ea92' // borderColor: '#ca2824',
+        // borderColor0: '#09a443'
+
+      }
+    }
+  };
+  theme.categoryAxis.splitLine.show = false;
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * 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 =
+  /** @class */
+  function () {
+    function ECEventProcessor() {}
+
+    ECEventProcessor.prototype.normalizeQuery = function (query) {
+      var cptQuery = {};
+      var dataQuery = {};
+      var otherQuery = {}; // `query` is `mainType` or `mainType.subType` of component.
+
+      if (isString(query)) {
+        var condCptType = parseClassType(query); // `.main` and `.sub` may be ''.
+
+        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 i = 0; i < suffixes_1.length; i++) {
+              var propSuffix = suffixes_1[i];
+              var suffixPos = key.lastIndexOf(propSuffix);
+
+              if (suffixPos > 0 && suffixPos === key.length - propSuffix.length) {
+                var mainType = key.slice(0, suffixPos); // Consider `dataIndex`.
+
+                if (mainType !== 'data') {
+                  cptQuery.mainType = mainType;
+                  cptQuery[propSuffix.toLowerCase()] = val;
+                  reserved = true;
+                }
+              }
+            }
+
+            if (dataKeys_1.hasOwnProperty(key)) {
+              dataQuery[key] = val;
+              reserved = true;
+            }
+
+            if (!reserved) {
+              otherQuery[key] = val;
+            }
+          });
+        }
+
+      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 (!eventInfo) {
+        return true;
+      }
+
+      var targetEl = eventInfo.targetEl;
+      var packedEvent = eventInfo.packedEvent;
+      var model = eventInfo.model;
+      var view = eventInfo.view; // For event like 'globalout'.
+
+      if (!model || !view) {
+        return true;
+      }
+
+      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];
+      }
+    };
+
+    ECEventProcessor.prototype.afterTrigger = function () {
+      // Make sure the eventInfo wont be used in next trigger.
+      this.eventInfo = null;
+    };
+
+    return ECEventProcessor;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 SYMBOL_PROPS_WITH_CB = ['symbol', 'symbolSize', 'symbolRotate', 'symbolOffset'];
+  var SYMBOL_PROPS = SYMBOL_PROPS_WITH_CB.concat(['symbolKeepAspect']); // Encoding visual for all series include which is filtered for legend drawing
+
+  var seriesSymbolTask = {
+    createOnAllSeries: true,
+    // For legend.
+    performRawSeries: true,
+    reset: function (seriesModel, ecModel) {
+      var data = seriesModel.getData();
+
+      if (seriesModel.legendIcon) {
+        data.setVisual('legendIcon', seriesModel.legendIcon);
+      }
+
+      if (!seriesModel.hasSymbolVisual) {
+        return;
+      }
+
+      var symbolOptions = {};
+      var symbolOptionsCb = {};
+      var hasCallback = false;
+
+      for (var i = 0; i < SYMBOL_PROPS_WITH_CB.length; i++) {
+        var symbolPropName = SYMBOL_PROPS_WITH_CB[i];
+        var val = seriesModel.get(symbolPropName);
+
+        if (isFunction(val)) {
+          hasCallback = true;
+          symbolOptionsCb[symbolPropName] = val;
+        } else {
+          symbolOptions[symbolPropName] = val;
+        }
+      }
+
+      symbolOptions.symbol = symbolOptions.symbol || seriesModel.defaultSymbol;
+      data.setVisual(extend({
+        legendIcon: seriesModel.legendIcon || symbolOptions.symbol,
+        symbolKeepAspect: seriesModel.get('symbolKeepAspect')
+      }, symbolOptions)); // Only visible series has each data be visual encoded
+
+      if (ecModel.isSeriesFiltered(seriesModel)) {
+        return;
+      }
+
+      var symbolPropsCb = keys(symbolOptionsCb);
+
+      function dataEach(data, idx) {
+        var rawValue = seriesModel.getRawValue(idx);
+        var params = seriesModel.getDataParams(idx);
+
+        for (var i = 0; i < symbolPropsCb.length; i++) {
+          var symbolPropName = symbolPropsCb[i];
+          data.setItemVisual(idx, symbolPropName, symbolOptionsCb[symbolPropName](rawValue, params));
+        }
+      }
+
+      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
+
+
+      if (ecModel.isSeriesFiltered(seriesModel)) {
+        return;
+      }
+
+      var data = seriesModel.getData();
+
+      function dataEach(data, idx) {
+        var itemModel = data.getItemModel(idx);
+
+        for (var i = 0; i < SYMBOL_PROPS.length; i++) {
+          var symbolPropName = SYMBOL_PROPS[i];
+          var val = itemModel.getShallow(symbolPropName, true);
+
+          if (val != null) {
+            data.setItemVisual(idx, symbolPropName, val);
+          }
+        }
+      }
+
+      return {
+        dataEach: data.hasItemOption ? dataEach : null
+      };
+    }
+  };
+  /*
+  * 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.
+   */
+
+  /*
+  * 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')];
+
+      case 'opacity':
+        return data.getItemVisual(dataIndex, 'style').opacity;
+
+      case 'symbol':
+      case 'symbolSize':
+      case 'liftZ':
+        return data.getItemVisual(dataIndex, key);
+
+      default:
+        {
+          console.warn("Unknown visual type " + key);
+        }
+    }
+  }
+
+  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;
+
+      case 'symbol':
+      case 'symbolSize':
+      case 'liftZ':
+        return data.getVisual(key);
+
+      default:
+        {
+          console.warn("Unknown visual type " + key);
+        }
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // Inlucdes: pieSelect, pieUnSelect, pieToggleSelect, mapSelect, mapUnSelect, mapToggleSelect
+
+
+  function createLegacyDataSelectAction(seriesType, ecRegisterAction) {
+    function getSeriesIndices(ecModel, payload) {
+      var seriesIndices = [];
+      ecModel.eachComponent({
+        mainType: 'series',
+        subType: seriesType,
+        query: payload
+      }, function (seriesModel) {
+        seriesIndices.push(seriesModel.seriesIndex);
+      });
+      return seriesIndices;
+    }
+
+    each([[seriesType + 'ToggleSelect', 'toggleSelect'], [seriesType + 'Select', 'select'], [seriesType + 'UnSelect', 'unselect']], function (eventsMap) {
+      ecRegisterAction(eventsMap[0], function (payload, ecModel, api) {
+        payload = extend({}, payload);
+        {
+          deprecateReplaceLog(payload.type, eventsMap[1]);
+        }
+        api.dispatchAction(extend(payload, {
+          type: eventsMap[1],
+          seriesIndex: getSeriesIndices(ecModel, payload)
+        }));
+      });
+    });
+  }
+
+  function handleSeriesLegacySelectEvents(type, eventPostfix, ecIns, ecModel, payload) {
+    var legacyEventName = type + eventPostfix;
+
+    if (!ecIns.isSilent(legacyEventName)) {
+      {
+        deprecateLog("event " + legacyEventName + " is deprecated.");
+      }
+      ecModel.eachComponent({
+        mainType: 'series',
+        subType: 'pie'
+      }, function (seriesModel) {
+        var seriesIndex = seriesModel.seriesIndex;
+        var selectedMap = seriesModel.option.selectedMap;
+        var selected = payload.selected;
+
+        for (var i = 0; i < selected.length; i++) {
+          if (selected[i].seriesIndex === seriesIndex) {
+            var data = seriesModel.getData();
+            var dataIndex = queryDataIndex(data, payload.fromActionPayload);
+            ecIns.trigger(legacyEventName, {
+              type: legacyEventName,
+              seriesId: seriesModel.id,
+              name: isArray(dataIndex) ? data.getName(dataIndex[0]) : data.getName(dataIndex),
+              selected: isString(selectedMap) ? selectedMap : extend({}, selectedMap)
+            });
+          }
+        }
+      });
+    }
+  }
+
+  function handleLegacySelectEvents(messageCenter, ecIns, api) {
+    messageCenter.on('selectchanged', function (params) {
+      var ecModel = api.getModel();
+
+      if (params.isFromClick) {
+        handleSeriesLegacySelectEvents('map', 'selectchanged', ecIns, ecModel, params);
+        handleSeriesLegacySelectEvents('pie', 'selectchanged', ecIns, ecModel, params);
+      } else if (params.fromAction === 'select') {
+        handleSeriesLegacySelectEvents('map', 'selected', ecIns, ecModel, params);
+        handleSeriesLegacySelectEvents('pie', 'selected', ecIns, ecModel, params);
+      } else if (params.fromAction === 'unselect') {
+        handleSeriesLegacySelectEvents('map', 'unselected', ecIns, ecModel, params);
+        handleSeriesLegacySelectEvents('pie', 'unselected', ecIns, ecModel, params);
+      }
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 findEventDispatcher(target, det, returnFirstMatch) {
+    var found;
+
+    while (target) {
+      if (det(target)) {
+        found = target;
+
+        if (returnFirstMatch) {
+          break;
+        }
+      }
+
+      target = target.__hostTarget || target.parent;
+    }
+
+    return found;
+  }
+
+  var wmUniqueIndex = Math.round(Math.random() * 9);
+  var supportDefineProperty = typeof Object.defineProperty === 'function';
+
+  var WeakMap = function () {
+    function WeakMap() {
+      this._id = '__ec_inner_' + wmUniqueIndex++;
+    }
+
+    WeakMap.prototype.get = function (key) {
+      return this._guard(key)[this._id];
+    };
+
+    WeakMap.prototype.set = function (key, value) {
+      var target = this._guard(key);
+
+      if (supportDefineProperty) {
+        Object.defineProperty(target, this._id, {
+          value: value,
+          enumerable: false,
+          configurable: true
+        });
+      } else {
+        target[this._id] = value;
+      }
+
+      return this;
+    };
+
+    WeakMap.prototype["delete"] = function (key) {
+      if (this.has(key)) {
+        delete this._guard(key)[this._id];
+        return true;
+      }
+
+      return false;
+    };
+
+    WeakMap.prototype.has = function (key) {
+      return !!this._guard(key)[this._id];
+    };
+
+    WeakMap.prototype._guard = function (key) {
+      if (key !== Object(key)) {
+        throw TypeError('Value of WeakMap is not a non-null object.');
+      }
+
+      return key;
+    };
+
+    return WeakMap;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // Symbol factory
+
+  /**
+   * Triangle shape
+   * @inner
+   */
+
+
+  var Triangle = Path.extend({
+    type: 'triangle',
+    shape: {
+      cx: 0,
+      cy: 0,
+      width: 0,
+      height: 0
+    },
+    buildPath: function (path, shape) {
+      var cx = shape.cx;
+      var cy = shape.cy;
+      var width = shape.width / 2;
+      var height = shape.height / 2;
+      path.moveTo(cx, cy - height);
+      path.lineTo(cx + width, cy + height);
+      path.lineTo(cx - width, cy + height);
+      path.closePath();
+    }
+  });
+  /**
+   * Diamond shape
+   * @inner
+   */
+
+  var Diamond = Path.extend({
+    type: 'diamond',
+    shape: {
+      cx: 0,
+      cy: 0,
+      width: 0,
+      height: 0
+    },
+    buildPath: function (path, shape) {
+      var cx = shape.cx;
+      var cy = shape.cy;
+      var width = shape.width / 2;
+      var height = shape.height / 2;
+      path.moveTo(cx, cy - height);
+      path.lineTo(cx + width, cy);
+      path.lineTo(cx, cy + height);
+      path.lineTo(cx - width, cy);
+      path.closePath();
+    }
+  });
+  /**
+   * Pin shape
+   * @inner
+   */
+
+  var Pin = Path.extend({
+    type: 'pin',
+    shape: {
+      // x, y on the cusp
+      x: 0,
+      y: 0,
+      width: 0,
+      height: 0
+    },
+    buildPath: function (path, shape) {
+      var x = shape.x;
+      var y = shape.y;
+      var w = shape.width / 5 * 3; // Height must be larger than width
+
+      var h = Math.max(w, shape.height);
+      var r = w / 2; // Dist on y with tangent point and circle center
+
+      var dy = r * r / (h - r);
+      var cy = y - h + r + dy;
+      var angle = Math.asin(dy / r); // Dist on x with tangent point and circle center
+
+      var dx = Math.cos(angle) * r;
+      var tanX = Math.sin(angle);
+      var tanY = Math.cos(angle);
+      var cpLen = r * 0.6;
+      var cpLen2 = r * 0.7;
+      path.moveTo(x - dx, cy + dy);
+      path.arc(x, cy, r, Math.PI - angle, Math.PI * 2 + angle);
+      path.bezierCurveTo(x + dx - tanX * cpLen, cy + dy + tanY * cpLen, x, y - cpLen2, x, y);
+      path.bezierCurveTo(x, y - cpLen2, x - dx + tanX * cpLen, cy + dy + tanY * cpLen, x - dx, cy + dy);
+      path.closePath();
+    }
+  });
+  /**
+   * Arrow shape
+   * @inner
+   */
+
+  var Arrow = Path.extend({
+    type: 'arrow',
+    shape: {
+      x: 0,
+      y: 0,
+      width: 0,
+      height: 0
+    },
+    buildPath: function (ctx, shape) {
+      var height = shape.height;
+      var width = shape.width;
+      var x = shape.x;
+      var y = shape.y;
+      var dx = width / 3 * 2;
+      ctx.moveTo(x, y);
+      ctx.lineTo(x + dx, y + height);
+      ctx.lineTo(x, y + height / 4 * 3);
+      ctx.lineTo(x - dx, y + height);
+      ctx.lineTo(x, y);
+      ctx.closePath();
+    }
+  });
+  /**
+   * Map of path contructors
+   */
+  // TODO Use function to build symbol path.
+
+  var symbolCtors = {
+    line: Line,
+    rect: Rect,
+    roundRect: Rect,
+    square: Rect,
+    circle: Circle,
+    diamond: Diamond,
+    pin: Pin,
+    arrow: Arrow,
+    triangle: Triangle
+  };
+  var symbolShapeMakers = {
+    line: function (x, y, w, h, shape) {
+      shape.x1 = x;
+      shape.y1 = y + h / 2;
+      shape.x2 = x + w;
+      shape.y2 = y + h / 2;
+    },
+    rect: function (x, y, w, h, shape) {
+      shape.x = x;
+      shape.y = y;
+      shape.width = w;
+      shape.height = h;
+    },
+    roundRect: function (x, y, w, h, shape) {
+      shape.x = x;
+      shape.y = y;
+      shape.width = w;
+      shape.height = h;
+      shape.r = Math.min(w, h) / 4;
+    },
+    square: function (x, y, w, h, shape) {
+      var size = Math.min(w, h);
+      shape.x = x;
+      shape.y = y;
+      shape.width = size;
+      shape.height = size;
+    },
+    circle: function (x, y, w, h, shape) {
+      // Put circle in the center of square
+      shape.cx = x + w / 2;
+      shape.cy = y + h / 2;
+      shape.r = Math.min(w, h) / 2;
+    },
+    diamond: function (x, y, w, h, shape) {
+      shape.cx = x + w / 2;
+      shape.cy = y + h / 2;
+      shape.width = w;
+      shape.height = h;
+    },
+    pin: function (x, y, w, h, shape) {
+      shape.x = x + w / 2;
+      shape.y = y + h / 2;
+      shape.width = w;
+      shape.height = h;
+    },
+    arrow: function (x, y, w, h, shape) {
+      shape.x = x + w / 2;
+      shape.y = y + h / 2;
+      shape.width = w;
+      shape.height = h;
+    },
+    triangle: function (x, y, w, h, shape) {
+      shape.cx = x + w / 2;
+      shape.cy = y + h / 2;
+      shape.width = w;
+      shape.height = h;
+    }
+  };
+  var symbolBuildProxies = {};
+  each(symbolCtors, function (Ctor, name) {
+    symbolBuildProxies[name] = new Ctor();
+  });
+  var SymbolClz = Path.extend({
+    type: 'symbol',
+    shape: {
+      symbolType: '',
+      x: 0,
+      y: 0,
+      width: 0,
+      height: 0
+    },
+    calculateTextPosition: function (out, config, rect) {
+      var res = calculateTextPosition(out, config, rect);
+      var shape = this.shape;
+
+      if (shape && shape.symbolType === 'pin' && config.position === 'inside') {
+        res.y = rect.y + rect.height * 0.4;
+      }
+
+      return res;
+    },
+    buildPath: function (ctx, shape, inBundle) {
+      var symbolType = shape.symbolType;
+
+      if (symbolType !== 'none') {
+        var proxySymbol = symbolBuildProxies[symbolType];
+
+        if (!proxySymbol) {
+          // Default rect
+          symbolType = 'rect';
+          proxySymbol = symbolBuildProxies[symbolType];
+        }
+
+        symbolShapeMakers[symbolType](shape.x, shape.y, shape.width, shape.height, proxySymbol.shape);
+        proxySymbol.buildPath(ctx, proxySymbol.shape, inBundle);
+      }
+    }
+  }); // Provide setColor helper method to avoid determine if set the fill or stroke outside
+
+  function symbolPathSetColor(color, innerColor) {
+    if (this.type !== 'image') {
+      var symbolStyle = this.style;
+
+      if (this.__isEmptyBrush) {
+        symbolStyle.stroke = color;
+        symbolStyle.fill = innerColor || '#fff'; // TODO Same width with lineStyle in LineView
+
+        symbolStyle.lineWidth = 2;
+      } else if (this.shape.symbolType === 'line') {
+        symbolStyle.stroke = color;
+      } else {
+        symbolStyle.fill = color;
+      }
+
+      this.markRedraw();
+    }
+  }
+  /**
+   * Create a symbol element with given symbol configuration: shape, x, y, width, height, color
+   */
+
+
+  function createSymbol(symbolType, x, y, w, h, color, // whether to keep the ratio of w/h,
+  keepAspect) {
+    // TODO Support image object, DynamicImage.
+    var isEmpty = symbolType.indexOf('empty') === 0;
+
+    if (isEmpty) {
+      symbolType = symbolType.substr(5, 1).toLowerCase() + symbolType.substr(6);
+    }
+
+    var symbolPath;
+
+    if (symbolType.indexOf('image://') === 0) {
+      symbolPath = makeImage(symbolType.slice(8), new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover');
+    } else if (symbolType.indexOf('path://') === 0) {
+      symbolPath = makePath(symbolType.slice(7), {}, new BoundingRect(x, y, w, h), keepAspect ? 'center' : 'cover');
+    } else {
+      symbolPath = new SymbolClz({
+        shape: {
+          symbolType: symbolType,
+          x: x,
+          y: y,
+          width: w,
+          height: h
+        }
+      });
+    }
+
+    symbolPath.__isEmptyBrush = isEmpty; // TODO Should deprecate setColor
+
+    symbolPath.setColor = symbolPathSetColor;
+
+    if (color) {
+      symbolPath.setColor(color);
+    }
+
+    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 isSafeNum(num) {
+    return isFinite(num);
+  }
+
+  function createLinearGradient(ctx, obj, rect) {
+    var x = obj.x == null ? 0 : obj.x;
+    var x2 = obj.x2 == null ? 1 : obj.x2;
+    var y = obj.y == null ? 0 : obj.y;
+    var y2 = obj.y2 == null ? 0 : obj.y2;
+
+    if (!obj.global) {
+      x = x * rect.width + rect.x;
+      x2 = x2 * rect.width + rect.x;
+      y = y * rect.height + rect.y;
+      y2 = y2 * rect.height + rect.y;
+    }
+
+    x = isSafeNum(x) ? x : 0;
+    x2 = isSafeNum(x2) ? x2 : 1;
+    y = isSafeNum(y) ? y : 0;
+    y2 = isSafeNum(y2) ? y2 : 0;
+    var canvasGradient = ctx.createLinearGradient(x, y, x2, y2);
+    return canvasGradient;
+  }
+
+  function createRadialGradient(ctx, obj, rect) {
+    var width = rect.width;
+    var height = rect.height;
+    var min = Math.min(width, height);
+    var x = obj.x == null ? 0.5 : obj.x;
+    var y = obj.y == null ? 0.5 : obj.y;
+    var r = obj.r == null ? 0.5 : obj.r;
+
+    if (!obj.global) {
+      x = x * width + rect.x;
+      y = y * height + rect.y;
+      r = r * min;
+    }
+
+    x = isSafeNum(x) ? x : 0.5;
+    y = isSafeNum(y) ? y : 0.5;
+    r = r >= 0 && isSafeNum(r) ? r : 0.5;
+    var canvasGradient = ctx.createRadialGradient(x, y, 0, x, y, r);
+    return canvasGradient;
+  }
+
+  function getCanvasGradient(ctx, obj, rect) {
+    var canvasGradient = obj.type === 'radial' ? createRadialGradient(ctx, obj, rect) : createLinearGradient(ctx, obj, rect);
+    var colorStops = obj.colorStops;
+
+    for (var i = 0; i < colorStops.length; i++) {
+      canvasGradient.addColorStop(colorStops[i].offset, colorStops[i].color);
+    }
+
+    return canvasGradient;
+  }
+
+  function isClipPathChanged(clipPaths, prevClipPaths) {
+    if (clipPaths === prevClipPaths || !clipPaths && !prevClipPaths) {
+      return false;
+    }
+
+    if (!clipPaths || !prevClipPaths || clipPaths.length !== prevClipPaths.length) {
+      return true;
+    }
+
+    for (var i = 0; i < clipPaths.length; i++) {
+      if (clipPaths[i] !== prevClipPaths[i]) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  function parseInt10(val) {
+    return parseInt(val, 10);
+  }
+
+  function getSize(root, whIdx, opts) {
+    var wh = ['width', 'height'][whIdx];
+    var cwh = ['clientWidth', 'clientHeight'][whIdx];
+    var plt = ['paddingLeft', 'paddingTop'][whIdx];
+    var prb = ['paddingRight', 'paddingBottom'][whIdx];
+
+    if (opts[wh] != null && opts[wh] !== 'auto') {
+      return parseFloat(opts[wh]);
+    }
+
+    var stl = document.defaultView.getComputedStyle(root);
+    return (root[cwh] || parseInt10(stl[wh]) || parseInt10(root.style[wh])) - (parseInt10(stl[plt]) || 0) - (parseInt10(stl[prb]) || 0) | 0;
+  }
+
+  function normalizeLineDash(lineType, lineWidth) {
+    if (!lineType || lineType === 'solid' || !(lineWidth > 0)) {
+      return null;
+    }
+
+    return lineType === 'dashed' ? [4 * lineWidth, 2 * lineWidth] : lineType === 'dotted' ? [lineWidth] : isNumber(lineType) ? [lineType] : isArray(lineType) ? lineType : null;
+  }
+
+  function getLineDash(el) {
+    var style = el.style;
+    var lineDash = style.lineDash && style.lineWidth > 0 && normalizeLineDash(style.lineDash, style.lineWidth);
+    var lineDashOffset = style.lineDashOffset;
+
+    if (lineDash) {
+      var lineScale_1 = style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1;
+
+      if (lineScale_1 && lineScale_1 !== 1) {
+        lineDash = map(lineDash, function (rawVal) {
+          return rawVal / lineScale_1;
+        });
+        lineDashOffset /= lineScale_1;
+      }
+    }
+
+    return [lineDash, lineDashOffset];
+  }
+
+  var pathProxyForDraw = new PathProxy(true);
+
+  function styleHasStroke(style) {
+    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';
+  }
+
+  function doFillPath(ctx, style) {
+    if (style.fillOpacity != null && style.fillOpacity !== 1) {
+      var originalGlobalAlpha = ctx.globalAlpha;
+      ctx.globalAlpha = style.fillOpacity * style.opacity;
+      ctx.fill();
+      ctx.globalAlpha = originalGlobalAlpha;
+    } else {
+      ctx.fill();
+    }
+  }
+
+  function doStrokePath(ctx, style) {
+    if (style.strokeOpacity != null && style.strokeOpacity !== 1) {
+      var originalGlobalAlpha = ctx.globalAlpha;
+      ctx.globalAlpha = style.strokeOpacity * style.opacity;
+      ctx.stroke();
+      ctx.globalAlpha = originalGlobalAlpha;
+    } else {
+      ctx.stroke();
+    }
+  }
+
+  function createCanvasPattern(ctx, pattern, el) {
+    var image = createOrUpdateImage(pattern.image, pattern.__image, el);
+
+    if (isImageReady(image)) {
+      var canvasPattern = ctx.createPattern(image, pattern.repeat || 'repeat');
+
+      if (typeof DOMMatrix === 'function' && canvasPattern && canvasPattern.setTransform) {
+        var matrix = new DOMMatrix();
+        matrix.translateSelf(pattern.x || 0, pattern.y || 0);
+        matrix.rotateSelf(0, 0, (pattern.rotation || 0) * RADIAN_TO_DEGREE);
+        matrix.scaleSelf(pattern.scaleX || 1, pattern.scaleY || 1);
+        canvasPattern.setTransform(matrix);
+      }
+
+      return canvasPattern;
+    }
+  }
+
+  function brushPath(ctx, el, style, inBatch) {
+    var _a;
+
+    var hasStroke = styleHasStroke(style);
+    var hasFill = styleHasFill(style);
+    var strokePercent = style.strokePercent;
+    var strokePart = strokePercent < 1;
+    var firstDraw = !el.path;
+
+    if ((!el.silent || strokePart) && firstDraw) {
+      el.createPathProxy();
+    }
+
+    var path = el.path || pathProxyForDraw;
+    var dirtyFlag = el.__dirty;
+
+    if (!inBatch) {
+      var fill = style.fill;
+      var stroke = style.stroke;
+      var hasFillGradient = hasFill && !!fill.colorStops;
+      var hasStrokeGradient = hasStroke && !!stroke.colorStops;
+      var hasFillPattern = hasFill && !!fill.image;
+      var hasStrokePattern = hasStroke && !!stroke.image;
+      var fillGradient = void 0;
+      var strokeGradient = void 0;
+      var fillPattern = void 0;
+      var strokePattern = void 0;
+      var rect = void 0;
+
+      if (hasFillGradient || hasStrokeGradient) {
+        rect = el.getBoundingRect();
+      }
+
+      if (hasFillGradient) {
+        fillGradient = dirtyFlag ? getCanvasGradient(ctx, fill, rect) : el.__canvasFillGradient;
+        el.__canvasFillGradient = fillGradient;
+      }
+
+      if (hasStrokeGradient) {
+        strokeGradient = dirtyFlag ? getCanvasGradient(ctx, stroke, rect) : el.__canvasStrokeGradient;
+        el.__canvasStrokeGradient = strokeGradient;
+      }
+
+      if (hasFillPattern) {
+        fillPattern = dirtyFlag || !el.__canvasFillPattern ? createCanvasPattern(ctx, fill, el) : el.__canvasFillPattern;
+        el.__canvasFillPattern = fillPattern;
+      }
+
+      if (hasStrokePattern) {
+        strokePattern = dirtyFlag || !el.__canvasStrokePattern ? createCanvasPattern(ctx, stroke, el) : el.__canvasStrokePattern;
+        el.__canvasStrokePattern = fillPattern;
+      }
+
+      if (hasFillGradient) {
+        ctx.fillStyle = fillGradient;
+      } else if (hasFillPattern) {
+        if (fillPattern) {
+          ctx.fillStyle = fillPattern;
+        } else {
+          hasFill = false;
+        }
+      }
+
+      if (hasStrokeGradient) {
+        ctx.strokeStyle = strokeGradient;
+      } else if (hasStrokePattern) {
+        if (strokePattern) {
+          ctx.strokeStyle = strokePattern;
+        } else {
+          hasStroke = false;
+        }
+      }
+    }
+
+    var scale = el.getGlobalScale();
+    path.setScale(scale[0], scale[1], el.segmentIgnoreThreshold);
+    var lineDash;
+    var lineDashOffset;
+
+    if (ctx.setLineDash && style.lineDash) {
+      _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1];
+    }
+
+    var needsRebuild = true;
+
+    if (firstDraw || dirtyFlag & SHAPE_CHANGED_BIT) {
+      path.setDPR(ctx.dpr);
+
+      if (strokePart) {
+        path.setContext(null);
+      } else {
+        path.setContext(ctx);
+        needsRebuild = false;
+      }
+
+      path.reset();
+      el.buildPath(path, el.shape, inBatch);
+      path.toStatic();
+      el.pathUpdated();
+    }
+
+    if (needsRebuild) {
+      path.rebuildPath(ctx, strokePart ? strokePercent : 1);
+    }
+
+    if (lineDash) {
+      ctx.setLineDash(lineDash);
+      ctx.lineDashOffset = lineDashOffset;
+    }
+
+    if (!inBatch) {
+      if (style.strokeFirst) {
+        if (hasStroke) {
+          doStrokePath(ctx, style);
+        }
+
+        if (hasFill) {
+          doFillPath(ctx, style);
+        }
+      } else {
+        if (hasFill) {
+          doFillPath(ctx, style);
+        }
+
+        if (hasStroke) {
+          doStrokePath(ctx, style);
+        }
+      }
+    }
+
+    if (lineDash) {
+      ctx.setLineDash([]);
+    }
+  }
+
+  function brushImage(ctx, el, style) {
+    var image = el.__image = createOrUpdateImage(style.image, el.__image, el, el.onload);
+
+    if (!image || !isImageReady(image)) {
+      return;
+    }
+
+    var x = style.x || 0;
+    var y = style.y || 0;
+    var width = el.getWidth();
+    var height = el.getHeight();
+    var aspect = image.width / image.height;
+
+    if (width == null && height != null) {
+      width = height * aspect;
+    } else if (height == null && width != null) {
+      height = width / aspect;
+    } else if (width == null && height == null) {
+      width = image.width;
+      height = image.height;
+    }
+
+    if (style.sWidth && style.sHeight) {
+      var sx = style.sx || 0;
+      var sy = style.sy || 0;
+      ctx.drawImage(image, sx, sy, style.sWidth, style.sHeight, x, y, width, height);
+    } else if (style.sx && style.sy) {
+      var sx = style.sx;
+      var sy = style.sy;
+      var sWidth = width - sx;
+      var sHeight = height - sy;
+      ctx.drawImage(image, sx, sy, sWidth, sHeight, x, y, width, height);
+    } else {
+      ctx.drawImage(image, x, y, width, height);
+    }
+  }
+
+  function brushText(ctx, el, style) {
+    var _a;
+
+    var text = style.text;
+    text != null && (text += '');
+
+    if (text) {
+      ctx.font = style.font || DEFAULT_FONT;
+      ctx.textAlign = style.textAlign;
+      ctx.textBaseline = style.textBaseline;
+      var lineDash = void 0;
+      var lineDashOffset = void 0;
+
+      if (ctx.setLineDash && style.lineDash) {
+        _a = getLineDash(el), lineDash = _a[0], lineDashOffset = _a[1];
+      }
+
+      if (lineDash) {
+        ctx.setLineDash(lineDash);
+        ctx.lineDashOffset = lineDashOffset;
+      }
+
+      if (style.strokeFirst) {
+        if (styleHasStroke(style)) {
+          ctx.strokeText(text, style.x, style.y);
+        }
+
+        if (styleHasFill(style)) {
+          ctx.fillText(text, style.x, style.y);
+        }
+      } else {
+        if (styleHasFill(style)) {
+          ctx.fillText(text, style.x, style.y);
+        }
+
+        if (styleHasStroke(style)) {
+          ctx.strokeText(text, style.x, style.y);
+        }
+      }
+
+      if (lineDash) {
+        ctx.setLineDash([]);
+      }
+    }
+  }
+
+  var SHADOW_NUMBER_PROPS = ['shadowBlur', 'shadowOffsetX', 'shadowOffsetY'];
+  var STROKE_PROPS = [['lineCap', 'butt'], ['lineJoin', 'miter'], ['miterLimit', 10]];
+
+  function bindCommonProps(ctx, style, prevStyle, forceSetAll, scope) {
+    var styleChanged = false;
+
+    if (!forceSetAll) {
+      prevStyle = prevStyle || {};
+
+      if (style === prevStyle) {
+        return false;
+      }
+    }
+
+    if (forceSetAll || style.opacity !== prevStyle.opacity) {
+      flushPathDrawn(ctx, scope);
+      styleChanged = true;
+      var opacity = Math.max(Math.min(style.opacity, 1), 0);
+      ctx.globalAlpha = isNaN(opacity) ? DEFAULT_COMMON_STYLE.opacity : opacity;
+    }
+
+    if (forceSetAll || style.blend !== prevStyle.blend) {
+      if (!styleChanged) {
+        flushPathDrawn(ctx, scope);
+        styleChanged = true;
+      }
+
+      ctx.globalCompositeOperation = style.blend || DEFAULT_COMMON_STYLE.blend;
+    }
+
+    for (var i = 0; i < SHADOW_NUMBER_PROPS.length; i++) {
+      var propName = SHADOW_NUMBER_PROPS[i];
+
+      if (forceSetAll || style[propName] !== prevStyle[propName]) {
+        if (!styleChanged) {
+          flushPathDrawn(ctx, scope);
+          styleChanged = true;
+        }
+
+        ctx[propName] = ctx.dpr * (style[propName] || 0);
+      }
+    }
+
+    if (forceSetAll || style.shadowColor !== prevStyle.shadowColor) {
+      if (!styleChanged) {
+        flushPathDrawn(ctx, scope);
+        styleChanged = true;
+      }
+
+      ctx.shadowColor = style.shadowColor || DEFAULT_COMMON_STYLE.shadowColor;
+    }
+
+    return styleChanged;
+  }
+
+  function bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetAll, scope) {
+    var style = getStyle(el, scope.inHover);
+    var prevStyle = forceSetAll ? null : prevEl && getStyle(prevEl, scope.inHover) || {};
+
+    if (style === prevStyle) {
+      return false;
+    }
+
+    var styleChanged = bindCommonProps(ctx, style, prevStyle, forceSetAll, scope);
+
+    if (forceSetAll || style.fill !== prevStyle.fill) {
+      if (!styleChanged) {
+        flushPathDrawn(ctx, scope);
+        styleChanged = true;
+      }
+
+      isValidStrokeFillStyle(style.fill) && (ctx.fillStyle = style.fill);
+    }
+
+    if (forceSetAll || style.stroke !== prevStyle.stroke) {
+      if (!styleChanged) {
+        flushPathDrawn(ctx, scope);
+        styleChanged = true;
+      }
+
+      isValidStrokeFillStyle(style.stroke) && (ctx.strokeStyle = style.stroke);
+    }
+
+    if (forceSetAll || style.opacity !== prevStyle.opacity) {
+      if (!styleChanged) {
+        flushPathDrawn(ctx, scope);
+        styleChanged = true;
+      }
+
+      ctx.globalAlpha = style.opacity == null ? 1 : style.opacity;
+    }
+
+    if (el.hasStroke()) {
+      var lineWidth = style.lineWidth;
+      var newLineWidth = lineWidth / (style.strokeNoScale && el.getLineScale ? el.getLineScale() : 1);
+
+      if (ctx.lineWidth !== newLineWidth) {
+        if (!styleChanged) {
+          flushPathDrawn(ctx, scope);
+          styleChanged = true;
+        }
+
+        ctx.lineWidth = newLineWidth;
+      }
+    }
+
+    for (var i = 0; i < STROKE_PROPS.length; i++) {
+      var prop = STROKE_PROPS[i];
+      var propName = prop[0];
+
+      if (forceSetAll || style[propName] !== prevStyle[propName]) {
+        if (!styleChanged) {
+          flushPathDrawn(ctx, scope);
+          styleChanged = true;
+        }
+
+        ctx[propName] = style[propName] || prop[1];
+      }
+    }
+
+    return styleChanged;
+  }
+
+  function bindImageStyle(ctx, el, prevEl, forceSetAll, scope) {
+    return bindCommonProps(ctx, getStyle(el, scope.inHover), prevEl && getStyle(prevEl, scope.inHover), forceSetAll, scope);
+  }
+
+  function setContextTransform(ctx, el) {
+    var m = el.transform;
+    var dpr = ctx.dpr || 1;
+
+    if (m) {
+      ctx.setTransform(dpr * m[0], dpr * m[1], dpr * m[2], dpr * m[3], dpr * m[4], dpr * m[5]);
+    } else {
+      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
+    }
+  }
+
+  function updateClipStatus(clipPaths, ctx, scope) {
+    var allClipped = false;
+
+    for (var i = 0; i < clipPaths.length; i++) {
+      var clipPath = clipPaths[i];
+      allClipped = allClipped || clipPath.isZeroArea();
+      setContextTransform(ctx, clipPath);
+      ctx.beginPath();
+      clipPath.buildPath(ctx, clipPath.shape);
+      ctx.clip();
+    }
+
+    scope.allClipped = allClipped;
+  }
+
+  function isTransformChanged(m0, m1) {
+    if (m0 && m1) {
+      return m0[0] !== m1[0] || m0[1] !== m1[1] || m0[2] !== m1[2] || m0[3] !== m1[3] || m0[4] !== m1[4] || m0[5] !== m1[5];
+    } else if (!m0 && !m1) {
+      return false;
+    }
+
+    return true;
+  }
+
+  var DRAW_TYPE_PATH = 1;
+  var DRAW_TYPE_IMAGE = 2;
+  var DRAW_TYPE_TEXT = 3;
+  var DRAW_TYPE_INCREMENTAL = 4;
+
+  function canPathBatch(style) {
+    var hasFill = styleHasFill(style);
+    var hasStroke = styleHasStroke(style);
+    return !(style.lineDash || !(+hasFill ^ +hasStroke) || hasFill && typeof style.fill !== 'string' || hasStroke && typeof style.stroke !== 'string' || style.strokePercent < 1 || style.strokeOpacity < 1 || style.fillOpacity < 1);
+  }
+
+  function flushPathDrawn(ctx, scope) {
+    scope.batchFill && ctx.fill();
+    scope.batchStroke && ctx.stroke();
+    scope.batchFill = '';
+    scope.batchStroke = '';
+  }
+
+  function getStyle(el, inHover) {
+    return inHover ? el.__hoverStyle || el.style : el.style;
+  }
+
+  function brushSingle(ctx, el) {
+    brush(ctx, el, {
+      inHover: false,
+      viewWidth: 0,
+      viewHeight: 0
+    }, true);
+  }
+
+  function brush(ctx, el, scope, isLast) {
+    var m = el.transform;
+
+    if (!el.shouldBePainted(scope.viewWidth, scope.viewHeight, false, false)) {
+      el.__dirty &= ~REDRAW_BIT;
+      el.__isRendered = false;
+      return;
+    }
+
+    var clipPaths = el.__clipPaths;
+    var prevElClipPaths = scope.prevElClipPaths;
+    var forceSetTransform = false;
+    var forceSetStyle = false;
+
+    if (!prevElClipPaths || isClipPathChanged(clipPaths, prevElClipPaths)) {
+      if (prevElClipPaths && prevElClipPaths.length) {
+        flushPathDrawn(ctx, scope);
+        ctx.restore();
+        forceSetStyle = forceSetTransform = true;
+        scope.prevElClipPaths = null;
+        scope.allClipped = false;
+        scope.prevEl = null;
+      }
+
+      if (clipPaths && clipPaths.length) {
+        flushPathDrawn(ctx, scope);
+        ctx.save();
+        updateClipStatus(clipPaths, ctx, scope);
+        forceSetTransform = true;
+      }
+
+      scope.prevElClipPaths = clipPaths;
+    }
+
+    if (scope.allClipped) {
+      el.__isRendered = false;
+      return;
+    }
+
+    el.beforeBrush && el.beforeBrush();
+    el.innerBeforeBrush();
+    var prevEl = scope.prevEl;
+
+    if (!prevEl) {
+      forceSetStyle = forceSetTransform = true;
+    }
+
+    var canBatchPath = el instanceof Path && el.autoBatch && canPathBatch(el.style);
+
+    if (forceSetTransform || isTransformChanged(m, prevEl.transform)) {
+      flushPathDrawn(ctx, scope);
+      setContextTransform(ctx, el);
+    } else if (!canBatchPath) {
+      flushPathDrawn(ctx, scope);
+    }
+
+    var style = getStyle(el, scope.inHover);
+
+    if (el instanceof Path) {
+      if (scope.lastDrawType !== DRAW_TYPE_PATH) {
+        forceSetStyle = true;
+        scope.lastDrawType = DRAW_TYPE_PATH;
+      }
+
+      bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope);
+
+      if (!canBatchPath || !scope.batchFill && !scope.batchStroke) {
+        ctx.beginPath();
+      }
+
+      brushPath(ctx, el, style, canBatchPath);
+
+      if (canBatchPath) {
+        scope.batchFill = style.fill || '';
+        scope.batchStroke = style.stroke || '';
+      }
+    } else {
+      if (el instanceof TSpan) {
+        if (scope.lastDrawType !== DRAW_TYPE_TEXT) {
+          forceSetStyle = true;
+          scope.lastDrawType = DRAW_TYPE_TEXT;
+        }
+
+        bindPathAndTextCommonStyle(ctx, el, prevEl, forceSetStyle, scope);
+        brushText(ctx, el, style);
+      } else if (el instanceof ZRImage) {
+        if (scope.lastDrawType !== DRAW_TYPE_IMAGE) {
+          forceSetStyle = true;
+          scope.lastDrawType = DRAW_TYPE_IMAGE;
+        }
+
+        bindImageStyle(ctx, el, prevEl, forceSetStyle, scope);
+        brushImage(ctx, el, style);
+      } else if (el.getTemporalDisplayables) {
+        if (scope.lastDrawType !== DRAW_TYPE_INCREMENTAL) {
+          forceSetStyle = true;
+          scope.lastDrawType = DRAW_TYPE_INCREMENTAL;
+        }
+
+        brushIncremental(ctx, el, scope);
+      }
+    }
+
+    if (canBatchPath && isLast) {
+      flushPathDrawn(ctx, scope);
+    }
+
+    el.innerAfterBrush();
+    el.afterBrush && el.afterBrush();
+    scope.prevEl = el;
+    el.__dirty = 0;
+    el.__isRendered = true;
+  }
+
+  function brushIncremental(ctx, el, scope) {
+    var displayables = el.getDisplayables();
+    var temporalDisplayables = el.getTemporalDisplayables();
+    ctx.save();
+    var innerScope = {
+      prevElClipPaths: null,
+      prevEl: null,
+      allClipped: false,
+      viewWidth: scope.viewWidth,
+      viewHeight: scope.viewHeight,
+      inHover: scope.inHover
+    };
+    var i;
+    var len;
+
+    for (i = el.getCursor(), len = displayables.length; i < len; i++) {
+      var displayable = displayables[i];
+      displayable.beforeBrush && displayable.beforeBrush();
+      displayable.innerBeforeBrush();
+      brush(ctx, displayable, innerScope, i === len - 1);
+      displayable.innerAfterBrush();
+      displayable.afterBrush && displayable.afterBrush();
+      innerScope.prevEl = displayable;
+    }
+
+    for (var i_1 = 0, len_1 = temporalDisplayables.length; i_1 < len_1; i_1++) {
+      var displayable = temporalDisplayables[i_1];
+      displayable.beforeBrush && displayable.beforeBrush();
+      displayable.innerBeforeBrush();
+      brush(ctx, displayable, innerScope, i_1 === len_1 - 1);
+      displayable.innerAfterBrush();
+      displayable.afterBrush && displayable.afterBrush();
+      innerScope.prevEl = displayable;
+    }
+
+    el.clearTemporalDisplayables();
+    el.notClear = true;
+    ctx.restore();
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 decalMap = new WeakMap();
+  var decalCache = new LRU(100);
+  var decalKeys = ['symbol', 'symbolSize', 'symbolKeepAspect', 'color', 'backgroundColor', 'dashArrayX', 'dashArrayY', 'maxTileWidth', 'maxTileHeight'];
+  /**
+   * Create or update pattern image from decal options
+   *
+   * @param {InnerDecalObject | 'none'} decalObject decal options, 'none' if no decal
+   * @return {Pattern} pattern with generated image, null if no decal
+   */
+
+  function createOrUpdatePatternFromDecal(decalObject, api) {
+    if (decalObject === 'none') {
+      return null;
+    }
+
+    var dpr = api.getDevicePixelRatio();
+    var zr = api.getZr();
+    var isSVG = zr.painter.type === 'svg';
+
+    if (decalObject.dirty) {
+      decalMap["delete"](decalObject);
+    }
+
+    var oldPattern = decalMap.get(decalObject);
+
+    if (oldPattern) {
+      return oldPattern;
+    }
+
+    var decalOpt = defaults(decalObject, {
+      symbol: 'rect',
+      symbolSize: 1,
+      symbolKeepAspect: true,
+      color: 'rgba(0, 0, 0, 0.2)',
+      backgroundColor: null,
+      dashArrayX: 5,
+      dashArrayY: 5,
+      rotation: 0,
+      maxTileWidth: 512,
+      maxTileHeight: 512
+    });
+
+    if (decalOpt.backgroundColor === 'none') {
+      decalOpt.backgroundColor = null;
+    }
+
+    var pattern = {
+      repeat: 'repeat'
+    };
+    setPatternnSource(pattern);
+    pattern.rotation = decalOpt.rotation;
+    pattern.scaleX = pattern.scaleY = isSVG ? 1 : 1 / dpr;
+    decalMap.set(decalObject, pattern);
+    decalObject.dirty = false;
+    return pattern;
+
+    function setPatternnSource(pattern) {
+      var keys$$1 = [dpr];
+      var isValidKey = true;
+
+      for (var i = 0; i < decalKeys.length; ++i) {
+        var value = decalOpt[decalKeys[i]];
+
+        if (value != null && !isArray(value) && !isString(value) && !isNumber(value) && typeof value !== 'boolean') {
+          isValidKey = false;
+          break;
+        }
+
+        keys$$1.push(value);
+      }
+
+      var cacheKey;
+
+      if (isValidKey) {
+        cacheKey = keys$$1.join(',') + (isSVG ? '-svg' : '');
+        var cache = decalCache.get(cacheKey);
+
+        if (cache) {
+          isSVG ? pattern.svgElement = cache : pattern.image = cache;
+        }
+      }
+
+      var dashArrayX = normalizeDashArrayX(decalOpt.dashArrayX);
+      var dashArrayY = normalizeDashArrayY(decalOpt.dashArrayY);
+      var symbolArray = normalizeSymbolArray(decalOpt.symbol);
+      var lineBlockLengthsX = getLineBlockLengthX(dashArrayX);
+      var lineBlockLengthY = getLineBlockLengthY(dashArrayY);
+      var canvas = !isSVG && platformApi.createCanvas();
+      var svgRoot = isSVG && {
+        tag: 'g',
+        attrs: {},
+        key: 'dcl',
+        children: []
+      };
+      var pSize = getPatternSize();
+      var ctx;
+
+      if (canvas) {
+        canvas.width = pSize.width * dpr;
+        canvas.height = pSize.height * dpr;
+        ctx = canvas.getContext('2d');
+      }
+
+      brushDecal();
+
+      if (isValidKey) {
+        decalCache.put(cacheKey, canvas || svgRoot);
+      }
+
+      pattern.image = canvas;
+      pattern.svgElement = svgRoot;
+      pattern.svgWidth = pSize.width;
+      pattern.svgHeight = pSize.height;
+      /**
+       * Get minumum length that can make a repeatable pattern.
+       *
+       * @return {Object} pattern width and height
+       */
+
+      function getPatternSize() {
+        /**
+         * For example, if dash is [[3, 2], [2, 1]] for X, it looks like
+         * |---  ---  ---  ---  --- ...
+         * |-- -- -- -- -- -- -- -- ...
+         * |---  ---  ---  ---  --- ...
+         * |-- -- -- -- -- -- -- -- ...
+         * So the minumum length of X is 15,
+         * which is the least common multiple of `3 + 2` and `2 + 1`
+         * |---  ---  ---  |---  --- ...
+         * |-- -- -- -- -- |-- -- -- ...
+         */
+        var width = 1;
+
+        for (var i = 0, xlen = lineBlockLengthsX.length; i < xlen; ++i) {
+          width = getLeastCommonMultiple(width, lineBlockLengthsX[i]);
+        }
+
+        var symbolRepeats = 1;
+
+        for (var i = 0, xlen = symbolArray.length; i < xlen; ++i) {
+          symbolRepeats = getLeastCommonMultiple(symbolRepeats, symbolArray[i].length);
+        }
+
+        width *= symbolRepeats;
+        var height = lineBlockLengthY * lineBlockLengthsX.length * symbolArray.length;
+        {
+          var warn = function (attrName) {
+            /* eslint-disable-next-line */
+            console.warn("Calculated decal size is greater than " + attrName + " due to decal option settings so " + attrName + " is used for the decal size. Please consider changing the decal option to make a smaller decal or set " + attrName + " to be larger to avoid incontinuity.");
+          };
+
+          if (width > decalOpt.maxTileWidth) {
+            warn('maxTileWidth');
+          }
+
+          if (height > decalOpt.maxTileHeight) {
+            warn('maxTileHeight');
+          }
+        }
+        return {
+          width: Math.max(1, Math.min(width, decalOpt.maxTileWidth)),
+          height: Math.max(1, Math.min(height, decalOpt.maxTileHeight))
+        };
+      }
+
+      function brushDecal() {
+        if (ctx) {
+          ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+          if (decalOpt.backgroundColor) {
+            ctx.fillStyle = decalOpt.backgroundColor;
+            ctx.fillRect(0, 0, canvas.width, canvas.height);
+          }
+        }
+
+        var ySum = 0;
+
+        for (var i = 0; i < dashArrayY.length; ++i) {
+          ySum += dashArrayY[i];
+        }
+
+        if (ySum <= 0) {
+          // dashArrayY is 0, draw nothing
+          return;
+        }
+
+        var y = -lineBlockLengthY;
+        var yId = 0;
+        var yIdTotal = 0;
+        var xId0 = 0;
+
+        while (y < pSize.height) {
+          if (yId % 2 === 0) {
+            var symbolYId = yIdTotal / 2 % symbolArray.length;
+            var x = 0;
+            var xId1 = 0;
+            var xId1Total = 0;
+
+            while (x < pSize.width * 2) {
+              var xSum = 0;
+
+              for (var i = 0; i < dashArrayX[xId0].length; ++i) {
+                xSum += dashArrayX[xId0][i];
+              }
+
+              if (xSum <= 0) {
+                // Skip empty line
+                break;
+              } // E.g., [15, 5, 20, 5] draws only for 15 and 20
+
+
+              if (xId1 % 2 === 0) {
+                var size = (1 - decalOpt.symbolSize) * 0.5;
+                var left = x + dashArrayX[xId0][xId1] * size;
+                var top_1 = y + dashArrayY[yId] * size;
+                var width = dashArrayX[xId0][xId1] * decalOpt.symbolSize;
+                var height = dashArrayY[yId] * decalOpt.symbolSize;
+                var symbolXId = xId1Total / 2 % symbolArray[symbolYId].length;
+                brushSymbol(left, top_1, width, height, symbolArray[symbolYId][symbolXId]);
+              }
+
+              x += dashArrayX[xId0][xId1];
+              ++xId1Total;
+              ++xId1;
+
+              if (xId1 === dashArrayX[xId0].length) {
+                xId1 = 0;
+              }
+            }
+
+            ++xId0;
+
+            if (xId0 === dashArrayX.length) {
+              xId0 = 0;
+            }
+          }
+
+          y += dashArrayY[yId];
+          ++yIdTotal;
+          ++yId;
+
+          if (yId === dashArrayY.length) {
+            yId = 0;
+          }
+        }
+
+        function brushSymbol(x, y, width, height, symbolType) {
+          var scale = isSVG ? 1 : dpr;
+          var symbol = createSymbol(symbolType, x * scale, y * scale, width * scale, height * scale, decalOpt.color, decalOpt.symbolKeepAspect);
+
+          if (isSVG) {
+            var symbolVNode = zr.painter.renderOneToVNode(symbol);
+
+            if (symbolVNode) {
+              svgRoot.children.push(symbolVNode);
+            }
+          } else {
+            // Paint to canvas for all other renderers.
+            brushSingle(ctx, symbol);
+          }
+        }
+      }
+    }
+  }
+  /**
+   * Convert symbol array into normalized array
+   *
+   * @param {string | (string | string[])[]} symbol symbol input
+   * @return {string[][]} normolized symbol array
+   */
+
+
+  function normalizeSymbolArray(symbol) {
+    if (!symbol || symbol.length === 0) {
+      return [['rect']];
+    }
+
+    if (isString(symbol)) {
+      return [[symbol]];
+    }
+
+    var isAllString = true;
+
+    for (var i = 0; i < symbol.length; ++i) {
+      if (!isString(symbol[i])) {
+        isAllString = false;
+        break;
+      }
+    }
+
+    if (isAllString) {
+      return normalizeSymbolArray([symbol]);
+    }
+
+    var result = [];
+
+    for (var i = 0; i < symbol.length; ++i) {
+      if (isString(symbol[i])) {
+        result.push([symbol[i]]);
+      } else {
+        result.push(symbol[i]);
+      }
+    }
+
+    return result;
+  }
+  /**
+   * Convert dash input into dashArray
+   *
+   * @param {DecalDashArrayX} dash dash input
+   * @return {number[][]} normolized dash array
+   */
+
+
+  function normalizeDashArrayX(dash) {
+    if (!dash || dash.length === 0) {
+      return [[0, 0]];
+    }
+
+    if (isNumber(dash)) {
+      var dashValue = Math.ceil(dash);
+      return [[dashValue, dashValue]];
+    }
+    /**
+     * [20, 5] should be normalized into [[20, 5]],
+     * while [20, [5, 10]] should be normalized into [[20, 20], [5, 10]]
+     */
+
+
+    var isAllNumber = true;
+
+    for (var i = 0; i < dash.length; ++i) {
+      if (!isNumber(dash[i])) {
+        isAllNumber = false;
+        break;
+      }
+    }
+
+    if (isAllNumber) {
+      return normalizeDashArrayX([dash]);
+    }
+
+    var result = [];
+
+    for (var i = 0; i < dash.length; ++i) {
+      if (isNumber(dash[i])) {
+        var dashValue = Math.ceil(dash[i]);
+        result.push([dashValue, dashValue]);
+      } else {
+        var dashValue = map(dash[i], function (n) {
+          return Math.ceil(n);
+        });
+
+        if (dashValue.length % 2 === 1) {
+          // [4, 2, 1] means |----  -    -- |----  -    -- |
+          // so normalize it to be [4, 2, 1, 4, 2, 1]
+          result.push(dashValue.concat(dashValue));
+        } else {
+          result.push(dashValue);
+        }
+      }
+    }
+
+    return result;
+  }
+  /**
+   * Convert dash input into dashArray
+   *
+   * @param {DecalDashArrayY} dash dash input
+   * @return {number[]} normolized dash array
+   */
+
+
+  function normalizeDashArrayY(dash) {
+    if (!dash || typeof dash === 'object' && dash.length === 0) {
+      return [0, 0];
+    }
+
+    if (isNumber(dash)) {
+      var dashValue_1 = Math.ceil(dash);
+      return [dashValue_1, dashValue_1];
+    }
+
+    var dashValue = map(dash, function (n) {
+      return Math.ceil(n);
+    });
+    return dash.length % 2 ? dashValue.concat(dashValue) : dashValue;
+  }
+  /**
+   * Get block length of each line. A block is the length of dash line and space.
+   * For example, a line with [4, 1] has a dash line of 4 and a space of 1 after
+   * that, so the block length of this line is 5.
+   *
+   * @param {number[][]} dash dash arrary of X or Y
+   * @return {number[]} block length of each line
+   */
+
+
+  function getLineBlockLengthX(dash) {
+    return map(dash, function (line) {
+      return getLineBlockLengthY(line);
+    });
+  }
+
+  function getLineBlockLengthY(dash) {
+    var blockLength = 0;
+
+    for (var i = 0; i < dash.length; ++i) {
+      blockLength += dash[i];
+    }
+
+    if (dash.length % 2 === 1) {
+      // [4, 2, 1] means |----  -    -- |----  -    -- |
+      // So total length is (4 + 2 + 1) * 2
+      return blockLength * 2;
+    }
+
+    return blockLength;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 decalVisual(ecModel, api) {
+    ecModel.eachRawSeries(function (seriesModel) {
+      if (ecModel.isSeriesFiltered(seriesModel)) {
+        return;
+      }
+
+      var data = seriesModel.getData();
+
+      if (data.hasItemVisual()) {
+        data.each(function (idx) {
+          var decal = data.getItemVisual(idx, 'decal');
+
+          if (decal) {
+            var itemStyle = data.ensureUniqueItemVisual(idx, 'style');
+            itemStyle.decal = createOrUpdatePatternFromDecal(decal, api);
+          }
+        });
+      }
+
+      var decal = data.getVisual('decal');
+
+      if (decal) {
+        var style = data.getVisual('style');
+        style.decal = createOrUpdatePatternFromDecal(decal, api);
+      }
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 lifecycle = new Eventful();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // The implentations will be registered when installing the component.
+  // Avoid these code being bundled to the core module.
+
+  var implsStore = {}; // TODO Type
+
+  function registerImpl(name, impl) {
+    {
+      if (implsStore[name]) {
+        error("Already has an implementation of " + name + ".");
+      }
+    }
+    implsStore[name] = impl;
+  }
+
+  function getImpl(name) {
+    {
+      if (!implsStore[name]) {
+        error("Implementation of " + name + " doesn't exists.");
+      }
+    }
+    return implsStore[name];
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 hasWindow = typeof window !== 'undefined';
+  var version = '5.3.3';
+  var dependencies = {
+    zrender: '5.3.2'
+  };
+  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).
+  // So data stack stage should be in front of data processing stage.
+
+  var PRIORITY_PROCESSOR_DATASTACK = 900; // "Data filter" will block the stream, so it should be
+  // put at the begining of data processing.
+
+  var PRIORITY_PROCESSOR_FILTER = 1000;
+  var PRIORITY_PROCESSOR_DEFAULT = 2000;
+  var PRIORITY_PROCESSOR_STATISTIC = 5000;
+  var PRIORITY_VISUAL_LAYOUT = 1000;
+  var PRIORITY_VISUAL_PROGRESSIVE_LAYOUT = 1100;
+  var PRIORITY_VISUAL_GLOBAL = 2000;
+  var PRIORITY_VISUAL_CHART = 3000;
+  var PRIORITY_VISUAL_COMPONENT = 4000; // Visual property in data. Greater than `PRIORITY_VISUAL_COMPONENT` to enable to
+  // overwrite the viusal result of component (like `visualMap`)
+  // using data item specific setting (like itemStyle.xxx on data item)
+
+  var PRIORITY_VISUAL_CHART_DATA_CUSTOM = 4500; // Greater than `PRIORITY_VISUAL_CHART_DATA_CUSTOM` to enable to layout based on
+  // visual result like `symbolSize`.
+
+  var PRIORITY_VISUAL_POST_CHART_LAYOUT = 4600;
+  var PRIORITY_VISUAL_BRUSH = 5000;
+  var PRIORITY_VISUAL_ARIA = 6000;
+  var PRIORITY_VISUAL_DECAL = 7000;
+  var PRIORITY = {
+    PROCESSOR: {
+      FILTER: PRIORITY_PROCESSOR_FILTER,
+      SERIES_FILTER: PRIORITY_PROCESSOR_SERIES_FILTER,
+      STATISTIC: PRIORITY_PROCESSOR_STATISTIC
+    },
+    VISUAL: {
+      LAYOUT: PRIORITY_VISUAL_LAYOUT,
+      PROGRESSIVE_LAYOUT: PRIORITY_VISUAL_PROGRESSIVE_LAYOUT,
+      GLOBAL: PRIORITY_VISUAL_GLOBAL,
+      CHART: PRIORITY_VISUAL_CHART,
+      POST_CHART_LAYOUT: PRIORITY_VISUAL_POST_CHART_LAYOUT,
+      COMPONENT: PRIORITY_VISUAL_COMPONENT,
+      BRUSH: PRIORITY_VISUAL_BRUSH,
+      CHART_ITEM: PRIORITY_VISUAL_CHART_DATA_CUSTOM,
+      ARIA: PRIORITY_VISUAL_ARIA,
+      DECAL: PRIORITY_VISUAL_DECAL
+    }
+  }; // Main process have three entries: `setOption`, `dispatchAction` and `resize`,
+  // where they must not be invoked nestedly, except the only case: invoke
+  // dispatchAction with updateMethod "none" in main process.
+  // This flag is used to carry out this rule.
+  // All events will be triggered out side main process (i.e. when !this[IN_MAIN_PROCESS]).
+
+  var IN_MAIN_PROCESS_KEY = '__flagInMainProcess';
+  var PENDING_UPDATE = '__pendingUpdate';
+  var STATUS_NEEDS_UPDATE_KEY = '__needsUpdateStatus';
+  var ACTION_REG = /^[a-zA-Z0-9_]+$/;
+  var CONNECT_STATUS_KEY = '__connectUpdateStatus';
+  var CONNECT_STATUS_PENDING = 0;
+  var CONNECT_STATUS_UPDATING = 1;
+  var CONNECT_STATUS_UPDATED = 2;
+
+  function createRegisterEventWithLowercaseECharts(method) {
+    return function () {
+      var args = [];
+
+      for (var _i = 0; _i < arguments.length; _i++) {
+        args[_i] = arguments[_i];
+      }
+
+      if (this.isDisposed()) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      return toLowercaseNameAndCallEventful(this, method, args);
+    };
+  }
+
+  function createRegisterEventWithLowercaseMessageCenter(method) {
+    return function () {
+      var args = [];
+
+      for (var _i = 0; _i < arguments.length; _i++) {
+        args[_i] = arguments[_i];
+      }
+
+      return toLowercaseNameAndCallEventful(this, method, args);
+    };
+  }
+
+  function toLowercaseNameAndCallEventful(host, method, args) {
+    // `args[0]` is event name. Event name is all lowercase.
+    args[0] = args[0] && args[0].toLowerCase();
+    return Eventful.prototype[method].apply(host, args);
+  }
+
+  var MessageCenter =
+  /** @class */
+  function (_super) {
+    __extends(MessageCenter, _super);
+
+    function MessageCenter() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    return MessageCenter;
+  }(Eventful);
+
+  var messageCenterProto = MessageCenter.prototype;
+  messageCenterProto.on = createRegisterEventWithLowercaseMessageCenter('on');
+  messageCenterProto.off = createRegisterEventWithLowercaseMessageCenter('off'); // ---------------------------------------
+  // Internal method names for class ECharts
+  // ---------------------------------------
+
+  var prepare;
+  var prepareView;
+  var updateDirectly;
+  var updateMethods;
+  var doConvertPixel;
+  var updateStreamModes;
+  var doDispatchAction;
+  var flushPendingActions;
+  var triggerUpdatedEvent;
+  var bindRenderedEvent;
+  var bindMouseEvent;
+  var render;
+  var renderComponents;
+  var renderSeries;
+  var createExtensionAPI;
+  var enableConnect;
+  var markStatusToUpdate;
+  var applyChangedStates;
+
+  var ECharts =
+  /** @class */
+  function (_super) {
+    __extends(ECharts, _super);
+
+    function ECharts(dom, // Theme name or themeOption.
+    theme$$1, opts) {
+      var _this = _super.call(this, new ECEventProcessor()) || this;
+
+      _this._chartsViews = [];
+      _this._chartsMap = {};
+      _this._componentsViews = [];
+      _this._componentsMap = {}; // Can't dispatch action during rendering procedure
+
+      _this._pendingActions = [];
+      opts = opts || {}; // Get theme by name
+
+      if (isString(theme$$1)) {
+        theme$$1 = themeStorage[theme$$1];
+      }
+
+      _this._dom = dom;
+      var defaultRenderer = 'canvas';
+      var defaultUseDirtyRect = false;
+      {
+        var root =
+        /* eslint-disable-next-line */
+        hasWindow ? window : global;
+        defaultRenderer = root.__ECHARTS__DEFAULT__RENDERER__ || defaultRenderer;
+        var devUseDirtyRect = root.__ECHARTS__DEFAULT__USE_DIRTY_RECT__;
+        defaultUseDirtyRect = devUseDirtyRect == null ? defaultUseDirtyRect : devUseDirtyRect;
+      }
+      var zr = _this._zr = init$1(dom, {
+        renderer: opts.renderer || defaultRenderer,
+        devicePixelRatio: opts.devicePixelRatio,
+        width: opts.width,
+        height: opts.height,
+        ssr: opts.ssr,
+        useDirtyRect: opts.useDirtyRect == null ? defaultUseDirtyRect : opts.useDirtyRect
+      });
+      _this._ssr = opts.ssr; // Expect 60 fps.
+
+      _this._throttledZrFlush = throttle(bind(zr.flush, zr), 17);
+      theme$$1 = clone(theme$$1);
+      theme$$1 && globalBackwardCompat(theme$$1, true);
+      _this._theme = theme$$1;
+      _this._locale = createLocaleObject(opts.locale || SYSTEM_LANG);
+      _this._coordSysMgr = new CoordinateSystemManager();
+      var api = _this._api = createExtensionAPI(_this); // Sort on demand
+
+      function prioritySortFunc(a, b) {
+        return a.__prio - b.__prio;
+      }
+
+      sort(visualFuncs, prioritySortFunc);
+      sort(dataProcessorFuncs, prioritySortFunc);
+      _this._scheduler = new Scheduler(_this, api, dataProcessorFuncs, visualFuncs);
+      _this._messageCenter = new MessageCenter(); // Init mouse events
+
+      _this._initEvents(); // In case some people write `window.onresize = chart.resize`
+
+
+      _this.resize = bind(_this.resize, _this);
+      zr.animation.on('frame', _this._onframe, _this);
+      bindRenderedEvent(zr, _this);
+      bindMouseEvent(zr, _this); // ECharts instance can be used as value.
+
+      setAsPrimitive(_this);
+      return _this;
+    }
+
+    ECharts.prototype._onframe = function () {
+      if (this._disposed) {
+        return;
+      }
+
+      applyChangedStates(this);
+      var scheduler = this._scheduler; // Lazy update
+
+      if (this[PENDING_UPDATE]) {
+        var silent = this[PENDING_UPDATE].silent;
+        this[IN_MAIN_PROCESS_KEY] = true;
+
+        try {
+          prepare(this);
+          updateMethods.update.call(this, null, this[PENDING_UPDATE].updateParams);
+        } catch (e) {
+          this[IN_MAIN_PROCESS_KEY] = false;
+          this[PENDING_UPDATE] = null;
+          throw e;
+        } // At present, in each frame, zrender performs:
+        //   (1) animation step forward.
+        //   (2) trigger('frame') (where this `_onframe` is called)
+        //   (3) zrender flush (render).
+        // If we do nothing here, since we use `setToFinal: true`, the step (3) above
+        // will render the final state of the elements before the real animation started.
+
+
+        this._zr.flush();
+
+        this[IN_MAIN_PROCESS_KEY] = false;
+        this[PENDING_UPDATE] = null;
+        flushPendingActions.call(this, silent);
+        triggerUpdatedEvent.call(this, silent);
+      } // Avoid do both lazy update and progress in one frame.
+      else if (scheduler.unfinished) {
+          // Stream progress.
+          var remainTime = TEST_FRAME_REMAIN_TIME;
+          var ecModel = this._model;
+          var api = this._api;
+          scheduler.unfinished = false;
+
+          do {
+            var startTime = +new Date();
+            scheduler.performSeriesTasks(ecModel); // Currently dataProcessorFuncs do not check threshold.
+
+            scheduler.performDataProcessorTasks(ecModel);
+            updateStreamModes(this, ecModel); // Do not update coordinate system here. Because that coord system update in
+            // each frame is not a good user experience. So we follow the rule that
+            // the extent of the coordinate system is determin in the first frame (the
+            // frame is executed immedietely after task reset.
+            // this._coordSysMgr.update(ecModel, api);
+            // console.log('--- ec frame visual ---', remainTime);
+
+            scheduler.performVisualTasks(ecModel);
+            renderSeries(this, this._model, api, 'remain', {});
+            remainTime -= +new Date() - startTime;
+          } while (remainTime > 0 && scheduler.unfinished); // Call flush explicitly for trigger finished event.
+
+
+          if (!scheduler.unfinished) {
+            this._zr.flush();
+          } // Else, zr flushing be ensue within the same frame,
+          // because zr flushing is after onframe event.
+
+        }
+    };
+
+    ECharts.prototype.getDom = function () {
+      return this._dom;
+    };
+
+    ECharts.prototype.getId = function () {
+      return this.id;
+    };
+
+    ECharts.prototype.getZr = function () {
+      return this._zr;
+    };
+
+    ECharts.prototype.isSSR = function () {
+      return this._ssr;
+    };
+    /* eslint-disable-next-line */
+
+
+    ECharts.prototype.setOption = function (option, notMerge, lazyUpdate) {
+      if (this[IN_MAIN_PROCESS_KEY]) {
+        {
+          error('`setOption` should not be called during main process.');
+        }
+        return;
+      }
+
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      var silent;
+      var replaceMerge;
+      var transitionOpt;
+
+      if (isObject(notMerge)) {
+        lazyUpdate = notMerge.lazyUpdate;
+        silent = notMerge.silent;
+        replaceMerge = notMerge.replaceMerge;
+        transitionOpt = notMerge.transition;
+        notMerge = notMerge.notMerge;
+      }
+
+      this[IN_MAIN_PROCESS_KEY] = true;
+
+      if (!this._model || notMerge) {
+        var optionManager = new OptionManager(this._api);
+        var theme$$1 = this._theme;
+        var ecModel = this._model = new GlobalModel();
+        ecModel.scheduler = this._scheduler;
+        ecModel.ssr = this._ssr;
+        ecModel.init(null, null, null, theme$$1, this._locale, optionManager);
+      }
+
+      this._model.setOption(option, {
+        replaceMerge: replaceMerge
+      }, optionPreprocessorFuncs);
+
+      var updateParams = {
+        seriesTransition: transitionOpt,
+        optionChanged: true
+      };
+
+      if (lazyUpdate) {
+        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.
+
+        this.getZr().wakeUp();
+      } else {
+        try {
+          prepare(this);
+          updateMethods.update.call(this, null, updateParams);
+        } catch (e) {
+          this[PENDING_UPDATE] = null;
+          this[IN_MAIN_PROCESS_KEY] = false;
+          throw e;
+        } // Ensure zr refresh sychronously, and then pixel in canvas can be
+        // fetched after `setOption`.
+
+
+        if (!this._ssr) {
+          // not use flush when using ssr mode.
+          this._zr.flush();
+        }
+
+        this[PENDING_UPDATE] = null;
+        this[IN_MAIN_PROCESS_KEY] = false;
+        flushPendingActions.call(this, silent);
+        triggerUpdatedEvent.call(this, silent);
+      }
+    };
+    /**
+     * @deprecated
+     */
+
+
+    ECharts.prototype.setTheme = function () {
+      deprecateLog('ECharts#setTheme() is DEPRECATED in ECharts 3.0');
+    }; // We don't want developers to use getModel directly.
+
+
+    ECharts.prototype.getModel = function () {
+      return this._model;
+    };
+
+    ECharts.prototype.getOption = function () {
+      return this._model && this._model.getOption();
+    };
+
+    ECharts.prototype.getWidth = function () {
+      return this._zr.getWidth();
+    };
+
+    ECharts.prototype.getHeight = function () {
+      return this._zr.getHeight();
+    };
+
+    ECharts.prototype.getDevicePixelRatio = function () {
+      return this._zr.painter.dpr
+      /* eslint-disable-next-line */
+      || hasWindow && window.devicePixelRatio || 1;
+    };
+    /**
+     * Get canvas which has all thing rendered
+     * @deprecated Use renderToCanvas instead.
+     */
+
+
+    ECharts.prototype.getRenderedCanvas = function (opts) {
+      {
+        deprecateReplaceLog('getRenderedCanvas', 'renderToCanvas');
+      }
+      return this.renderToCanvas(opts);
+    };
+
+    ECharts.prototype.renderToCanvas = function (opts) {
+      opts = opts || {};
+      var painter = this._zr.painter;
+      {
+        if (painter.type !== 'canvas') {
+          throw new Error('renderToCanvas can only be used in the canvas renderer.');
+        }
+      }
+      return painter.getRenderedCanvas({
+        backgroundColor: opts.backgroundColor || this._model.get('backgroundColor'),
+        pixelRatio: opts.pixelRatio || this.getDevicePixelRatio()
+      });
+    };
+
+    ECharts.prototype.renderToSVGString = function (opts) {
+      opts = opts || {};
+      var painter = this._zr.painter;
+      {
+        if (painter.type !== 'svg') {
+          throw new Error('renderToSVGString can only be used in the svg renderer.');
+        }
+      }
+      return painter.renderToString({
+        useViewBox: opts.useViewBox
+      });
+    };
+    /**
+     * Get svg data url
+     */
+
+
+    ECharts.prototype.getSvgDataURL = function () {
+      if (!env.svgSupported) {
+        return;
+      }
+
+      var zr = this._zr;
+      var list = zr.storage.getDisplayList(); // Stop animations
+
+      each(list, function (el) {
+        el.stopAnimation(null, true);
+      });
+      return zr.painter.toDataURL();
+    };
+
+    ECharts.prototype.getDataURL = function (opts) {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      opts = opts || {};
+      var excludeComponents = opts.excludeComponents;
+      var ecModel = this._model;
+      var excludesComponentViews = [];
+      var self = this;
+      each(excludeComponents, function (componentType) {
+        ecModel.eachComponent({
+          mainType: componentType
+        }, function (component) {
+          var view = self._componentsMap[component.__viewId];
+
+          if (!view.group.ignore) {
+            excludesComponentViews.push(view);
+            view.group.ignore = true;
+          }
+        });
+      });
+      var url = this._zr.painter.getType() === 'svg' ? this.getSvgDataURL() : this.renderToCanvas(opts).toDataURL('image/' + (opts && opts.type || 'png'));
+      each(excludesComponentViews, function (view) {
+        view.group.ignore = false;
+      });
+      return url;
+    };
+
+    ECharts.prototype.getConnectedDataURL = function (opts) {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      var isSvg = opts.type === 'svg';
+      var groupId = this.group;
+      var mathMin = Math.min;
+      var mathMax = Math.max;
+      var MAX_NUMBER = Infinity;
+
+      if (connectedGroups[groupId]) {
+        var left_1 = MAX_NUMBER;
+        var top_1 = MAX_NUMBER;
+        var right_1 = -MAX_NUMBER;
+        var bottom_1 = -MAX_NUMBER;
+        var canvasList_1 = [];
+        var dpr_1 = opts && opts.pixelRatio || this.getDevicePixelRatio();
+        each(instances, function (chart, id) {
+          if (chart.group === groupId) {
+            var canvas = isSvg ? chart.getZr().painter.getSvgDom().innerHTML : chart.renderToCanvas(clone(opts));
+            var boundingRect = chart.getDom().getBoundingClientRect();
+            left_1 = mathMin(boundingRect.left, left_1);
+            top_1 = mathMin(boundingRect.top, top_1);
+            right_1 = mathMax(boundingRect.right, right_1);
+            bottom_1 = mathMax(boundingRect.bottom, bottom_1);
+            canvasList_1.push({
+              dom: canvas,
+              left: boundingRect.left,
+              top: boundingRect.top
+            });
+          }
+        });
+        left_1 *= dpr_1;
+        top_1 *= dpr_1;
+        right_1 *= dpr_1;
+        bottom_1 *= dpr_1;
+        var width = right_1 - left_1;
+        var height = bottom_1 - top_1;
+        var targetCanvas = platformApi.createCanvas();
+        var zr_1 = init$1(targetCanvas, {
+          renderer: isSvg ? 'svg' : 'canvas'
+        });
+        zr_1.resize({
+          width: width,
+          height: height
+        });
+
+        if (isSvg) {
+          var content_1 = '';
+          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>';
+          });
+          zr_1.painter.getSvgRoot().innerHTML = content_1;
+
+          if (opts.connectedBackgroundColor) {
+            zr_1.painter.setBackgroundColor(opts.connectedBackgroundColor);
+          }
+
+          zr_1.refreshImmediately();
+          return zr_1.painter.toDataURL();
+        } else {
+          // Background between the charts
+          if (opts.connectedBackgroundColor) {
+            zr_1.add(new Rect({
+              shape: {
+                x: 0,
+                y: 0,
+                width: width,
+                height: height
+              },
+              style: {
+                fill: opts.connectedBackgroundColor
+              }
+            }));
+          }
+
+          each(canvasList_1, function (item) {
+            var img = new ZRImage({
+              style: {
+                x: item.left * dpr_1 - left_1,
+                y: item.top * dpr_1 - top_1,
+                image: item.dom
+              }
+            });
+            zr_1.add(img);
+          });
+          zr_1.refreshImmediately();
+          return targetCanvas.toDataURL('image/' + (opts && opts.type || 'png'));
+        }
+      } else {
+        return this.getDataURL(opts);
+      }
+    };
+
+    ECharts.prototype.convertToPixel = function (finder, value) {
+      return doConvertPixel(this, 'convertToPixel', finder, value);
+    };
+
+    ECharts.prototype.convertFromPixel = function (finder, value) {
+      return doConvertPixel(this, 'convertFromPixel', finder, value);
+    };
+    /**
+     * Is the specified coordinate systems or components contain the given pixel point.
+     * @param {Array|number} value
+     * @return {boolean} result
+     */
+
+
+    ECharts.prototype.containPixel = function (finder, value) {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      var ecModel = this._model;
+      var result;
+      var findResult = parseFinder(ecModel, finder);
+      each(findResult, function (models, key) {
+        key.indexOf('Models') >= 0 && each(models, function (model) {
+          var coordSys = model.coordinateSystem;
+
+          if (coordSys && coordSys.containPoint) {
+            result = result || !!coordSys.containPoint(value);
+          } else if (key === 'seriesModels') {
+            var view = this._chartsMap[model.__viewId];
+
+            if (view && view.containPoint) {
+              result = result || view.containPoint(value, model);
+            } else {
+              {
+                console.warn(key + ': ' + (view ? 'The found component do not support containPoint.' : 'No view mapping to the found component.'));
+              }
+            }
+          } else {
+            {
+              console.warn(key + ': containPoint is not supported');
+            }
+          }
+        }, this);
+      }, this);
+      return !!result;
+    };
+    /**
+     * Get visual from series or data.
+     * @param finder
+     *        If string, e.g., 'series', means {seriesIndex: 0}.
+     *        If Object, could contain some of these properties below:
+     *        {
+     *            seriesIndex / seriesId / seriesName,
+     *            dataIndex / dataIndexInside
+     *        }
+     *        If dataIndex is not specified, series visual will be fetched,
+     *        but not data item visual.
+     *        If all of seriesIndex, seriesId, seriesName are not specified,
+     *        visual will be fetched from first series.
+     * @param visualType 'color', 'symbol', 'symbolSize'
+     */
+
+
+    ECharts.prototype.getVisual = function (finder, visualType) {
+      var ecModel = this._model;
+      var parsedFinder = parseFinder(ecModel, finder, {
+        defaultMainType: 'series'
+      });
+      var seriesModel = parsedFinder.seriesModel;
+      {
+        if (!seriesModel) {
+          console.warn('There is no specified seires model');
+        }
+      }
+      var data = seriesModel.getData();
+      var dataIndexInside = parsedFinder.hasOwnProperty('dataIndexInside') ? parsedFinder.dataIndexInside : parsedFinder.hasOwnProperty('dataIndex') ? data.indexOfRawIndex(parsedFinder.dataIndex) : null;
+      return dataIndexInside != null ? getItemVisualFromData(data, dataIndexInside, visualType) : getVisualFromData(data, visualType);
+    };
+    /**
+     * Get view of corresponding component model
+     */
+
+
+    ECharts.prototype.getViewOfComponentModel = function (componentModel) {
+      return this._componentsMap[componentModel.__viewId];
+    };
+    /**
+     * Get view of corresponding series model
+     */
+
+
+    ECharts.prototype.getViewOfSeriesModel = function (seriesModel) {
+      return this._chartsMap[seriesModel.__viewId];
+    };
+
+    ECharts.prototype._initEvents = function () {
+      var _this = this;
+
+      each(MOUSE_EVENT_NAMES, function (eveName) {
+        var handler = function (e) {
+          var ecModel = _this.getModel();
+
+          var el = e.target;
+          var params;
+          var isGlobalOut = eveName === 'globalout'; // no e.target when 'globalout'.
+
+          if (isGlobalOut) {
+            params = {};
+          } else {
+            el && findEventDispatcher(el, function (parent) {
+              var ecData = getECData(parent);
+
+              if (ecData && ecData.dataIndex != null) {
+                var dataModel = ecData.dataModel || ecModel.getSeriesByIndex(ecData.seriesIndex);
+                params = dataModel && dataModel.getDataParams(ecData.dataIndex, ecData.dataType) || {};
+                return true;
+              } // If element has custom eventData of components
+              else if (ecData.eventData) {
+                  params = extend({}, ecData.eventData);
+                  return true;
+                }
+            }, true);
+          } // Contract: if params prepared in mouse event,
+          // these properties must be specified:
+          // {
+          //    componentType: string (component main type)
+          //    componentIndex: number
+          // }
+          // Otherwise event query can not work.
+
+
+          if (params) {
+            var componentType = params.componentType;
+            var componentIndex = params.componentIndex; // Special handling for historic reason: when trigger by
+            // markLine/markPoint/markArea, the componentType is
+            // 'markLine'/'markPoint'/'markArea', but we should better
+            // enable them to be queried by seriesIndex, since their
+            // option is set in each series.
+
+            if (componentType === 'markLine' || componentType === 'markPoint' || componentType === 'markArea') {
+              componentType = 'series';
+              componentIndex = params.seriesIndex;
+            }
+
+            var model = componentType && componentIndex != null && ecModel.getComponent(componentType, componentIndex);
+            var view = model && _this[model.mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId];
+            {
+              // `event.componentType` and `event[componentTpype + 'Index']` must not
+              // be missed, otherwise there is no way to distinguish source component.
+              // See `dataFormat.getDataParams`.
+              if (!isGlobalOut && !(model && view)) {
+                console.warn('model or view can not be found by params');
+              }
+            }
+            params.event = e;
+            params.type = eveName;
+            _this._$eventProcessor.eventInfo = {
+              targetEl: el,
+              packedEvent: params,
+              model: model,
+              view: view
+            };
+
+            _this.trigger(eveName, params);
+          }
+        }; // Consider that some component (like tooltip, brush, ...)
+        // register zr event handler, but user event handler might
+        // do anything, such as call `setOption` or `dispatchAction`,
+        // which probably update any of the content and probably
+        // cause problem if it is called previous other inner handlers.
+
+
+        handler.zrEventfulCallAtLast = true;
+
+        _this._zr.on(eveName, handler, _this);
+      });
+      each(eventActionMap, function (actionType, eventType) {
+        _this._messageCenter.on(eventType, function (event) {
+          this.trigger(eventType, event);
+        }, _this);
+      }); // Extra events
+      // TODO register?
+
+      each(['selectchanged'], function (eventType) {
+        _this._messageCenter.on(eventType, function (event) {
+          this.trigger(eventType, event);
+        }, _this);
+      });
+      handleLegacySelectEvents(this._messageCenter, this, this._api);
+    };
+
+    ECharts.prototype.isDisposed = function () {
+      return this._disposed;
+    };
+
+    ECharts.prototype.clear = function () {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      this.setOption({
+        series: []
+      }, true);
+    };
+
+    ECharts.prototype.dispose = function () {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      this._disposed = true;
+      var dom = this.getDom();
+
+      if (dom) {
+        setAttribute(this.getDom(), DOM_ATTRIBUTE_KEY, '');
+      }
+
+      var chart = this;
+      var api = chart._api;
+      var ecModel = chart._model;
+      each(chart._componentsViews, function (component) {
+        component.dispose(ecModel, api);
+      });
+      each(chart._chartsViews, function (chart) {
+        chart.dispose(ecModel, api);
+      }); // Dispose after all views disposed
+
+      chart._zr.dispose(); // Set properties to null.
+      // To reduce the memory cost in case the top code still holds this instance unexpectedly.
+
+
+      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[chart.id];
+    };
+    /**
+     * Resize the chart
+     */
+
+
+    ECharts.prototype.resize = function (opts) {
+      if (this[IN_MAIN_PROCESS_KEY]) {
+        {
+          error('`resize` should not be called during main process.');
+        }
+        return;
+      }
+
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      this._zr.resize(opts);
+
+      var ecModel = this._model; // Resize loading effect
+
+      this._loadingFX && this._loadingFX.resize();
+
+      if (!ecModel) {
+        return;
+      }
+
+      var needPrepare = ecModel.resetOption('media');
+      var silent = opts && opts.silent; // There is some real cases that:
+      // chart.setOption(option, { lazyUpdate: true });
+      // chart.resize();
+
+      if (this[PENDING_UPDATE]) {
+        if (silent == null) {
+          silent = this[PENDING_UPDATE].silent;
+        }
+
+        needPrepare = true;
+        this[PENDING_UPDATE] = null;
+      }
+
+      this[IN_MAIN_PROCESS_KEY] = true;
+
+      try {
+        needPrepare && prepare(this);
+        updateMethods.update.call(this, {
+          type: 'resize',
+          animation: extend({
+            // Disable animation
+            duration: 0
+          }, opts && opts.animation)
+        });
+      } catch (e) {
+        this[IN_MAIN_PROCESS_KEY] = false;
+        throw e;
+      }
+
+      this[IN_MAIN_PROCESS_KEY] = false;
+      flushPendingActions.call(this, silent);
+      triggerUpdatedEvent.call(this, silent);
+    };
+
+    ECharts.prototype.showLoading = function (name, cfg) {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      if (isObject(name)) {
+        cfg = name;
+        name = '';
+      }
+
+      name = name || 'default';
+      this.hideLoading();
+
+      if (!loadingEffects[name]) {
+        {
+          console.warn('Loading effects ' + name + ' not exists.');
+        }
+        return;
+      }
+
+      var el = loadingEffects[name](this._api, cfg);
+      var zr = this._zr;
+      this._loadingFX = el;
+      zr.add(el);
+    };
+    /**
+     * Hide loading effect
+     */
+
+
+    ECharts.prototype.hideLoading = function () {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      this._loadingFX && this._zr.remove(this._loadingFX);
+      this._loadingFX = null;
+    };
+
+    ECharts.prototype.makeActionFromEvent = function (eventObj) {
+      var payload = extend({}, eventObj);
+      payload.type = eventActionMap[eventObj.type];
+      return payload;
+    };
+    /**
+     * @param opt If pass boolean, means opt.silent
+     * @param opt.silent Default `false`. Whether trigger events.
+     * @param opt.flush Default `undefined`.
+     *        true: Flush immediately, and then pixel in canvas can be fetched
+     *            immediately. Caution: it might affect performance.
+     *        false: Not flush.
+     *        undefined: Auto decide whether perform flush.
+     */
+
+
+    ECharts.prototype.dispatchAction = function (payload, opt) {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      if (!isObject(opt)) {
+        opt = {
+          silent: !!opt
+        };
+      }
+
+      if (!actions[payload.type]) {
+        return;
+      } // Avoid dispatch action before setOption. Especially in `connect`.
+
+
+      if (!this._model) {
+        return;
+      } // May dispatchAction in rendering procedure
+
+
+      if (this[IN_MAIN_PROCESS_KEY]) {
+        this._pendingActions.push(payload);
+
+        return;
+      }
+
+      var silent = opt.silent;
+      doDispatchAction.call(this, payload, silent);
+      var flush = opt.flush;
+
+      if (flush) {
+        this._zr.flush();
+      } else if (flush !== false && env.browser.weChat) {
+        // In WeChat embeded browser, `requestAnimationFrame` and `setInterval`
+        // hang when sliding page (on touch event), which cause that zr does not
+        // refresh util user interaction finished, which is not expected.
+        // But `dispatchAction` may be called too frequently when pan on touch
+        // screen, which impacts performance if do not throttle them.
+        this._throttledZrFlush();
+      }
+
+      flushPendingActions.call(this, silent);
+      triggerUpdatedEvent.call(this, silent);
+    };
+
+    ECharts.prototype.updateLabelLayout = function () {
+      lifecycle.trigger('series:layoutlabels', this._model, this._api, {
+        // Not adding series labels.
+        // TODO
+        updatedSeries: []
+      });
+    };
+
+    ECharts.prototype.appendData = function (params) {
+      if (this._disposed) {
+        disposedWarning(this.id);
+        return;
+      }
+
+      var seriesIndex = params.seriesIndex;
+      var ecModel = this.getModel();
+      var seriesModel = ecModel.getSeriesByIndex(seriesIndex);
+      {
+        assert(params.data && seriesModel);
+      }
+      seriesModel.appendData(params); // Note: `appendData` does not support that update extent of coordinate
+      // system, util some scenario require that. In the expected usage of
+      // `appendData`, the initial extent of coordinate system should better
+      // be fixed by axis `min`/`max` setting or initial data, otherwise if
+      // the extent changed while `appendData`, the location of the painted
+      // graphic elements have to be changed, which make the usage of
+      // `appendData` meaningless.
+
+      this._scheduler.unfinished = true;
+      this.getZr().wakeUp();
+    }; // A work around for no `internal` modifier in ts yet but
+    // need to strictly hide private methods to JS users.
+
+
+    ECharts.internalField = function () {
+      prepare = function (ecIns) {
+        var scheduler = ecIns._scheduler;
+        scheduler.restorePipelines(ecIns._model);
+        scheduler.prepareStageTasks();
+        prepareView(ecIns, true);
+        prepareView(ecIns, false);
+        scheduler.plan();
+      };
+      /**
+       * Prepare view instances of charts and components
+       */
+
+
+      prepareView = function (ecIns, isComponent) {
+        var ecModel = ecIns._model;
+        var scheduler = ecIns._scheduler;
+        var viewList = isComponent ? ecIns._componentsViews : ecIns._chartsViews;
+        var viewMap = isComponent ? ecIns._componentsMap : ecIns._chartsMap;
+        var zr = ecIns._zr;
+        var api = ecIns._api;
+
+        for (var i = 0; i < viewList.length; i++) {
+          viewList[i].__alive = false;
+        }
+
+        isComponent ? ecModel.eachComponent(function (componentType, model) {
+          componentType !== 'series' && doPrepare(model);
+        }) : ecModel.eachSeries(doPrepare);
+
+        function doPrepare(model) {
+          // By defaut view will be reused if possible for the case that `setOption` with "notMerge"
+          // mode and need to enable transition animation. (Usually, when they have the same id, or
+          // especially no id but have the same type & name & index. See the `model.id` generation
+          // rule in `makeIdAndName` and `viewId` generation rule here).
+          // But in `replaceMerge` mode, this feature should be able to disabled when it is clear that
+          // the new model has nothing to do with the old model.
+          var requireNewView = model.__requireNewView; // This command should not work twice.
+
+          model.__requireNewView = false; // Consider: id same and type changed.
+
+          var viewId = '_ec_' + model.id + '_' + model.type;
+          var view = !requireNewView && viewMap[viewId];
+
+          if (!view) {
+            var classType = parseClassType(model.type);
+            var Clazz = isComponent ? ComponentView.getClass(classType.main, classType.sub) : // FIXME:TS
+            // (ChartView as ChartViewConstructor).getClass('series', classType.sub)
+            // For backward compat, still support a chart type declared as only subType
+            // like "liquidfill", but recommend "series.liquidfill"
+            // But need a base class to make a type series.
+            ChartView.getClass(classType.sub);
+            {
+              assert(Clazz, classType.sub + ' does not exist.');
+            }
+            view = new Clazz();
+            view.init(ecModel, api);
+            viewMap[viewId] = view;
+            viewList.push(view);
+            zr.add(view.group);
+          }
+
+          model.__viewId = view.__id = viewId;
+          view.__alive = true;
+          view.__model = model;
+          view.group.__ecComponentInfo = {
+            mainType: model.mainType,
+            index: model.componentIndex
+          };
+          !isComponent && scheduler.prepareView(view, model, ecModel, api);
+        }
+
+        for (var i = 0; i < viewList.length;) {
+          var view = viewList[i];
+
+          if (!view.__alive) {
+            !isComponent && view.renderTask.dispose();
+            zr.remove(view.group);
+            view.dispose(ecModel, api);
+            viewList.splice(i, 1);
+
+            if (viewMap[view.__id] === view) {
+              delete viewMap[view.__id];
+            }
+
+            view.__id = view.group.__ecComponentInfo = null;
+          } else {
+            i++;
+          }
+        }
+      };
+
+      updateDirectly = function (ecIns, method, payload, mainType, subType) {
+        var ecModel = ecIns._model;
+        ecModel.setUpdatePayload(payload); // broadcast
+
+        if (!mainType) {
+          // FIXME
+          // Chart will not be update directly here, except set dirty.
+          // But there is no such scenario now.
+          each([].concat(ecIns._componentsViews).concat(ecIns._chartsViews), callView);
+          return;
+        }
+
+        var query = {};
+        query[mainType + 'Id'] = payload[mainType + 'Id'];
+        query[mainType + 'Index'] = payload[mainType + 'Index'];
+        query[mainType + 'Name'] = payload[mainType + 'Name'];
+        var condition = {
+          mainType: mainType,
+          query: query
+        };
+        subType && (condition.subType = subType); // subType may be '' by parseClassType;
+
+        var excludeSeriesId = payload.excludeSeriesId;
+        var excludeSeriesIdMap;
+
+        if (excludeSeriesId != null) {
+          excludeSeriesIdMap = createHashMap();
+          each(normalizeToArray(excludeSeriesId), function (id) {
+            var modelId = convertOptionIdName(id, null);
+
+            if (modelId != null) {
+              excludeSeriesIdMap.set(modelId, true);
+            }
+          });
+        } // If dispatchAction before setOption, do nothing.
+
+
+        ecModel && ecModel.eachComponent(condition, function (model) {
+          var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) !== null;
+
+          if (isExcluded) {
+            return;
+          }
+
+          if (isHighDownPayload(payload)) {
+            if (model instanceof SeriesModel) {
+              if (payload.type === HIGHLIGHT_ACTION_TYPE && !payload.notBlur && !model.get(['emphasis', 'disabled'])) {
+                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.
+
+
+              if (dispatchers) {
+                each(dispatchers, function (dispatcher) {
+                  payload.type === HIGHLIGHT_ACTION_TYPE ? enterEmphasis(dispatcher) : leaveEmphasis(dispatcher);
+                });
+              }
+            }
+          } else if (isSelectChangePayload(payload)) {
+            // TODO geo
+            if (model instanceof SeriesModel) {
+              toggleSelectionFromPayload(model, payload, ecIns._api);
+              updateSeriesElementSelection(model);
+              markStatusToUpdate(ecIns);
+            }
+          }
+        }, ecIns);
+        ecModel && ecModel.eachComponent(condition, function (model) {
+          var isExcluded = excludeSeriesIdMap && excludeSeriesIdMap.get(model.id) !== null;
+
+          if (isExcluded) {
+            return;
+          }
+
+          callView(ecIns[mainType === 'series' ? '_chartsMap' : '_componentsMap'][model.__viewId]);
+        }, ecIns);
+
+        function callView(view) {
+          view && view.__alive && view[method] && view[method](view.__model, ecModel, ecIns._api, payload);
+        }
+      };
+
+      updateMethods = {
+        prepareAndUpdate: function (payload) {
+          prepare(this);
+          updateMethods.update.call(this, payload, {
+            // Needs to mark option changed if newOption is given.
+            // It's from MagicType.
+            // TODO If use a separate flag optionChanged in payload?
+            optionChanged: payload.newOption != null
+          });
+        },
+        update: function (payload, updateParams) {
+          var ecModel = this._model;
+          var api = this._api;
+          var zr = this._zr;
+          var coordSysMgr = this._coordSysMgr;
+          var scheduler = this._scheduler; // update before setOption
+
+          if (!ecModel) {
+            return;
+          }
+
+          ecModel.setUpdatePayload(payload);
+          scheduler.restoreData(ecModel, payload);
+          scheduler.performSeriesTasks(ecModel); // TODO
+          // Save total ecModel here for undo/redo (after restoring data and before processing data).
+          // Undo (restoration of total ecModel) can be carried out in 'action' or outside API call.
+          // Create new coordinate system each update
+          // In LineView may save the old coordinate system and use it to get the orignal point
+
+          coordSysMgr.create(ecModel, api);
+          scheduler.performDataProcessorTasks(ecModel, payload); // Current stream render is not supported in data process. So we can update
+          // stream modes after data processing, where the filtered data is used to
+          // deteming whether use progressive rendering.
+
+          updateStreamModes(this, ecModel); // We update stream modes before coordinate system updated, then the modes info
+          // can be fetched when coord sys updating (consider the barGrid extent fix). But
+          // the drawback is the full coord info can not be fetched. Fortunately this full
+          // coord is not requied in stream mode updater currently.
+
+          coordSysMgr.update(ecModel, api);
+          clearColorPalette(ecModel);
+          scheduler.performVisualTasks(ecModel, payload);
+          render(this, ecModel, api, payload, updateParams); // Set background
+
+          var backgroundColor = ecModel.get('backgroundColor') || 'transparent';
+          var darkMode = ecModel.get('darkMode');
+          zr.setBackgroundColor(backgroundColor); // Force set dark mode.
+
+          if (darkMode != null && darkMode !== 'auto') {
+            zr.setDarkMode(darkMode);
+          }
+
+          lifecycle.trigger('afterupdate', ecModel, api);
+        },
+        updateTransform: function (payload) {
+          var _this = this;
+
+          var ecModel = this._model;
+          var api = this._api; // update before setOption
+
+          if (!ecModel) {
+            return;
+          }
+
+          ecModel.setUpdatePayload(payload); // ChartView.markUpdateMethod(payload, 'updateTransform');
+
+          var componentDirtyList = [];
+          ecModel.eachComponent(function (componentType, componentModel) {
+            if (componentType === 'series') {
+              return;
+            }
+
+            var componentView = _this.getViewOfComponentModel(componentModel);
+
+            if (componentView && componentView.__alive) {
+              if (componentView.updateTransform) {
+                var result = componentView.updateTransform(componentModel, ecModel, api, payload);
+                result && result.update && componentDirtyList.push(componentView);
+              } else {
+                componentDirtyList.push(componentView);
+              }
+            }
+          });
+          var seriesDirtyMap = createHashMap();
+          ecModel.eachSeries(function (seriesModel) {
+            var chartView = _this._chartsMap[seriesModel.__viewId];
+
+            if (chartView.updateTransform) {
+              var result = chartView.updateTransform(seriesModel, ecModel, api, payload);
+              result && result.update && seriesDirtyMap.set(seriesModel.uid, 1);
+            } else {
+              seriesDirtyMap.set(seriesModel.uid, 1);
+            }
+          });
+          clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
+          // this._scheduler.performVisualTasks(ecModel, payload, 'layout', true);
+
+          this._scheduler.performVisualTasks(ecModel, payload, {
+            setDirty: true,
+            dirtyMap: seriesDirtyMap
+          }); // Currently, not call render of components. Geo render cost a lot.
+          // renderComponents(ecIns, ecModel, api, payload, componentDirtyList);
+
+
+          renderSeries(this, ecModel, api, payload, {}, seriesDirtyMap);
+          lifecycle.trigger('afterupdate', ecModel, api);
+        },
+        updateView: function (payload) {
+          var ecModel = this._model; // update before setOption
+
+          if (!ecModel) {
+            return;
+          }
+
+          ecModel.setUpdatePayload(payload);
+          ChartView.markUpdateMethod(payload, 'updateView');
+          clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
+
+          this._scheduler.performVisualTasks(ecModel, payload, {
+            setDirty: true
+          });
+
+          render(this, ecModel, this._api, payload, {});
+          lifecycle.trigger('afterupdate', ecModel, this._api);
+        },
+        updateVisual: function (payload) {
+          // updateMethods.update.call(this, payload);
+          var _this = this;
+
+          var ecModel = this._model; // update before setOption
+
+          if (!ecModel) {
+            return;
+          }
+
+          ecModel.setUpdatePayload(payload); // clear all visual
+
+          ecModel.eachSeries(function (seriesModel) {
+            seriesModel.getData().clearAllVisual();
+          }); // Perform visual
+
+          ChartView.markUpdateMethod(payload, 'updateVisual');
+          clearColorPalette(ecModel); // Keep pipe to the exist pipeline because it depends on the render task of the full pipeline.
+
+          this._scheduler.performVisualTasks(ecModel, payload, {
+            visualType: 'visual',
+            setDirty: true
+          });
+
+          ecModel.eachComponent(function (componentType, componentModel) {
+            if (componentType !== 'series') {
+              var componentView = _this.getViewOfComponentModel(componentModel);
+
+              componentView && componentView.__alive && componentView.updateVisual(componentModel, ecModel, _this._api, payload);
+            }
+          });
+          ecModel.eachSeries(function (seriesModel) {
+            var chartView = _this._chartsMap[seriesModel.__viewId];
+            chartView.updateVisual(seriesModel, ecModel, _this._api, payload);
+          });
+          lifecycle.trigger('afterupdate', ecModel, this._api);
+        },
+        updateLayout: function (payload) {
+          updateMethods.update.call(this, payload);
+        }
+      };
+
+      doConvertPixel = function (ecIns, methodName, finder, value) {
+        if (ecIns._disposed) {
+          disposedWarning(ecIns.id);
+          return;
+        }
+
+        var ecModel = ecIns._model;
+
+        var coordSysList = ecIns._coordSysMgr.getCoordinateSystems();
+
+        var result;
+        var parsedFinder = parseFinder(ecModel, finder);
+
+        for (var i = 0; i < coordSysList.length; i++) {
+          var coordSys = coordSysList[i];
+
+          if (coordSys[methodName] && (result = coordSys[methodName](ecModel, parsedFinder, value)) != null) {
+            return result;
+          }
+        }
+
+        {
+          console.warn('No coordinate system that supports ' + methodName + ' found by the given finder.');
+        }
+      };
+
+      updateStreamModes = function (ecIns, ecModel) {
+        var chartsMap = ecIns._chartsMap;
+        var scheduler = ecIns._scheduler;
+        ecModel.eachSeries(function (seriesModel) {
+          scheduler.updateStreamModes(seriesModel, chartsMap[seriesModel.__viewId]);
+        });
+      };
+
+      doDispatchAction = function (payload, silent) {
+        var _this = this;
+
+        var ecModel = this.getModel();
+        var payloadType = payload.type;
+        var escapeConnect = payload.escapeConnect;
+        var actionWrap = actions[payloadType];
+        var actionInfo = actionWrap.actionInfo;
+        var cptTypeTmp = (actionInfo.update || 'update').split(':');
+        var updateMethod = cptTypeTmp.pop();
+        var cptType = cptTypeTmp[0] != null && parseClassType(cptTypeTmp[0]);
+        this[IN_MAIN_PROCESS_KEY] = true;
+        var payloads = [payload];
+        var batched = false; // Batch action
+
+        if (payload.batch) {
+          batched = true;
+          payloads = map(payload.batch, function (item) {
+            item = defaults(extend({}, item), payload);
+            item.batch = null;
+            return item;
+          });
+        }
+
+        var eventObjBatch = [];
+        var eventObj;
+        var isSelectChange = isSelectChangePayload(payload);
+        var isHighDown = isHighDownPayload(payload); // Only leave blur once if there are multiple batches.
+
+        if (isHighDown) {
+          allLeaveBlur(this._api);
+        }
+
+        each(payloads, function (batchItem) {
+          // Action can specify the event by return it.
+          eventObj = actionWrap.action(batchItem, _this._model, _this._api); // Emit event outside
+
+          eventObj = eventObj || extend({}, batchItem); // Convert type to eventType
+
+          eventObj.type = actionInfo.event || eventObj.type;
+          eventObjBatch.push(eventObj); // light update does not perform data process, layout and visual.
+
+          if (isHighDown) {
+            var _a = preParseFinder(payload),
+                queryOptionMap = _a.queryOptionMap,
+                mainTypeSpecified = _a.mainTypeSpecified;
+
+            var componentMainType = mainTypeSpecified ? queryOptionMap.keys()[0] : 'series';
+            updateDirectly(_this, updateMethod, batchItem, componentMainType);
+            markStatusToUpdate(_this);
+          } else if (isSelectChange) {
+            // At present `dispatchAction({ type: 'select', ... })` is not supported on components.
+            // geo still use 'geoselect'.
+            updateDirectly(_this, updateMethod, batchItem, 'series');
+            markStatusToUpdate(_this);
+          } else if (cptType) {
+            updateDirectly(_this, updateMethod, batchItem, cptType.main, cptType.sub);
+          }
+        });
+
+        if (updateMethod !== 'none' && !isHighDown && !isSelectChange && !cptType) {
+          try {
+            // Still dirty
+            if (this[PENDING_UPDATE]) {
+              prepare(this);
+              updateMethods.update.call(this, payload);
+              this[PENDING_UPDATE] = null;
+            } else {
+              updateMethods[updateMethod].call(this, payload);
+            }
+          } catch (e) {
+            this[IN_MAIN_PROCESS_KEY] = false;
+            throw e;
+          }
+        } // Follow the rule of action batch
+
+
+        if (batched) {
+          eventObj = {
+            type: actionInfo.event || payloadType,
+            escapeConnect: escapeConnect,
+            batch: eventObjBatch
+          };
+        } else {
+          eventObj = eventObjBatch[0];
+        }
+
+        this[IN_MAIN_PROCESS_KEY] = false;
+
+        if (!silent) {
+          var messageCenter = this._messageCenter;
+          messageCenter.trigger(eventObj.type, eventObj); // Extra triggered 'selectchanged' event
+
+          if (isSelectChange) {
+            var newObj = {
+              type: 'selectchanged',
+              escapeConnect: escapeConnect,
+              selected: getAllSelectedIndices(ecModel),
+              isFromClick: payload.isFromClick || false,
+              fromAction: payload.type,
+              fromActionPayload: payload
+            };
+            messageCenter.trigger(newObj.type, newObj);
+          }
+        }
+      };
+
+      flushPendingActions = function (silent) {
+        var pendingActions = this._pendingActions;
+
+        while (pendingActions.length) {
+          var payload = pendingActions.shift();
+          doDispatchAction.call(this, payload, silent);
+        }
+      };
+
+      triggerUpdatedEvent = function (silent) {
+        !silent && this.trigger('updated');
+      };
+      /**
+       * Event `rendered` is triggered when zr
+       * rendered. It is useful for realtime
+       * snapshot (reflect animation).
+       *
+       * Event `finished` is triggered when:
+       * (1) zrender rendering finished.
+       * (2) initial animation finished.
+       * (3) progressive rendering finished.
+       * (4) no pending action.
+       * (5) no delayed setOption needs to be processed.
+       */
+
+
+      bindRenderedEvent = function (zr, ecIns) {
+        zr.on('rendered', function (params) {
+          ecIns.trigger('rendered', params); // The `finished` event should not be triggered repeatly,
+          // so it should only be triggered when rendering indeed happend
+          // in zrender. (Consider the case that dipatchAction is keep
+          // triggering when mouse move).
+
+          if ( // Although zr is dirty if initial animation is not finished
+          // and this checking is called on frame, we also check
+          // animation finished for robustness.
+          zr.animation.isFinished() && !ecIns[PENDING_UPDATE] && !ecIns._scheduler.unfinished && !ecIns._pendingActions.length) {
+            ecIns.trigger('finished');
+          }
+        });
+      };
+
+      bindMouseEvent = function (zr, ecIns) {
+        zr.on('mouseover', function (e) {
+          var el = e.target;
+          var dispatcher = findEventDispatcher(el, isHighDownDispatcher);
+
+          if (dispatcher) {
+            handleGlobalMouseOverForHighDown(dispatcher, e, ecIns._api);
+            markStatusToUpdate(ecIns);
+          }
+        }).on('mouseout', function (e) {
+          var el = e.target;
+          var dispatcher = findEventDispatcher(el, isHighDownDispatcher);
+
+          if (dispatcher) {
+            handleGlobalMouseOutForHighDown(dispatcher, e, ecIns._api);
+            markStatusToUpdate(ecIns);
+          }
+        }).on('click', function (e) {
+          var el = e.target;
+          var dispatcher = findEventDispatcher(el, function (target) {
+            return getECData(target).dataIndex != null;
+          }, true);
+
+          if (dispatcher) {
+            var actionType = dispatcher.selected ? 'unselect' : 'select';
+            var ecData = getECData(dispatcher);
+
+            ecIns._api.dispatchAction({
+              type: actionType,
+              dataType: ecData.dataType,
+              dataIndexInside: ecData.dataIndex,
+              seriesIndex: ecData.seriesIndex,
+              isFromClick: true
+            });
+          }
+        });
+      };
+
+      function clearColorPalette(ecModel) {
+        ecModel.clearColorPalette();
+        ecModel.eachSeries(function (seriesModel) {
+          seriesModel.clearColorPalette();
+        });
+      } // Allocate zlevels for series and components
+
+
+      function allocateZlevels(ecModel) {
+        var componentZLevels = [];
+        var seriesZLevels = [];
+        var hasSeperateZLevel = false;
+        ecModel.eachComponent(function (componentType, componentModel) {
+          var zlevel = componentModel.get('zlevel') || 0;
+          var z = componentModel.get('z') || 0;
+          var zlevelKey = componentModel.getZLevelKey();
+          hasSeperateZLevel = hasSeperateZLevel || !!zlevelKey;
+          (componentType === 'series' ? seriesZLevels : componentZLevels).push({
+            zlevel: zlevel,
+            z: z,
+            idx: componentModel.componentIndex,
+            type: componentType,
+            key: zlevelKey
+          });
+        });
+
+        if (hasSeperateZLevel) {
+          // Series after component
+          var zLevels = componentZLevels.concat(seriesZLevels);
+          var lastSeriesZLevel_1;
+          var lastSeriesKey_1;
+          sort(zLevels, function (a, b) {
+            if (a.zlevel === b.zlevel) {
+              return a.z - b.z;
+            }
+
+            return a.zlevel - b.zlevel;
+          });
+          each(zLevels, function (item) {
+            var componentModel = ecModel.getComponent(item.type, item.idx);
+            var zlevel = item.zlevel;
+            var key = item.key;
+
+            if (lastSeriesZLevel_1 != null) {
+              zlevel = Math.max(lastSeriesZLevel_1, zlevel);
+            }
+
+            if (key) {
+              if (zlevel === lastSeriesZLevel_1 && key !== lastSeriesKey_1) {
+                zlevel++;
+              }
+
+              lastSeriesKey_1 = key;
+            } else if (lastSeriesKey_1) {
+              if (zlevel === lastSeriesZLevel_1) {
+                zlevel++;
+              }
+
+              lastSeriesKey_1 = '';
+            }
+
+            lastSeriesZLevel_1 = zlevel;
+            componentModel.setZLevel(zlevel);
+          });
+        }
+      }
+
+      render = function (ecIns, ecModel, api, payload, updateParams) {
+        allocateZlevels(ecModel);
+        renderComponents(ecIns, ecModel, api, payload, updateParams);
+        each(ecIns._chartsViews, function (chart) {
+          chart.__alive = false;
+        });
+        renderSeries(ecIns, ecModel, api, payload, updateParams); // Remove groups of unrendered charts
+
+        each(ecIns._chartsViews, function (chart) {
+          if (!chart.__alive) {
+            chart.remove(ecModel, api);
+          }
+        });
+      };
+
+      renderComponents = function (ecIns, ecModel, api, payload, updateParams, dirtyList) {
+        each(dirtyList || ecIns._componentsViews, function (componentView) {
+          var componentModel = componentView.__model;
+          clearStates$$1(componentModel, componentView);
+          componentView.render(componentModel, ecModel, api, payload);
+          updateZ(componentModel, componentView);
+          updateStates(componentModel, componentView);
+        });
+      };
+      /**
+       * Render each chart and component
+       */
+
+
+      renderSeries = function (ecIns, ecModel, api, payload, updateParams, dirtyMap) {
+        // Render all charts
+        var scheduler = ecIns._scheduler;
+        updateParams = extend(updateParams || {}, {
+          updatedSeries: ecModel.getSeries()
+        }); // TODO progressive?
+
+        lifecycle.trigger('series:beforeupdate', ecModel, api, updateParams);
+        var unfinished = false;
+        ecModel.eachSeries(function (seriesModel) {
+          var chartView = ecIns._chartsMap[seriesModel.__viewId];
+          chartView.__alive = true;
+          var renderTask = chartView.renderTask;
+          scheduler.updatePayload(renderTask, payload); // TODO states on marker.
+
+          clearStates$$1(seriesModel, chartView);
+
+          if (dirtyMap && dirtyMap.get(seriesModel.uid)) {
+            renderTask.dirty();
+          }
+
+          if (renderTask.perform(scheduler.getPerformArgs(renderTask))) {
+            unfinished = true;
+          }
+
+          chartView.group.silent = !!seriesModel.get('silent'); // Should not call markRedraw on group, because it will disable zrender
+          // increamental render (alway render from the __startIndex each frame)
+          // chartView.group.markRedraw();
+
+          updateBlend(seriesModel, chartView);
+          updateSeriesElementSelection(seriesModel);
+        });
+        scheduler.unfinished = unfinished || scheduler.unfinished;
+        lifecycle.trigger('series:layoutlabels', ecModel, api, updateParams); // transition after label is layouted.
+
+        lifecycle.trigger('series:transition', ecModel, api, updateParams);
+        ecModel.eachSeries(function (seriesModel) {
+          var chartView = ecIns._chartsMap[seriesModel.__viewId]; // Update Z after labels updated. Before applying states.
+
+          updateZ(seriesModel, chartView); // NOTE: Update states after label is updated.
+          // label should be in normal status when layouting.
+
+          updateStates(seriesModel, chartView);
+        }); // If use hover layer
+
+        updateHoverLayerStatus(ecIns, ecModel);
+        lifecycle.trigger('series:afterupdate', ecModel, api, updateParams);
+      };
+
+      markStatusToUpdate = function (ecIns) {
+        ecIns[STATUS_NEEDS_UPDATE_KEY] = true; // Wake up zrender if it's sleep. Let it update states in the next frame.
+
+        ecIns.getZr().wakeUp();
+      };
+
+      applyChangedStates = function (ecIns) {
+        if (!ecIns[STATUS_NEEDS_UPDATE_KEY]) {
+          return;
+        }
+
+        ecIns.getZr().storage.traverse(function (el) {
+          // Not applied on removed elements, it may still in fading.
+          if (isElementRemoved(el)) {
+            return;
+          }
+
+          applyElementStates(el);
+        });
+        ecIns[STATUS_NEEDS_UPDATE_KEY] = false;
+      };
+
+      function applyElementStates(el) {
+        var newStates = [];
+        var oldStates = el.currentStates; // Keep other states.
+
+        for (var i = 0; i < oldStates.length; i++) {
+          var stateName = oldStates[i];
+
+          if (!(stateName === 'emphasis' || stateName === 'blur' || stateName === 'select')) {
+            newStates.push(stateName);
+          }
+        } // Only use states when it's exists.
+
+
+        if (el.selected && el.states.select) {
+          newStates.push('select');
+        }
+
+        if (el.hoverState === HOVER_STATE_EMPHASIS && el.states.emphasis) {
+          newStates.push('emphasis');
+        } else if (el.hoverState === HOVER_STATE_BLUR && el.states.blur) {
+          newStates.push('blur');
+        }
+
+        el.useStates(newStates);
+      }
+
+      function updateHoverLayerStatus(ecIns, ecModel) {
+        var zr = ecIns._zr;
+        var storage = zr.storage;
+        var elCount = 0;
+        storage.traverse(function (el) {
+          if (!el.isGroup) {
+            elCount++;
+          }
+        });
+
+        if (elCount > ecModel.get('hoverLayerThreshold') && !env.node && !env.worker) {
+          ecModel.eachSeries(function (seriesModel) {
+            if (seriesModel.preventUsingHoverLayer) {
+              return;
+            }
+
+            var chartView = ecIns._chartsMap[seriesModel.__viewId];
+
+            if (chartView.__alive) {
+              chartView.eachRendered(function (el) {
+                if (el.states.emphasis) {
+                  el.states.emphasis.hoverLayer = true;
+                }
+              });
+            }
+          });
+        }
+      }
+      /**
+       * Update chart and blend.
+       */
+
+
+      function updateBlend(seriesModel, chartView) {
+        var blendMode = seriesModel.get('blendMode') || null;
+        chartView.eachRendered(function (el) {
+          // FIXME marker and other components
+          if (!el.isGroup) {
+            // DONT mark the element dirty. In case element is incremental and don't wan't to rerender.
+            el.style.blend = blendMode;
+          }
+        });
+      }
+
+      function updateZ(model, view) {
+        if (model.preventAutoZ) {
+          return;
+        }
+
+        var z = model.get('z') || 0;
+        var zlevel = model.get('zlevel') || 0; // Set z and zlevel
+
+        view.eachRendered(function (el) {
+          doUpdateZ(el, z, zlevel, -Infinity); // Don't traverse the children because it has been traversed in _updateZ.
+
+          return true;
+        });
+      }
+
+      function doUpdateZ(el, z, zlevel, maxZ2) {
+        // Group may also have textContent
+        var label = el.getTextContent();
+        var labelLine = el.getTextGuideLine();
+        var isGroup = el.isGroup;
+
+        if (isGroup) {
+          // set z & zlevel of children elements of Group
+          var children = el.childrenRef();
+
+          for (var i = 0; i < children.length; i++) {
+            maxZ2 = Math.max(doUpdateZ(children[i], z, zlevel, maxZ2), maxZ2);
+          }
+        } else {
+          // not Group
+          el.z = z;
+          el.zlevel = zlevel;
+          maxZ2 = Math.max(el.z2, maxZ2);
+        } // always set z and zlevel if label/labelLine exists
+
+
+        if (label) {
+          label.z = z;
+          label.zlevel = zlevel; // lift z2 of text content
+          // TODO if el.emphasis.z2 is spcefied, what about textContent.
+
+          isFinite(maxZ2) && (label.z2 = maxZ2 + 2);
+        }
+
+        if (labelLine) {
+          var textGuideLineConfig = el.textGuideLineConfig;
+          labelLine.z = z;
+          labelLine.zlevel = zlevel;
+          isFinite(maxZ2) && (labelLine.z2 = maxZ2 + (textGuideLineConfig && textGuideLineConfig.showAbove ? 1 : -1));
+        }
+
+        return maxZ2;
+      } // Clear states without animation.
+      // TODO States on component.
+
+
+      function clearStates$$1(model, view) {
+        view.eachRendered(function (el) {
+          // Not applied on removed elements, it may still in fading.
+          if (isElementRemoved(el)) {
+            return;
+          }
+
+          var textContent = el.getTextContent();
+          var textGuide = el.getTextGuideLine();
+
+          if (el.stateTransition) {
+            el.stateTransition = null;
+          }
+
+          if (textContent && textContent.stateTransition) {
+            textContent.stateTransition = null;
+          }
+
+          if (textGuide && textGuide.stateTransition) {
+            textGuide.stateTransition = null;
+          } // TODO If el is incremental.
+
+
+          if (el.hasState()) {
+            el.prevStates = el.currentStates;
+            el.clearStates();
+          } else if (el.prevStates) {
+            el.prevStates = null;
+          }
+        });
+      }
+
+      function updateStates(model, view) {
+        var stateAnimationModel = model.getModel('stateAnimation');
+        var enableAnimation = model.isAnimationEnabled();
+        var duration = stateAnimationModel.get('duration');
+        var stateTransition = duration > 0 ? {
+          duration: duration,
+          delay: stateAnimationModel.get('delay'),
+          easing: stateAnimationModel.get('easing') // additive: stateAnimationModel.get('additive')
+
+        } : null;
+        view.eachRendered(function (el) {
+          if (el.states && el.states.emphasis) {
+            // Not applied on removed elements, it may still in fading.
+            if (isElementRemoved(el)) {
+              return;
+            }
+
+            if (el instanceof Path) {
+              savePathStates(el);
+            } // Only updated on changed element. In case element is incremental and don't wan't to rerender.
+            // TODO, a more proper way?
+
+
+            if (el.__dirty) {
+              var prevStates = el.prevStates; // Restore states without animation
+
+              if (prevStates) {
+                el.useStates(prevStates);
+              }
+            } // Update state transition and enable animation again.
+
+
+            if (enableAnimation) {
+              el.stateTransition = stateTransition;
+              var textContent = el.getTextContent();
+              var textGuide = el.getTextGuideLine(); // TODO Is it necessary to animate label?
+
+              if (textContent) {
+                textContent.stateTransition = stateTransition;
+              }
+
+              if (textGuide) {
+                textGuide.stateTransition = stateTransition;
+              }
+            } // The use higlighted and selected flag to toggle states.
+
+
+            if (el.__dirty) {
+              applyElementStates(el);
+            }
+          }
+        });
+      }
+
+      createExtensionAPI = function (ecIns) {
+        return new (
+        /** @class */
+        function (_super) {
+          __extends(class_1, _super);
+
+          function class_1() {
+            return _super !== null && _super.apply(this, arguments) || this;
+          }
+
+          class_1.prototype.getCoordinateSystems = function () {
+            return ecIns._coordSysMgr.getCoordinateSystems();
+          };
+
+          class_1.prototype.getComponentByElement = function (el) {
+            while (el) {
+              var modelInfo = el.__ecComponentInfo;
+
+              if (modelInfo != null) {
+                return ecIns._model.getComponent(modelInfo.mainType, modelInfo.index);
+              }
+
+              el = el.parent;
+            }
+          };
+
+          class_1.prototype.enterEmphasis = function (el, highlightDigit) {
+            enterEmphasis(el, highlightDigit);
+            markStatusToUpdate(ecIns);
+          };
+
+          class_1.prototype.leaveEmphasis = function (el, highlightDigit) {
+            leaveEmphasis(el, highlightDigit);
+            markStatusToUpdate(ecIns);
+          };
+
+          class_1.prototype.enterBlur = function (el) {
+            enterBlur(el);
+            markStatusToUpdate(ecIns);
+          };
+
+          class_1.prototype.leaveBlur = function (el) {
+            leaveBlur(el);
+            markStatusToUpdate(ecIns);
+          };
+
+          class_1.prototype.enterSelect = function (el) {
+            enterSelect(el);
+            markStatusToUpdate(ecIns);
+          };
+
+          class_1.prototype.leaveSelect = function (el) {
+            leaveSelect(el);
+            markStatusToUpdate(ecIns);
+          };
+
+          class_1.prototype.getModel = function () {
+            return ecIns.getModel();
+          };
+
+          class_1.prototype.getViewOfComponentModel = function (componentModel) {
+            return ecIns.getViewOfComponentModel(componentModel);
+          };
+
+          class_1.prototype.getViewOfSeriesModel = function (seriesModel) {
+            return ecIns.getViewOfSeriesModel(seriesModel);
+          };
+
+          return class_1;
+        }(ExtensionAPI))(ecIns);
+      };
+
+      enableConnect = function (chart) {
+        function updateConnectedChartsStatus(charts, status) {
+          for (var i = 0; i < charts.length; i++) {
+            var otherChart = charts[i];
+            otherChart[CONNECT_STATUS_KEY] = status;
+          }
+        }
+
+        each(eventActionMap, function (actionType, eventType) {
+          chart._messageCenter.on(eventType, function (event) {
+            if (connectedGroups[chart.group] && chart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_PENDING) {
+              if (event && event.escapeConnect) {
+                return;
+              }
+
+              var action_1 = chart.makeActionFromEvent(event);
+              var otherCharts_1 = [];
+              each(instances, function (otherChart) {
+                if (otherChart !== chart && otherChart.group === chart.group) {
+                  otherCharts_1.push(otherChart);
+                }
+              });
+              updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_PENDING);
+              each(otherCharts_1, function (otherChart) {
+                if (otherChart[CONNECT_STATUS_KEY] !== CONNECT_STATUS_UPDATING) {
+                  otherChart.dispatchAction(action_1);
+                }
+              });
+              updateConnectedChartsStatus(otherCharts_1, CONNECT_STATUS_UPDATED);
+            }
+          });
+        });
+      };
+    }();
+
+    return ECharts;
+  }(Eventful);
+
+  var echartsProto = ECharts.prototype;
+  echartsProto.on = createRegisterEventWithLowercaseECharts('on');
+  echartsProto.off = createRegisterEventWithLowercaseECharts('off');
+  /**
+   * @deprecated
+   */
+  // @ts-ignore
+
+  echartsProto.one = function (eventName, cb, ctx) {
+    var self = this;
+    deprecateLog('ECharts#one is deprecated.');
+
+    function wrapped() {
+      var args2 = [];
+
+      for (var _i = 0; _i < arguments.length; _i++) {
+        args2[_i] = arguments[_i];
+      }
+
+      cb && cb.apply && cb.apply(this, args2); // @ts-ignore
+
+      self.off(eventName, wrapped);
+    } // @ts-ignore
+
+
+    this.on.call(this, eventName, wrapped, ctx);
+  };
+
+  var MOUSE_EVENT_NAMES = ['click', 'dblclick', 'mouseover', 'mouseout', 'mousemove', 'mousedown', 'mouseup', 'globalout', 'contextmenu'];
+
+  function disposedWarning(id) {
+    {
+      console.warn('Instance ' + id + ' has been disposed');
+    }
+  }
+
+  var actions = {};
+  /**
+   * Map eventType to actionType
+   */
+
+  var eventActionMap = {};
+  var dataProcessorFuncs = [];
+  var optionPreprocessorFuncs = [];
+  var visualFuncs = [];
+  var themeStorage = {};
+  var loadingEffects = {};
+  var instances = {};
+  var connectedGroups = {};
+  var idBase = +new Date() - 0;
+  var groupIdBase = +new Date() - 0;
+  var DOM_ATTRIBUTE_KEY = '_echarts_instance_';
+  /**
+   * @param opts.devicePixelRatio Use window.devicePixelRatio by default
+   * @param opts.renderer Can choose 'canvas' or 'svg' to render the chart.
+   * @param opts.width Use clientWidth of the input `dom` by default.
+   *        Can be 'auto' (the same as null/undefined)
+   * @param opts.height Use clientHeight of the input `dom` by default.
+   *        Can be 'auto' (the same as null/undefined)
+   * @param opts.locale Specify the locale.
+   * @param opts.useDirtyRect Enable dirty rectangle rendering or not.
+   */
+
+  function init(dom, theme$$1, opts) {
+    var isClient = !(opts && opts.ssr);
+
+    if (isClient) {
+      {
+        if (!dom) {
+          throw new Error('Initialize failed: invalid dom.');
+        }
+      }
+      var existInstance = getInstanceByDom(dom);
+
+      if (existInstance) {
+        {
+          console.warn('There is a chart instance already initialized on the dom.');
+        }
+        return existInstance;
+      }
+
+      {
+        if (isDom(dom) && dom.nodeName.toUpperCase() !== 'CANVAS' && (!dom.clientWidth && (!opts || opts.width == null) || !dom.clientHeight && (!opts || opts.height == null))) {
+          console.warn('Can\'t get DOM width or height. Please check ' + 'dom.clientWidth and dom.clientHeight. They should not be 0.' + 'For example, you may need to call this in the callback ' + 'of window.onload.');
+        }
+      }
+    }
+
+    var chart = new ECharts(dom, theme$$1, opts);
+    chart.id = 'ec_' + idBase++;
+    instances[chart.id] = chart;
+    isClient && setAttribute(dom, DOM_ATTRIBUTE_KEY, chart.id);
+    enableConnect(chart);
+    lifecycle.trigger('afterinit', chart);
+    return chart;
+  }
+  /**
+   * @usage
+   * (A)
+   * ```js
+   * let chart1 = echarts.init(dom1);
+   * let chart2 = echarts.init(dom2);
+   * chart1.group = 'xxx';
+   * chart2.group = 'xxx';
+   * echarts.connect('xxx');
+   * ```
+   * (B)
+   * ```js
+   * let chart1 = echarts.init(dom1);
+   * let chart2 = echarts.init(dom2);
+   * echarts.connect('xxx', [chart1, chart2]);
+   * ```
+   */
+
+
+  function connect(groupId) {
+    // Is array of charts
+    if (isArray(groupId)) {
+      var charts = groupId;
+      groupId = null; // If any chart has group
+
+      each(charts, function (chart) {
+        if (chart.group != null) {
+          groupId = chart.group;
+        }
+      });
+      groupId = groupId || 'g_' + groupIdBase++;
+      each(charts, function (chart) {
+        chart.group = groupId;
+      });
+    }
+
+    connectedGroups[groupId] = true;
+    return groupId;
+  }
+  /**
+   * @deprecated
+   */
+
+
+  function disConnect(groupId) {
+    connectedGroups[groupId] = false;
+  }
+  /**
+   * Alias and backword compat
+   */
+
+
+  var disconnect = disConnect;
+  /**
+   * Dispose a chart instance
+   */
+
+  function dispose(chart) {
+    if (isString(chart)) {
+      chart = instances[chart];
+    } else if (!(chart instanceof ECharts)) {
+      // Try to treat as dom
+      chart = getInstanceByDom(chart);
+    }
+
+    if (chart instanceof ECharts && !chart.isDisposed()) {
+      chart.dispose();
+    }
+  }
+
+  function getInstanceByDom(dom) {
+    return instances[getAttribute(dom, DOM_ATTRIBUTE_KEY)];
+  }
+
+  function getInstanceById(key) {
+    return instances[key];
+  }
+  /**
+   * Register theme
+   */
+
+
+  function registerTheme(name, theme$$1) {
+    themeStorage[name] = theme$$1;
+  }
+  /**
+   * Register option preprocessor
+   */
+
+
+  function registerPreprocessor(preprocessorFunc) {
+    if (indexOf(optionPreprocessorFuncs, preprocessorFunc) < 0) {
+      optionPreprocessorFuncs.push(preprocessorFunc);
+    }
+  }
+
+  function registerProcessor(priority, processor) {
+    normalizeRegister(dataProcessorFuncs, priority, processor, PRIORITY_PROCESSOR_DEFAULT);
+  }
+  /**
+   * Register postIniter
+   * @param {Function} postInitFunc
+   */
+
+
+  function registerPostInit(postInitFunc) {
+    registerUpdateLifecycle('afterinit', postInitFunc);
+  }
+  /**
+   * Register postUpdater
+   * @param {Function} postUpdateFunc
+   */
+
+
+  function registerPostUpdate(postUpdateFunc) {
+    registerUpdateLifecycle('afterupdate', postUpdateFunc);
+  }
+
+  function registerUpdateLifecycle(name, cb) {
+    lifecycle.on(name, cb);
+  }
+
+  function registerAction(actionInfo, eventName, action) {
+    if (isFunction(eventName)) {
+      action = eventName;
+      eventName = '';
+    }
+
+    var actionType = isObject(actionInfo) ? actionInfo.type : [actionInfo, actionInfo = {
+      event: eventName
+    }][0]; // Event name is all lowercase
+
+    actionInfo.event = (actionInfo.event || actionType).toLowerCase();
+    eventName = actionInfo.event;
+
+    if (eventActionMap[eventName]) {
+      // Already registered.
+      return;
+    } // Validate action type and event name.
+
+
+    assert(ACTION_REG.test(actionType) && ACTION_REG.test(eventName));
+
+    if (!actions[actionType]) {
+      actions[actionType] = {
+        action: action,
+        actionInfo: actionInfo
+      };
+    }
+
+    eventActionMap[eventName] = actionType;
+  }
+
+  function registerCoordinateSystem(type, coordSysCreator) {
+    CoordinateSystemManager.register(type, coordSysCreator);
+  }
+  /**
+   * Get dimensions of specified coordinate system.
+   * @param {string} type
+   * @return {Array.<string|Object>}
+   */
+
+
+  function getCoordinateSystemDimensions(type) {
+    var coordSysCreator = CoordinateSystemManager.get(type);
+
+    if (coordSysCreator) {
+      return coordSysCreator.getDimensionsInfo ? coordSysCreator.getDimensionsInfo() : coordSysCreator.dimensions.slice();
+    }
+  }
+
+  function registerLayout(priority, layoutTask) {
+    normalizeRegister(visualFuncs, priority, layoutTask, PRIORITY_VISUAL_LAYOUT, 'layout');
+  }
+
+  function registerVisual(priority, visualTask) {
+    normalizeRegister(visualFuncs, priority, visualTask, PRIORITY_VISUAL_CHART, 'visual');
+  }
+
+  var registeredTasks = [];
+
+  function normalizeRegister(targetList, priority, fn, defaultPriority, visualType) {
+    if (isFunction(priority) || isObject(priority)) {
+      fn = priority;
+      priority = defaultPriority;
+    }
+
+    {
+      if (isNaN(priority) || priority == null) {
+        throw new Error('Illegal priority');
+      } // Check duplicate
+
+
+      each(targetList, function (wrap) {
+        assert(wrap.__raw !== fn);
+      });
+    } // Already registered
+
+    if (indexOf(registeredTasks, fn) >= 0) {
+      return;
+    }
+
+    registeredTasks.push(fn);
+    var stageHandler = Scheduler.wrapStageHandler(fn, visualType);
+    stageHandler.__prio = priority;
+    stageHandler.__raw = fn;
+    targetList.push(stageHandler);
+  }
+
+  function registerLoading(name, loadingFx) {
+    loadingEffects[name] = loadingFx;
+  }
+  /**
+   * ZRender need a canvas context to do measureText.
+   * But in node environment canvas may be created by node-canvas.
+   * So we need to specify how to create a canvas instead of using document.createElement('canvas')
+   *
+   *
+   * @deprecated use setPlatformAPI({ createCanvas }) instead.
+   *
+   * @example
+   *     let Canvas = require('canvas');
+   *     let echarts = require('echarts');
+   *     echarts.setCanvasCreator(function () {
+   *         // Small size is enough.
+   *         return new Canvas(32, 32);
+   *     });
+   */
+
+
+  function setCanvasCreator(creator) {
+    {
+      deprecateLog('setCanvasCreator is deprecated. Use setPlatformAPI({ createCanvas }) instead.');
+    }
+    setPlatformAPI({
+      createCanvas: creator
+    });
+  }
+  /**
+   * The parameters and usage: see `geoSourceManager.registerMap`.
+   * Compatible with previous `echarts.registerMap`.
+   */
+
+
+  function registerMap(mapName, geoJson, specialAreas) {
+    var registerMap = getImpl('registerMap');
+    registerMap && registerMap(mapName, geoJson, specialAreas);
+  }
+
+  function getMap(mapName) {
+    var getMap = getImpl('getMap');
+    return getMap && getMap(mapName);
+  }
+
+  var registerTransform = registerExternalTransform;
+  /**
+   * Globa dispatchAction to a specified chart instance.
+   */
+  // export function dispatchAction(payload: { chartId: string } & Payload, opt?: Parameters<ECharts['dispatchAction']>[1]) {
+  //     if (!payload || !payload.chartId) {
+  //         // Must have chartId to find chart
+  //         return;
+  //     }
+  //     const chart = instances[payload.chartId];
+  //     if (chart) {
+  //         chart.dispatchAction(payload, opt);
+  //     }
+  // }
+  // Buitlin global visual
+
+  registerVisual(PRIORITY_VISUAL_GLOBAL, seriesStyleTask);
+  registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataStyleTask);
+  registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataColorPaletteTask);
+  registerVisual(PRIORITY_VISUAL_GLOBAL, seriesSymbolTask);
+  registerVisual(PRIORITY_VISUAL_CHART_DATA_CUSTOM, dataSymbolTask);
+  registerVisual(PRIORITY_VISUAL_DECAL, decalVisual);
+  registerPreprocessor(globalBackwardCompat);
+  registerProcessor(PRIORITY_PROCESSOR_DATASTACK, dataStack);
+  registerLoading('default', defaultLoading); // Default actions
+
+  registerAction({
+    type: HIGHLIGHT_ACTION_TYPE,
+    event: HIGHLIGHT_ACTION_TYPE,
+    update: HIGHLIGHT_ACTION_TYPE
+  }, noop);
+  registerAction({
+    type: DOWNPLAY_ACTION_TYPE,
+    event: DOWNPLAY_ACTION_TYPE,
+    update: DOWNPLAY_ACTION_TYPE
+  }, noop);
+  registerAction({
+    type: SELECT_ACTION_TYPE,
+    event: SELECT_ACTION_TYPE,
+    update: SELECT_ACTION_TYPE
+  }, noop);
+  registerAction({
+    type: UNSELECT_ACTION_TYPE,
+    event: UNSELECT_ACTION_TYPE,
+    update: UNSELECT_ACTION_TYPE
+  }, noop);
+  registerAction({
+    type: TOGGLE_SELECT_ACTION_TYPE,
+    event: TOGGLE_SELECT_ACTION_TYPE,
+    update: TOGGLE_SELECT_ACTION_TYPE
+  }, noop); // Default theme
+
+  registerTheme('light', lightTheme);
+  registerTheme('dark', theme); // For backward compatibility, where the namespace `dataTool` will
+  // be mounted on `echarts` is the extension `dataTool` is imported.
+
+  var dataTool = {};
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 dataIndexMapValueLength(valNumOrArrLengthMoreThan2) {
+    return valNumOrArrLengthMoreThan2 == null ? 0 : valNumOrArrLengthMoreThan2.length || 1;
+  }
+
+  function defaultKeyGetter(item) {
+    return item;
+  }
+
+  var DataDiffer =
+  /** @class */
+  function () {
+    /**
+     * @param context Can be visited by this.context in callback.
+     */
+    function DataDiffer(oldArr, newArr, oldKeyGetter, newKeyGetter, context, // By default: 'oneToOne'.
+    diffMode) {
+      this._old = oldArr;
+      this._new = newArr;
+      this._oldKeyGetter = oldKeyGetter || defaultKeyGetter;
+      this._newKeyGetter = newKeyGetter || defaultKeyGetter; // Visible in callback via `this.context`;
+
+      this.context = context;
+      this._diffModeMultiple = diffMode === 'multiple';
+    }
+    /**
+     * Callback function when add a data
+     */
+
+
+    DataDiffer.prototype.add = function (func) {
+      this._add = func;
+      return this;
+    };
+    /**
+     * Callback function when update a data
+     */
+
+
+    DataDiffer.prototype.update = function (func) {
+      this._update = func;
+      return this;
+    };
+    /**
+     * Callback function when update a data and only work in `cbMode: 'byKey'`.
+     */
+
+
+    DataDiffer.prototype.updateManyToOne = function (func) {
+      this._updateManyToOne = func;
+      return this;
+    };
+    /**
+     * Callback function when update a data and only work in `cbMode: 'byKey'`.
+     */
+
+
+    DataDiffer.prototype.updateOneToMany = function (func) {
+      this._updateOneToMany = func;
+      return this;
+    };
+    /**
+     * Callback function when update a data and only work in `cbMode: 'byKey'`.
+     */
+
+
+    DataDiffer.prototype.updateManyToMany = function (func) {
+      this._updateManyToMany = func;
+      return this;
+    };
+    /**
+     * Callback function when remove a data
+     */
+
+
+    DataDiffer.prototype.remove = function (func) {
+      this._remove = func;
+      return this;
+    };
+
+    DataDiffer.prototype.execute = function () {
+      this[this._diffModeMultiple ? '_executeMultiple' : '_executeOneToOne']();
+    };
+
+    DataDiffer.prototype._executeOneToOne = function () {
+      var oldArr = this._old;
+      var newArr = this._new;
+      var newDataIndexMap = {};
+      var oldDataKeyArr = new Array(oldArr.length);
+      var newDataKeyArr = new Array(newArr.length);
+
+      this._initIndexMap(oldArr, null, oldDataKeyArr, '_oldKeyGetter');
+
+      this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter');
+
+      for (var i = 0; i < oldArr.length; i++) {
+        var oldKey = oldDataKeyArr[i];
+        var newIdxMapVal = newDataIndexMap[oldKey];
+        var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal); // idx can never be empty array here. see 'set null' logic below.
+
+        if (newIdxMapValLen > 1) {
+          // Consider there is duplicate key (for example, use dataItem.name as key).
+          // We should make sure every item in newArr and oldArr can be visited.
+          var newIdx = newIdxMapVal.shift();
+
+          if (newIdxMapVal.length === 1) {
+            newDataIndexMap[oldKey] = newIdxMapVal[0];
+          }
+
+          this._update && this._update(newIdx, i);
+        } else if (newIdxMapValLen === 1) {
+          newDataIndexMap[oldKey] = null;
+          this._update && this._update(newIdxMapVal, i);
+        } else {
+          this._remove && this._remove(i);
+        }
+      }
+
+      this._performRestAdd(newDataKeyArr, newDataIndexMap);
+    };
+    /**
+     * For example, consider the case:
+     * oldData: [o0, o1, o2, o3, o4, o5, o6, o7],
+     * newData: [n0, n1, n2, n3, n4, n5, n6, n7, n8],
+     * Where:
+     *     o0, o1, n0 has key 'a' (many to one)
+     *     o5, n4, n5, n6 has key 'b' (one to many)
+     *     o2, n1 has key 'c' (one to one)
+     *     n2, n3 has key 'd' (add)
+     *     o3, o4 has key 'e' (remove)
+     *     o6, o7, n7, n8 has key 'f' (many to many, treated as add and remove)
+     * Then:
+     *     (The order of the following directives are not ensured.)
+     *     this._updateManyToOne(n0, [o0, o1]);
+     *     this._updateOneToMany([n4, n5, n6], o5);
+     *     this._update(n1, o2);
+     *     this._remove(o3);
+     *     this._remove(o4);
+     *     this._remove(o6);
+     *     this._remove(o7);
+     *     this._add(n2);
+     *     this._add(n3);
+     *     this._add(n7);
+     *     this._add(n8);
+     */
+
+
+    DataDiffer.prototype._executeMultiple = function () {
+      var oldArr = this._old;
+      var newArr = this._new;
+      var oldDataIndexMap = {};
+      var newDataIndexMap = {};
+      var oldDataKeyArr = [];
+      var newDataKeyArr = [];
+
+      this._initIndexMap(oldArr, oldDataIndexMap, oldDataKeyArr, '_oldKeyGetter');
+
+      this._initIndexMap(newArr, newDataIndexMap, newDataKeyArr, '_newKeyGetter');
+
+      for (var i = 0; i < oldDataKeyArr.length; i++) {
+        var oldKey = oldDataKeyArr[i];
+        var oldIdxMapVal = oldDataIndexMap[oldKey];
+        var newIdxMapVal = newDataIndexMap[oldKey];
+        var oldIdxMapValLen = dataIndexMapValueLength(oldIdxMapVal);
+        var newIdxMapValLen = dataIndexMapValueLength(newIdxMapVal);
+
+        if (oldIdxMapValLen > 1 && newIdxMapValLen === 1) {
+          this._updateManyToOne && this._updateManyToOne(newIdxMapVal, oldIdxMapVal);
+          newDataIndexMap[oldKey] = null;
+        } else if (oldIdxMapValLen === 1 && newIdxMapValLen > 1) {
+          this._updateOneToMany && this._updateOneToMany(newIdxMapVal, oldIdxMapVal);
+          newDataIndexMap[oldKey] = null;
+        } else if (oldIdxMapValLen === 1 && newIdxMapValLen === 1) {
+          this._update && this._update(newIdxMapVal, oldIdxMapVal);
+          newDataIndexMap[oldKey] = null;
+        } else if (oldIdxMapValLen > 1 && newIdxMapValLen > 1) {
+          this._updateManyToMany && this._updateManyToMany(newIdxMapVal, oldIdxMapVal);
+          newDataIndexMap[oldKey] = null;
+        } else if (oldIdxMapValLen > 1) {
+          for (var i_1 = 0; i_1 < oldIdxMapValLen; i_1++) {
+            this._remove && this._remove(oldIdxMapVal[i_1]);
+          }
+        } else {
+          this._remove && this._remove(oldIdxMapVal);
+        }
+      }
+
+      this._performRestAdd(newDataKeyArr, newDataIndexMap);
+    };
+
+    DataDiffer.prototype._performRestAdd = function (newDataKeyArr, newDataIndexMap) {
+      for (var i = 0; i < newDataKeyArr.length; i++) {
+        var newKey = newDataKeyArr[i];
+        var newIdxMapVal = newDataIndexMap[newKey];
+        var idxMapValLen = dataIndexMapValueLength(newIdxMapVal);
+
+        if (idxMapValLen > 1) {
+          for (var j = 0; j < idxMapValLen; j++) {
+            this._add && this._add(newIdxMapVal[j]);
+          }
+        } else if (idxMapValLen === 1) {
+          this._add && this._add(newIdxMapVal);
+        } // Support both `newDataKeyArr` are duplication removed or not removed.
+
+
+        newDataIndexMap[newKey] = null;
+      }
+    };
+
+    DataDiffer.prototype._initIndexMap = function (arr, // Can be null.
+    map, // In 'byKey', the output `keyArr` is duplication removed.
+    // In 'byIndex', the output `keyArr` is not duplication removed and
+    //     its indices are accurately corresponding to `arr`.
+    keyArr, keyGetterName) {
+      var cbModeMultiple = this._diffModeMultiple;
+
+      for (var i = 0; i < arr.length; i++) {
+        // Add prefix to avoid conflict with Object.prototype.
+        var key = '_ec_' + this[keyGetterName](arr[i], i);
+
+        if (!cbModeMultiple) {
+          keyArr[i] = key;
+        }
+
+        if (!map) {
+          continue;
+        }
+
+        var idxMapVal = map[key];
+        var idxMapValLen = dataIndexMapValueLength(idxMapVal);
+
+        if (idxMapValLen === 0) {
+          // Simple optimize: in most cases, one index has one key,
+          // do not need array.
+          map[key] = i;
+
+          if (cbModeMultiple) {
+            keyArr.push(key);
+          }
+        } else if (idxMapValLen === 1) {
+          map[key] = [idxMapVal, i];
+        } else {
+          idxMapVal.push(i);
+        }
+      }
+    };
+
+    return DataDiffer;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 DimensionUserOuput =
+  /** @class */
+  function () {
+    function DimensionUserOuput(encode, dimRequest) {
+      this._encode = encode;
+      this._schema = dimRequest;
+    }
+
+    DimensionUserOuput.prototype.get = function () {
+      return {
+        // Do not generate full dimension name until fist used.
+        fullDimensions: this._getFullDimensionNames(),
+        encode: this._encode
+      };
+    };
+    /**
+     * Get all data store dimension names.
+     * Theoretically a series data store is defined both by series and used dataset (if any).
+     * If some dimensions are omitted for performance reason in `this.dimensions`,
+     * the dimension name may not be auto-generated if user does not specify a dimension name.
+     * In this case, the dimension name is `null`/`undefined`.
+     */
+
+
+    DimensionUserOuput.prototype._getFullDimensionNames = function () {
+      if (!this._cachedDimNames) {
+        this._cachedDimNames = this._schema ? this._schema.makeOutputDimensionNames() : [];
+      }
+
+      return this._cachedDimNames;
+    };
+
+    return DimensionUserOuput;
+  }();
+
+  function summarizeDimensions(data, schema) {
+    var summary = {};
+    var encode = summary.encode = {};
+    var notExtraCoordDimMap = createHashMap();
+    var defaultedLabel = [];
+    var defaultedTooltip = [];
+    var userOutputEncode = {};
+    each(data.dimensions, function (dimName) {
+      var dimItem = data.getDimensionInfo(dimName);
+      var coordDim = dimItem.coordDim;
+
+      if (coordDim) {
+        {
+          assert(VISUAL_DIMENSIONS.get(coordDim) == null);
+        }
+        var coordDimIndex = dimItem.coordDimIndex;
+        getOrCreateEncodeArr(encode, coordDim)[coordDimIndex] = dimName;
+
+        if (!dimItem.isExtraCoord) {
+          notExtraCoordDimMap.set(coordDim, 1); // Use the last coord dim (and label friendly) as default label,
+          // because when dataset is used, it is hard to guess which dimension
+          // can be value dimension. If both show x, y on label is not look good,
+          // and conventionally y axis is focused more.
+
+          if (mayLabelDimType(dimItem.type)) {
+            defaultedLabel[0] = dimName;
+          } // User output encode do not contain generated coords.
+          // And it only has index. User can use index to retrieve value from the raw item array.
+
+
+          getOrCreateEncodeArr(userOutputEncode, coordDim)[coordDimIndex] = data.getDimensionIndex(dimItem.name);
+        }
+
+        if (dimItem.defaultTooltip) {
+          defaultedTooltip.push(dimName);
+        }
+      }
+
+      VISUAL_DIMENSIONS.each(function (v, otherDim) {
+        var encodeArr = getOrCreateEncodeArr(encode, otherDim);
+        var dimIndex = dimItem.otherDims[otherDim];
+
+        if (dimIndex != null && dimIndex !== false) {
+          encodeArr[dimIndex] = dimItem.name;
+        }
+      });
+    });
+    var dataDimsOnCoord = [];
+    var encodeFirstDimNotExtra = {};
+    notExtraCoordDimMap.each(function (v, coordDim) {
+      var dimArr = encode[coordDim];
+      encodeFirstDimNotExtra[coordDim] = dimArr[0]; // Not necessary to remove duplicate, because a data
+      // dim canot on more than one coordDim.
+
+      dataDimsOnCoord = dataDimsOnCoord.concat(dimArr);
+    });
+    summary.dataDimsOnCoord = dataDimsOnCoord;
+    summary.dataDimIndicesOnCoord = map(dataDimsOnCoord, function (dimName) {
+      return data.getDimensionInfo(dimName).storeDimIndex;
+    });
+    summary.encodeFirstDimNotExtra = encodeFirstDimNotExtra;
+    var encodeLabel = encode.label; // FIXME `encode.label` is not recommanded, because formatter can not be set
+    // in this way. Use label.formatter instead. May be remove this approach someday.
+
+    if (encodeLabel && encodeLabel.length) {
+      defaultedLabel = encodeLabel.slice();
+    }
+
+    var encodeTooltip = encode.tooltip;
+
+    if (encodeTooltip && encodeTooltip.length) {
+      defaultedTooltip = encodeTooltip.slice();
+    } else if (!defaultedTooltip.length) {
+      defaultedTooltip = defaultedLabel.slice();
+    }
+
+    encode.defaultedLabel = defaultedLabel;
+    encode.defaultedTooltip = defaultedTooltip;
+    summary.userOutput = new DimensionUserOuput(userOutputEncode, schema);
+    return summary;
+  }
+
+  function getOrCreateEncodeArr(encode, dim) {
+    if (!encode.hasOwnProperty(dim)) {
+      encode[dim] = [];
+    }
+
+    return encode[dim];
+  } // FIXME:TS should be type `AxisType`
+
+
+  function getDimensionTypeByAxis(axisType) {
+    return axisType === 'category' ? 'ordinal' : axisType === 'time' ? 'time' : 'float';
+  }
+
+  function mayLabelDimType(dimType) {
+    // In most cases, ordinal and time do not suitable for label.
+    // Ordinal info can be displayed on axis. Time is too long.
+    return !(dimType === 'ordinal' || dimType === 'time');
+  } // function findTheLastDimMayLabel(data) {
+  //     // Get last value dim
+  //     let dimensions = data.dimensions.slice();
+  //     let valueType;
+  //     let valueDim;
+  //     while (dimensions.length && (
+  //         valueDim = dimensions.pop(),
+  //         valueType = data.getDimensionInfo(valueDim).type,
+  //         valueType === 'ordinal' || valueType === 'time'
+  //     )) {} // jshint ignore:line
+  //     return valueDim;
+  // }
+
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 SeriesDimensionDefine =
+  /** @class */
+  function () {
+    /**
+     * @param opt All of the fields will be shallow copied.
+     */
+    function SeriesDimensionDefine(opt) {
+      /**
+       * The format of `otherDims` is:
+       * ```js
+       * {
+       *     tooltip?: number
+       *     label?: number
+       *     itemName?: number
+       *     seriesName?: number
+       * }
+       * ```
+       *
+       * A `series.encode` can specified these fields:
+       * ```js
+       * encode: {
+       *     // "3, 1, 5" is the index of data dimension.
+       *     tooltip: [3, 1, 5],
+       *     label: [0, 3],
+       *     ...
+       * }
+       * ```
+       * `otherDims` is the parse result of the `series.encode` above, like:
+       * ```js
+       * // Suppose the index of this data dimension is `3`.
+       * this.otherDims = {
+       *     // `3` is at the index `0` of the `encode.tooltip`
+       *     tooltip: 0,
+       *     // `3` is at the index `1` of the `encode.label`
+       *     label: 1
+       * };
+       * ```
+       *
+       * This prop should never be `null`/`undefined` after initialized.
+       */
+      this.otherDims = {};
+
+      if (opt != null) {
+        extend(this, opt);
+      }
+    }
+
+    return SeriesDimensionDefine;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$4 = makeInner();
+  var dimTypeShort = {
+    float: 'f',
+    int: 'i',
+    ordinal: 'o',
+    number: 'n',
+    time: 't'
+  };
+  /**
+   * Represents the dimension requirement of a series.
+   *
+   * NOTICE:
+   * When there are too many dimensions in dataset and many series, only the used dimensions
+   * (i.e., used by coord sys and declared in `series.encode`) are add to `dimensionDefineList`.
+   * But users may query data by other unused dimension names.
+   * In this case, users can only query data if and only if they have defined dimension names
+   * via ec option, so we provide `getDimensionIndexFromSource`, which only query them from
+   * `source` dimensions.
+   */
+
+  var SeriesDataSchema =
+  /** @class */
+  function () {
+    function SeriesDataSchema(opt) {
+      this.dimensions = opt.dimensions;
+      this._dimOmitted = opt.dimensionOmitted;
+      this.source = opt.source;
+      this._fullDimCount = opt.fullDimensionCount;
+
+      this._updateDimOmitted(opt.dimensionOmitted);
+    }
+
+    SeriesDataSchema.prototype.isDimensionOmitted = function () {
+      return this._dimOmitted;
+    };
+
+    SeriesDataSchema.prototype._updateDimOmitted = function (dimensionOmitted) {
+      this._dimOmitted = dimensionOmitted;
+
+      if (!dimensionOmitted) {
+        return;
+      }
+
+      if (!this._dimNameMap) {
+        this._dimNameMap = ensureSourceDimNameMap(this.source);
+      }
+    };
+    /**
+     * @caution Can only be used when `dimensionOmitted: true`.
+     *
+     * Get index by user defined dimension name (i.e., not internal generate name).
+     * That is, get index from `dimensionsDefine`.
+     * If no `dimensionsDefine`, or no name get, return -1.
+     */
+
+
+    SeriesDataSchema.prototype.getSourceDimensionIndex = function (dimName) {
+      return retrieve2(this._dimNameMap.get(dimName), -1);
+    };
+    /**
+     * @caution Can only be used when `dimensionOmitted: true`.
+     *
+     * Notice: may return `null`/`undefined` if user not specify dimension names.
+     */
+
+
+    SeriesDataSchema.prototype.getSourceDimension = function (dimIndex) {
+      var dimensionsDefine = this.source.dimensionsDefine;
+
+      if (dimensionsDefine) {
+        return dimensionsDefine[dimIndex];
+      }
+    };
+
+    SeriesDataSchema.prototype.makeStoreSchema = function () {
+      var dimCount = this._fullDimCount;
+      var willRetrieveDataByName = shouldRetrieveDataByName(this.source);
+      var makeHashStrict = !shouldOmitUnusedDimensions(dimCount); // If source don't have dimensions or series don't omit unsed dimensions.
+      // Generate from seriesDimList directly
+
+      var dimHash = '';
+      var dims = [];
+
+      for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < dimCount; fullDimIdx++) {
+        var property = void 0;
+        var type = void 0;
+        var ordinalMeta = void 0;
+        var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc.
+
+        if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) {
+          property = willRetrieveDataByName ? seriesDimDef.name : null;
+          type = seriesDimDef.type;
+          ordinalMeta = seriesDimDef.ordinalMeta;
+          seriesDimIdx++;
+        } else {
+          var sourceDimDef = this.getSourceDimension(fullDimIdx);
+
+          if (sourceDimDef) {
+            property = willRetrieveDataByName ? sourceDimDef.name : null;
+            type = sourceDimDef.type;
+          }
+        }
+
+        dims.push({
+          property: property,
+          type: type,
+          ordinalMeta: ordinalMeta
+        }); // If retrieving data by index,
+        //   use <index, type, ordinalMeta> to determine whether data can be shared.
+        //   (Becuase in this case there might be no dimension name defined in dataset, but indices always exists).
+        //   (indices are always 0, 1, 2, ..., so we can ignore them to shorten the hash).
+        // Otherwise if retrieving data by property name (like `data: [{aa: 123, bb: 765}, ...]`),
+        //   use <property, type, ordinalMeta> in hash.
+
+        if (willRetrieveDataByName && property != null // For data stack, we have make sure each series has its own dim on this store.
+        // So we do not add property to hash to make sure they can share this store.
+        && (!seriesDimDef || !seriesDimDef.isCalculationCoord)) {
+          dimHash += makeHashStrict // Use escape character '`' in case that property name contains '$'.
+          ? property.replace(/\`/g, '`1').replace(/\$/g, '`2') // For better performance, when there are large dimensions, tolerant this defects that hardly meet.
+          : property;
+        }
+
+        dimHash += '$';
+        dimHash += dimTypeShort[type] || 'f';
+
+        if (ordinalMeta) {
+          dimHash += ordinalMeta.uid;
+        }
+
+        dimHash += '$';
+      } // Source from endpoint(usually series) will be read differently
+      // when seriesLayoutBy or startIndex(which is affected by sourceHeader) are different.
+      // So we use this three props as key.
+
+
+      var source = this.source;
+      var hash = [source.seriesLayoutBy, source.startIndex, dimHash].join('$$');
+      return {
+        dimensions: dims,
+        hash: hash
+      };
+    };
+
+    SeriesDataSchema.prototype.makeOutputDimensionNames = function () {
+      var result = [];
+
+      for (var fullDimIdx = 0, seriesDimIdx = 0; fullDimIdx < this._fullDimCount; fullDimIdx++) {
+        var name_1 = void 0;
+        var seriesDimDef = this.dimensions[seriesDimIdx]; // The list has been sorted by `storeDimIndex` asc.
+
+        if (seriesDimDef && seriesDimDef.storeDimIndex === fullDimIdx) {
+          if (!seriesDimDef.isCalculationCoord) {
+            name_1 = seriesDimDef.name;
+          }
+
+          seriesDimIdx++;
+        } else {
+          var sourceDimDef = this.getSourceDimension(fullDimIdx);
+
+          if (sourceDimDef) {
+            name_1 = sourceDimDef.name;
+          }
+        }
+
+        result.push(name_1);
+      }
+
+      return result;
+    };
+
+    SeriesDataSchema.prototype.appendCalculationDimension = function (dimDef) {
+      this.dimensions.push(dimDef);
+      dimDef.isCalculationCoord = true;
+      this._fullDimCount++; // If append dimension on a data store, consider the store
+      // might be shared by different series, series dimensions not
+      // really map to store dimensions.
+
+      this._updateDimOmitted(true);
+    };
+
+    return SeriesDataSchema;
+  }();
+
+  function isSeriesDataSchema(schema) {
+    return schema instanceof SeriesDataSchema;
+  }
+
+  function createDimNameMap(dimsDef) {
+    var dataDimNameMap = createHashMap();
+
+    for (var i = 0; i < (dimsDef || []).length; i++) {
+      var dimDefItemRaw = dimsDef[i];
+      var userDimName = isObject(dimDefItemRaw) ? dimDefItemRaw.name : dimDefItemRaw;
+
+      if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
+        dataDimNameMap.set(userDimName, i);
+      }
+    }
+
+    return dataDimNameMap;
+  }
+
+  function ensureSourceDimNameMap(source) {
+    var innerSource = inner$4(source);
+    return innerSource.dimNameMap || (innerSource.dimNameMap = createDimNameMap(source.dimensionsDefine));
+  }
+
+  function shouldOmitUnusedDimensions(dimCount) {
+    return dimCount > 30;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /* global Int32Array */
+
+
+  var isObject$2 = isObject;
+  var map$1 = map;
+  var CtorInt32Array$1 = typeof Int32Array === 'undefined' ? Array : Int32Array; // Use prefix to avoid index to be the same as otherIdList[idx],
+  // which will cause weird udpate animation.
+
+  var ID_PREFIX = 'e\0\0';
+  var INDEX_NOT_FOUND = -1; // type SeriesDimensionIndex = DimensionIndex;
+
+  var TRANSFERABLE_PROPERTIES = ['hasItemOption', '_nameList', '_idList', '_invertedIndicesMap', '_dimSummary', 'userOutput', '_rawData', '_dimValueGetter', '_nameDimIdx', '_idDimIdx', '_nameRepeatCount'];
+  var CLONE_PROPERTIES = ['_approximateExtent']; // -----------------------------
+  // Internal method declarations:
+  // -----------------------------
+
+  var prepareInvertedIndex;
+  var getId;
+  var getIdNameFromStore;
+  var normalizeDimensions;
+  var transferProperties;
+  var cloneListForMapAndSample;
+  var makeIdFromName;
+
+  var SeriesData =
+  /** @class */
+  function () {
+    /**
+     * @param dimensionsInput.dimensions
+     *        For example, ['someDimName', {name: 'someDimName', type: 'someDimType'}, ...].
+     *        Dimensions should be concrete names like x, y, z, lng, lat, angle, radius
+     */
+    function SeriesData(dimensionsInput, hostModel) {
+      this.type = 'list';
+      this._dimOmitted = false;
+      this._nameList = [];
+      this._idList = []; // Models of data option is stored sparse for optimizing memory cost
+      // Never used yet (not used yet).
+      // private _optionModels: Model[] = [];
+      // Global visual properties after visual coding
+
+      this._visual = {}; // Globel layout properties.
+
+      this._layout = {}; // Item visual properties after visual coding
+
+      this._itemVisuals = []; // Item layout properties after layout
+
+      this._itemLayouts = []; // Graphic elemnents
+
+      this._graphicEls = []; // key: dim, value: extent
+
+      this._approximateExtent = {};
+      this._calculationInfo = {}; // Having detected that there is data item is non primitive type
+      // (in type `OptionDataItemObject`).
+      // Like `data: [ { value: xx, itemStyle: {...} }, ...]`
+      // At present it only happen in `SOURCE_FORMAT_ORIGINAL`.
+
+      this.hasItemOption = false; // Methods that create a new list based on this list should be listed here.
+      // Notice that those method should `RETURN` the new list.
+
+      this.TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'lttbDownSample', 'map']; // Methods that change indices of this list should be listed here.
+
+      this.CHANGABLE_METHODS = ['filterSelf', 'selectRange'];
+      this.DOWNSAMPLE_METHODS = ['downSample', 'lttbDownSample'];
+      var dimensions;
+      var assignStoreDimIdx = false;
+
+      if (isSeriesDataSchema(dimensionsInput)) {
+        dimensions = dimensionsInput.dimensions;
+        this._dimOmitted = dimensionsInput.isDimensionOmitted();
+        this._schema = dimensionsInput;
+      } else {
+        assignStoreDimIdx = true;
+        dimensions = dimensionsInput;
+      }
+
+      dimensions = dimensions || ['x', 'y'];
+      var dimensionInfos = {};
+      var dimensionNames = [];
+      var invertedIndicesMap = {};
+      var needsHasOwn = false;
+      var emptyObj = {};
+
+      for (var i = 0; i < dimensions.length; i++) {
+        // Use the original dimensions[i], where other flag props may exists.
+        var dimInfoInput = dimensions[i];
+        var dimensionInfo = isString(dimInfoInput) ? new SeriesDimensionDefine({
+          name: dimInfoInput
+        }) : !(dimInfoInput instanceof SeriesDimensionDefine) ? new SeriesDimensionDefine(dimInfoInput) : dimInfoInput;
+        var dimensionName = dimensionInfo.name;
+        dimensionInfo.type = dimensionInfo.type || 'float';
+
+        if (!dimensionInfo.coordDim) {
+          dimensionInfo.coordDim = dimensionName;
+          dimensionInfo.coordDimIndex = 0;
+        }
+
+        var otherDims = dimensionInfo.otherDims = dimensionInfo.otherDims || {};
+        dimensionNames.push(dimensionName);
+        dimensionInfos[dimensionName] = dimensionInfo;
+
+        if (emptyObj[dimensionName] != null) {
+          needsHasOwn = true;
+        }
+
+        if (dimensionInfo.createInvertedIndices) {
+          invertedIndicesMap[dimensionName] = [];
+        }
+
+        if (otherDims.itemName === 0) {
+          this._nameDimIdx = i;
+        }
+
+        if (otherDims.itemId === 0) {
+          this._idDimIdx = i;
+        }
+
+        {
+          assert(assignStoreDimIdx || dimensionInfo.storeDimIndex >= 0);
+        }
+
+        if (assignStoreDimIdx) {
+          dimensionInfo.storeDimIndex = i;
+        }
+      }
+
+      this.dimensions = dimensionNames;
+      this._dimInfos = dimensionInfos;
+
+      this._initGetDimensionInfo(needsHasOwn);
+
+      this.hostModel = hostModel;
+      this._invertedIndicesMap = invertedIndicesMap;
+
+      if (this._dimOmitted) {
+        var dimIdxToName_1 = this._dimIdxToName = createHashMap();
+        each(dimensionNames, function (dimName) {
+          dimIdxToName_1.set(dimensionInfos[dimName].storeDimIndex, dimName);
+        });
+      }
+    }
+    /**
+     *
+     * Get concrete dimension name by dimension name or dimension index.
+     * If input a dimension name, do not validate whether the dimension name exits.
+     *
+     * @caution
+     * @param dim Must make sure the dimension is `SeriesDimensionLoose`.
+     * Because only those dimensions will have auto-generated dimension names if not
+     * have a user-specified name, and other dimensions will get a return of null/undefined.
+     *
+     * @notice Becuause of this reason, should better use `getDimensionIndex` instead, for examples:
+     * ```js
+     * const val = data.getStore().get(data.getDimensionIndex(dim), dataIdx);
+     * ```
+     *
+     * @return Concrete dim name.
+     */
+
+
+    SeriesData.prototype.getDimension = function (dim) {
+      var dimIdx = this._recognizeDimIndex(dim);
+
+      if (dimIdx == null) {
+        return dim;
+      }
+
+      dimIdx = dim;
+
+      if (!this._dimOmitted) {
+        return this.dimensions[dimIdx];
+      } // Retrieve from series dimension definition becuase it probably contains
+      // generated dimension name (like 'x', 'y').
+
+
+      var dimName = this._dimIdxToName.get(dimIdx);
+
+      if (dimName != null) {
+        return dimName;
+      }
+
+      var sourceDimDef = this._schema.getSourceDimension(dimIdx);
+
+      if (sourceDimDef) {
+        return sourceDimDef.name;
+      }
+    };
+    /**
+     * Get dimension index in data store. Return -1 if not found.
+     * Can be used to index value from getRawValue.
+     */
+
+
+    SeriesData.prototype.getDimensionIndex = function (dim) {
+      var dimIdx = this._recognizeDimIndex(dim);
+
+      if (dimIdx != null) {
+        return dimIdx;
+      }
+
+      if (dim == null) {
+        return -1;
+      }
+
+      var dimInfo = this._getDimInfo(dim);
+
+      return dimInfo ? dimInfo.storeDimIndex : this._dimOmitted ? this._schema.getSourceDimensionIndex(dim) : -1;
+    };
+    /**
+     * The meanings of the input parameter `dim`:
+     *
+     * + If dim is a number (e.g., `1`), it means the index of the dimension.
+     *   For example, `getDimension(0)` will return 'x' or 'lng' or 'radius'.
+     * + If dim is a number-like string (e.g., `"1"`):
+     *     + If there is the same concrete dim name defined in `series.dimensions` or `dataset.dimensions`,
+     *        it means that concrete name.
+     *     + If not, it will be converted to a number, which means the index of the dimension.
+     *        (why? because of the backward compatbility. We have been tolerating number-like string in
+     *        dimension setting, although now it seems that it is not a good idea.)
+     *     For example, `visualMap[i].dimension: "1"` is the same meaning as `visualMap[i].dimension: 1`,
+     *     if no dimension name is defined as `"1"`.
+     * + If dim is a not-number-like string, it means the concrete dim name.
+     *   For example, it can be be default name `"x"`, `"y"`, `"z"`, `"lng"`, `"lat"`, `"angle"`, `"radius"`,
+     *   or customized in `dimensions` property of option like `"age"`.
+     *
+     * @return recogonized `DimensionIndex`. Otherwise return null/undefined (means that dim is `DimensionName`).
+     */
+
+
+    SeriesData.prototype._recognizeDimIndex = function (dim) {
+      if (isNumber(dim) // If being a number-like string but not being defined as a dimension name.
+      || dim != null && !isNaN(dim) && !this._getDimInfo(dim) && (!this._dimOmitted || this._schema.getSourceDimensionIndex(dim) < 0)) {
+        return +dim;
+      }
+    };
+
+    SeriesData.prototype._getStoreDimIndex = function (dim) {
+      var dimIdx = this.getDimensionIndex(dim);
+      {
+        if (dimIdx == null) {
+          throw new Error('Unkown dimension ' + dim);
+        }
+      }
+      return dimIdx;
+    };
+    /**
+     * Get type and calculation info of particular dimension
+     * @param dim
+     *        Dimension can be concrete names like x, y, z, lng, lat, angle, radius
+     *        Or a ordinal number. For example getDimensionInfo(0) will return 'x' or 'lng' or 'radius'
+     */
+
+
+    SeriesData.prototype.getDimensionInfo = function (dim) {
+      // Do not clone, because there may be categories in dimInfo.
+      return this._getDimInfo(this.getDimension(dim));
+    };
+
+    SeriesData.prototype._initGetDimensionInfo = function (needsHasOwn) {
+      var dimensionInfos = this._dimInfos;
+      this._getDimInfo = needsHasOwn ? function (dimName) {
+        return dimensionInfos.hasOwnProperty(dimName) ? dimensionInfos[dimName] : undefined;
+      } : function (dimName) {
+        return dimensionInfos[dimName];
+      };
+    };
+    /**
+     * concrete dimension name list on coord.
+     */
+
+
+    SeriesData.prototype.getDimensionsOnCoord = function () {
+      return this._dimSummary.dataDimsOnCoord.slice();
+    };
+
+    SeriesData.prototype.mapDimension = function (coordDim, idx) {
+      var dimensionsSummary = this._dimSummary;
+
+      if (idx == null) {
+        return dimensionsSummary.encodeFirstDimNotExtra[coordDim];
+      }
+
+      var dims = dimensionsSummary.encode[coordDim];
+      return dims ? dims[idx] : null;
+    };
+
+    SeriesData.prototype.mapDimensionsAll = function (coordDim) {
+      var dimensionsSummary = this._dimSummary;
+      var dims = dimensionsSummary.encode[coordDim];
+      return (dims || []).slice();
+    };
+
+    SeriesData.prototype.getStore = function () {
+      return this._store;
+    };
+    /**
+     * Initialize from data
+     * @param data source or data or data store.
+     * @param nameList The name of a datum is used on data diff and
+     *        default label/tooltip.
+     *        A name can be specified in encode.itemName,
+     *        or dataItem.name (only for series option data),
+     *        or provided in nameList from outside.
+     */
+
+
+    SeriesData.prototype.initData = function (data, nameList, dimValueGetter) {
+      var _this = this;
+
+      var store;
+
+      if (data instanceof DataStore) {
+        store = data;
+      }
+
+      if (!store) {
+        var dimensions = this.dimensions;
+        var provider = isSourceInstance(data) || isArrayLike(data) ? new DefaultDataProvider(data, dimensions.length) : data;
+        store = new DataStore();
+        var dimensionInfos = map$1(dimensions, function (dimName) {
+          return {
+            type: _this._dimInfos[dimName].type,
+            property: dimName
+          };
+        });
+        store.initData(provider, dimensionInfos, dimValueGetter);
+      }
+
+      this._store = store; // Reset
+
+      this._nameList = (nameList || []).slice();
+      this._idList = [];
+      this._nameRepeatCount = {};
+
+      this._doInit(0, store.count()); // Cache summary info for fast visit. See "dimensionHelper".
+      // Needs to be initialized after store is prepared.
+
+
+      this._dimSummary = summarizeDimensions(this, this._schema);
+      this.userOutput = this._dimSummary.userOutput;
+    };
+    /**
+     * Caution: Can be only called on raw data (before `this._indices` created).
+     */
+
+
+    SeriesData.prototype.appendData = function (data) {
+      var range = this._store.appendData(data);
+
+      this._doInit(range[0], range[1]);
+    };
+    /**
+     * Caution: Can be only called on raw data (before `this._indices` created).
+     * This method does not modify `rawData` (`dataProvider`), but only
+     * add values to store.
+     *
+     * The final count will be increased by `Math.max(values.length, names.length)`.
+     *
+     * @param values That is the SourceType: 'arrayRows', like
+     *        [
+     *            [12, 33, 44],
+     *            [NaN, 43, 1],
+     *            ['-', 'asdf', 0]
+     *        ]
+     *        Each item is exaclty cooresponding to a dimension.
+     */
+
+
+    SeriesData.prototype.appendValues = function (values, names) {
+      var _a = this._store.appendValues(values, names.length),
+          start = _a.start,
+          end = _a.end;
+
+      var shouldMakeIdFromName = this._shouldMakeIdFromName();
+
+      this._updateOrdinalMeta();
+
+      if (names) {
+        for (var idx = start; idx < end; idx++) {
+          var sourceIdx = idx - start;
+          this._nameList[idx] = names[sourceIdx];
+
+          if (shouldMakeIdFromName) {
+            makeIdFromName(this, idx);
+          }
+        }
+      }
+    };
+
+    SeriesData.prototype._updateOrdinalMeta = function () {
+      var store = this._store;
+      var dimensions = this.dimensions;
+
+      for (var i = 0; i < dimensions.length; i++) {
+        var dimInfo = this._dimInfos[dimensions[i]];
+
+        if (dimInfo.ordinalMeta) {
+          store.collectOrdinalMeta(dimInfo.storeDimIndex, dimInfo.ordinalMeta);
+        }
+      }
+    };
+
+    SeriesData.prototype._shouldMakeIdFromName = function () {
+      var provider = this._store.getProvider();
+
+      return this._idDimIdx == null && provider.getSource().sourceFormat !== SOURCE_FORMAT_TYPED_ARRAY && !provider.fillStorage;
+    };
+
+    SeriesData.prototype._doInit = function (start, end) {
+      if (start >= end) {
+        return;
+      }
+
+      var store = this._store;
+      var provider = store.getProvider();
+
+      this._updateOrdinalMeta();
+
+      var nameList = this._nameList;
+      var idList = this._idList;
+      var sourceFormat = provider.getSource().sourceFormat;
+      var isFormatOriginal = sourceFormat === SOURCE_FORMAT_ORIGINAL; // 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
+      // If dataItem is {name: ...} or {id: ...}, it has highest priority.
+      // This kind of ids and names are always stored `_nameList` and `_idList`.
+
+      if (isFormatOriginal && !provider.pure) {
+        var sharedDataItem = [];
+
+        for (var idx = start; idx < end; idx++) {
+          // NOTICE: Try not to write things into dataItem
+          var dataItem = provider.getItem(idx, sharedDataItem);
+
+          if (!this.hasItemOption && isDataItemOption(dataItem)) {
+            this.hasItemOption = true;
+          }
+
+          if (dataItem) {
+            var itemName = dataItem.name;
+
+            if (nameList[idx] == null && itemName != null) {
+              nameList[idx] = convertOptionIdName(itemName, null);
+            }
+
+            var itemId = dataItem.id;
+
+            if (idList[idx] == null && itemId != null) {
+              idList[idx] = convertOptionIdName(itemId, null);
+            }
+          }
+        }
+      }
+
+      if (this._shouldMakeIdFromName()) {
+        for (var idx = start; idx < end; idx++) {
+          makeIdFromName(this, idx);
+        }
+      }
+
+      prepareInvertedIndex(this);
+    };
+    /**
+     * PENDING: In fact currently this function is only used to short-circuit
+     * the calling of `scale.unionExtentFromData` when data have been filtered by modules
+     * like "dataZoom". `scale.unionExtentFromData` is used to calculate data extent for series on
+     * an axis, but if a "axis related data filter module" is used, the extent of the axis have
+     * been fixed and no need to calling `scale.unionExtentFromData` actually.
+     * But if we add "custom data filter" in future, which is not "axis related", this method may
+     * be still needed.
+     *
+     * Optimize for the scenario that data is filtered by a given extent.
+     * Consider that if data amount is more than hundreds of thousand,
+     * extent calculation will cost more than 10ms and the cache will
+     * be erased because of the filtering.
+     */
+
+
+    SeriesData.prototype.getApproximateExtent = function (dim) {
+      return this._approximateExtent[dim] || this._store.getDataExtent(this._getStoreDimIndex(dim));
+    };
+    /**
+     * Calculate extent on a filtered data might be time consuming.
+     * Approximate extent is only used for: calculte extent of filtered data outside.
+     */
+
+
+    SeriesData.prototype.setApproximateExtent = function (extent, dim) {
+      dim = this.getDimension(dim);
+      this._approximateExtent[dim] = extent.slice();
+    };
+
+    SeriesData.prototype.getCalculationInfo = function (key) {
+      return this._calculationInfo[key];
+    };
+
+    SeriesData.prototype.setCalculationInfo = function (key, value) {
+      isObject$2(key) ? extend(this._calculationInfo, key) : this._calculationInfo[key] = value;
+    };
+    /**
+     * @return Never be null/undefined. `number` will be converted to string. Becuase:
+     * In most cases, name is used in display, where returning a string is more convenient.
+     * In other cases, name is used in query (see `indexOfName`), where we can keep the
+     * rule that name `2` equals to name `'2'`.
+     */
+
+
+    SeriesData.prototype.getName = function (idx) {
+      var rawIndex = this.getRawIndex(idx);
+      var name = this._nameList[rawIndex];
+
+      if (name == null && this._nameDimIdx != null) {
+        name = getIdNameFromStore(this, this._nameDimIdx, rawIndex);
+      }
+
+      if (name == null) {
+        name = '';
+      }
+
+      return name;
+    };
+
+    SeriesData.prototype._getCategory = function (dimIdx, idx) {
+      var ordinal = this._store.get(dimIdx, idx);
+
+      var ordinalMeta = this._store.getOrdinalMeta(dimIdx);
+
+      if (ordinalMeta) {
+        return ordinalMeta.categories[ordinal];
+      }
+
+      return ordinal;
+    };
+    /**
+     * @return Never null/undefined. `number` will be converted to string. Becuase:
+     * In all cases having encountered at present, id is used in making diff comparison, which
+     * are usually based on hash map. We can keep the rule that the internal id are always string
+     * (treat `2` is the same as `'2'`) to make the related logic simple.
+     */
+
+
+    SeriesData.prototype.getId = function (idx) {
+      return getId(this, this.getRawIndex(idx));
+    };
+
+    SeriesData.prototype.count = function () {
+      return this._store.count();
+    };
+    /**
+     * Get value. Return NaN if idx is out of range.
+     *
+     * @notice Should better to use `data.getStore().get(dimIndex, dataIdx)` instead.
+     */
+
+
+    SeriesData.prototype.get = function (dim, idx) {
+      var store = this._store;
+      var dimInfo = this._dimInfos[dim];
+
+      if (dimInfo) {
+        return store.get(dimInfo.storeDimIndex, idx);
+      }
+    };
+    /**
+     * @notice Should better to use `data.getStore().getByRawIndex(dimIndex, dataIdx)` instead.
+     */
+
+
+    SeriesData.prototype.getByRawIndex = function (dim, rawIdx) {
+      var store = this._store;
+      var dimInfo = this._dimInfos[dim];
+
+      if (dimInfo) {
+        return store.getByRawIndex(dimInfo.storeDimIndex, rawIdx);
+      }
+    };
+
+    SeriesData.prototype.getIndices = function () {
+      return this._store.getIndices();
+    };
+
+    SeriesData.prototype.getDataExtent = function (dim) {
+      return this._store.getDataExtent(this._getStoreDimIndex(dim));
+    };
+
+    SeriesData.prototype.getSum = function (dim) {
+      return this._store.getSum(this._getStoreDimIndex(dim));
+    };
+
+    SeriesData.prototype.getMedian = function (dim) {
+      return this._store.getMedian(this._getStoreDimIndex(dim));
+    };
+
+    SeriesData.prototype.getValues = function (dimensions, idx) {
+      var _this = this;
+
+      var store = this._store;
+      return isArray(dimensions) ? store.getValues(map$1(dimensions, function (dim) {
+        return _this._getStoreDimIndex(dim);
+      }), idx) : store.getValues(dimensions);
+    };
+    /**
+     * If value is NaN. Inlcuding '-'
+     * Only check the coord dimensions.
+     */
+
+
+    SeriesData.prototype.hasValue = function (idx) {
+      var dataDimIndicesOnCoord = this._dimSummary.dataDimIndicesOnCoord;
+
+      for (var i = 0, len = dataDimIndicesOnCoord.length; i < len; i++) {
+        // Ordinal type originally can be string or number.
+        // But when an ordinal type is used on coord, it can
+        // not be string but only number. So we can also use isNaN.
+        if (isNaN(this._store.get(dataDimIndicesOnCoord[i], idx))) {
+          return false;
+        }
+      }
+
+      return true;
+    };
+    /**
+     * Retreive the index with given name
+     */
+
+
+    SeriesData.prototype.indexOfName = function (name) {
+      for (var i = 0, len = this._store.count(); i < len; i++) {
+        if (this.getName(i) === name) {
+          return i;
+        }
+      }
+
+      return -1;
+    };
+
+    SeriesData.prototype.getRawIndex = function (idx) {
+      return this._store.getRawIndex(idx);
+    };
+
+    SeriesData.prototype.indexOfRawIndex = function (rawIndex) {
+      return this._store.indexOfRawIndex(rawIndex);
+    };
+    /**
+     * Only support the dimension which inverted index created.
+     * Do not support other cases until required.
+     * @param dim concrete dim
+     * @param value ordinal index
+     * @return rawIndex
+     */
+
+
+    SeriesData.prototype.rawIndexOf = function (dim, value) {
+      var invertedIndices = dim && this._invertedIndicesMap[dim];
+      {
+        if (!invertedIndices) {
+          throw new Error('Do not supported yet');
+        }
+      }
+      var rawIndex = invertedIndices[value];
+
+      if (rawIndex == null || isNaN(rawIndex)) {
+        return INDEX_NOT_FOUND;
+      }
+
+      return rawIndex;
+    };
+    /**
+     * 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.
+     */
+
+
+    SeriesData.prototype.indicesOfNearest = function (dim, value, maxDistance) {
+      return this._store.indicesOfNearest(this._getStoreDimIndex(dim), value, maxDistance);
+    };
+
+    SeriesData.prototype.each = function (dims, cb, ctx) {
+      'use strict';
+
+      if (isFunction(dims)) {
+        ctx = cb;
+        cb = dims;
+        dims = [];
+      } // ctxCompat just for compat echarts3
+
+
+      var fCtx = ctx || this;
+      var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this);
+
+      this._store.each(dimIndices, fCtx ? bind(cb, fCtx) : cb);
+    };
+
+    SeriesData.prototype.filterSelf = function (dims, cb, ctx) {
+      'use strict';
+
+      if (isFunction(dims)) {
+        ctx = cb;
+        cb = dims;
+        dims = [];
+      } // ctxCompat just for compat echarts3
+
+
+      var fCtx = ctx || this;
+      var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this);
+      this._store = this._store.filter(dimIndices, fCtx ? bind(cb, fCtx) : cb);
+      return this;
+    };
+    /**
+     * Select data in range. (For optimization of filter)
+     * (Manually inline code, support 5 million data filtering in data zoom.)
+     */
+
+
+    SeriesData.prototype.selectRange = function (range) {
+      'use strict';
+
+      var _this = this;
+
+      var innerRange = {};
+      var dims = keys(range);
+      var dimIndices = [];
+      each(dims, function (dim) {
+        var dimIdx = _this._getStoreDimIndex(dim);
+
+        innerRange[dimIdx] = range[dim];
+        dimIndices.push(dimIdx);
+      });
+      this._store = this._store.selectRange(innerRange);
+      return this;
+    };
+    /* eslint-enable max-len */
+
+
+    SeriesData.prototype.mapArray = function (dims, cb, ctx) {
+      'use strict';
+
+      if (isFunction(dims)) {
+        ctx = cb;
+        cb = dims;
+        dims = [];
+      } // ctxCompat just for compat echarts3
+
+
+      ctx = ctx || this;
+      var result = [];
+      this.each(dims, function () {
+        result.push(cb && cb.apply(this, arguments));
+      }, ctx);
+      return result;
+    };
+
+    SeriesData.prototype.map = function (dims, cb, ctx, ctxCompat) {
+      'use strict'; // ctxCompat just for compat echarts3
+
+      var fCtx = ctx || ctxCompat || this;
+      var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this);
+      var list = cloneListForMapAndSample(this);
+      list._store = this._store.map(dimIndices, fCtx ? bind(cb, fCtx) : cb);
+      return list;
+    };
+
+    SeriesData.prototype.modify = function (dims, cb, ctx, ctxCompat) {
+      var _this = this; // ctxCompat just for compat echarts3
+
+
+      var fCtx = ctx || ctxCompat || this;
+      {
+        each(normalizeDimensions(dims), function (dim) {
+          var dimInfo = _this.getDimensionInfo(dim);
+
+          if (!dimInfo.isCalculationCoord) {
+            console.error('Danger: only stack dimension can be modified');
+          }
+        });
+      }
+      var dimIndices = map$1(normalizeDimensions(dims), this._getStoreDimIndex, this); // If do shallow clone here, if there are too many stacked series,
+      // it still cost lots of memory, becuase `_store.dimensions` are not shared.
+      // We should consider there probably be shallow clone happen in each sereis
+      // in consequent filter/map.
+
+      this._store.modify(dimIndices, fCtx ? bind(cb, fCtx) : cb);
+    };
+    /**
+     * Large data down sampling on given dimension
+     * @param sampleIndex Sample index for name and id
+     */
+
+
+    SeriesData.prototype.downSample = function (dimension, rate, sampleValue, sampleIndex) {
+      var list = cloneListForMapAndSample(this);
+      list._store = this._store.downSample(this._getStoreDimIndex(dimension), rate, sampleValue, sampleIndex);
+      return list;
+    };
+    /**
+     * Large data down sampling using largest-triangle-three-buckets
+     * @param {string} valueDimension
+     * @param {number} targetCount
+     */
+
+
+    SeriesData.prototype.lttbDownSample = function (valueDimension, rate) {
+      var list = cloneListForMapAndSample(this);
+      list._store = this._store.lttbDownSample(this._getStoreDimIndex(valueDimension), rate);
+      return list;
+    };
+
+    SeriesData.prototype.getRawDataItem = function (idx) {
+      return this._store.getRawDataItem(idx);
+    };
+    /**
+     * Get model of one data item.
+     */
+    // TODO: Type of data item
+
+
+    SeriesData.prototype.getItemModel = function (idx) {
+      var hostModel = this.hostModel;
+      var dataItem = this.getRawDataItem(idx);
+      return new Model(dataItem, hostModel, hostModel && hostModel.ecModel);
+    };
+    /**
+     * Create a data differ
+     */
+
+
+    SeriesData.prototype.diff = function (otherList) {
+      var thisList = this;
+      return new DataDiffer(otherList ? otherList.getStore().getIndices() : [], this.getStore().getIndices(), function (idx) {
+        return getId(otherList, idx);
+      }, function (idx) {
+        return getId(thisList, idx);
+      });
+    };
+    /**
+     * Get visual property.
+     */
+
+
+    SeriesData.prototype.getVisual = function (key) {
+      var visual = this._visual;
+      return visual && visual[key];
+    };
+
+    SeriesData.prototype.setVisual = function (kvObj, val) {
+      this._visual = this._visual || {};
+
+      if (isObject$2(kvObj)) {
+        extend(this._visual, kvObj);
+      } else {
+        this._visual[kvObj] = val;
+      }
+    };
+    /**
+     * Get visual property of single data item
+     */
+    // eslint-disable-next-line
+
+
+    SeriesData.prototype.getItemVisual = function (idx, key) {
+      var itemVisual = this._itemVisuals[idx];
+      var val = itemVisual && itemVisual[key];
+
+      if (val == null) {
+        // Use global visual property
+        return this.getVisual(key);
+      }
+
+      return val;
+    };
+    /**
+     * If exists visual property of single data item
+     */
+
+
+    SeriesData.prototype.hasItemVisual = function () {
+      return this._itemVisuals.length > 0;
+    };
+    /**
+     * Make sure itemVisual property is unique
+     */
+    // TODO: use key to save visual to reduce memory.
+
+
+    SeriesData.prototype.ensureUniqueItemVisual = function (idx, key) {
+      var itemVisuals = this._itemVisuals;
+      var itemVisual = itemVisuals[idx];
+
+      if (!itemVisual) {
+        itemVisual = itemVisuals[idx] = {};
+      }
+
+      var val = itemVisual[key];
+
+      if (val == null) {
+        val = this.getVisual(key); // TODO Performance?
+
+        if (isArray(val)) {
+          val = val.slice();
+        } else if (isObject$2(val)) {
+          val = extend({}, val);
+        }
+
+        itemVisual[key] = val;
+      }
+
+      return val;
+    }; // eslint-disable-next-line
+
+
+    SeriesData.prototype.setItemVisual = function (idx, key, value) {
+      var itemVisual = this._itemVisuals[idx] || {};
+      this._itemVisuals[idx] = itemVisual;
+
+      if (isObject$2(key)) {
+        extend(itemVisual, key);
+      } else {
+        itemVisual[key] = value;
+      }
+    };
+    /**
+     * Clear itemVisuals and list visual.
+     */
+
+
+    SeriesData.prototype.clearAllVisual = function () {
+      this._visual = {};
+      this._itemVisuals = [];
+    };
+
+    SeriesData.prototype.setLayout = function (key, val) {
+      isObject$2(key) ? extend(this._layout, key) : this._layout[key] = val;
+    };
+    /**
+     * Get layout property.
+     */
+
+
+    SeriesData.prototype.getLayout = function (key) {
+      return this._layout[key];
+    };
+    /**
+     * Get layout of single data item
+     */
+
+
+    SeriesData.prototype.getItemLayout = function (idx) {
+      return this._itemLayouts[idx];
+    };
+    /**
+     * Set layout of single data item
+     */
+
+
+    SeriesData.prototype.setItemLayout = function (idx, layout, merge$$1) {
+      this._itemLayouts[idx] = merge$$1 ? extend(this._itemLayouts[idx] || {}, layout) : layout;
+    };
+    /**
+     * Clear all layout of single data item
+     */
+
+
+    SeriesData.prototype.clearItemLayouts = function () {
+      this._itemLayouts.length = 0;
+    };
+    /**
+     * Set graphic element relative to data. It can be set as null
+     */
+
+
+    SeriesData.prototype.setItemGraphicEl = function (idx, el) {
+      var seriesIndex = this.hostModel && this.hostModel.seriesIndex;
+      setCommonECData(seriesIndex, this.dataType, idx, el);
+      this._graphicEls[idx] = el;
+    };
+
+    SeriesData.prototype.getItemGraphicEl = function (idx) {
+      return this._graphicEls[idx];
+    };
+
+    SeriesData.prototype.eachItemGraphicEl = function (cb, context) {
+      each(this._graphicEls, function (el, idx) {
+        if (el) {
+          cb && cb.call(context, el, idx);
+        }
+      });
+    };
+    /**
+     * Shallow clone a new list except visual and layout properties, and graph elements.
+     * New list only change the indices.
+     */
+
+
+    SeriesData.prototype.cloneShallow = function (list) {
+      if (!list) {
+        list = new SeriesData(this._schema ? this._schema : map$1(this.dimensions, this._getDimInfo, this), this.hostModel);
+      }
+
+      transferProperties(list, this);
+      list._store = this._store;
+      return list;
+    };
+    /**
+     * Wrap some method to add more feature
+     */
+
+
+    SeriesData.prototype.wrapMethod = function (methodName, injectFunction) {
+      var originalMethod = this[methodName];
+
+      if (!isFunction(originalMethod)) {
+        return;
+      }
+
+      this.__wrappedMethods = this.__wrappedMethods || [];
+
+      this.__wrappedMethods.push(methodName);
+
+      this[methodName] = function () {
+        var res = originalMethod.apply(this, arguments);
+        return injectFunction.apply(this, [res].concat(slice(arguments)));
+      };
+    }; // ----------------------------------------------------------
+    // A work around for internal method visiting private member.
+    // ----------------------------------------------------------
+
+
+    SeriesData.internalField = function () {
+      prepareInvertedIndex = function (data) {
+        var invertedIndicesMap = data._invertedIndicesMap;
+        each(invertedIndicesMap, function (invertedIndices, dim) {
+          var dimInfo = data._dimInfos[dim]; // Currently, only dimensions that has ordinalMeta can create inverted indices.
+
+          var ordinalMeta = dimInfo.ordinalMeta;
+          var store = data._store;
+
+          if (ordinalMeta) {
+            invertedIndices = invertedIndicesMap[dim] = new CtorInt32Array$1(ordinalMeta.categories.length); // The default value of TypedArray is 0. To avoid miss
+            // mapping to 0, we should set it as INDEX_NOT_FOUND.
+
+            for (var i = 0; i < invertedIndices.length; i++) {
+              invertedIndices[i] = INDEX_NOT_FOUND;
+            }
+
+            for (var i = 0; i < store.count(); i++) {
+              // Only support the case that all values are distinct.
+              invertedIndices[store.get(dimInfo.storeDimIndex, i)] = i;
+            }
+          }
+        });
+      };
+
+      getIdNameFromStore = function (data, dimIdx, idx) {
+        return convertOptionIdName(data._getCategory(dimIdx, idx), null);
+      };
+      /**
+       * @see the comment of `List['getId']`.
+       */
+
+
+      getId = function (data, rawIndex) {
+        var id = data._idList[rawIndex];
+
+        if (id == null && data._idDimIdx != null) {
+          id = getIdNameFromStore(data, data._idDimIdx, rawIndex);
+        }
+
+        if (id == null) {
+          id = ID_PREFIX + rawIndex;
+        }
+
+        return id;
+      };
+
+      normalizeDimensions = function (dimensions) {
+        if (!isArray(dimensions)) {
+          dimensions = dimensions != null ? [dimensions] : [];
+        }
+
+        return dimensions;
+      };
+      /**
+       * Data in excludeDimensions is copied, otherwise transfered.
+       */
+
+
+      cloneListForMapAndSample = function (original) {
+        var list = new SeriesData(original._schema ? original._schema : map$1(original.dimensions, original._getDimInfo, original), original.hostModel); // FIXME If needs stackedOn, value may already been stacked
+
+        transferProperties(list, original);
+        return list;
+      };
+
+      transferProperties = function (target, source) {
+        each(TRANSFERABLE_PROPERTIES.concat(source.__wrappedMethods || []), function (propName) {
+          if (source.hasOwnProperty(propName)) {
+            target[propName] = source[propName];
+          }
+        });
+        target.__wrappedMethods = source.__wrappedMethods;
+        each(CLONE_PROPERTIES, function (propName) {
+          target[propName] = clone(source[propName]);
+        });
+        target._calculationInfo = extend({}, source._calculationInfo);
+      };
+
+      makeIdFromName = function (data, idx) {
+        var nameList = data._nameList;
+        var idList = data._idList;
+        var nameDimIdx = data._nameDimIdx;
+        var idDimIdx = data._idDimIdx;
+        var name = nameList[idx];
+        var id = idList[idx];
+
+        if (name == null && nameDimIdx != null) {
+          nameList[idx] = name = getIdNameFromStore(data, nameDimIdx, idx);
+        }
+
+        if (id == null && idDimIdx != null) {
+          idList[idx] = id = getIdNameFromStore(data, idDimIdx, idx);
+        }
+
+        if (id == null && name != null) {
+          var nameRepeatCount = data._nameRepeatCount;
+          var nmCnt = nameRepeatCount[name] = (nameRepeatCount[name] || 0) + 1;
+          id = name;
+
+          if (nmCnt > 1) {
+            id += '__ec__' + nmCnt;
+          }
+
+          idList[idx] = id;
+        }
+      };
+    }();
+
+    return SeriesData;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * For outside usage compat (like echarts-gl are using it).
+   */
+
+
+  function createDimensions(source, opt) {
+    return prepareSeriesDataSchema(source, opt).dimensions;
+  }
+  /**
+   * This method builds the relationship between:
+   * + "what the coord sys or series requires (see `coordDimensions`)",
+   * + "what the user defines (in `encode` and `dimensions`, see `opt.dimensionsDefine` and `opt.encodeDefine`)"
+   * + "what the data source provids (see `source`)".
+   *
+   * Some guess strategy will be adapted if user does not define something.
+   * If no 'value' dimension specified, the first no-named dimension will be
+   * named as 'value'.
+   *
+   * @return The results are always sorted by `storeDimIndex` asc.
+   */
+
+
+  function prepareSeriesDataSchema( // TODO: TYPE completeDimensions type
+  source, opt) {
+    if (!isSourceInstance(source)) {
+      source = createSourceFromSeriesDataOption(source);
+    }
+
+    opt = opt || {};
+    var sysDims = opt.coordDimensions || [];
+    var dimsDef = opt.dimensionsDefine || source.dimensionsDefine || [];
+    var coordDimNameMap = createHashMap();
+    var resultList = [];
+    var dimCount = getDimCount(source, sysDims, dimsDef, opt.dimensionsCount); // Try to ignore unsed dimensions if sharing a high dimension datastore
+    // 30 is an experience value.
+
+    var omitUnusedDimensions = opt.canOmitUnusedDimensions && shouldOmitUnusedDimensions(dimCount);
+    var isUsingSourceDimensionsDef = dimsDef === source.dimensionsDefine;
+    var dataDimNameMap = isUsingSourceDimensionsDef ? ensureSourceDimNameMap(source) : createDimNameMap(dimsDef);
+    var encodeDef = opt.encodeDefine;
+
+    if (!encodeDef && opt.encodeDefaulter) {
+      encodeDef = opt.encodeDefaulter(source, dimCount);
+    }
+
+    var encodeDefMap = createHashMap(encodeDef);
+    var indicesMap = new CtorInt32Array(dimCount);
+
+    for (var i = 0; i < indicesMap.length; i++) {
+      indicesMap[i] = -1;
+    }
+
+    function getResultItem(dimIdx) {
+      var idx = indicesMap[dimIdx];
+
+      if (idx < 0) {
+        var dimDefItemRaw = dimsDef[dimIdx];
+        var dimDefItem = isObject(dimDefItemRaw) ? dimDefItemRaw : {
+          name: dimDefItemRaw
+        };
+        var resultItem = new SeriesDimensionDefine();
+        var userDimName = dimDefItem.name;
+
+        if (userDimName != null && dataDimNameMap.get(userDimName) != null) {
+          // Only if `series.dimensions` is defined in option
+          // displayName, will be set, and dimension will be diplayed vertically in
+          // tooltip by default.
+          resultItem.name = resultItem.displayName = userDimName;
+        }
+
+        dimDefItem.type != null && (resultItem.type = dimDefItem.type);
+        dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
+        var newIdx = resultList.length;
+        indicesMap[dimIdx] = newIdx;
+        resultItem.storeDimIndex = dimIdx;
+        resultList.push(resultItem);
+        return resultItem;
+      }
+
+      return resultList[idx];
+    }
+
+    if (!omitUnusedDimensions) {
+      for (var i = 0; i < dimCount; i++) {
+        getResultItem(i);
+      }
+    } // Set `coordDim` and `coordDimIndex` by `encodeDefMap` and normalize `encodeDefMap`.
+
+
+    encodeDefMap.each(function (dataDimsRaw, coordDim) {
+      var dataDims = normalizeToArray(dataDimsRaw).slice(); // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
+      // `{encode: {x: -1, y: 1}}`. Should not filter anything in
+      // this case.
+
+      if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
+        encodeDefMap.set(coordDim, false);
+        return;
+      }
+
+      var validDataDims = encodeDefMap.set(coordDim, []);
+      each(dataDims, function (resultDimIdxOrName, idx) {
+        // The input resultDimIdx can be dim name or index.
+        var resultDimIdx = isString(resultDimIdxOrName) ? dataDimNameMap.get(resultDimIdxOrName) : resultDimIdxOrName;
+
+        if (resultDimIdx != null && resultDimIdx < dimCount) {
+          validDataDims[idx] = resultDimIdx;
+          applyDim(getResultItem(resultDimIdx), coordDim, idx);
+        }
+      });
+    }); // Apply templetes and default order from `sysDims`.
+
+    var availDimIdx = 0;
+    each(sysDims, function (sysDimItemRaw) {
+      var coordDim;
+      var sysDimItemDimsDef;
+      var sysDimItemOtherDims;
+      var sysDimItem;
+
+      if (isString(sysDimItemRaw)) {
+        coordDim = sysDimItemRaw;
+        sysDimItem = {};
+      } else {
+        sysDimItem = sysDimItemRaw;
+        coordDim = sysDimItem.name;
+        var ordinalMeta = sysDimItem.ordinalMeta;
+        sysDimItem.ordinalMeta = null;
+        sysDimItem = extend({}, sysDimItem);
+        sysDimItem.ordinalMeta = ordinalMeta; // `coordDimIndex` should not be set directly.
+
+        sysDimItemDimsDef = sysDimItem.dimsDef;
+        sysDimItemOtherDims = sysDimItem.otherDims;
+        sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex = sysDimItem.dimsDef = sysDimItem.otherDims = null;
+      }
+
+      var dataDims = encodeDefMap.get(coordDim); // negative resultDimIdx means no need to mapping.
+
+      if (dataDims === false) {
+        return;
+      }
+
+      dataDims = normalizeToArray(dataDims); // dimensions provides default dim sequences.
+
+      if (!dataDims.length) {
+        for (var i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
+          while (availDimIdx < dimCount && getResultItem(availDimIdx).coordDim != null) {
+            availDimIdx++;
+          }
+
+          availDimIdx < dimCount && dataDims.push(availDimIdx++);
+        }
+      } // Apply templates.
+
+
+      each(dataDims, function (resultDimIdx, coordDimIndex) {
+        var resultItem = getResultItem(resultDimIdx); // Coordinate system has a higher priority on dim type than source.
+
+        if (isUsingSourceDimensionsDef && sysDimItem.type != null) {
+          resultItem.type = sysDimItem.type;
+        }
+
+        applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
+
+        if (resultItem.name == null && sysDimItemDimsDef) {
+          var sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
+          !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {
+            name: sysDimItemDimsDefItem
+          });
+          resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
+          resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
+        } // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
+
+
+        sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
+      });
+    });
+
+    function applyDim(resultItem, coordDim, coordDimIndex) {
+      if (VISUAL_DIMENSIONS.get(coordDim) != null) {
+        resultItem.otherDims[coordDim] = coordDimIndex;
+      } else {
+        resultItem.coordDim = coordDim;
+        resultItem.coordDimIndex = coordDimIndex;
+        coordDimNameMap.set(coordDim, true);
+      }
+    } // Make sure the first extra dim is 'value'.
+
+
+    var generateCoord = opt.generateCoord;
+    var generateCoordCount = opt.generateCoordCount;
+    var fromZero = generateCoordCount != null;
+    generateCoordCount = generateCoord ? generateCoordCount || 1 : 0;
+    var extra = generateCoord || 'value';
+
+    function ifNoNameFillWithCoordName(resultItem) {
+      if (resultItem.name == null) {
+        // Duplication will be removed in the next step.
+        resultItem.name = resultItem.coordDim;
+      }
+    } // Set dim `name` and other `coordDim` and other props.
+
+
+    if (!omitUnusedDimensions) {
+      for (var resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
+        var resultItem = getResultItem(resultDimIdx);
+        var coordDim = resultItem.coordDim;
+
+        if (coordDim == null) {
+          // TODO no need to generate coordDim for isExtraCoord?
+          resultItem.coordDim = genCoordDimName(extra, coordDimNameMap, fromZero);
+          resultItem.coordDimIndex = 0; // Series specified generateCoord is using out.
+
+          if (!generateCoord || generateCoordCount <= 0) {
+            resultItem.isExtraCoord = true;
+          }
+
+          generateCoordCount--;
+        }
+
+        ifNoNameFillWithCoordName(resultItem);
+
+        if (resultItem.type == null && (guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must // Consider the case:
+        // {
+        //    dataset: {source: [
+        //        ['2001', 123],
+        //        ['2002', 456],
+        //        ...
+        //        ['The others', 987],
+        //    ]},
+        //    series: {type: 'pie'}
+        // }
+        // The first colum should better be treated as a "ordinal" although it
+        // might not able to be detected as an "ordinal" by `guessOrdinal`.
+        || resultItem.isExtraCoord && (resultItem.otherDims.itemName != null || resultItem.otherDims.seriesName != null))) {
+          resultItem.type = 'ordinal';
+        }
+      }
+    } else {
+      each(resultList, function (resultItem) {
+        // PENDING: guessOrdinal or let user specify type: 'ordinal' manually?
+        ifNoNameFillWithCoordName(resultItem);
+      }); // Sort dimensions: there are some rule that use the last dim as label,
+      // and for some latter travel process easier.
+
+      resultList.sort(function (item0, item1) {
+        return item0.storeDimIndex - item1.storeDimIndex;
+      });
+    }
+
+    removeDuplication(resultList);
+    return new SeriesDataSchema({
+      source: source,
+      dimensions: resultList,
+      fullDimensionCount: dimCount,
+      dimensionOmitted: omitUnusedDimensions
+    });
+  }
+
+  function removeDuplication(result) {
+    var duplicationMap = createHashMap();
+
+    for (var i = 0; i < result.length; i++) {
+      var dim = result[i];
+      var dimOriginalName = dim.name;
+      var count = duplicationMap.get(dimOriginalName) || 0;
+
+      if (count > 0) {
+        // Starts from 0.
+        dim.name = dimOriginalName + (count - 1);
+      }
+
+      count++;
+      duplicationMap.set(dimOriginalName, count);
+    }
+  } // ??? TODO
+  // Originally detect dimCount by data[0]. Should we
+  // optimize it to only by sysDims and dimensions and encode.
+  // So only necessary dims will be initialized.
+  // But
+  // (1) custom series should be considered. where other dims
+  // may be visited.
+  // (2) sometimes user need to calcualte bubble size or use visualMap
+  // on other dimensions besides coordSys needed.
+  // So, dims that is not used by system, should be shared in data store?
+
+
+  function getDimCount(source, sysDims, dimsDef, optDimCount) {
+    // Note that the result dimCount should not small than columns count
+    // of data, otherwise `dataDimNameMap` checking will be incorrect.
+    var dimCount = Math.max(source.dimensionsDetectedCount || 1, sysDims.length, dimsDef.length, optDimCount || 0);
+    each(sysDims, function (sysDimItem) {
+      var sysDimItemDimsDef;
+
+      if (isObject(sysDimItem) && (sysDimItemDimsDef = sysDimItem.dimsDef)) {
+        dimCount = Math.max(dimCount, sysDimItemDimsDef.length);
+      }
+    });
+    return dimCount;
+  }
+
+  function genCoordDimName(name, map$$1, fromZero) {
+    var mapData = map$$1.data;
+
+    if (fromZero || mapData.hasOwnProperty(name)) {
+      var i = 0;
+
+      while (mapData.hasOwnProperty(name + i)) {
+        i++;
+      }
+
+      name += i;
+    }
+
+    map$$1.set(name, true);
+    return name;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Helper for model references.
+   * There are many manners to refer axis/coordSys.
+   */
+  // TODO
+  // merge relevant logic to this file?
+  // check: "modelHelper" of tooltip and "BrushTargetManager".
+
+  /**
+   * @class
+   * For example:
+   * {
+   *     coordSysName: 'cartesian2d',
+   *     coordSysDims: ['x', 'y', ...],
+   *     axisMap: HashMap({
+   *         x: xAxisModel,
+   *         y: yAxisModel
+   *     }),
+   *     categoryAxisMap: HashMap({
+   *         x: xAxisModel,
+   *         y: undefined
+   *     }),
+   *     // The index of the first category axis in `coordSysDims`.
+   *     // `null/undefined` means no category axis exists.
+   *     firstCategoryDimIndex: 1,
+   *     // To replace user specified encode.
+   * }
+   */
+
+
+  var CoordSysInfo =
+  /** @class */
+  function () {
+    function CoordSysInfo(coordSysName) {
+      this.coordSysDims = [];
+      this.axisMap = createHashMap();
+      this.categoryAxisMap = createHashMap();
+      this.coordSysName = coordSysName;
+    }
+
+    return CoordSysInfo;
+  }();
+
+  function getCoordSysInfoBySeries(seriesModel) {
+    var coordSysName = seriesModel.get('coordinateSystem');
+    var result = new CoordSysInfo(coordSysName);
+    var fetch = fetchers[coordSysName];
+
+    if (fetch) {
+      fetch(seriesModel, result, result.axisMap, result.categoryAxisMap);
+      return result;
+    }
+  }
+
+  var fetchers = {
+    cartesian2d: function (seriesModel, result, axisMap, categoryAxisMap) {
+      var xAxisModel = seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0];
+      var yAxisModel = seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0];
+      {
+        if (!xAxisModel) {
+          throw new Error('xAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('xAxisId'), 0) + '" not found');
+        }
+
+        if (!yAxisModel) {
+          throw new Error('yAxis "' + retrieve(seriesModel.get('xAxisIndex'), seriesModel.get('yAxisId'), 0) + '" not found');
+        }
+      }
+      result.coordSysDims = ['x', 'y'];
+      axisMap.set('x', xAxisModel);
+      axisMap.set('y', yAxisModel);
+
+      if (isCategory(xAxisModel)) {
+        categoryAxisMap.set('x', xAxisModel);
+        result.firstCategoryDimIndex = 0;
+      }
+
+      if (isCategory(yAxisModel)) {
+        categoryAxisMap.set('y', yAxisModel);
+        result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1);
+      }
+    },
+    singleAxis: function (seriesModel, result, axisMap, categoryAxisMap) {
+      var singleAxisModel = seriesModel.getReferringComponents('singleAxis', SINGLE_REFERRING).models[0];
+      {
+        if (!singleAxisModel) {
+          throw new Error('singleAxis should be specified.');
+        }
+      }
+      result.coordSysDims = ['single'];
+      axisMap.set('single', singleAxisModel);
+
+      if (isCategory(singleAxisModel)) {
+        categoryAxisMap.set('single', singleAxisModel);
+        result.firstCategoryDimIndex = 0;
+      }
+    },
+    polar: function (seriesModel, result, axisMap, categoryAxisMap) {
+      var polarModel = seriesModel.getReferringComponents('polar', SINGLE_REFERRING).models[0];
+      var radiusAxisModel = polarModel.findAxisModel('radiusAxis');
+      var angleAxisModel = polarModel.findAxisModel('angleAxis');
+      {
+        if (!angleAxisModel) {
+          throw new Error('angleAxis option not found');
+        }
+
+        if (!radiusAxisModel) {
+          throw new Error('radiusAxis option not found');
+        }
+      }
+      result.coordSysDims = ['radius', 'angle'];
+      axisMap.set('radius', radiusAxisModel);
+      axisMap.set('angle', angleAxisModel);
+
+      if (isCategory(radiusAxisModel)) {
+        categoryAxisMap.set('radius', radiusAxisModel);
+        result.firstCategoryDimIndex = 0;
+      }
+
+      if (isCategory(angleAxisModel)) {
+        categoryAxisMap.set('angle', angleAxisModel);
+        result.firstCategoryDimIndex == null && (result.firstCategoryDimIndex = 1);
+      }
+    },
+    geo: function (seriesModel, result, axisMap, categoryAxisMap) {
+      result.coordSysDims = ['lng', 'lat'];
+    },
+    parallel: function (seriesModel, result, axisMap, categoryAxisMap) {
+      var ecModel = seriesModel.ecModel;
+      var parallelModel = ecModel.getComponent('parallel', seriesModel.get('parallelIndex'));
+      var coordSysDims = result.coordSysDims = parallelModel.dimensions.slice();
+      each(parallelModel.parallelAxisIndex, function (axisIndex, index) {
+        var axisModel = ecModel.getComponent('parallelAxis', axisIndex);
+        var axisDim = coordSysDims[index];
+        axisMap.set(axisDim, axisModel);
+
+        if (isCategory(axisModel)) {
+          categoryAxisMap.set(axisDim, axisModel);
+
+          if (result.firstCategoryDimIndex == null) {
+            result.firstCategoryDimIndex = index;
+          }
+        }
+      });
+    }
+  };
+
+  function isCategory(axisModel) {
+    return axisModel.get('type') === 'category';
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Note that it is too complicated to support 3d stack by value
+   * (have to create two-dimension inverted index), so in 3d case
+   * we just support that stacked by index.
+   *
+   * @param seriesModel
+   * @param dimensionsInput The same as the input of <module:echarts/data/SeriesData>.
+   *        The input will be modified.
+   * @param opt
+   * @param opt.stackedCoordDimension Specify a coord dimension if needed.
+   * @param opt.byIndex=false
+   * @return calculationInfo
+   * {
+   *     stackedDimension: string
+   *     stackedByDimension: string
+   *     isStackedByIndex: boolean
+   *     stackedOverDimension: string
+   *     stackResultDimension: string
+   * }
+   */
+
+
+  function enableDataStack(seriesModel, dimensionsInput, opt) {
+    opt = opt || {};
+    var byIndex = opt.byIndex;
+    var stackedCoordDimension = opt.stackedCoordDimension;
+    var dimensionDefineList;
+    var schema;
+    var store;
+
+    if (isLegacyDimensionsInput(dimensionsInput)) {
+      dimensionDefineList = dimensionsInput;
+    } else {
+      schema = dimensionsInput.schema;
+      dimensionDefineList = schema.dimensions;
+      store = dimensionsInput.store;
+    } // Compatibal: when `stack` is set as '', do not stack.
+
+
+    var mayStack = !!(seriesModel && seriesModel.get('stack'));
+    var stackedByDimInfo;
+    var stackedDimInfo;
+    var stackResultDimension;
+    var stackedOverDimension;
+    each(dimensionDefineList, function (dimensionInfo, index) {
+      if (isString(dimensionInfo)) {
+        dimensionDefineList[index] = dimensionInfo = {
+          name: dimensionInfo
+        };
+      }
+
+      if (mayStack && !dimensionInfo.isExtraCoord) {
+        // Find the first ordinal dimension as the stackedByDimInfo.
+        if (!byIndex && !stackedByDimInfo && dimensionInfo.ordinalMeta) {
+          stackedByDimInfo = dimensionInfo;
+        } // Find the first stackable dimension as the stackedDimInfo.
+
+
+        if (!stackedDimInfo && dimensionInfo.type !== 'ordinal' && dimensionInfo.type !== 'time' && (!stackedCoordDimension || stackedCoordDimension === dimensionInfo.coordDim)) {
+          stackedDimInfo = dimensionInfo;
+        }
+      }
+    });
+
+    if (stackedDimInfo && !byIndex && !stackedByDimInfo) {
+      // Compatible with previous design, value axis (time axis) only stack by index.
+      // It may make sense if the user provides elaborately constructed data.
+      byIndex = true;
+    } // Add stack dimension, they can be both calculated by coordinate system in `unionExtent`.
+    // That put stack logic in List is for using conveniently in echarts extensions, but it
+    // might not be a good way.
+
+
+    if (stackedDimInfo) {
+      // Use a weird name that not duplicated with other names.
+      // Also need to use seriesModel.id as postfix because different
+      // series may share same data store. The stack dimension needs to be distinguished.
+      stackResultDimension = '__\0ecstackresult_' + seriesModel.id;
+      stackedOverDimension = '__\0ecstackedover_' + seriesModel.id; // Create inverted index to fast query index by value.
+
+      if (stackedByDimInfo) {
+        stackedByDimInfo.createInvertedIndices = true;
+      }
+
+      var stackedDimCoordDim_1 = stackedDimInfo.coordDim;
+      var stackedDimType = stackedDimInfo.type;
+      var stackedDimCoordIndex_1 = 0;
+      each(dimensionDefineList, function (dimensionInfo) {
+        if (dimensionInfo.coordDim === stackedDimCoordDim_1) {
+          stackedDimCoordIndex_1++;
+        }
+      });
+      var stackedOverDimensionDefine = {
+        name: stackResultDimension,
+        coordDim: stackedDimCoordDim_1,
+        coordDimIndex: stackedDimCoordIndex_1,
+        type: stackedDimType,
+        isExtraCoord: true,
+        isCalculationCoord: true,
+        storeDimIndex: dimensionDefineList.length
+      };
+      var stackResultDimensionDefine = {
+        name: stackedOverDimension,
+        // This dimension contains stack base (generally, 0), so do not set it as
+        // `stackedDimCoordDim` to avoid extent calculation, consider log scale.
+        coordDim: stackedOverDimension,
+        coordDimIndex: stackedDimCoordIndex_1 + 1,
+        type: stackedDimType,
+        isExtraCoord: true,
+        isCalculationCoord: true,
+        storeDimIndex: dimensionDefineList.length + 1
+      };
+
+      if (schema) {
+        if (store) {
+          stackedOverDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackedOverDimension, stackedDimType);
+          stackResultDimensionDefine.storeDimIndex = store.ensureCalculationDimension(stackResultDimension, stackedDimType);
+        }
+
+        schema.appendCalculationDimension(stackedOverDimensionDefine);
+        schema.appendCalculationDimension(stackResultDimensionDefine);
+      } else {
+        dimensionDefineList.push(stackedOverDimensionDefine);
+        dimensionDefineList.push(stackResultDimensionDefine);
+      }
+    }
+
+    return {
+      stackedDimension: stackedDimInfo && stackedDimInfo.name,
+      stackedByDimension: stackedByDimInfo && stackedByDimInfo.name,
+      isStackedByIndex: byIndex,
+      stackedOverDimension: stackedOverDimension,
+      stackResultDimension: stackResultDimension
+    };
+  }
+
+  function isLegacyDimensionsInput(dimensionsInput) {
+    return !isSeriesDataSchema(dimensionsInput.schema);
+  }
+
+  function isDimensionStacked(data, stackedDim) {
+    // Each single series only maps to one pair of axis. So we do not need to
+    // check stackByDim, whatever stacked by a dimension or stacked by index.
+    return !!stackedDim && stackedDim === data.getCalculationInfo('stackedDimension');
+  }
+
+  function getStackedDimension(data, targetDim) {
+    return isDimensionStacked(data, targetDim) ? data.getCalculationInfo('stackResultDimension') : targetDim;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 getCoordSysDimDefs(seriesModel, coordSysInfo) {
+    var coordSysName = seriesModel.get('coordinateSystem');
+    var registeredCoordSys = CoordinateSystemManager.get(coordSysName);
+    var coordSysDimDefs;
+
+    if (coordSysInfo && coordSysInfo.coordSysDims) {
+      coordSysDimDefs = map(coordSysInfo.coordSysDims, function (dim) {
+        var dimInfo = {
+          name: dim
+        };
+        var axisModel = coordSysInfo.axisMap.get(dim);
+
+        if (axisModel) {
+          var axisType = axisModel.get('type');
+          dimInfo.type = getDimensionTypeByAxis(axisType);
+        }
+
+        return dimInfo;
+      });
+    }
+
+    if (!coordSysDimDefs) {
+      // Get dimensions from registered coordinate system
+      coordSysDimDefs = registeredCoordSys && (registeredCoordSys.getDimensionsInfo ? registeredCoordSys.getDimensionsInfo() : registeredCoordSys.dimensions.slice()) || ['x', 'y'];
+    }
+
+    return coordSysDimDefs;
+  }
+
+  function injectOrdinalMeta(dimInfoList, createInvertedIndices, coordSysInfo) {
+    var firstCategoryDimIndex;
+    var hasNameEncode;
+    coordSysInfo && each(dimInfoList, function (dimInfo, dimIndex) {
+      var coordDim = dimInfo.coordDim;
+      var categoryAxisModel = coordSysInfo.categoryAxisMap.get(coordDim);
+
+      if (categoryAxisModel) {
+        if (firstCategoryDimIndex == null) {
+          firstCategoryDimIndex = dimIndex;
+        }
+
+        dimInfo.ordinalMeta = categoryAxisModel.getOrdinalMeta();
+
+        if (createInvertedIndices) {
+          dimInfo.createInvertedIndices = true;
+        }
+      }
+
+      if (dimInfo.otherDims.itemName != null) {
+        hasNameEncode = true;
+      }
+    });
+
+    if (!hasNameEncode && firstCategoryDimIndex != null) {
+      dimInfoList[firstCategoryDimIndex].otherDims.itemName = 0;
+    }
+
+    return firstCategoryDimIndex;
+  }
+  /**
+   * Caution: there are side effects to `sourceManager` in this method.
+   * Should better only be called in `Series['getInitialData']`.
+   */
+
+
+  function createSeriesData(sourceRaw, seriesModel, opt) {
+    opt = opt || {};
+    var sourceManager = seriesModel.getSourceManager();
+    var source;
+    var isOriginalSource = false;
+
+    if (sourceRaw) {
+      isOriginalSource = true;
+      source = createSourceFromSeriesDataOption(sourceRaw);
+    } else {
+      source = sourceManager.getSource(); // Is series.data. not dataset.
+
+      isOriginalSource = source.sourceFormat === SOURCE_FORMAT_ORIGINAL;
+    }
+
+    var coordSysInfo = getCoordSysInfoBySeries(seriesModel);
+    var coordSysDimDefs = getCoordSysDimDefs(seriesModel, coordSysInfo);
+    var useEncodeDefaulter = opt.useEncodeDefaulter;
+    var encodeDefaulter = isFunction(useEncodeDefaulter) ? useEncodeDefaulter : useEncodeDefaulter ? curry(makeSeriesEncodeForAxisCoordSys, coordSysDimDefs, seriesModel) : null;
+    var createDimensionOptions = {
+      coordDimensions: coordSysDimDefs,
+      generateCoord: opt.generateCoord,
+      encodeDefine: seriesModel.getEncode(),
+      encodeDefaulter: encodeDefaulter,
+      canOmitUnusedDimensions: !isOriginalSource
+    };
+    var schema = prepareSeriesDataSchema(source, createDimensionOptions);
+    var firstCategoryDimIndex = injectOrdinalMeta(schema.dimensions, opt.createInvertedIndices, coordSysInfo);
+    var store = !isOriginalSource ? sourceManager.getSharedDataStore(schema) : null;
+    var stackCalculationInfo = enableDataStack(seriesModel, {
+      schema: schema,
+      store: store
+    });
+    var data = new SeriesData(schema, seriesModel);
+    data.setCalculationInfo(stackCalculationInfo);
+    var dimValueGetter = firstCategoryDimIndex != null && isNeedCompleteOrdinalData(source) ? function (itemOpt, dimName, dataIndex, dimIndex) {
+      // Use dataIndex as ordinal value in categoryAxis
+      return dimIndex === firstCategoryDimIndex ? dataIndex : this.defaultDimValueGetter(itemOpt, dimName, dataIndex, dimIndex);
+    } : null;
+    data.hasItemOption = false;
+    data.initData( // Try to reuse the data store in sourceManager if using dataset.
+    isOriginalSource ? source : store, null, dimValueGetter);
+    return data;
+  }
+
+  function isNeedCompleteOrdinalData(source) {
+    if (source.sourceFormat === SOURCE_FORMAT_ORIGINAL) {
+      var sampleItem = firstDataNotNull(source.data || []);
+      return !isArray(getDataItemValue(sampleItem));
+    }
+  }
+
+  function firstDataNotNull(arr) {
+    var i = 0;
+
+    while (i < arr.length && arr[i] == null) {
+      i++;
+    }
+
+    return arr[i];
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 Scale =
+  /** @class */
+  function () {
+    function Scale(setting) {
+      this._setting = setting || {};
+      this._extent = [Infinity, -Infinity];
+    }
+
+    Scale.prototype.getSetting = function (name) {
+      return this._setting[name];
+    };
+    /**
+     * Set extent from data
+     */
+
+
+    Scale.prototype.unionExtent = function (other) {
+      var extent = this._extent;
+      other[0] < extent[0] && (extent[0] = other[0]);
+      other[1] > extent[1] && (extent[1] = other[1]); // not setExtent because in log axis it may transformed to power
+      // this.setExtent(extent[0], extent[1]);
+    };
+    /**
+     * Set extent from data
+     */
+
+
+    Scale.prototype.unionExtentFromData = function (data, dim) {
+      this.unionExtent(data.getApproximateExtent(dim));
+    };
+    /**
+     * Get extent
+     *
+     * Extent is always in increase order.
+     */
+
+
+    Scale.prototype.getExtent = function () {
+      return this._extent.slice();
+    };
+    /**
+     * Set extent
+     */
+
+
+    Scale.prototype.setExtent = function (start, end) {
+      var thisExtent = this._extent;
+
+      if (!isNaN(start)) {
+        thisExtent[0] = start;
+      }
+
+      if (!isNaN(end)) {
+        thisExtent[1] = end;
+      }
+    };
+    /**
+     * If value is in extent range
+     */
+
+
+    Scale.prototype.isInExtentRange = function (value) {
+      return this._extent[0] <= value && this._extent[1] >= value;
+    };
+    /**
+     * When axis extent depends on data and no data exists,
+     * axis ticks should not be drawn, which is named 'blank'.
+     */
+
+
+    Scale.prototype.isBlank = function () {
+      return this._isBlank;
+    };
+    /**
+     * When axis extent depends on data and no data exists,
+     * axis ticks should not be drawn, which is named 'blank'.
+     */
+
+
+    Scale.prototype.setBlank = function (isBlank) {
+      this._isBlank = isBlank;
+    };
+
+    return Scale;
+  }();
+
+  enableClassManagement(Scale);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 uidBase = 0;
+
+  var OrdinalMeta =
+  /** @class */
+  function () {
+    function OrdinalMeta(opt) {
+      this.categories = opt.categories || [];
+      this._needCollect = opt.needCollect;
+      this._deduplication = opt.deduplication;
+      this.uid = ++uidBase;
+    }
+
+    OrdinalMeta.createByAxisModel = function (axisModel) {
+      var option = axisModel.option;
+      var data = option.data;
+      var categories = data && map(data, getName);
+      return new OrdinalMeta({
+        categories: categories,
+        needCollect: !categories,
+        // deduplication is default in axis.
+        deduplication: option.dedplication !== false
+      });
+    };
+
+    OrdinalMeta.prototype.getOrdinal = function (category) {
+      // @ts-ignore
+      return this._getOrCreateMap().get(category);
+    };
+    /**
+     * @return The ordinal. If not found, return NaN.
+     */
+
+
+    OrdinalMeta.prototype.parseAndCollect = function (category) {
+      var index;
+      var needCollect = this._needCollect; // The value of category dim can be the index of the given category set.
+      // This feature is only supported when !needCollect, because we should
+      // consider a common case: a value is 2017, which is a number but is
+      // expected to be tread as a category. This case usually happen in dataset,
+      // where it happent to be no need of the index feature.
+
+      if (!isString(category) && !needCollect) {
+        return category;
+      } // Optimize for the scenario:
+      // category is ['2012-01-01', '2012-01-02', ...], where the input
+      // data has been ensured not duplicate and is large data.
+      // Notice, if a dataset dimension provide categroies, usually echarts
+      // should remove duplication except user tell echarts dont do that
+      // (set axis.deduplication = false), because echarts do not know whether
+      // the values in the category dimension has duplication (consider the
+      // parallel-aqi example)
+
+
+      if (needCollect && !this._deduplication) {
+        index = this.categories.length;
+        this.categories[index] = category;
+        return index;
+      }
+
+      var map$$1 = this._getOrCreateMap(); // @ts-ignore
+
+
+      index = map$$1.get(category);
+
+      if (index == null) {
+        if (needCollect) {
+          index = this.categories.length;
+          this.categories[index] = category; // @ts-ignore
+
+          map$$1.set(category, index);
+        } else {
+          index = NaN;
+        }
+      }
+
+      return index;
+    }; // Consider big data, do not create map until needed.
+
+
+    OrdinalMeta.prototype._getOrCreateMap = function () {
+      return this._map || (this._map = createHashMap(this.categories));
+    };
+
+    return OrdinalMeta;
+  }();
+
+  function getName(obj) {
+    if (isObject(obj) && obj.value != null) {
+      return obj.value;
+    } else {
+      return obj + '';
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 isValueNice(val) {
+    var exp10 = Math.pow(10, quantityExponent(Math.abs(val)));
+    var f = Math.abs(val / exp10);
+    return f === 0 || f === 1 || f === 2 || f === 3 || f === 5;
+  }
+
+  function isIntervalOrLogScale(scale) {
+    return scale.type === 'interval' || scale.type === 'log';
+  }
+  /**
+   * @param extent Both extent[0] and extent[1] should be valid number.
+   *               Should be extent[0] < extent[1].
+   * @param splitNumber splitNumber should be >= 1.
+   */
+
+
+  function intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval) {
+    var result = {};
+    var span = extent[1] - extent[0];
+    var interval = result.interval = nice(span / splitNumber, true);
+
+    if (minInterval != null && interval < minInterval) {
+      interval = result.interval = minInterval;
+    }
+
+    if (maxInterval != null && interval > maxInterval) {
+      interval = result.interval = maxInterval;
+    } // Tow more digital for tick.
+
+
+    var precision = result.intervalPrecision = getIntervalPrecision(interval); // Niced extent inside original extent
+
+    var niceTickExtent = result.niceTickExtent = [round(Math.ceil(extent[0] / interval) * interval, precision), round(Math.floor(extent[1] / interval) * interval, precision)];
+    fixExtent(niceTickExtent, extent);
+    return result;
+  }
+
+  function increaseInterval(interval) {
+    var exp10 = Math.pow(10, quantityExponent(interval)); // Increase interval
+
+    var f = interval / exp10;
+
+    if (!f) {
+      f = 1;
+    } else if (f === 2) {
+      f = 3;
+    } else if (f === 3) {
+      f = 5;
+    } else {
+      // f is 1 or 5
+      f *= 2;
+    }
+
+    return round(f * exp10);
+  }
+  /**
+   * @return interval precision
+   */
+
+
+  function getIntervalPrecision(interval) {
+    // Tow more digital for tick.
+    return getPrecision(interval) + 2;
+  }
+
+  function clamp(niceTickExtent, idx, extent) {
+    niceTickExtent[idx] = Math.max(Math.min(niceTickExtent[idx], extent[1]), extent[0]);
+  } // In some cases (e.g., splitNumber is 1), niceTickExtent may be out of extent.
+
+
+  function fixExtent(niceTickExtent, extent) {
+    !isFinite(niceTickExtent[0]) && (niceTickExtent[0] = extent[0]);
+    !isFinite(niceTickExtent[1]) && (niceTickExtent[1] = extent[1]);
+    clamp(niceTickExtent, 0, extent);
+    clamp(niceTickExtent, 1, extent);
+
+    if (niceTickExtent[0] > niceTickExtent[1]) {
+      niceTickExtent[0] = niceTickExtent[1];
+    }
+  }
+
+  function contain$1(val, extent) {
+    return val >= extent[0] && val <= extent[1];
+  }
+
+  function normalize$1(val, extent) {
+    if (extent[1] === extent[0]) {
+      return 0.5;
+    }
+
+    return (val - extent[0]) / (extent[1] - extent[0]);
+  }
+
+  function scale$2(val, extent) {
+    return val * (extent[1] - extent[0]) + extent[0];
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Linear continuous scale
+   * http://en.wikipedia.org/wiki/Level_of_measurement
+   */
+  // FIXME only one data
+
+
+  var OrdinalScale =
+  /** @class */
+  function (_super) {
+    __extends(OrdinalScale, _super);
+
+    function OrdinalScale(setting) {
+      var _this = _super.call(this, setting) || this;
+
+      _this.type = 'ordinal';
+
+      var ordinalMeta = _this.getSetting('ordinalMeta'); // Caution: Should not use instanceof, consider ec-extensions using
+      // import approach to get OrdinalMeta class.
+
+
+      if (!ordinalMeta) {
+        ordinalMeta = new OrdinalMeta({});
+      }
+
+      if (isArray(ordinalMeta)) {
+        ordinalMeta = new OrdinalMeta({
+          categories: map(ordinalMeta, function (item) {
+            return isObject(item) ? item.value : item;
+          })
+        });
+      }
+
+      _this._ordinalMeta = ordinalMeta;
+      _this._extent = _this.getSetting('extent') || [0, ordinalMeta.categories.length - 1];
+      return _this;
+    }
+
+    OrdinalScale.prototype.parse = function (val) {
+      // Caution: Math.round(null) will return `0` rather than `NaN`
+      if (val == null) {
+        return NaN;
+      }
+
+      return isString(val) ? this._ordinalMeta.getOrdinal(val) // val might be float.
+      : Math.round(val);
+    };
+
+    OrdinalScale.prototype.contain = function (rank) {
+      rank = this.parse(rank);
+      return contain$1(rank, this._extent) && this._ordinalMeta.categories[rank] != null;
+    };
+    /**
+     * Normalize given rank or name to linear [0, 1]
+     * @param val raw ordinal number.
+     * @return normalized value in [0, 1].
+     */
+
+
+    OrdinalScale.prototype.normalize = function (val) {
+      val = this._getTickNumber(this.parse(val));
+      return normalize$1(val, this._extent);
+    };
+    /**
+     * @param val normalized value in [0, 1].
+     * @return raw ordinal number.
+     */
+
+
+    OrdinalScale.prototype.scale = function (val) {
+      val = Math.round(scale$2(val, this._extent));
+      return this.getRawOrdinalNumber(val);
+    };
+
+    OrdinalScale.prototype.getTicks = function () {
+      var ticks = [];
+      var extent = this._extent;
+      var rank = extent[0];
+
+      while (rank <= extent[1]) {
+        ticks.push({
+          value: rank
+        });
+        rank++;
+      }
+
+      return ticks;
+    };
+
+    OrdinalScale.prototype.getMinorTicks = function (splitNumber) {
+      // Not support.
+      return;
+    };
+    /**
+     * @see `Ordinal['_ordinalNumbersByTick']`
+     */
+
+
+    OrdinalScale.prototype.setSortInfo = function (info) {
+      if (info == null) {
+        this._ordinalNumbersByTick = this._ticksByOrdinalNumber = null;
+        return;
+      }
+
+      var infoOrdinalNumbers = info.ordinalNumbers;
+      var ordinalsByTick = this._ordinalNumbersByTick = [];
+      var ticksByOrdinal = this._ticksByOrdinalNumber = []; // Unnecessary support negative tick in `realtimeSort`.
+
+      var tickNum = 0;
+      var allCategoryLen = this._ordinalMeta.categories.length;
+
+      for (var len = Math.min(allCategoryLen, infoOrdinalNumbers.length); tickNum < len; ++tickNum) {
+        var ordinalNumber = infoOrdinalNumbers[tickNum];
+        ordinalsByTick[tickNum] = ordinalNumber;
+        ticksByOrdinal[ordinalNumber] = tickNum;
+      } // Handle that `series.data` only covers part of the `axis.category.data`.
+
+
+      var unusedOrdinal = 0;
+
+      for (; tickNum < allCategoryLen; ++tickNum) {
+        while (ticksByOrdinal[unusedOrdinal] != null) {
+          unusedOrdinal++;
+        }
+
+        ordinalsByTick.push(unusedOrdinal);
+        ticksByOrdinal[unusedOrdinal] = tickNum;
+      }
+    };
+
+    OrdinalScale.prototype._getTickNumber = function (ordinal) {
+      var ticksByOrdinalNumber = this._ticksByOrdinalNumber; // also support ordinal out of range of `ordinalMeta.categories.length`,
+      // where ordinal numbers are used as tick value directly.
+
+      return ticksByOrdinalNumber && ordinal >= 0 && ordinal < ticksByOrdinalNumber.length ? ticksByOrdinalNumber[ordinal] : ordinal;
+    };
+    /**
+     * @usage
+     * ```js
+     * const ordinalNumber = ordinalScale.getRawOrdinalNumber(tickVal);
+     *
+     * // case0
+     * const rawOrdinalValue = axisModel.getCategories()[ordinalNumber];
+     * // case1
+     * const rawOrdinalValue = this._ordinalMeta.categories[ordinalNumber];
+     * // case2
+     * const coord = axis.dataToCoord(ordinalNumber);
+     * ```
+     *
+     * @param {OrdinalNumber} tickNumber index of display
+     */
+
+
+    OrdinalScale.prototype.getRawOrdinalNumber = function (tickNumber) {
+      var ordinalNumbersByTick = this._ordinalNumbersByTick; // tickNumber may be out of range, e.g., when axis max is larger than `ordinalMeta.categories.length`.,
+      // where ordinal numbers are used as tick value directly.
+
+      return ordinalNumbersByTick && tickNumber >= 0 && tickNumber < ordinalNumbersByTick.length ? ordinalNumbersByTick[tickNumber] : tickNumber;
+    };
+    /**
+     * Get item on tick
+     */
+
+
+    OrdinalScale.prototype.getLabel = function (tick) {
+      if (!this.isBlank()) {
+        var ordinalNumber = this.getRawOrdinalNumber(tick.value);
+        var cateogry = this._ordinalMeta.categories[ordinalNumber]; // Note that if no data, ordinalMeta.categories is an empty array.
+        // Return empty if it's not exist.
+
+        return cateogry == null ? '' : cateogry + '';
+      }
+    };
+
+    OrdinalScale.prototype.count = function () {
+      return this._extent[1] - this._extent[0] + 1;
+    };
+
+    OrdinalScale.prototype.unionExtentFromData = function (data, dim) {
+      this.unionExtent(data.getApproximateExtent(dim));
+    };
+    /**
+     * @override
+     * If value is in extent range
+     */
+
+
+    OrdinalScale.prototype.isInExtentRange = function (value) {
+      value = this._getTickNumber(value);
+      return this._extent[0] <= value && this._extent[1] >= value;
+    };
+
+    OrdinalScale.prototype.getOrdinalMeta = function () {
+      return this._ordinalMeta;
+    };
+
+    OrdinalScale.prototype.calcNiceTicks = function () {};
+
+    OrdinalScale.prototype.calcNiceExtent = function () {};
+
+    OrdinalScale.type = 'ordinal';
+    return OrdinalScale;
+  }(Scale);
+
+  Scale.registerClass(OrdinalScale);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 roundNumber = round;
+
+  var IntervalScale =
+  /** @class */
+  function (_super) {
+    __extends(IntervalScale, _super);
+
+    function IntervalScale() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = 'interval'; // Step is calculated in adjustExtent.
+
+      _this._interval = 0;
+      _this._intervalPrecision = 2;
+      return _this;
+    }
+
+    IntervalScale.prototype.parse = function (val) {
+      return val;
+    };
+
+    IntervalScale.prototype.contain = function (val) {
+      return contain$1(val, this._extent);
+    };
+
+    IntervalScale.prototype.normalize = function (val) {
+      return normalize$1(val, this._extent);
+    };
+
+    IntervalScale.prototype.scale = function (val) {
+      return scale$2(val, this._extent);
+    };
+
+    IntervalScale.prototype.setExtent = function (start, end) {
+      var thisExtent = this._extent; // start,end may be a Number like '25',so...
+
+      if (!isNaN(start)) {
+        thisExtent[0] = parseFloat(start);
+      }
+
+      if (!isNaN(end)) {
+        thisExtent[1] = parseFloat(end);
+      }
+    };
+
+    IntervalScale.prototype.unionExtent = function (other) {
+      var extent = this._extent;
+      other[0] < extent[0] && (extent[0] = other[0]);
+      other[1] > extent[1] && (extent[1] = other[1]); // unionExtent may called by it's sub classes
+
+      this.setExtent(extent[0], extent[1]);
+    };
+
+    IntervalScale.prototype.getInterval = function () {
+      return this._interval;
+    };
+
+    IntervalScale.prototype.setInterval = function (interval) {
+      this._interval = interval; // Dropped auto calculated niceExtent and use user setted extent
+      // We assume user wan't to set both interval, min, max to get a better result
+
+      this._niceExtent = this._extent.slice();
+      this._intervalPrecision = getIntervalPrecision(interval);
+    };
+    /**
+     * @param expandToNicedExtent Whether expand the ticks to niced extent.
+     */
+
+
+    IntervalScale.prototype.getTicks = function (expandToNicedExtent) {
+      var interval = this._interval;
+      var extent = this._extent;
+      var niceTickExtent = this._niceExtent;
+      var intervalPrecision = this._intervalPrecision;
+      var ticks = []; // If interval is 0, return [];
+
+      if (!interval) {
+        return ticks;
+      } // Consider this case: using dataZoom toolbox, zoom and zoom.
+
+
+      var safeLimit = 10000;
+
+      if (extent[0] < niceTickExtent[0]) {
+        if (expandToNicedExtent) {
+          ticks.push({
+            value: roundNumber(niceTickExtent[0] - interval, intervalPrecision)
+          });
+        } else {
+          ticks.push({
+            value: extent[0]
+          });
+        }
+      }
+
+      var tick = niceTickExtent[0];
+
+      while (tick <= niceTickExtent[1]) {
+        ticks.push({
+          value: tick
+        }); // Avoid rounding error
+
+        tick = roundNumber(tick + interval, intervalPrecision);
+
+        if (tick === ticks[ticks.length - 1].value) {
+          // Consider out of safe float point, e.g.,
+          // -3711126.9907707 + 2e-10 === -3711126.9907707
+          break;
+        }
+
+        if (ticks.length > safeLimit) {
+          return [];
+        }
+      } // Consider this case: the last item of ticks is smaller
+      // than niceTickExtent[1] and niceTickExtent[1] === extent[1].
+
+
+      var lastNiceTick = ticks.length ? ticks[ticks.length - 1].value : niceTickExtent[1];
+
+      if (extent[1] > lastNiceTick) {
+        if (expandToNicedExtent) {
+          ticks.push({
+            value: roundNumber(lastNiceTick + interval, intervalPrecision)
+          });
+        } else {
+          ticks.push({
+            value: extent[1]
+          });
+        }
+      }
+
+      return ticks;
+    };
+
+    IntervalScale.prototype.getMinorTicks = function (splitNumber) {
+      var ticks = this.getTicks(true);
+      var minorTicks = [];
+      var extent = this.getExtent();
+
+      for (var i = 1; i < ticks.length; i++) {
+        var nextTick = ticks[i];
+        var prevTick = ticks[i - 1];
+        var count = 0;
+        var minorTicksGroup = [];
+        var interval = nextTick.value - prevTick.value;
+        var minorInterval = interval / splitNumber;
+
+        while (count < splitNumber - 1) {
+          var minorTick = roundNumber(prevTick.value + (count + 1) * minorInterval); // For the first and last interval. The count may be less than splitNumber.
+
+          if (minorTick > extent[0] && minorTick < extent[1]) {
+            minorTicksGroup.push(minorTick);
+          }
+
+          count++;
+        }
+
+        minorTicks.push(minorTicksGroup);
+      }
+
+      return minorTicks;
+    };
+    /**
+     * @param opt.precision If 'auto', use nice presision.
+     * @param opt.pad returns 1.50 but not 1.5 if precision is 2.
+     */
+
+
+    IntervalScale.prototype.getLabel = function (data, opt) {
+      if (data == null) {
+        return '';
+      }
+
+      var precision = opt && opt.precision;
+
+      if (precision == null) {
+        precision = getPrecision(data.value) || 0;
+      } else if (precision === 'auto') {
+        // Should be more precise then tick.
+        precision = this._intervalPrecision;
+      } // (1) If `precision` is set, 12.005 should be display as '12.00500'.
+      // (2) Use roundNumber (toFixed) to avoid scientific notation like '3.5e-7'.
+
+
+      var dataNum = roundNumber(data.value, precision, true);
+      return addCommas(dataNum);
+    };
+    /**
+     * @param splitNumber By default `5`.
+     */
+
+
+    IntervalScale.prototype.calcNiceTicks = function (splitNumber, minInterval, maxInterval) {
+      splitNumber = splitNumber || 5;
+      var extent = this._extent;
+      var span = extent[1] - extent[0];
+
+      if (!isFinite(span)) {
+        return;
+      } // User may set axis min 0 and data are all negative
+      // FIXME If it needs to reverse ?
+
+
+      if (span < 0) {
+        span = -span;
+        extent.reverse();
+      }
+
+      var result = intervalScaleNiceTicks(extent, splitNumber, minInterval, maxInterval);
+      this._intervalPrecision = result.intervalPrecision;
+      this._interval = result.interval;
+      this._niceExtent = result.niceTickExtent;
+    };
+
+    IntervalScale.prototype.calcNiceExtent = function (opt) {
+      var extent = this._extent; // If extent start and end are same, expand them
+
+      if (extent[0] === extent[1]) {
+        if (extent[0] !== 0) {
+          // Expand extent
+          var expandSize = extent[0]; // In the fowllowing case
+          //      Axis has been fixed max 100
+          //      Plus data are all 100 and axis extent are [100, 100].
+          // Extend to the both side will cause expanded max is larger than fixed max.
+          // So only expand to the smaller side.
+
+          if (!opt.fixMax) {
+            extent[1] += expandSize / 2;
+            extent[0] -= expandSize / 2;
+          } else {
+            extent[0] -= expandSize / 2;
+          }
+        } else {
+          extent[1] = 1;
+        }
+      }
+
+      var span = extent[1] - extent[0]; // If there are no data and extent are [Infinity, -Infinity]
+
+      if (!isFinite(span)) {
+        extent[0] = 0;
+        extent[1] = 1;
+      }
+
+      this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval); // let extent = this._extent;
+
+      var interval = this._interval;
+
+      if (!opt.fixMin) {
+        extent[0] = roundNumber(Math.floor(extent[0] / interval) * interval);
+      }
+
+      if (!opt.fixMax) {
+        extent[1] = roundNumber(Math.ceil(extent[1] / interval) * interval);
+      }
+    };
+
+    IntervalScale.prototype.setNiceExtent = function (min, max) {
+      this._niceExtent = [min, max];
+    };
+
+    IntervalScale.type = 'interval';
+    return IntervalScale;
+  }(Scale);
+
+  Scale.registerClass(IntervalScale);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /* global Float32Array */
+
+  var supportFloat32Array = typeof Float32Array !== 'undefined';
+  var Float32ArrayCtor = !supportFloat32Array ? Array : Float32Array;
+
+  function createFloat32Array(arg) {
+    if (isArray(arg)) {
+      // Return self directly if don't support TypedArray.
+      return supportFloat32Array ? new Float32Array(arg) : arg;
+    } // Else is number
+
+
+    return new Float32ArrayCtor(arg);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 STACK_PREFIX = '__ec_stack_';
+
+  function getSeriesStackId(seriesModel) {
+    return seriesModel.get('stack') || STACK_PREFIX + seriesModel.seriesIndex;
+  }
+
+  function getAxisKey(axis) {
+    return axis.dim + axis.index;
+  }
+  /**
+   * @return {Object} {width, offset, offsetCenter} If axis.type is not 'category', return undefined.
+   */
+
+
+  function prepareLayoutBarSeries(seriesType, ecModel) {
+    var seriesModels = [];
+    ecModel.eachSeriesByType(seriesType, function (seriesModel) {
+      // Check series coordinate, do layout for cartesian2d only
+      if (isOnCartesian(seriesModel)) {
+        seriesModels.push(seriesModel);
+      }
+    });
+    return seriesModels;
+  }
+  /**
+   * Map from (baseAxis.dim + '_' + baseAxis.index) to min gap of two adjacent
+   * values.
+   * This works for time axes, value axes, and log axes.
+   * For a single time axis, return value is in the form like
+   * {'x_0': [1000000]}.
+   * The value of 1000000 is in milliseconds.
+   */
+
+
+  function getValueAxesMinGaps(barSeries) {
+    /**
+     * Map from axis.index to values.
+     * For a single time axis, axisValues is in the form like
+     * {'x_0': [1495555200000, 1495641600000, 1495728000000]}.
+     * Items in axisValues[x], e.g. 1495555200000, are time values of all
+     * series.
+     */
+    var axisValues = {};
+    each(barSeries, function (seriesModel) {
+      var cartesian = seriesModel.coordinateSystem;
+      var baseAxis = cartesian.getBaseAxis();
+
+      if (baseAxis.type !== 'time' && baseAxis.type !== 'value') {
+        return;
+      }
+
+      var data = seriesModel.getData();
+      var key = baseAxis.dim + '_' + baseAxis.index;
+      var dimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim));
+      var store = data.getStore();
+
+      for (var i = 0, cnt = store.count(); i < cnt; ++i) {
+        var value = store.get(dimIdx, i);
+
+        if (!axisValues[key]) {
+          // No previous data for the axis
+          axisValues[key] = [value];
+        } else {
+          // No value in previous series
+          axisValues[key].push(value);
+        } // Ignore duplicated time values in the same axis
+
+      }
+    });
+    var axisMinGaps = {};
+
+    for (var key in axisValues) {
+      if (axisValues.hasOwnProperty(key)) {
+        var valuesInAxis = axisValues[key];
+
+        if (valuesInAxis) {
+          // Sort axis values into ascending order to calculate gaps
+          valuesInAxis.sort(function (a, b) {
+            return a - b;
+          });
+          var min = null;
+
+          for (var j = 1; j < valuesInAxis.length; ++j) {
+            var delta = valuesInAxis[j] - valuesInAxis[j - 1];
+
+            if (delta > 0) {
+              // Ignore 0 delta because they are of the same axis value
+              min = min === null ? delta : Math.min(min, delta);
+            }
+          } // Set to null if only have one data
+
+
+          axisMinGaps[key] = min;
+        }
+      }
+    }
+
+    return axisMinGaps;
+  }
+
+  function makeColumnLayout(barSeries) {
+    var axisMinGaps = getValueAxesMinGaps(barSeries);
+    var seriesInfoList = [];
+    each(barSeries, function (seriesModel) {
+      var cartesian = seriesModel.coordinateSystem;
+      var baseAxis = cartesian.getBaseAxis();
+      var axisExtent = baseAxis.getExtent();
+      var bandWidth;
+
+      if (baseAxis.type === 'category') {
+        bandWidth = baseAxis.getBandWidth();
+      } else if (baseAxis.type === 'value' || baseAxis.type === 'time') {
+        var key = baseAxis.dim + '_' + baseAxis.index;
+        var minGap = axisMinGaps[key];
+        var extentSpan = Math.abs(axisExtent[1] - axisExtent[0]);
+        var scale = baseAxis.scale.getExtent();
+        var scaleSpan = Math.abs(scale[1] - scale[0]);
+        bandWidth = minGap ? extentSpan / scaleSpan * minGap : extentSpan; // When there is only one data value
+      } else {
+        var data = seriesModel.getData();
+        bandWidth = Math.abs(axisExtent[1] - axisExtent[0]) / data.count();
+      }
+
+      var barWidth = parsePercent$1(seriesModel.get('barWidth'), bandWidth);
+      var barMaxWidth = parsePercent$1(seriesModel.get('barMaxWidth'), bandWidth);
+      var barMinWidth = parsePercent$1( // barMinWidth by default is 0.5 / 1 in cartesian. Because in value axis,
+      // the auto-calculated bar width might be less than 0.5 / 1.
+      seriesModel.get('barMinWidth') || (isInLargeMode(seriesModel) ? 0.5 : 1), bandWidth);
+      var barGap = seriesModel.get('barGap');
+      var barCategoryGap = seriesModel.get('barCategoryGap');
+      seriesInfoList.push({
+        bandWidth: bandWidth,
+        barWidth: barWidth,
+        barMaxWidth: barMaxWidth,
+        barMinWidth: barMinWidth,
+        barGap: barGap,
+        barCategoryGap: barCategoryGap,
+        axisKey: getAxisKey(baseAxis),
+        stackId: getSeriesStackId(seriesModel)
+      });
+    });
+    return doCalBarWidthAndOffset(seriesInfoList);
+  }
+
+  function doCalBarWidthAndOffset(seriesInfoList) {
+    // Columns info on each category axis. Key is cartesian name
+    var columnsMap = {};
+    each(seriesInfoList, function (seriesInfo, idx) {
+      var axisKey = seriesInfo.axisKey;
+      var bandWidth = seriesInfo.bandWidth;
+      var columnsOnAxis = columnsMap[axisKey] || {
+        bandWidth: bandWidth,
+        remainedWidth: bandWidth,
+        autoWidthCount: 0,
+        categoryGap: null,
+        gap: '20%',
+        stacks: {}
+      };
+      var stacks = columnsOnAxis.stacks;
+      columnsMap[axisKey] = columnsOnAxis;
+      var stackId = seriesInfo.stackId;
+
+      if (!stacks[stackId]) {
+        columnsOnAxis.autoWidthCount++;
+      }
+
+      stacks[stackId] = stacks[stackId] || {
+        width: 0,
+        maxWidth: 0
+      }; // Caution: In a single coordinate system, these barGrid attributes
+      // will be shared by series. Consider that they have default values,
+      // only the attributes set on the last series will work.
+      // Do not change this fact unless there will be a break change.
+
+      var barWidth = seriesInfo.barWidth;
+
+      if (barWidth && !stacks[stackId].width) {
+        // See #6312, do not restrict width.
+        stacks[stackId].width = barWidth;
+        barWidth = Math.min(columnsOnAxis.remainedWidth, barWidth);
+        columnsOnAxis.remainedWidth -= barWidth;
+      }
+
+      var barMaxWidth = seriesInfo.barMaxWidth;
+      barMaxWidth && (stacks[stackId].maxWidth = barMaxWidth);
+      var barMinWidth = seriesInfo.barMinWidth;
+      barMinWidth && (stacks[stackId].minWidth = barMinWidth);
+      var barGap = seriesInfo.barGap;
+      barGap != null && (columnsOnAxis.gap = barGap);
+      var barCategoryGap = seriesInfo.barCategoryGap;
+      barCategoryGap != null && (columnsOnAxis.categoryGap = barCategoryGap);
+    });
+    var result = {};
+    each(columnsMap, function (columnsOnAxis, coordSysName) {
+      result[coordSysName] = {};
+      var stacks = columnsOnAxis.stacks;
+      var bandWidth = columnsOnAxis.bandWidth;
+      var categoryGapPercent = columnsOnAxis.categoryGap;
+
+      if (categoryGapPercent == null) {
+        var columnCount = keys(stacks).length; // More columns in one group
+        // the spaces between group is smaller. Or the column will be too thin.
+
+        categoryGapPercent = Math.max(35 - columnCount * 4, 15) + '%';
+      }
+
+      var categoryGap = parsePercent$1(categoryGapPercent, bandWidth);
+      var barGapPercent = parsePercent$1(columnsOnAxis.gap, 1);
+      var remainedWidth = columnsOnAxis.remainedWidth;
+      var autoWidthCount = columnsOnAxis.autoWidthCount;
+      var autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
+      autoWidth = Math.max(autoWidth, 0); // Find if any auto calculated bar exceeded maxBarWidth
+
+      each(stacks, function (column) {
+        var maxWidth = column.maxWidth;
+        var minWidth = column.minWidth;
+
+        if (!column.width) {
+          var finalWidth = autoWidth;
+
+          if (maxWidth && maxWidth < finalWidth) {
+            finalWidth = Math.min(maxWidth, remainedWidth);
+          } // `minWidth` has higher priority. `minWidth` decide that wheter the
+          // bar is able to be visible. So `minWidth` should not be restricted
+          // by `maxWidth` or `remainedWidth` (which is from `bandWidth`). In
+          // the extreme cases for `value` axis, bars are allowed to overlap
+          // with each other if `minWidth` specified.
+
+
+          if (minWidth && minWidth > finalWidth) {
+            finalWidth = minWidth;
+          }
+
+          if (finalWidth !== autoWidth) {
+            column.width = finalWidth;
+            remainedWidth -= finalWidth + barGapPercent * finalWidth;
+            autoWidthCount--;
+          }
+        } else {
+          // `barMinWidth/barMaxWidth` has higher priority than `barWidth`, as
+          // CSS does. Becuase barWidth can be a percent value, where
+          // `barMaxWidth` can be used to restrict the final width.
+          var finalWidth = column.width;
+
+          if (maxWidth) {
+            finalWidth = Math.min(finalWidth, maxWidth);
+          } // `minWidth` has higher priority, as described above
+
+
+          if (minWidth) {
+            finalWidth = Math.max(finalWidth, minWidth);
+          }
+
+          column.width = finalWidth;
+          remainedWidth -= finalWidth + barGapPercent * finalWidth;
+          autoWidthCount--;
+        }
+      }); // Recalculate width again
+
+      autoWidth = (remainedWidth - categoryGap) / (autoWidthCount + (autoWidthCount - 1) * barGapPercent);
+      autoWidth = Math.max(autoWidth, 0);
+      var widthSum = 0;
+      var lastColumn;
+      each(stacks, function (column, idx) {
+        if (!column.width) {
+          column.width = autoWidth;
+        }
+
+        lastColumn = column;
+        widthSum += column.width * (1 + barGapPercent);
+      });
+
+      if (lastColumn) {
+        widthSum -= lastColumn.width * barGapPercent;
+      }
+
+      var offset = -widthSum / 2;
+      each(stacks, function (column, stackId) {
+        result[coordSysName][stackId] = result[coordSysName][stackId] || {
+          bandWidth: bandWidth,
+          offset: offset,
+          width: column.width
+        };
+        offset += column.width * (1 + barGapPercent);
+      });
+    });
+    return result;
+  }
+
+  function retrieveColumnLayout(barWidthAndOffset, axis, seriesModel) {
+    if (barWidthAndOffset && axis) {
+      var result = barWidthAndOffset[getAxisKey(axis)];
+
+      if (result != null && seriesModel != null) {
+        return result[getSeriesStackId(seriesModel)];
+      }
+
+      return result;
+    }
+  }
+
+  function layout(seriesType, ecModel) {
+    var seriesModels = prepareLayoutBarSeries(seriesType, ecModel);
+    var barWidthAndOffset = makeColumnLayout(seriesModels);
+    each(seriesModels, function (seriesModel) {
+      var data = seriesModel.getData();
+      var cartesian = seriesModel.coordinateSystem;
+      var baseAxis = cartesian.getBaseAxis();
+      var stackId = getSeriesStackId(seriesModel);
+      var columnLayoutInfo = barWidthAndOffset[getAxisKey(baseAxis)][stackId];
+      var columnOffset = columnLayoutInfo.offset;
+      var columnWidth = columnLayoutInfo.width;
+      data.setLayout({
+        bandWidth: columnLayoutInfo.bandWidth,
+        offset: columnOffset,
+        size: columnWidth
+      });
+    });
+  } // TODO: Do not support stack in large mode yet.
+
+
+  function createProgressiveLayout(seriesType) {
+    return {
+      seriesType: seriesType,
+      plan: createRenderPlanner(),
+      reset: function (seriesModel) {
+        if (!isOnCartesian(seriesModel)) {
+          return;
+        }
+
+        var data = seriesModel.getData();
+        var cartesian = seriesModel.coordinateSystem;
+        var baseAxis = cartesian.getBaseAxis();
+        var valueAxis = cartesian.getOtherAxis(baseAxis);
+        var valueDimIdx = data.getDimensionIndex(data.mapDimension(valueAxis.dim));
+        var baseDimIdx = data.getDimensionIndex(data.mapDimension(baseAxis.dim));
+        var drawBackground = seriesModel.get('showBackground', true);
+        var valueDim = data.mapDimension(valueAxis.dim);
+        var stackResultDim = data.getCalculationInfo('stackResultDimension');
+        var stacked = isDimensionStacked(data, valueDim) && !!data.getCalculationInfo('stackedOnSeries');
+        var isValueAxisH = valueAxis.isHorizontal();
+        var valueAxisStart = getValueAxisStart(baseAxis, valueAxis);
+        var isLarge = isInLargeMode(seriesModel);
+        var barMinHeight = seriesModel.get('barMinHeight') || 0;
+        var stackedDimIdx = stackResultDim && data.getDimensionIndex(stackResultDim); // Layout info.
+
+        var columnWidth = data.getLayout('size');
+        var columnOffset = data.getLayout('offset');
+        return {
+          progress: function (params, data) {
+            var count = params.count;
+            var largePoints = isLarge && createFloat32Array(count * 3);
+            var largeBackgroundPoints = isLarge && drawBackground && createFloat32Array(count * 3);
+            var largeDataIndices = isLarge && createFloat32Array(count);
+            var coordLayout = cartesian.master.getRect();
+            var bgSize = isValueAxisH ? coordLayout.width : coordLayout.height;
+            var dataIndex;
+            var store = data.getStore();
+            var idxOffset = 0;
+
+            while ((dataIndex = params.next()) != null) {
+              var value = store.get(stacked ? stackedDimIdx : valueDimIdx, dataIndex);
+              var baseValue = store.get(baseDimIdx, dataIndex);
+              var baseCoord = valueAxisStart;
+              var startValue = void 0; // Because of the barMinHeight, we can not use the value in
+              // stackResultDimension directly.
+
+              if (stacked) {
+                startValue = +value - store.get(valueDimIdx, dataIndex);
+              }
+
+              var x = void 0;
+              var y = void 0;
+              var width = void 0;
+              var height = void 0;
+
+              if (isValueAxisH) {
+                var coord = cartesian.dataToPoint([value, baseValue]);
+
+                if (stacked) {
+                  var startCoord = cartesian.dataToPoint([startValue, baseValue]);
+                  baseCoord = startCoord[0];
+                }
+
+                x = baseCoord;
+                y = coord[1] + columnOffset;
+                width = coord[0] - baseCoord;
+                height = columnWidth;
+
+                if (Math.abs(width) < barMinHeight) {
+                  width = (width < 0 ? -1 : 1) * barMinHeight;
+                }
+              } else {
+                var coord = cartesian.dataToPoint([baseValue, value]);
+
+                if (stacked) {
+                  var startCoord = cartesian.dataToPoint([baseValue, startValue]);
+                  baseCoord = startCoord[1];
+                }
+
+                x = coord[0] + columnOffset;
+                y = baseCoord;
+                width = columnWidth;
+                height = coord[1] - baseCoord;
+
+                if (Math.abs(height) < barMinHeight) {
+                  // Include zero to has a positive bar
+                  height = (height <= 0 ? -1 : 1) * barMinHeight;
+                }
+              }
+
+              if (!isLarge) {
+                data.setItemLayout(dataIndex, {
+                  x: x,
+                  y: y,
+                  width: width,
+                  height: height
+                });
+              } else {
+                largePoints[idxOffset] = x;
+                largePoints[idxOffset + 1] = y;
+                largePoints[idxOffset + 2] = isValueAxisH ? width : height;
+
+                if (largeBackgroundPoints) {
+                  largeBackgroundPoints[idxOffset] = isValueAxisH ? coordLayout.x : x;
+                  largeBackgroundPoints[idxOffset + 1] = isValueAxisH ? y : coordLayout.y;
+                  largeBackgroundPoints[idxOffset + 2] = bgSize;
+                }
+
+                largeDataIndices[dataIndex] = dataIndex;
+              }
+
+              idxOffset += 3;
+            }
+
+            if (isLarge) {
+              data.setLayout({
+                largePoints: largePoints,
+                largeDataIndices: largeDataIndices,
+                largeBackgroundPoints: largeBackgroundPoints,
+                valueAxisHorizontal: isValueAxisH
+              });
+            }
+          }
+        };
+      }
+    };
+  }
+
+  function isOnCartesian(seriesModel) {
+    return seriesModel.coordinateSystem && seriesModel.coordinateSystem.type === 'cartesian2d';
+  }
+
+  function isInLargeMode(seriesModel) {
+    return seriesModel.pipelineContext && seriesModel.pipelineContext.large;
+  } // See cases in `test/bar-start.html` and `#7412`, `#8747`.
+
+
+  function getValueAxisStart(baseAxis, valueAxis) {
+    return valueAxis.toGlobalCoord(valueAxis.dataToCoord(valueAxis.type === 'log' ? 1 : 0));
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /*
+  * A third-party license is embeded for some of the code in this file:
+  * The "scaleLevels" was originally copied from "d3.js" with some
+  * modifications made for this project.
+  * (See more details in the comment on the definition of "scaleLevels" below.)
+  * The use of the source code of this file is also subject to the terms
+  * and consitions of the license of "d3.js" (BSD-3Clause, see
+  * </licenses/LICENSE-d3>).
+  */
+  // [About UTC and local time zone]:
+  // In most cases, `number.parseDate` will treat input data string as local time
+  // (except time zone is specified in time string). And `format.formateTime` returns
+  // local time by default. option.useUTC is false by default. This design have
+  // concidered these common case:
+  // (1) Time that is persistent in server is in UTC, but it is needed to be diplayed
+  // in local time by default.
+  // (2) By default, the input data string (e.g., '2011-01-02') should be displayed
+  // as its original time, without any time difference.
+
+
+  var bisect = function (a, x, lo, hi) {
+    while (lo < hi) {
+      var mid = lo + hi >>> 1;
+
+      if (a[mid][1] < x) {
+        lo = mid + 1;
+      } else {
+        hi = mid;
+      }
+    }
+
+    return lo;
+  };
+
+  var TimeScale =
+  /** @class */
+  function (_super) {
+    __extends(TimeScale, _super);
+
+    function TimeScale(settings) {
+      var _this = _super.call(this, settings) || this;
+
+      _this.type = 'time';
+      return _this;
+    }
+    /**
+     * Get label is mainly for other components like dataZoom, tooltip.
+     */
+
+
+    TimeScale.prototype.getLabel = function (tick) {
+      var useUTC = this.getSetting('useUTC');
+      return format(tick.value, fullLeveledFormatter[getDefaultFormatPrecisionOfInterval(getPrimaryTimeUnit(this._minLevelUnit))] || fullLeveledFormatter.second, useUTC, this.getSetting('locale'));
+    };
+
+    TimeScale.prototype.getFormattedLabel = function (tick, idx, labelFormatter) {
+      var isUTC = this.getSetting('useUTC');
+      var lang = this.getSetting('locale');
+      return leveledFormat(tick, idx, labelFormatter, lang, isUTC);
+    };
+    /**
+     * @override
+     */
+
+
+    TimeScale.prototype.getTicks = function () {
+      var interval = this._interval;
+      var extent = this._extent;
+      var ticks = []; // If interval is 0, return [];
+
+      if (!interval) {
+        return ticks;
+      }
+
+      ticks.push({
+        value: extent[0],
+        level: 0
+      });
+      var useUTC = this.getSetting('useUTC');
+      var innerTicks = getIntervalTicks(this._minLevelUnit, this._approxInterval, useUTC, extent);
+      ticks = ticks.concat(innerTicks);
+      ticks.push({
+        value: extent[1],
+        level: 0
+      });
+      return ticks;
+    };
+
+    TimeScale.prototype.calcNiceExtent = function (opt) {
+      var extent = this._extent; // If extent start and end are same, expand them
+
+      if (extent[0] === extent[1]) {
+        // Expand extent
+        extent[0] -= ONE_DAY;
+        extent[1] += ONE_DAY;
+      } // If there are no data and extent are [Infinity, -Infinity]
+
+
+      if (extent[1] === -Infinity && extent[0] === Infinity) {
+        var d = new Date();
+        extent[1] = +new Date(d.getFullYear(), d.getMonth(), d.getDate());
+        extent[0] = extent[1] - ONE_DAY;
+      }
+
+      this.calcNiceTicks(opt.splitNumber, opt.minInterval, opt.maxInterval);
+    };
+
+    TimeScale.prototype.calcNiceTicks = function (approxTickNum, minInterval, maxInterval) {
+      approxTickNum = approxTickNum || 10;
+      var extent = this._extent;
+      var span = extent[1] - extent[0];
+      this._approxInterval = span / approxTickNum;
+
+      if (minInterval != null && this._approxInterval < minInterval) {
+        this._approxInterval = minInterval;
+      }
+
+      if (maxInterval != null && this._approxInterval > maxInterval) {
+        this._approxInterval = maxInterval;
+      }
+
+      var scaleIntervalsLen = scaleIntervals.length;
+      var idx = Math.min(bisect(scaleIntervals, this._approxInterval, 0, scaleIntervalsLen), scaleIntervalsLen - 1); // Interval that can be used to calculate ticks
+
+      this._interval = scaleIntervals[idx][1]; // Min level used when picking ticks from top down.
+      // We check one more level to avoid the ticks are to sparse in some case.
+
+      this._minLevelUnit = scaleIntervals[Math.max(idx - 1, 0)][0];
+    };
+
+    TimeScale.prototype.parse = function (val) {
+      // val might be float.
+      return isNumber(val) ? val : +parseDate(val);
+    };
+
+    TimeScale.prototype.contain = function (val) {
+      return contain$1(this.parse(val), this._extent);
+    };
+
+    TimeScale.prototype.normalize = function (val) {
+      return normalize$1(this.parse(val), this._extent);
+    };
+
+    TimeScale.prototype.scale = function (val) {
+      return scale$2(val, this._extent);
+    };
+
+    TimeScale.type = 'time';
+    return TimeScale;
+  }(IntervalScale);
+  /**
+   * This implementation was originally copied from "d3.js"
+   * <https://github.com/d3/d3/blob/b516d77fb8566b576088e73410437494717ada26/src/time/scale.js>
+   * with some modifications made for this program.
+   * See the license statement at the head of this file.
+   */
+
+
+  var scaleIntervals = [// Format                           interval
+  ['second', ONE_SECOND], ['minute', ONE_MINUTE], ['hour', ONE_HOUR], ['quarter-day', ONE_HOUR * 6], ['half-day', ONE_HOUR * 12], ['day', ONE_DAY * 1.2], ['half-week', ONE_DAY * 3.5], ['week', ONE_DAY * 7], ['month', ONE_DAY * 31], ['quarter', ONE_DAY * 95], ['half-year', ONE_YEAR / 2], ['year', ONE_YEAR] // 1Y
+  ];
+
+  function isUnitValueSame(unit, valueA, valueB, isUTC) {
+    var dateA = parseDate(valueA);
+    var dateB = parseDate(valueB);
+
+    var isSame = function (unit) {
+      return getUnitValue(dateA, unit, isUTC) === getUnitValue(dateB, unit, isUTC);
+    };
+
+    var isSameYear = function () {
+      return isSame('year');
+    }; // const isSameHalfYear = () => isSameYear() && isSame('half-year');
+    // const isSameQuater = () => isSameYear() && isSame('quarter');
+
+
+    var isSameMonth = function () {
+      return isSameYear() && isSame('month');
+    };
+
+    var isSameDay = function () {
+      return isSameMonth() && isSame('day');
+    }; // const isSameHalfDay = () => isSameDay() && isSame('half-day');
+
+
+    var isSameHour = function () {
+      return isSameDay() && isSame('hour');
+    };
+
+    var isSameMinute = function () {
+      return isSameHour() && isSame('minute');
+    };
+
+    var isSameSecond = function () {
+      return isSameMinute() && isSame('second');
+    };
+
+    var isSameMilliSecond = function () {
+      return isSameSecond() && isSame('millisecond');
+    };
+
+    switch (unit) {
+      case 'year':
+        return isSameYear();
+
+      case 'month':
+        return isSameMonth();
+
+      case 'day':
+        return isSameDay();
+
+      case 'hour':
+        return isSameHour();
+
+      case 'minute':
+        return isSameMinute();
+
+      case 'second':
+        return isSameSecond();
+
+      case 'millisecond':
+        return isSameMilliSecond();
+    }
+  } // const primaryUnitGetters = {
+  //     year: fullYearGetterName(),
+  //     month: monthGetterName(),
+  //     day: dateGetterName(),
+  //     hour: hoursGetterName(),
+  //     minute: minutesGetterName(),
+  //     second: secondsGetterName(),
+  //     millisecond: millisecondsGetterName()
+  // };
+  // const primaryUnitUTCGetters = {
+  //     year: fullYearGetterName(true),
+  //     month: monthGetterName(true),
+  //     day: dateGetterName(true),
+  //     hour: hoursGetterName(true),
+  //     minute: minutesGetterName(true),
+  //     second: secondsGetterName(true),
+  //     millisecond: millisecondsGetterName(true)
+  // };
+  // function moveTick(date: Date, unitName: TimeUnit, step: number, isUTC: boolean) {
+  //     step = step || 1;
+  //     switch (getPrimaryTimeUnit(unitName)) {
+  //         case 'year':
+  //             date[fullYearSetterName(isUTC)](date[fullYearGetterName(isUTC)]() + step);
+  //             break;
+  //         case 'month':
+  //             date[monthSetterName(isUTC)](date[monthGetterName(isUTC)]() + step);
+  //             break;
+  //         case 'day':
+  //             date[dateSetterName(isUTC)](date[dateGetterName(isUTC)]() + step);
+  //             break;
+  //         case 'hour':
+  //             date[hoursSetterName(isUTC)](date[hoursGetterName(isUTC)]() + step);
+  //             break;
+  //         case 'minute':
+  //             date[minutesSetterName(isUTC)](date[minutesGetterName(isUTC)]() + step);
+  //             break;
+  //         case 'second':
+  //             date[secondsSetterName(isUTC)](date[secondsGetterName(isUTC)]() + step);
+  //             break;
+  //         case 'millisecond':
+  //             date[millisecondsSetterName(isUTC)](date[millisecondsGetterName(isUTC)]() + step);
+  //             break;
+  //     }
+  //     return date.getTime();
+  // }
+  // const DATE_INTERVALS = [[8, 7.5], [4, 3.5], [2, 1.5]];
+  // const MONTH_INTERVALS = [[6, 5.5], [3, 2.5], [2, 1.5]];
+  // const MINUTES_SECONDS_INTERVALS = [[30, 30], [20, 20], [15, 15], [10, 10], [5, 5], [2, 2]];
+
+
+  function getDateInterval(approxInterval, daysInMonth) {
+    approxInterval /= ONE_DAY;
+    return approxInterval > 16 ? 16 // Math.floor(daysInMonth / 2) + 1  // In this case we only want one tick betwen two month.
+    : approxInterval > 7.5 ? 7 // TODO week 7 or day 8?
+    : approxInterval > 3.5 ? 4 : approxInterval > 1.5 ? 2 : 1;
+  }
+
+  function getMonthInterval(approxInterval) {
+    var APPROX_ONE_MONTH = 30 * ONE_DAY;
+    approxInterval /= APPROX_ONE_MONTH;
+    return approxInterval > 6 ? 6 : approxInterval > 3 ? 3 : approxInterval > 2 ? 2 : 1;
+  }
+
+  function getHourInterval(approxInterval) {
+    approxInterval /= ONE_HOUR;
+    return approxInterval > 12 ? 12 : approxInterval > 6 ? 6 : approxInterval > 3.5 ? 4 : approxInterval > 2 ? 2 : 1;
+  }
+
+  function getMinutesAndSecondsInterval(approxInterval, isMinutes) {
+    approxInterval /= isMinutes ? ONE_MINUTE : ONE_SECOND;
+    return approxInterval > 30 ? 30 : approxInterval > 20 ? 20 : approxInterval > 15 ? 15 : approxInterval > 10 ? 10 : approxInterval > 5 ? 5 : approxInterval > 2 ? 2 : 1;
+  }
+
+  function getMillisecondsInterval(approxInterval) {
+    return nice(approxInterval, true);
+  }
+
+  function getFirstTimestampOfUnit(date, unitName, isUTC) {
+    var outDate = new Date(date);
+
+    switch (getPrimaryTimeUnit(unitName)) {
+      case 'year':
+      case 'month':
+        outDate[monthSetterName(isUTC)](0);
+
+      case 'day':
+        outDate[dateSetterName(isUTC)](1);
+
+      case 'hour':
+        outDate[hoursSetterName(isUTC)](0);
+
+      case 'minute':
+        outDate[minutesSetterName(isUTC)](0);
+
+      case 'second':
+        outDate[secondsSetterName(isUTC)](0);
+        outDate[millisecondsSetterName(isUTC)](0);
+    }
+
+    return outDate.getTime();
+  }
+
+  function getIntervalTicks(bottomUnitName, approxInterval, isUTC, extent) {
+    var safeLimit = 10000;
+    var unitNames = timeUnits;
+    var iter = 0;
+
+    function addTicksInSpan(interval, minTimestamp, maxTimestamp, getMethodName, setMethodName, isDate, out) {
+      var date = new Date(minTimestamp);
+      var dateTime = minTimestamp;
+      var d = date[getMethodName](); // if (isDate) {
+      //     d -= 1; // Starts with 0;   PENDING
+      // }
+
+      while (dateTime < maxTimestamp && dateTime <= extent[1]) {
+        out.push({
+          value: dateTime
+        });
+        d += interval;
+        date[setMethodName](d);
+        dateTime = date.getTime();
+      } // This extra tick is for calcuating ticks of next level. Will not been added to the final result
+
+
+      out.push({
+        value: dateTime,
+        notAdd: true
+      });
+    }
+
+    function addLevelTicks(unitName, lastLevelTicks, levelTicks) {
+      var newAddedTicks = [];
+      var isFirstLevel = !lastLevelTicks.length;
+
+      if (isUnitValueSame(getPrimaryTimeUnit(unitName), extent[0], extent[1], isUTC)) {
+        return;
+      }
+
+      if (isFirstLevel) {
+        lastLevelTicks = [{
+          // TODO Optimize. Not include so may ticks.
+          value: getFirstTimestampOfUnit(new Date(extent[0]), unitName, isUTC)
+        }, {
+          value: extent[1]
+        }];
+      }
+
+      for (var i = 0; i < lastLevelTicks.length - 1; i++) {
+        var startTick = lastLevelTicks[i].value;
+        var endTick = lastLevelTicks[i + 1].value;
+
+        if (startTick === endTick) {
+          continue;
+        }
+
+        var interval = void 0;
+        var getterName = void 0;
+        var setterName = void 0;
+        var isDate = false;
+
+        switch (unitName) {
+          case 'year':
+            interval = Math.max(1, Math.round(approxInterval / ONE_DAY / 365));
+            getterName = fullYearGetterName(isUTC);
+            setterName = fullYearSetterName(isUTC);
+            break;
+
+          case 'half-year':
+          case 'quarter':
+          case 'month':
+            interval = getMonthInterval(approxInterval);
+            getterName = monthGetterName(isUTC);
+            setterName = monthSetterName(isUTC);
+            break;
+
+          case 'week': // PENDING If week is added. Ignore day.
+
+          case 'half-week':
+          case 'day':
+            interval = getDateInterval(approxInterval, 31); // Use 32 days and let interval been 16
+
+            getterName = dateGetterName(isUTC);
+            setterName = dateSetterName(isUTC);
+            isDate = true;
+            break;
+
+          case 'half-day':
+          case 'quarter-day':
+          case 'hour':
+            interval = getHourInterval(approxInterval);
+            getterName = hoursGetterName(isUTC);
+            setterName = hoursSetterName(isUTC);
+            break;
+
+          case 'minute':
+            interval = getMinutesAndSecondsInterval(approxInterval, true);
+            getterName = minutesGetterName(isUTC);
+            setterName = minutesSetterName(isUTC);
+            break;
+
+          case 'second':
+            interval = getMinutesAndSecondsInterval(approxInterval, false);
+            getterName = secondsGetterName(isUTC);
+            setterName = secondsSetterName(isUTC);
+            break;
+
+          case 'millisecond':
+            interval = getMillisecondsInterval(approxInterval);
+            getterName = millisecondsGetterName(isUTC);
+            setterName = millisecondsSetterName(isUTC);
+            break;
+        }
+
+        addTicksInSpan(interval, startTick, endTick, getterName, setterName, isDate, newAddedTicks);
+
+        if (unitName === 'year' && levelTicks.length > 1 && i === 0) {
+          // Add nearest years to the left extent.
+          levelTicks.unshift({
+            value: levelTicks[0].value - interval
+          });
+        }
+      }
+
+      for (var i = 0; i < newAddedTicks.length; i++) {
+        levelTicks.push(newAddedTicks[i]);
+      } // newAddedTicks.length && console.log(unitName, newAddedTicks);
+
+
+      return newAddedTicks;
+    }
+
+    var levelsTicks = [];
+    var currentLevelTicks = [];
+    var tickCount = 0;
+    var lastLevelTickCount = 0;
+
+    for (var i = 0; i < unitNames.length && iter++ < safeLimit; ++i) {
+      var primaryTimeUnit = getPrimaryTimeUnit(unitNames[i]);
+
+      if (!isPrimaryTimeUnit(unitNames[i])) {
+        // TODO
+        continue;
+      }
+
+      addLevelTicks(unitNames[i], levelsTicks[levelsTicks.length - 1] || [], currentLevelTicks);
+      var nextPrimaryTimeUnit = unitNames[i + 1] ? getPrimaryTimeUnit(unitNames[i + 1]) : null;
+
+      if (primaryTimeUnit !== nextPrimaryTimeUnit) {
+        if (currentLevelTicks.length) {
+          lastLevelTickCount = tickCount; // Remove the duplicate so the tick count can be precisely.
+
+          currentLevelTicks.sort(function (a, b) {
+            return a.value - b.value;
+          });
+          var levelTicksRemoveDuplicated = [];
+
+          for (var i_1 = 0; i_1 < currentLevelTicks.length; ++i_1) {
+            var tickValue = currentLevelTicks[i_1].value;
+
+            if (i_1 === 0 || currentLevelTicks[i_1 - 1].value !== tickValue) {
+              levelTicksRemoveDuplicated.push(currentLevelTicks[i_1]);
+
+              if (tickValue >= extent[0] && tickValue <= extent[1]) {
+                tickCount++;
+              }
+            }
+          }
+
+          var targetTickNum = (extent[1] - extent[0]) / approxInterval; // Added too much in this level and not too less in last level
+
+          if (tickCount > targetTickNum * 1.5 && lastLevelTickCount > targetTickNum / 1.5) {
+            break;
+          } // Only treat primary time unit as one level.
+
+
+          levelsTicks.push(levelTicksRemoveDuplicated);
+
+          if (tickCount > targetTickNum || bottomUnitName === unitNames[i]) {
+            break;
+          }
+        } // Reset if next unitName is primary
+
+
+        currentLevelTicks = [];
+      }
+    }
+
+    {
+      if (iter >= safeLimit) {
+        warn('Exceed safe limit.');
+      }
+    }
+    var levelsTicksInExtent = filter(map(levelsTicks, function (levelTicks) {
+      return filter(levelTicks, function (tick) {
+        return tick.value >= extent[0] && tick.value <= extent[1] && !tick.notAdd;
+      });
+    }), function (levelTicks) {
+      return levelTicks.length > 0;
+    });
+    var ticks = [];
+    var maxLevel = levelsTicksInExtent.length - 1;
+
+    for (var i = 0; i < levelsTicksInExtent.length; ++i) {
+      var levelTicks = levelsTicksInExtent[i];
+
+      for (var k = 0; k < levelTicks.length; ++k) {
+        ticks.push({
+          value: levelTicks[k].value,
+          level: maxLevel - i
+        });
+      }
+    }
+
+    ticks.sort(function (a, b) {
+      return a.value - b.value;
+    }); // Remove duplicates
+
+    var result = [];
+
+    for (var i = 0; i < ticks.length; ++i) {
+      if (i === 0 || ticks[i].value !== ticks[i - 1].value) {
+        result.push(ticks[i]);
+      }
+    }
+
+    return result;
+  }
+
+  Scale.registerClass(TimeScale);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 scaleProto = Scale.prototype; // FIXME:TS refactor: not good to call it directly with `this`?
+
+  var intervalScaleProto = IntervalScale.prototype;
+  var roundingErrorFix = round;
+  var mathFloor = Math.floor;
+  var mathCeil = Math.ceil;
+  var mathPow$1 = Math.pow;
+  var mathLog = Math.log;
+
+  var LogScale =
+  /** @class */
+  function (_super) {
+    __extends(LogScale, _super);
+
+    function LogScale() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = 'log';
+      _this.base = 10;
+      _this._originalScale = new IntervalScale(); // FIXME:TS actually used by `IntervalScale`
+
+      _this._interval = 0;
+      return _this;
+    }
+    /**
+     * @param Whether expand the ticks to niced extent.
+     */
+
+
+    LogScale.prototype.getTicks = function (expandToNicedExtent) {
+      var originalScale = this._originalScale;
+      var extent = this._extent;
+      var originalExtent = originalScale.getExtent();
+      var ticks = intervalScaleProto.getTicks.call(this, expandToNicedExtent);
+      return map(ticks, function (tick) {
+        var val = tick.value;
+        var powVal = round(mathPow$1(this.base, val)); // Fix #4158
+
+        powVal = val === extent[0] && this._fixMin ? fixRoundingError(powVal, originalExtent[0]) : powVal;
+        powVal = val === extent[1] && this._fixMax ? fixRoundingError(powVal, originalExtent[1]) : powVal;
+        return {
+          value: powVal
+        };
+      }, this);
+    };
+
+    LogScale.prototype.setExtent = function (start, end) {
+      var base = this.base;
+      start = mathLog(start) / mathLog(base);
+      end = mathLog(end) / mathLog(base);
+      intervalScaleProto.setExtent.call(this, start, end);
+    };
+    /**
+     * @return {number} end
+     */
+
+
+    LogScale.prototype.getExtent = function () {
+      var base = this.base;
+      var extent = scaleProto.getExtent.call(this);
+      extent[0] = mathPow$1(base, extent[0]);
+      extent[1] = mathPow$1(base, extent[1]); // Fix #4158
+
+      var originalScale = this._originalScale;
+      var originalExtent = originalScale.getExtent();
+      this._fixMin && (extent[0] = fixRoundingError(extent[0], originalExtent[0]));
+      this._fixMax && (extent[1] = fixRoundingError(extent[1], originalExtent[1]));
+      return extent;
+    };
+
+    LogScale.prototype.unionExtent = function (extent) {
+      this._originalScale.unionExtent(extent);
+
+      var base = this.base;
+      extent[0] = mathLog(extent[0]) / mathLog(base);
+      extent[1] = mathLog(extent[1]) / mathLog(base);
+      scaleProto.unionExtent.call(this, extent);
+    };
+
+    LogScale.prototype.unionExtentFromData = function (data, dim) {
+      // TODO
+      // filter value that <= 0
+      this.unionExtent(data.getApproximateExtent(dim));
+    };
+    /**
+     * Update interval and extent of intervals for nice ticks
+     * @param approxTickNum default 10 Given approx tick number
+     */
+
+
+    LogScale.prototype.calcNiceTicks = function (approxTickNum) {
+      approxTickNum = approxTickNum || 10;
+      var extent = this._extent;
+      var span = extent[1] - extent[0];
+
+      if (span === Infinity || span <= 0) {
+        return;
+      }
+
+      var interval = quantity(span);
+      var err = approxTickNum / span * interval; // Filter ticks to get closer to the desired count.
+
+      if (err <= 0.5) {
+        interval *= 10;
+      } // Interval should be integer
+
+
+      while (!isNaN(interval) && Math.abs(interval) < 1 && Math.abs(interval) > 0) {
+        interval *= 10;
+      }
+
+      var niceExtent = [round(mathCeil(extent[0] / interval) * interval), round(mathFloor(extent[1] / interval) * interval)];
+      this._interval = interval;
+      this._niceExtent = niceExtent;
+    };
+
+    LogScale.prototype.calcNiceExtent = function (opt) {
+      intervalScaleProto.calcNiceExtent.call(this, opt);
+      this._fixMin = opt.fixMin;
+      this._fixMax = opt.fixMax;
+    };
+
+    LogScale.prototype.parse = function (val) {
+      return val;
+    };
+
+    LogScale.prototype.contain = function (val) {
+      val = mathLog(val) / mathLog(this.base);
+      return contain$1(val, this._extent);
+    };
+
+    LogScale.prototype.normalize = function (val) {
+      val = mathLog(val) / mathLog(this.base);
+      return normalize$1(val, this._extent);
+    };
+
+    LogScale.prototype.scale = function (val) {
+      val = scale$2(val, this._extent);
+      return mathPow$1(this.base, val);
+    };
+
+    LogScale.type = 'log';
+    return LogScale;
+  }(Scale);
+
+  var proto = LogScale.prototype;
+  proto.getMinorTicks = intervalScaleProto.getMinorTicks;
+  proto.getLabel = intervalScaleProto.getLabel;
+
+  function fixRoundingError(val, originalVal) {
+    return roundingErrorFix(val, getPrecision(originalVal));
+  }
+
+  Scale.registerClass(LogScale);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 ScaleRawExtentInfo =
+  /** @class */
+  function () {
+    function ScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis.
+    originalExtent) {
+      this._prepareParams(scale, model, originalExtent);
+    }
+    /**
+     * Parameters depending on ouside (like model, user callback)
+     * are prepared and fixed here.
+     */
+
+
+    ScaleRawExtentInfo.prototype._prepareParams = function (scale, model, // Usually: data extent from all series on this axis.
+    dataExtent) {
+      if (dataExtent[1] < dataExtent[0]) {
+        dataExtent = [NaN, NaN];
+      }
+
+      this._dataMin = dataExtent[0];
+      this._dataMax = dataExtent[1];
+      var isOrdinal = this._isOrdinal = scale.type === 'ordinal';
+      this._needCrossZero = scale.type === 'interval' && model.getNeedCrossZero && model.getNeedCrossZero();
+      var modelMinRaw = this._modelMinRaw = model.get('min', true);
+
+      if (isFunction(modelMinRaw)) {
+        // This callback alway provide users the full data extent (before data filtered).
+        this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw({
+          min: dataExtent[0],
+          max: dataExtent[1]
+        }));
+      } else if (modelMinRaw !== 'dataMin') {
+        this._modelMinNum = parseAxisModelMinMax(scale, modelMinRaw);
+      }
+
+      var modelMaxRaw = this._modelMaxRaw = model.get('max', true);
+
+      if (isFunction(modelMaxRaw)) {
+        // This callback alway provide users the full data extent (before data filtered).
+        this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw({
+          min: dataExtent[0],
+          max: dataExtent[1]
+        }));
+      } else if (modelMaxRaw !== 'dataMax') {
+        this._modelMaxNum = parseAxisModelMinMax(scale, modelMaxRaw);
+      }
+
+      if (isOrdinal) {
+        // FIXME: there is a flaw here: if there is no "block" data processor like `dataZoom`,
+        // and progressive rendering is using, here the category result might just only contain
+        // the processed chunk rather than the entire result.
+        this._axisDataLen = model.getCategories().length;
+      } else {
+        var boundaryGap = model.get('boundaryGap');
+        var boundaryGapArr = isArray(boundaryGap) ? boundaryGap : [boundaryGap || 0, boundaryGap || 0];
+
+        if (typeof boundaryGapArr[0] === 'boolean' || typeof boundaryGapArr[1] === 'boolean') {
+          {
+            console.warn('Boolean type for boundaryGap is only ' + 'allowed for ordinal axis. Please use string in ' + 'percentage instead, e.g., "20%". Currently, ' + 'boundaryGap is set to be 0.');
+          }
+          this._boundaryGapInner = [0, 0];
+        } else {
+          this._boundaryGapInner = [parsePercent(boundaryGapArr[0], 1), parsePercent(boundaryGapArr[1], 1)];
+        }
+      }
+    };
+    /**
+     * Calculate extent by prepared parameters.
+     * This method has no external dependency and can be called duplicatedly,
+     * getting the same result.
+     * If parameters changed, should call this method to recalcuate.
+     */
+
+
+    ScaleRawExtentInfo.prototype.calculate = function () {
+      // Notice: When min/max is not set (that is, when there are null/undefined,
+      // which is the most common case), these cases should be ensured:
+      // (1) For 'ordinal', show all axis.data.
+      // (2) For others:
+      //      + `boundaryGap` is applied (if min/max set, boundaryGap is
+      //      disabled).
+      //      + If `needCrossZero`, min/max should be zero, otherwise, min/max should
+      //      be the result that originalExtent enlarged by boundaryGap.
+      // (3) If no data, it should be ensured that `scale.setBlank` is set.
+      var isOrdinal = this._isOrdinal;
+      var dataMin = this._dataMin;
+      var dataMax = this._dataMax;
+      var axisDataLen = this._axisDataLen;
+      var boundaryGapInner = this._boundaryGapInner;
+      var span = !isOrdinal ? dataMax - dataMin || Math.abs(dataMin) : null; // Currently if a `'value'` axis model min is specified as 'dataMin'/'dataMax',
+      // `boundaryGap` will not be used. It's the different from specifying as `null`/`undefined`.
+
+      var min = this._modelMinRaw === 'dataMin' ? dataMin : this._modelMinNum;
+      var max = this._modelMaxRaw === 'dataMax' ? dataMax : this._modelMaxNum; // If `_modelMinNum`/`_modelMaxNum` is `null`/`undefined`, should not be fixed.
+
+      var minFixed = min != null;
+      var maxFixed = max != null;
+
+      if (min == null) {
+        min = isOrdinal ? axisDataLen ? 0 : NaN : dataMin - boundaryGapInner[0] * span;
+      }
+
+      if (max == null) {
+        max = isOrdinal ? axisDataLen ? axisDataLen - 1 : NaN : dataMax + boundaryGapInner[1] * span;
+      }
+
+      (min == null || !isFinite(min)) && (min = NaN);
+      (max == null || !isFinite(max)) && (max = NaN);
+      var isBlank = eqNaN(min) || eqNaN(max) || isOrdinal && !axisDataLen; // If data extent modified, need to recalculated to ensure cross zero.
+
+      if (this._needCrossZero) {
+        // Axis is over zero and min is not set
+        if (min > 0 && max > 0 && !minFixed) {
+          min = 0; // minFixed = true;
+        } // Axis is under zero and max is not set
+
+
+        if (min < 0 && max < 0 && !maxFixed) {
+          max = 0; // maxFixed = true;
+        } // PENDING:
+        // When `needCrossZero` and all data is positive/negative, should it be ensured
+        // that the results processed by boundaryGap are positive/negative?
+        // If so, here `minFixed`/`maxFixed` need to be set.
+
+      }
+
+      var determinedMin = this._determinedMin;
+      var determinedMax = this._determinedMax;
+
+      if (determinedMin != null) {
+        min = determinedMin;
+        minFixed = true;
+      }
+
+      if (determinedMax != null) {
+        max = determinedMax;
+        maxFixed = true;
+      } // Ensure min/max be finite number or NaN here. (not to be null/undefined)
+      // `NaN` means min/max axis is blank.
+
+
+      return {
+        min: min,
+        max: max,
+        minFixed: minFixed,
+        maxFixed: maxFixed,
+        isBlank: isBlank
+      };
+    };
+
+    ScaleRawExtentInfo.prototype.modifyDataMinMax = function (minMaxName, val) {
+      {
+        assert(!this.frozen);
+      }
+      this[DATA_MIN_MAX_ATTR[minMaxName]] = val;
+    };
+
+    ScaleRawExtentInfo.prototype.setDeterminedMinMax = function (minMaxName, val) {
+      var attr = DETERMINED_MIN_MAX_ATTR[minMaxName];
+      {
+        assert(!this.frozen // Earse them usually means logic flaw.
+        && this[attr] == null);
+      }
+      this[attr] = val;
+    };
+
+    ScaleRawExtentInfo.prototype.freeze = function () {
+      // @ts-ignore
+      this.frozen = true;
+    };
+
+    return ScaleRawExtentInfo;
+  }();
+
+  var DETERMINED_MIN_MAX_ATTR = {
+    min: '_determinedMin',
+    max: '_determinedMax'
+  };
+  var DATA_MIN_MAX_ATTR = {
+    min: '_dataMin',
+    max: '_dataMax'
+  };
+  /**
+   * Get scale min max and related info only depends on model settings.
+   * This method can be called after coordinate system created.
+   * For example, in data processing stage.
+   *
+   * Scale extent info probably be required multiple times during a workflow.
+   * For example:
+   * (1) `dataZoom` depends it to get the axis extent in "100%" state.
+   * (2) `processor/extentCalculator` depends it to make sure whether axis extent is specified.
+   * (3) `coordSys.update` use it to finally decide the scale extent.
+   * But the callback of `min`/`max` should not be called multiple times.
+   * The code below should not be implemented repeatedly either.
+   * So we cache the result in the scale instance, which will be recreated at the begining
+   * of the workflow (because `scale` instance will be recreated each round of the workflow).
+   */
+
+  function ensureScaleRawExtentInfo(scale, model, // Usually: data extent from all series on this axis.
+  originalExtent) {
+    // Do not permit to recreate.
+    var rawExtentInfo = scale.rawExtentInfo;
+
+    if (rawExtentInfo) {
+      return rawExtentInfo;
+    }
+
+    rawExtentInfo = new ScaleRawExtentInfo(scale, model, originalExtent); // @ts-ignore
+
+    scale.rawExtentInfo = rawExtentInfo;
+    return rawExtentInfo;
+  }
+
+  function parseAxisModelMinMax(scale, minMax) {
+    return minMax == null ? null : eqNaN(minMax) ? NaN : scale.parse(minMax);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Get axis scale extent before niced.
+   * Item of returned array can only be number (including Infinity and NaN).
+   *
+   * Caution:
+   * Precondition of calling this method:
+   * The scale extent has been initialized using series data extent via
+   * `scale.setExtent` or `scale.unionExtentFromData`;
+   */
+
+
+  function getScaleExtent(scale, model) {
+    var scaleType = scale.type;
+    var rawExtentResult = ensureScaleRawExtentInfo(scale, model, scale.getExtent()).calculate();
+    scale.setBlank(rawExtentResult.isBlank);
+    var min = rawExtentResult.min;
+    var max = rawExtentResult.max; // If bars are placed on a base axis of type time or interval account for axis boundary overflow and current axis
+    // is base axis
+    // FIXME
+    // (1) Consider support value axis, where below zero and axis `onZero` should be handled properly.
+    // (2) Refactor the logic with `barGrid`. Is it not need to `makeBarWidthAndOffsetInfo` twice with different extent?
+    //     Should not depend on series type `bar`?
+    // (3) Fix that might overlap when using dataZoom.
+    // (4) Consider other chart types using `barGrid`?
+    // See #6728, #4862, `test/bar-overflow-time-plot.html`
+
+    var ecModel = model.ecModel;
+
+    if (ecModel && scaleType === 'time'
+    /*|| scaleType === 'interval' */
+    ) {
+        var barSeriesModels = prepareLayoutBarSeries('bar', ecModel);
+        var isBaseAxisAndHasBarSeries_1 = false;
+        each(barSeriesModels, function (seriesModel) {
+          isBaseAxisAndHasBarSeries_1 = isBaseAxisAndHasBarSeries_1 || seriesModel.getBaseAxis() === model.axis;
+        });
+
+        if (isBaseAxisAndHasBarSeries_1) {
+          // Calculate placement of bars on axis. TODO should be decoupled
+          // with barLayout
+          var barWidthAndOffset = makeColumnLayout(barSeriesModels); // Adjust axis min and max to account for overflow
+
+          var adjustedScale = adjustScaleForOverflow(min, max, model, barWidthAndOffset);
+          min = adjustedScale.min;
+          max = adjustedScale.max;
+        }
+      }
+
+    return {
+      extent: [min, max],
+      // "fix" means "fixed", the value should not be
+      // changed in the subsequent steps.
+      fixMin: rawExtentResult.minFixed,
+      fixMax: rawExtentResult.maxFixed
+    };
+  }
+
+  function adjustScaleForOverflow(min, max, model, // Only support cartesian coord yet.
+  barWidthAndOffset) {
+    // Get Axis Length
+    var axisExtent = model.axis.getExtent();
+    var axisLength = axisExtent[1] - axisExtent[0]; // Get bars on current base axis and calculate min and max overflow
+
+    var barsOnCurrentAxis = retrieveColumnLayout(barWidthAndOffset, model.axis);
+
+    if (barsOnCurrentAxis === undefined) {
+      return {
+        min: min,
+        max: max
+      };
+    }
+
+    var minOverflow = Infinity;
+    each(barsOnCurrentAxis, function (item) {
+      minOverflow = Math.min(item.offset, minOverflow);
+    });
+    var maxOverflow = -Infinity;
+    each(barsOnCurrentAxis, function (item) {
+      maxOverflow = Math.max(item.offset + item.width, maxOverflow);
+    });
+    minOverflow = Math.abs(minOverflow);
+    maxOverflow = Math.abs(maxOverflow);
+    var totalOverFlow = minOverflow + maxOverflow; // Calculate required buffer based on old range and overflow
+
+    var oldRange = max - min;
+    var oldRangePercentOfNew = 1 - (minOverflow + maxOverflow) / axisLength;
+    var overflowBuffer = oldRange / oldRangePercentOfNew - oldRange;
+    max += overflowBuffer * (maxOverflow / totalOverFlow);
+    min -= overflowBuffer * (minOverflow / totalOverFlow);
+    return {
+      min: min,
+      max: max
+    };
+  } // Precondition of calling this method:
+  // The scale extent has been initailized using series data extent via
+  // `scale.setExtent` or `scale.unionExtentFromData`;
+
+
+  function niceScaleExtent(scale, inModel) {
+    var model = inModel;
+    var extentInfo = getScaleExtent(scale, model);
+    var extent = extentInfo.extent;
+    var splitNumber = model.get('splitNumber');
+
+    if (scale instanceof LogScale) {
+      scale.base = model.get('logBase');
+    }
+
+    var scaleType = scale.type;
+    var interval = model.get('interval');
+    var isIntervalOrTime = scaleType === 'interval' || scaleType === 'time';
+    scale.setExtent(extent[0], extent[1]);
+    scale.calcNiceExtent({
+      splitNumber: splitNumber,
+      fixMin: extentInfo.fixMin,
+      fixMax: extentInfo.fixMax,
+      minInterval: isIntervalOrTime ? model.get('minInterval') : null,
+      maxInterval: isIntervalOrTime ? model.get('maxInterval') : null
+    }); // If some one specified the min, max. And the default calculated interval
+    // is not good enough. He can specify the interval. It is often appeared
+    // in angle axis with angle 0 - 360. Interval calculated in interval scale is hard
+    // to be 60.
+    // FIXME
+
+    if (interval != null) {
+      scale.setInterval && scale.setInterval(interval);
+    }
+  }
+  /**
+   * @param axisType Default retrieve from model.type
+   */
+
+
+  function createScaleByModel(model, axisType) {
+    axisType = axisType || model.get('type');
+
+    if (axisType) {
+      switch (axisType) {
+        // Buildin scale
+        case 'category':
+          return new OrdinalScale({
+            ordinalMeta: model.getOrdinalMeta ? model.getOrdinalMeta() : model.getCategories(),
+            extent: [Infinity, -Infinity]
+          });
+
+        case 'time':
+          return new TimeScale({
+            locale: model.ecModel.getLocaleModel(),
+            useUTC: model.ecModel.get('useUTC')
+          });
+
+        default:
+          // case 'value'/'interval', 'log', or others.
+          return new (Scale.getClass(axisType) || IntervalScale)();
+      }
+    }
+  }
+  /**
+   * Check if the axis cross 0
+   */
+
+
+  function ifAxisCrossZero(axis) {
+    var dataExtent = axis.scale.getExtent();
+    var min = dataExtent[0];
+    var max = dataExtent[1];
+    return !(min > 0 && max > 0 || min < 0 && max < 0);
+  }
+  /**
+   * @param axis
+   * @return Label formatter function.
+   *         param: {number} tickValue,
+   *         param: {number} idx, the index in all ticks.
+   *                         If category axis, this param is not required.
+   *         return: {string} label string.
+   */
+
+
+  function makeLabelFormatter(axis) {
+    var labelFormatter = axis.getLabelModel().get('formatter');
+    var categoryTickStart = axis.type === 'category' ? axis.scale.getExtent()[0] : null;
+
+    if (axis.scale.type === 'time') {
+      return function (tpl) {
+        return function (tick, idx) {
+          return axis.scale.getFormattedLabel(tick, idx, tpl);
+        };
+      }(labelFormatter);
+    } else if (isString(labelFormatter)) {
+      return function (tpl) {
+        return function (tick) {
+          // For category axis, get raw value; for numeric axis,
+          // get formatted label like '1,333,444'.
+          var label = axis.scale.getLabel(tick);
+          var text = tpl.replace('{value}', label != null ? label : '');
+          return text;
+        };
+      }(labelFormatter);
+    } else if (isFunction(labelFormatter)) {
+      return function (cb) {
+        return function (tick, idx) {
+          // The original intention of `idx` is "the index of the tick in all ticks".
+          // But the previous implementation of category axis do not consider the
+          // `axisLabel.interval`, which cause that, for example, the `interval` is
+          // `1`, then the ticks "name5", "name7", "name9" are displayed, where the
+          // corresponding `idx` are `0`, `2`, `4`, but not `0`, `1`, `2`. So we keep
+          // the definition here for back compatibility.
+          if (categoryTickStart != null) {
+            idx = tick.value - categoryTickStart;
+          }
+
+          return cb(getAxisRawValue(axis, tick), idx, tick.level != null ? {
+            level: tick.level
+          } : null);
+        };
+      }(labelFormatter);
+    } else {
+      return function (tick) {
+        return axis.scale.getLabel(tick);
+      };
+    }
+  }
+
+  function getAxisRawValue(axis, tick) {
+    // In category axis with data zoom, tick is not the original
+    // index of axis.data. So tick should not be exposed to user
+    // in category axis.
+    return axis.type === 'category' ? axis.scale.getLabel(tick) : tick.value;
+  }
+  /**
+   * @param axis
+   * @return Be null/undefined if no labels.
+   */
+
+
+  function estimateLabelUnionRect(axis) {
+    var axisModel = axis.model;
+    var scale = axis.scale;
+
+    if (!axisModel.get(['axisLabel', 'show']) || scale.isBlank()) {
+      return;
+    }
+
+    var realNumberScaleTicks;
+    var tickCount;
+    var categoryScaleExtent = scale.getExtent(); // Optimize for large category data, avoid call `getTicks()`.
+
+    if (scale instanceof OrdinalScale) {
+      tickCount = scale.count();
+    } else {
+      realNumberScaleTicks = scale.getTicks();
+      tickCount = realNumberScaleTicks.length;
+    }
+
+    var axisLabelModel = axis.getLabelModel();
+    var labelFormatter = makeLabelFormatter(axis);
+    var rect;
+    var step = 1; // Simple optimization for large amount of labels
+
+    if (tickCount > 40) {
+      step = Math.ceil(tickCount / 40);
+    }
+
+    for (var i = 0; i < tickCount; i += step) {
+      var tick = realNumberScaleTicks ? realNumberScaleTicks[i] : {
+        value: categoryScaleExtent[0] + i
+      };
+      var label = labelFormatter(tick, i);
+      var unrotatedSingleRect = axisLabelModel.getTextRect(label);
+      var singleRect = rotateTextRect(unrotatedSingleRect, axisLabelModel.get('rotate') || 0);
+      rect ? rect.union(singleRect) : rect = singleRect;
+    }
+
+    return rect;
+  }
+
+  function rotateTextRect(textRect, rotate) {
+    var rotateRadians = rotate * Math.PI / 180;
+    var beforeWidth = textRect.width;
+    var beforeHeight = textRect.height;
+    var afterWidth = beforeWidth * Math.abs(Math.cos(rotateRadians)) + Math.abs(beforeHeight * Math.sin(rotateRadians));
+    var afterHeight = beforeWidth * Math.abs(Math.sin(rotateRadians)) + Math.abs(beforeHeight * Math.cos(rotateRadians));
+    var rotatedRect = new BoundingRect(textRect.x, textRect.y, afterWidth, afterHeight);
+    return rotatedRect;
+  }
+  /**
+   * @param model axisLabelModel or axisTickModel
+   * @return {number|String} Can be null|'auto'|number|function
+   */
+
+
+  function getOptionCategoryInterval(model) {
+    var interval = model.get('interval');
+    return interval == null ? 'auto' : interval;
+  }
+  /**
+   * Set `categoryInterval` as 0 implicitly indicates that
+   * show all labels reguardless of overlap.
+   * @param {Object} axis axisModel.axis
+   */
+
+
+  function shouldShowAllLabels(axis) {
+    return axis.type === 'category' && getOptionCategoryInterval(axis.getLabelModel()) === 0;
+  }
+
+  function getDataDimensionsOnAxis(data, axisDim) {
+    // Remove duplicated dat dimensions caused by `getStackedDimension`.
+    var dataDimMap = {}; // Currently `mapDimensionsAll` will contain stack result dimension ('__\0ecstackresult').
+    // PENDING: is it reasonable? Do we need to remove the original dim from "coord dim" since
+    // there has been stacked result dim?
+
+    each(data.mapDimensionsAll(axisDim), function (dataDim) {
+      // For example, the extent of the original dimension
+      // is [0.1, 0.5], the extent of the `stackResultDimension`
+      // is [7, 9], the final extent should NOT include [0.1, 0.5],
+      // because there is no graphic corresponding to [0.1, 0.5].
+      // See the case in `test/area-stack.html` `main1`, where area line
+      // stack needs `yAxis` not start from 0.
+      dataDimMap[getStackedDimension(data, dataDim)] = true;
+    });
+    return keys(dataDimMap);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // eslint-disable-next-line @typescript-eslint/no-unused-vars
+
+
+  var AxisModelCommonMixin =
+  /** @class */
+  function () {
+    function AxisModelCommonMixin() {}
+
+    AxisModelCommonMixin.prototype.getNeedCrossZero = function () {
+      var option = this.option;
+      return !option.scale;
+    };
+    /**
+     * Should be implemented by each axis model if necessary.
+     * @return coordinate system model
+     */
+
+
+    AxisModelCommonMixin.prototype.getCoordSysModel = function () {
+      return;
+    };
+
+    return AxisModelCommonMixin;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * This module exposes helper functions for developing extensions.
+   */
+
+  /**
+   * Create a muti dimension List structure from seriesModel.
+   */
+
+
+  function createList(seriesModel) {
+    return createSeriesData(null, seriesModel);
+  } // export function createGraph(seriesModel) {
+
+
+  var dataStack$1 = {
+    isDimensionStacked: isDimensionStacked,
+    enableDataStack: enableDataStack,
+    getStackedDimension: getStackedDimension
+  };
+  /**
+   * Create scale
+   * @param {Array.<number>} dataExtent
+   * @param {Object|module:echarts/Model} option If `optoin.type`
+   *        is secified, it can only be `'value'` currently.
+   */
+
+  function createScale(dataExtent, option) {
+    var axisModel = option;
+
+    if (!(option instanceof Model)) {
+      axisModel = new Model(option); // FIXME
+      // Currently AxisModelCommonMixin has nothing to do with the
+      // the requirements of `axisHelper.createScaleByModel`. For
+      // example the method `getCategories` and `getOrdinalMeta`
+      // are required for `'category'` axis, and ecModel are required
+      // for `'time'` axis. But occationally echarts-gl happened
+      // to only use `'value'` axis.
+      // zrUtil.mixin(axisModel, AxisModelCommonMixin);
+    }
+
+    var scale = createScaleByModel(axisModel);
+    scale.setExtent(dataExtent[0], dataExtent[1]);
+    niceScaleExtent(scale, axisModel);
+    return scale;
+  }
+  /**
+   * Mixin common methods to axis model,
+   *
+   * Inlcude methods
+   * `getFormattedLabels() => Array.<string>`
+   * `getCategories() => Array.<string>`
+   * `getMin(origin: boolean) => number`
+   * `getMax(origin: boolean) => number`
+   * `getNeedCrossZero() => boolean`
+   */
+
+
+  function mixinAxisModelCommonMethods(Model$$1) {
+    mixin(Model$$1, AxisModelCommonMixin);
+  }
+
+  function createTextStyle$1(textStyleModel, opts) {
+    opts = opts || {};
+    return createTextStyle(textStyleModel, null, null, opts.state !== 'normal');
+  }
+
+  var helper = (Object.freeze || Object)({
+    createList: createList,
+    getLayoutRect: getLayoutRect,
+    dataStack: dataStack$1,
+    createScale: createScale,
+    mixinAxisModelCommonMethods: mixinAxisModelCommonMethods,
+    getECData: getECData,
+    createTextStyle: createTextStyle$1,
+    createDimensions: createDimensions,
+    createSymbol: createSymbol,
+    enableHoverEmphasis: enableHoverEmphasis
+  });
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 extensions = [];
+  var extensionRegisters = {
+    registerPreprocessor: registerPreprocessor,
+    registerProcessor: registerProcessor,
+    registerPostInit: registerPostInit,
+    registerPostUpdate: registerPostUpdate,
+    registerUpdateLifecycle: registerUpdateLifecycle,
+    registerAction: registerAction,
+    registerCoordinateSystem: registerCoordinateSystem,
+    registerLayout: registerLayout,
+    registerVisual: registerVisual,
+    registerTransform: registerTransform,
+    registerLoading: registerLoading,
+    registerMap: registerMap,
+    registerImpl: registerImpl,
+    PRIORITY: PRIORITY,
+    ComponentModel: ComponentModel,
+    ComponentView: ComponentView,
+    SeriesModel: SeriesModel,
+    ChartView: ChartView,
+    // TODO Use ComponentModel and SeriesModel instead of Constructor
+    registerComponentModel: function (ComponentModelClass) {
+      ComponentModel.registerClass(ComponentModelClass);
+    },
+    registerComponentView: function (ComponentViewClass) {
+      ComponentView.registerClass(ComponentViewClass);
+    },
+    registerSeriesModel: function (SeriesModelClass) {
+      SeriesModel.registerClass(SeriesModelClass);
+    },
+    registerChartView: function (ChartViewClass) {
+      ChartView.registerClass(ChartViewClass);
+    },
+    registerSubTypeDefaulter: function (componentType, defaulter) {
+      ComponentModel.registerSubTypeDefaulter(componentType, defaulter);
+    },
+    registerPainter: function (painterType, PainterCtor) {
+      registerPainter(painterType, PainterCtor);
+    }
+  };
+
+  function use(ext) {
+    if (isArray(ext)) {
+      // use([ChartLine, ChartBar]);
+      each(ext, function (singleExt) {
+        use(singleExt);
+      });
+      return;
+    }
+
+    if (indexOf(extensions, ext) >= 0) {
+      return;
+    }
+
+    extensions.push(ext);
+
+    if (isFunction(ext)) {
+      ext = {
+        install: ext
+      };
+    }
+
+    ext.install(extensionRegisters);
+  }
+
+  var EPSILON$4 = 1e-8;
+
+  function isAroundEqual$1(a, b) {
+    return Math.abs(a - b) < EPSILON$4;
+  }
+
+  function contain$2(points, x, y) {
+    var w = 0;
+    var p = points[0];
+
+    if (!p) {
+      return false;
+    }
+
+    for (var i = 1; i < points.length; i++) {
+      var p2 = points[i];
+      w += windingLine(p[0], p[1], p2[0], p2[1], x, y);
+      p = p2;
+    }
+
+    var p0 = points[0];
+
+    if (!isAroundEqual$1(p[0], p0[0]) || !isAroundEqual$1(p[1], p0[1])) {
+      w += windingLine(p[0], p[1], p0[0], p0[1], x, y);
+    }
+
+    return w !== 0;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 TMP_TRANSFORM = [];
+
+  function transformPoints(points, transform) {
+    for (var p = 0; p < points.length; p++) {
+      applyTransform(points[p], points[p], transform);
+    }
+  }
+
+  function updateBBoxFromPoints(points, min$$1, max$$1, projection) {
+    for (var i = 0; i < points.length; i++) {
+      var p = points[i];
+
+      if (projection) {
+        // projection may return null point.
+        p = projection.project(p);
+      }
+
+      if (p && isFinite(p[0]) && isFinite(p[1])) {
+        min(min$$1, min$$1, p);
+        max(max$$1, max$$1, p);
+      }
+    }
+  }
+
+  function centroid(points) {
+    var signedArea = 0;
+    var cx = 0;
+    var cy = 0;
+    var len$$1 = points.length;
+    var x0 = points[len$$1 - 1][0];
+    var y0 = points[len$$1 - 1][1]; // Polygon should been closed.
+
+    for (var i = 0; i < len$$1; i++) {
+      var x1 = points[i][0];
+      var y1 = points[i][1];
+      var a = x0 * y1 - x1 * y0;
+      signedArea += a;
+      cx += (x0 + x1) * a;
+      cy += (y0 + y1) * a;
+      x0 = x1;
+      y0 = y1;
+    }
+
+    return signedArea ? [cx / signedArea / 3, cy / signedArea / 3, signedArea] : [points[0][0] || 0, points[0][1] || 0];
+  }
+
+  var Region =
+  /** @class */
+  function () {
+    function Region(name) {
+      this.name = name;
+    }
+
+    Region.prototype.setCenter = function (center) {
+      this._center = center;
+    };
+    /**
+     * Get center point in data unit. That is,
+     * for GeoJSONRegion, the unit is lat/lng,
+     * for GeoSVGRegion, the unit is SVG local coord.
+     */
+
+
+    Region.prototype.getCenter = function () {
+      var center = this._center;
+
+      if (!center) {
+        // In most cases there are no need to calculate this center.
+        // So calculate only when called.
+        center = this._center = this.calcCenter();
+      }
+
+      return center;
+    };
+
+    return Region;
+  }();
+
+  var GeoJSONPolygonGeometry =
+  /** @class */
+  function () {
+    function GeoJSONPolygonGeometry(exterior, interiors) {
+      this.type = 'polygon';
+      this.exterior = exterior;
+      this.interiors = interiors;
+    }
+
+    return GeoJSONPolygonGeometry;
+  }();
+
+  var GeoJSONLineStringGeometry =
+  /** @class */
+  function () {
+    function GeoJSONLineStringGeometry(points) {
+      this.type = 'linestring';
+      this.points = points;
+    }
+
+    return GeoJSONLineStringGeometry;
+  }();
+
+  var GeoJSONRegion =
+  /** @class */
+  function (_super) {
+    __extends(GeoJSONRegion, _super);
+
+    function GeoJSONRegion(name, geometries, cp) {
+      var _this = _super.call(this, name) || this;
+
+      _this.type = 'geoJSON';
+      _this.geometries = geometries;
+      _this._center = cp && [cp[0], cp[1]];
+      return _this;
+    }
+
+    GeoJSONRegion.prototype.calcCenter = function () {
+      var geometries = this.geometries;
+      var largestGeo;
+      var largestGeoSize = 0;
+
+      for (var i = 0; i < geometries.length; i++) {
+        var geo = geometries[i];
+        var exterior = geo.exterior; // Simple trick to use points count instead of polygon area as region size.
+        // Ignore linestring
+
+        var size = exterior && exterior.length;
+
+        if (size > largestGeoSize) {
+          largestGeo = geo;
+          largestGeoSize = size;
+        }
+      }
+
+      if (largestGeo) {
+        return centroid(largestGeo.exterior);
+      } // from bounding rect by default.
+
+
+      var rect = this.getBoundingRect();
+      return [rect.x + rect.width / 2, rect.y + rect.height / 2];
+    };
+
+    GeoJSONRegion.prototype.getBoundingRect = function (projection) {
+      var rect = this._rect; // Always recalculate if using projection.
+
+      if (rect && !projection) {
+        return rect;
+      }
+
+      var min$$1 = [Infinity, Infinity];
+      var max$$1 = [-Infinity, -Infinity];
+      var geometries = this.geometries;
+      each(geometries, function (geo) {
+        if (geo.type === 'polygon') {
+          // Doesn't consider hole
+          updateBBoxFromPoints(geo.exterior, min$$1, max$$1, projection);
+        } else {
+          each(geo.points, function (points) {
+            updateBBoxFromPoints(points, min$$1, max$$1, projection);
+          });
+        }
+      }); // Normalie invalid bounding.
+
+      if (!(isFinite(min$$1[0]) && isFinite(min$$1[1]) && isFinite(max$$1[0]) && isFinite(max$$1[1]))) {
+        min$$1[0] = min$$1[1] = max$$1[0] = max$$1[1] = 0;
+      }
+
+      rect = new BoundingRect(min$$1[0], min$$1[1], max$$1[0] - min$$1[0], max$$1[1] - min$$1[1]);
+
+      if (!projection) {
+        this._rect = rect;
+      }
+
+      return rect;
+    };
+
+    GeoJSONRegion.prototype.contain = function (coord) {
+      var rect = this.getBoundingRect();
+      var geometries = this.geometries;
+
+      if (!rect.contain(coord[0], coord[1])) {
+        return false;
+      }
+
+      loopGeo: for (var i = 0, len$$1 = geometries.length; i < len$$1; i++) {
+        var geo = geometries[i]; // Only support polygon.
+
+        if (geo.type !== 'polygon') {
+          continue;
+        }
+
+        var exterior = geo.exterior;
+        var interiors = geo.interiors;
+
+        if (contain$2(exterior, coord[0], coord[1])) {
+          // Not in the region if point is in the hole.
+          for (var k = 0; k < (interiors ? interiors.length : 0); k++) {
+            if (contain$2(interiors[k], coord[0], coord[1])) {
+              continue loopGeo;
+            }
+          }
+
+          return true;
+        }
+      }
+
+      return false;
+    };
+    /**
+     * Transform the raw coords to target bounding.
+     * @param x
+     * @param y
+     * @param width
+     * @param height
+     */
+
+
+    GeoJSONRegion.prototype.transformTo = function (x, y, width, height) {
+      var rect = this.getBoundingRect();
+      var aspect = rect.width / rect.height;
+
+      if (!width) {
+        width = aspect * height;
+      } else if (!height) {
+        height = width / aspect;
+      }
+
+      var target = new BoundingRect(x, y, width, height);
+      var transform = rect.calculateTransform(target);
+      var geometries = this.geometries;
+
+      for (var i = 0; i < geometries.length; i++) {
+        var geo = geometries[i];
+
+        if (geo.type === 'polygon') {
+          transformPoints(geo.exterior, transform);
+          each(geo.interiors, function (interior) {
+            transformPoints(interior, transform);
+          });
+        } else {
+          each(geo.points, function (points) {
+            transformPoints(points, transform);
+          });
+        }
+      }
+
+      rect = this._rect;
+      rect.copy(target); // Update center
+
+      this._center = [rect.x + rect.width / 2, rect.y + rect.height / 2];
+    };
+
+    GeoJSONRegion.prototype.cloneShallow = function (name) {
+      name == null && (name = this.name);
+      var newRegion = new GeoJSONRegion(name, this.geometries, this._center);
+      newRegion._rect = this._rect;
+      newRegion.transformTo = null; // Simply avoid to be called.
+
+      return newRegion;
+    };
+
+    return GeoJSONRegion;
+  }(Region);
+
+  var GeoSVGRegion =
+  /** @class */
+  function (_super) {
+    __extends(GeoSVGRegion, _super);
+
+    function GeoSVGRegion(name, elOnlyForCalculate) {
+      var _this = _super.call(this, name) || this;
+
+      _this.type = 'geoSVG';
+      _this._elOnlyForCalculate = elOnlyForCalculate;
+      return _this;
+    }
+
+    GeoSVGRegion.prototype.calcCenter = function () {
+      var el = this._elOnlyForCalculate;
+      var rect = el.getBoundingRect();
+      var center = [rect.x + rect.width / 2, rect.y + rect.height / 2];
+      var mat = identity(TMP_TRANSFORM);
+      var target = el;
+
+      while (target && !target.isGeoSVGGraphicRoot) {
+        mul$1(mat, target.getLocalTransform(), mat);
+        target = target.parent;
+      }
+
+      invert(mat, mat);
+      applyTransform(center, center, mat);
+      return center;
+    };
+
+    return GeoSVGRegion;
+  }(Region);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Parse and decode geo json
+   */
+
+
+  function decode(json) {
+    if (!json.UTF8Encoding) {
+      return json;
+    }
+
+    var jsonCompressed = json;
+    var encodeScale = jsonCompressed.UTF8Scale;
+
+    if (encodeScale == null) {
+      encodeScale = 1024;
+    }
+
+    var features = jsonCompressed.features;
+    each(features, function (feature) {
+      var geometry = feature.geometry;
+      var encodeOffsets = geometry.encodeOffsets;
+      var coordinates = geometry.coordinates; // Geometry may be appeded manually in the script after json loaded.
+      // In this case this geometry is usually not encoded.
+
+      if (!encodeOffsets) {
+        return;
+      }
+
+      switch (geometry.type) {
+        case 'LineString':
+          geometry.coordinates = decodeRing(coordinates, encodeOffsets, encodeScale);
+          break;
+
+        case 'Polygon':
+          decodeRings(coordinates, encodeOffsets, encodeScale);
+          break;
+
+        case 'MultiLineString':
+          decodeRings(coordinates, encodeOffsets, encodeScale);
+          break;
+
+        case 'MultiPolygon':
+          each(coordinates, function (rings, idx) {
+            return decodeRings(rings, encodeOffsets[idx], encodeScale);
+          });
+      }
+    }); // Has been decoded
+
+    jsonCompressed.UTF8Encoding = false;
+    return jsonCompressed;
+  }
+
+  function decodeRings(rings, encodeOffsets, encodeScale) {
+    for (var c = 0; c < rings.length; c++) {
+      rings[c] = decodeRing(rings[c], encodeOffsets[c], encodeScale);
+    }
+  }
+
+  function decodeRing(coordinate, encodeOffsets, encodeScale) {
+    var result = [];
+    var prevX = encodeOffsets[0];
+    var prevY = encodeOffsets[1];
+
+    for (var i = 0; i < coordinate.length; i += 2) {
+      var x = coordinate.charCodeAt(i) - 64;
+      var y = coordinate.charCodeAt(i + 1) - 64; // ZigZag decoding
+
+      x = x >> 1 ^ -(x & 1);
+      y = y >> 1 ^ -(y & 1); // Delta deocding
+
+      x += prevX;
+      y += prevY;
+      prevX = x;
+      prevY = y; // Dequantize
+
+      result.push([x / encodeScale, y / encodeScale]);
+    }
+
+    return result;
+  }
+
+  function parseGeoJSON(geoJson, nameProperty) {
+    geoJson = decode(geoJson);
+    return map(filter(geoJson.features, function (featureObj) {
+      // Output of mapshaper may have geometry null
+      return featureObj.geometry && featureObj.properties && featureObj.geometry.coordinates.length > 0;
+    }), function (featureObj) {
+      var properties = featureObj.properties;
+      var geo = featureObj.geometry;
+      var geometries = [];
+
+      switch (geo.type) {
+        case 'Polygon':
+          var coordinates = geo.coordinates; // According to the GeoJSON specification.
+          // First must be exterior, and the rest are all interior(holes).
+
+          geometries.push(new GeoJSONPolygonGeometry(coordinates[0], coordinates.slice(1)));
+          break;
+
+        case 'MultiPolygon':
+          each(geo.coordinates, function (item) {
+            if (item[0]) {
+              geometries.push(new GeoJSONPolygonGeometry(item[0], item.slice(1)));
+            }
+          });
+          break;
+
+        case 'LineString':
+          geometries.push(new GeoJSONLineStringGeometry([geo.coordinates]));
+          break;
+
+        case 'MultiLineString':
+          geometries.push(new GeoJSONLineStringGeometry(geo.coordinates));
+      }
+
+      var region = new GeoJSONRegion(properties[nameProperty || 'name'], geometries, properties.cp);
+      region.properties = properties;
+      return region;
+    });
+  }
+
+  var number = (Object.freeze || Object)({
+    linearMap: linearMap,
+    round: round,
+    asc: asc,
+    getPrecision: getPrecision,
+    getPrecisionSafe: getPrecisionSafe,
+    getPixelPrecision: getPixelPrecision,
+    getPercentWithPrecision: getPercentWithPrecision,
+    MAX_SAFE_INTEGER: MAX_SAFE_INTEGER,
+    remRadian: remRadian,
+    isRadianAroundZero: isRadianAroundZero,
+    parseDate: parseDate,
+    quantity: quantity,
+    quantityExponent: quantityExponent,
+    nice: nice,
+    quantile: quantile,
+    reformIntervals: reformIntervals,
+    isNumeric: isNumeric,
+    numericToNumber: numericToNumber
+  });
+  var time = (Object.freeze || Object)({
+    parse: parseDate,
+    format: format
+  });
+  var graphic$1 = (Object.freeze || Object)({
+    extendShape: extendShape,
+    extendPath: extendPath,
+    makePath: makePath,
+    makeImage: makeImage,
+    mergePath: mergePath,
+    resizePath: resizePath,
+    createIcon: createIcon,
+    updateProps: updateProps,
+    initProps: initProps,
+    getTransform: getTransform,
+    clipPointsByRect: clipPointsByRect,
+    clipRectByRect: clipRectByRect,
+    registerShape: registerShape,
+    getShapeClass: getShapeClass,
+    Group: Group,
+    Image: ZRImage,
+    Text: ZRText,
+    Circle: Circle,
+    Ellipse: Ellipse,
+    Sector: Sector,
+    Ring: Ring,
+    Polygon: Polygon,
+    Polyline: Polyline,
+    Rect: Rect,
+    Line: Line,
+    BezierCurve: BezierCurve,
+    Arc: Arc,
+    IncrementalDisplayable: IncrementalDisplayable,
+    CompoundPath: CompoundPath,
+    LinearGradient: LinearGradient,
+    RadialGradient: RadialGradient,
+    BoundingRect: BoundingRect
+  });
+  var format$1 = (Object.freeze || Object)({
+    addCommas: addCommas,
+    toCamelCase: toCamelCase,
+    normalizeCssArray: normalizeCssArray$1,
+    encodeHTML: encodeHTML,
+    formatTpl: formatTpl,
+    getTooltipMarker: getTooltipMarker,
+    formatTime: formatTime,
+    capitalFirst: capitalFirst,
+    truncateText: truncateText,
+    getTextRect: getTextRect
+  });
+  var util$1 = (Object.freeze || Object)({
+    map: map,
+    each: each,
+    indexOf: indexOf,
+    inherits: inherits,
+    reduce: reduce,
+    filter: filter,
+    bind: bind,
+    curry: curry,
+    isArray: isArray,
+    isString: isString,
+    isObject: isObject,
+    isFunction: isFunction,
+    extend: extend,
+    defaults: defaults,
+    clone: clone,
+    merge: merge
+  });
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$5 = makeInner();
+
+  function createAxisLabels(axis) {
+    // Only ordinal scale support tick interval
+    return axis.type === 'category' ? makeCategoryLabels(axis) : makeRealNumberLabels(axis);
+  }
+  /**
+   * @param {module:echats/coord/Axis} axis
+   * @param {module:echarts/model/Model} tickModel For example, can be axisTick, splitLine, splitArea.
+   * @return {Object} {
+   *     ticks: Array.<number>
+   *     tickCategoryInterval: number
+   * }
+   */
+
+
+  function createAxisTicks(axis, tickModel) {
+    // Only ordinal scale support tick interval
+    return axis.type === 'category' ? makeCategoryTicks(axis, tickModel) : {
+      ticks: map(axis.scale.getTicks(), function (tick) {
+        return tick.value;
+      })
+    };
+  }
+
+  function makeCategoryLabels(axis) {
+    var labelModel = axis.getLabelModel();
+    var result = makeCategoryLabelsActually(axis, labelModel);
+    return !labelModel.get('show') || axis.scale.isBlank() ? {
+      labels: [],
+      labelCategoryInterval: result.labelCategoryInterval
+    } : result;
+  }
+
+  function makeCategoryLabelsActually(axis, labelModel) {
+    var labelsCache = getListCache(axis, 'labels');
+    var optionLabelInterval = getOptionCategoryInterval(labelModel);
+    var result = listCacheGet(labelsCache, optionLabelInterval);
+
+    if (result) {
+      return result;
+    }
+
+    var labels;
+    var numericLabelInterval;
+
+    if (isFunction(optionLabelInterval)) {
+      labels = makeLabelsByCustomizedCategoryInterval(axis, optionLabelInterval);
+    } else {
+      numericLabelInterval = optionLabelInterval === 'auto' ? makeAutoCategoryInterval(axis) : optionLabelInterval;
+      labels = makeLabelsByNumericCategoryInterval(axis, numericLabelInterval);
+    } // Cache to avoid calling interval function repeatly.
+
+
+    return listCacheSet(labelsCache, optionLabelInterval, {
+      labels: labels,
+      labelCategoryInterval: numericLabelInterval
+    });
+  }
+
+  function makeCategoryTicks(axis, tickModel) {
+    var ticksCache = getListCache(axis, 'ticks');
+    var optionTickInterval = getOptionCategoryInterval(tickModel);
+    var result = listCacheGet(ticksCache, optionTickInterval);
+
+    if (result) {
+      return result;
+    }
+
+    var ticks;
+    var tickCategoryInterval; // Optimize for the case that large category data and no label displayed,
+    // we should not return all ticks.
+
+    if (!tickModel.get('show') || axis.scale.isBlank()) {
+      ticks = [];
+    }
+
+    if (isFunction(optionTickInterval)) {
+      ticks = makeLabelsByCustomizedCategoryInterval(axis, optionTickInterval, true);
+    } // Always use label interval by default despite label show. Consider this
+    // scenario, Use multiple grid with the xAxis sync, and only one xAxis shows
+    // labels. `splitLine` and `axisTick` should be consistent in this case.
+    else if (optionTickInterval === 'auto') {
+        var labelsResult = makeCategoryLabelsActually(axis, axis.getLabelModel());
+        tickCategoryInterval = labelsResult.labelCategoryInterval;
+        ticks = map(labelsResult.labels, function (labelItem) {
+          return labelItem.tickValue;
+        });
+      } else {
+        tickCategoryInterval = optionTickInterval;
+        ticks = makeLabelsByNumericCategoryInterval(axis, tickCategoryInterval, true);
+      } // Cache to avoid calling interval function repeatly.
+
+
+    return listCacheSet(ticksCache, optionTickInterval, {
+      ticks: ticks,
+      tickCategoryInterval: tickCategoryInterval
+    });
+  }
+
+  function makeRealNumberLabels(axis) {
+    var ticks = axis.scale.getTicks();
+    var labelFormatter = makeLabelFormatter(axis);
+    return {
+      labels: map(ticks, function (tick, idx) {
+        return {
+          level: tick.level,
+          formattedLabel: labelFormatter(tick, idx),
+          rawLabel: axis.scale.getLabel(tick),
+          tickValue: tick.value
+        };
+      })
+    };
+  }
+
+  function getListCache(axis, prop) {
+    // Because key can be funciton, and cache size always be small, we use array cache.
+    return inner$5(axis)[prop] || (inner$5(axis)[prop] = []);
+  }
+
+  function listCacheGet(cache, key) {
+    for (var i = 0; i < cache.length; i++) {
+      if (cache[i].key === key) {
+        return cache[i].value;
+      }
+    }
+  }
+
+  function listCacheSet(cache, key, value) {
+    cache.push({
+      key: key,
+      value: value
+    });
+    return value;
+  }
+
+  function makeAutoCategoryInterval(axis) {
+    var result = inner$5(axis).autoInterval;
+    return result != null ? result : inner$5(axis).autoInterval = axis.calculateCategoryInterval();
+  }
+  /**
+   * Calculate interval for category axis ticks and labels.
+   * To get precise result, at least one of `getRotate` and `isHorizontal`
+   * should be implemented in axis.
+   */
+
+
+  function calculateCategoryInterval(axis) {
+    var params = fetchAutoCategoryIntervalCalculationParams(axis);
+    var labelFormatter = makeLabelFormatter(axis);
+    var rotation = (params.axisRotate - params.labelRotate) / 180 * Math.PI;
+    var ordinalScale = axis.scale;
+    var ordinalExtent = ordinalScale.getExtent(); // Providing this method is for optimization:
+    // avoid generating a long array by `getTicks`
+    // in large category data case.
+
+    var tickCount = ordinalScale.count();
+
+    if (ordinalExtent[1] - ordinalExtent[0] < 1) {
+      return 0;
+    }
+
+    var step = 1; // Simple optimization. Empirical value: tick count should less than 40.
+
+    if (tickCount > 40) {
+      step = Math.max(1, Math.floor(tickCount / 40));
+    }
+
+    var tickValue = ordinalExtent[0];
+    var unitSpan = axis.dataToCoord(tickValue + 1) - axis.dataToCoord(tickValue);
+    var unitW = Math.abs(unitSpan * Math.cos(rotation));
+    var unitH = Math.abs(unitSpan * Math.sin(rotation));
+    var maxW = 0;
+    var maxH = 0; // Caution: Performance sensitive for large category data.
+    // Consider dataZoom, we should make appropriate step to avoid O(n) loop.
+
+    for (; tickValue <= ordinalExtent[1]; tickValue += step) {
+      var width = 0;
+      var height = 0; // Not precise, do not consider align and vertical align
+      // and each distance from axis line yet.
+
+      var rect = getBoundingRect(labelFormatter({
+        value: tickValue
+      }), params.font, 'center', 'top'); // Magic number
+
+      width = rect.width * 1.3;
+      height = rect.height * 1.3; // Min size, void long loop.
+
+      maxW = Math.max(maxW, width, 7);
+      maxH = Math.max(maxH, height, 7);
+    }
+
+    var dw = maxW / unitW;
+    var dh = maxH / unitH; // 0/0 is NaN, 1/0 is Infinity.
+
+    isNaN(dw) && (dw = Infinity);
+    isNaN(dh) && (dh = Infinity);
+    var interval = Math.max(0, Math.floor(Math.min(dw, dh)));
+    var cache = inner$5(axis.model);
+    var axisExtent = axis.getExtent();
+    var lastAutoInterval = cache.lastAutoInterval;
+    var lastTickCount = cache.lastTickCount; // Use cache to keep interval stable while moving zoom window,
+    // otherwise the calculated interval might jitter when the zoom
+    // window size is close to the interval-changing size.
+    // For example, if all of the axis labels are `a, b, c, d, e, f, g`.
+    // The jitter will cause that sometimes the displayed labels are
+    // `a, d, g` (interval: 2) sometimes `a, c, e`(interval: 1).
+
+    if (lastAutoInterval != null && lastTickCount != null && Math.abs(lastAutoInterval - interval) <= 1 && Math.abs(lastTickCount - tickCount) <= 1 // Always choose the bigger one, otherwise the critical
+    // point is not the same when zooming in or zooming out.
+    && lastAutoInterval > interval // If the axis change is caused by chart resize, the cache should not
+    // be used. Otherwise some hiden labels might not be shown again.
+    && cache.axisExtent0 === axisExtent[0] && cache.axisExtent1 === axisExtent[1]) {
+      interval = lastAutoInterval;
+    } // Only update cache if cache not used, otherwise the
+    // changing of interval is too insensitive.
+    else {
+        cache.lastTickCount = tickCount;
+        cache.lastAutoInterval = interval;
+        cache.axisExtent0 = axisExtent[0];
+        cache.axisExtent1 = axisExtent[1];
+      }
+
+    return interval;
+  }
+
+  function fetchAutoCategoryIntervalCalculationParams(axis) {
+    var labelModel = axis.getLabelModel();
+    return {
+      axisRotate: axis.getRotate ? axis.getRotate() : axis.isHorizontal && !axis.isHorizontal() ? 90 : 0,
+      labelRotate: labelModel.get('rotate') || 0,
+      font: labelModel.getFont()
+    };
+  }
+
+  function makeLabelsByNumericCategoryInterval(axis, categoryInterval, onlyTick) {
+    var labelFormatter = makeLabelFormatter(axis);
+    var ordinalScale = axis.scale;
+    var ordinalExtent = ordinalScale.getExtent();
+    var labelModel = axis.getLabelModel();
+    var result = []; // TODO: axisType: ordinalTime, pick the tick from each month/day/year/...
+
+    var step = Math.max((categoryInterval || 0) + 1, 1);
+    var startTick = ordinalExtent[0];
+    var tickCount = ordinalScale.count(); // Calculate start tick based on zero if possible to keep label consistent
+    // while zooming and moving while interval > 0. Otherwise the selection
+    // of displayable ticks and symbols probably keep changing.
+    // 3 is empirical value.
+
+    if (startTick !== 0 && step > 1 && tickCount / step > 2) {
+      startTick = Math.round(Math.ceil(startTick / step) * step);
+    } // (1) Only add min max label here but leave overlap checking
+    // to render stage, which also ensure the returned list
+    // suitable for splitLine and splitArea rendering.
+    // (2) Scales except category always contain min max label so
+    // do not need to perform this process.
+
+
+    var showAllLabel = shouldShowAllLabels(axis);
+    var includeMinLabel = labelModel.get('showMinLabel') || showAllLabel;
+    var includeMaxLabel = labelModel.get('showMaxLabel') || showAllLabel;
+
+    if (includeMinLabel && startTick !== ordinalExtent[0]) {
+      addItem(ordinalExtent[0]);
+    } // Optimize: avoid generating large array by `ordinalScale.getTicks()`.
+
+
+    var tickValue = startTick;
+
+    for (; tickValue <= ordinalExtent[1]; tickValue += step) {
+      addItem(tickValue);
+    }
+
+    if (includeMaxLabel && tickValue - step !== ordinalExtent[1]) {
+      addItem(ordinalExtent[1]);
+    }
+
+    function addItem(tickValue) {
+      var tickObj = {
+        value: tickValue
+      };
+      result.push(onlyTick ? tickValue : {
+        formattedLabel: labelFormatter(tickObj),
+        rawLabel: ordinalScale.getLabel(tickObj),
+        tickValue: tickValue
+      });
+    }
+
+    return result;
+  }
+
+  function makeLabelsByCustomizedCategoryInterval(axis, categoryInterval, onlyTick) {
+    var ordinalScale = axis.scale;
+    var labelFormatter = makeLabelFormatter(axis);
+    var result = [];
+    each(ordinalScale.getTicks(), function (tick) {
+      var rawLabel = ordinalScale.getLabel(tick);
+      var tickValue = tick.value;
+
+      if (categoryInterval(tick.value, rawLabel)) {
+        result.push(onlyTick ? tickValue : {
+          formattedLabel: labelFormatter(tick),
+          rawLabel: rawLabel,
+          tickValue: tickValue
+        });
+      }
+    });
+    return result;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 NORMALIZED_EXTENT = [0, 1];
+  /**
+   * Base class of Axis.
+   */
+
+  var Axis =
+  /** @class */
+  function () {
+    function Axis(dim, scale, extent) {
+      this.onBand = false;
+      this.inverse = false;
+      this.dim = dim;
+      this.scale = scale;
+      this._extent = extent || [0, 0];
+    }
+    /**
+     * If axis extent contain given coord
+     */
+
+
+    Axis.prototype.contain = function (coord) {
+      var extent = this._extent;
+      var min = Math.min(extent[0], extent[1]);
+      var max = Math.max(extent[0], extent[1]);
+      return coord >= min && coord <= max;
+    };
+    /**
+     * If axis extent contain given data
+     */
+
+
+    Axis.prototype.containData = function (data) {
+      return this.scale.contain(data);
+    };
+    /**
+     * Get coord extent.
+     */
+
+
+    Axis.prototype.getExtent = function () {
+      return this._extent.slice();
+    };
+    /**
+     * Get precision used for formatting
+     */
+
+
+    Axis.prototype.getPixelPrecision = function (dataExtent) {
+      return getPixelPrecision(dataExtent || this.scale.getExtent(), this._extent);
+    };
+    /**
+     * Set coord extent
+     */
+
+
+    Axis.prototype.setExtent = function (start, end) {
+      var extent = this._extent;
+      extent[0] = start;
+      extent[1] = end;
+    };
+    /**
+     * Convert data to coord. Data is the rank if it has an ordinal scale
+     */
+
+
+    Axis.prototype.dataToCoord = function (data, clamp) {
+      var extent = this._extent;
+      var scale = this.scale;
+      data = scale.normalize(data);
+
+      if (this.onBand && scale.type === 'ordinal') {
+        extent = extent.slice();
+        fixExtentWithBands(extent, scale.count());
+      }
+
+      return linearMap(data, NORMALIZED_EXTENT, extent, clamp);
+    };
+    /**
+     * Convert coord to data. Data is the rank if it has an ordinal scale
+     */
+
+
+    Axis.prototype.coordToData = function (coord, clamp) {
+      var extent = this._extent;
+      var scale = this.scale;
+
+      if (this.onBand && scale.type === 'ordinal') {
+        extent = extent.slice();
+        fixExtentWithBands(extent, scale.count());
+      }
+
+      var t = linearMap(coord, extent, NORMALIZED_EXTENT, clamp);
+      return this.scale.scale(t);
+    };
+    /**
+     * Convert pixel point to data in axis
+     */
+
+
+    Axis.prototype.pointToData = function (point, clamp) {
+      // Should be implemented in derived class if necessary.
+      return;
+    };
+    /**
+     * Different from `zrUtil.map(axis.getTicks(), axis.dataToCoord, axis)`,
+     * `axis.getTicksCoords` considers `onBand`, which is used by
+     * `boundaryGap:true` of category axis and splitLine and splitArea.
+     * @param opt.tickModel default: axis.model.getModel('axisTick')
+     * @param opt.clamp If `true`, the first and the last
+     *        tick must be at the axis end points. Otherwise, clip ticks
+     *        that outside the axis extent.
+     */
+
+
+    Axis.prototype.getTicksCoords = function (opt) {
+      opt = opt || {};
+      var tickModel = opt.tickModel || this.getTickModel();
+      var result = createAxisTicks(this, tickModel);
+      var ticks = result.ticks;
+      var ticksCoords = map(ticks, function (tickVal) {
+        return {
+          coord: this.dataToCoord(this.scale.type === 'ordinal' ? this.scale.getRawOrdinalNumber(tickVal) : tickVal),
+          tickValue: tickVal
+        };
+      }, this);
+      var alignWithLabel = tickModel.get('alignWithLabel');
+      fixOnBandTicksCoords(this, ticksCoords, alignWithLabel, opt.clamp);
+      return ticksCoords;
+    };
+
+    Axis.prototype.getMinorTicksCoords = function () {
+      if (this.scale.type === 'ordinal') {
+        // Category axis doesn't support minor ticks
+        return [];
+      }
+
+      var minorTickModel = this.model.getModel('minorTick');
+      var splitNumber = minorTickModel.get('splitNumber'); // Protection.
+
+      if (!(splitNumber > 0 && splitNumber < 100)) {
+        splitNumber = 5;
+      }
+
+      var minorTicks = this.scale.getMinorTicks(splitNumber);
+      var minorTicksCoords = map(minorTicks, function (minorTicksGroup) {
+        return map(minorTicksGroup, function (minorTick) {
+          return {
+            coord: this.dataToCoord(minorTick),
+            tickValue: minorTick
+          };
+        }, this);
+      }, this);
+      return minorTicksCoords;
+    };
+
+    Axis.prototype.getViewLabels = function () {
+      return createAxisLabels(this).labels;
+    };
+
+    Axis.prototype.getLabelModel = function () {
+      return this.model.getModel('axisLabel');
+    };
+    /**
+     * Notice here we only get the default tick model. For splitLine
+     * or splitArea, we should pass the splitLineModel or splitAreaModel
+     * manually when calling `getTicksCoords`.
+     * In GL, this method may be overrided to:
+     * `axisModel.getModel('axisTick', grid3DModel.getModel('axisTick'));`
+     */
+
+
+    Axis.prototype.getTickModel = function () {
+      return this.model.getModel('axisTick');
+    };
+    /**
+     * Get width of band
+     */
+
+
+    Axis.prototype.getBandWidth = function () {
+      var axisExtent = this._extent;
+      var dataExtent = this.scale.getExtent();
+      var len = dataExtent[1] - dataExtent[0] + (this.onBand ? 1 : 0); // Fix #2728, avoid NaN when only one data.
+
+      len === 0 && (len = 1);
+      var size = Math.abs(axisExtent[1] - axisExtent[0]);
+      return Math.abs(size) / len;
+    };
+    /**
+     * Only be called in category axis.
+     * Can be overrided, consider other axes like in 3D.
+     * @return Auto interval for cateogry axis tick and label
+     */
+
+
+    Axis.prototype.calculateCategoryInterval = function () {
+      return calculateCategoryInterval(this);
+    };
+
+    return Axis;
+  }();
+
+  function fixExtentWithBands(extent, nTick) {
+    var size = extent[1] - extent[0];
+    var len = nTick;
+    var margin = size / len / 2;
+    extent[0] += margin;
+    extent[1] -= margin;
+  } // If axis has labels [1, 2, 3, 4]. Bands on the axis are
+  // |---1---|---2---|---3---|---4---|.
+  // So the displayed ticks and splitLine/splitArea should between
+  // each data item, otherwise cause misleading (e.g., split tow bars
+  // of a single data item when there are two bar series).
+  // Also consider if tickCategoryInterval > 0 and onBand, ticks and
+  // splitLine/spliteArea should layout appropriately corresponding
+  // to displayed labels. (So we should not use `getBandWidth` in this
+  // case).
+
+
+  function fixOnBandTicksCoords(axis, ticksCoords, alignWithLabel, clamp) {
+    var ticksLen = ticksCoords.length;
+
+    if (!axis.onBand || alignWithLabel || !ticksLen) {
+      return;
+    }
+
+    var axisExtent = axis.getExtent();
+    var last;
+    var diffSize;
+
+    if (ticksLen === 1) {
+      ticksCoords[0].coord = axisExtent[0];
+      last = ticksCoords[1] = {
+        coord: axisExtent[0]
+      };
+    } else {
+      var crossLen = ticksCoords[ticksLen - 1].tickValue - ticksCoords[0].tickValue;
+      var shift_1 = (ticksCoords[ticksLen - 1].coord - ticksCoords[0].coord) / crossLen;
+      each(ticksCoords, function (ticksItem) {
+        ticksItem.coord -= shift_1 / 2;
+      });
+      var dataExtent = axis.scale.getExtent();
+      diffSize = 1 + dataExtent[1] - ticksCoords[ticksLen - 1].tickValue;
+      last = {
+        coord: ticksCoords[ticksLen - 1].coord + shift_1 * diffSize
+      };
+      ticksCoords.push(last);
+    }
+
+    var inverse = axisExtent[0] > axisExtent[1]; // Handling clamp.
+
+    if (littleThan(ticksCoords[0].coord, axisExtent[0])) {
+      clamp ? ticksCoords[0].coord = axisExtent[0] : ticksCoords.shift();
+    }
+
+    if (clamp && littleThan(axisExtent[0], ticksCoords[0].coord)) {
+      ticksCoords.unshift({
+        coord: axisExtent[0]
+      });
+    }
+
+    if (littleThan(axisExtent[1], last.coord)) {
+      clamp ? last.coord = axisExtent[1] : ticksCoords.pop();
+    }
+
+    if (clamp && littleThan(last.coord, axisExtent[1])) {
+      ticksCoords.push({
+        coord: axisExtent[1]
+      });
+    }
+
+    function littleThan(a, b) {
+      // Avoid rounding error cause calculated tick coord different with extent.
+      // It may cause an extra unecessary tick added.
+      a = round(a);
+      b = round(b);
+      return inverse ? a > b : a < b;
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // These APIs are for more advanced usages
+  // For example extend charts and components, creating graphic elements, formatting.
+  // Should use `ComponentModel.extend` or `class XXXX extend ComponentModel` to create class.
+  // Then use `registerComponentModel` in `install` parameter when `use` this extension. For example:
+  // class Bar3DModel extends ComponentModel {}
+  // export function install(registers) { regsiters.registerComponentModel(Bar3DModel); }
+  // echarts.use(install);
+
+
+  function extendComponentModel(proto) {
+    var Model = ComponentModel.extend(proto);
+    ComponentModel.registerClass(Model);
+    return Model;
+  }
+
+  function extendComponentView(proto) {
+    var View = ComponentView.extend(proto);
+    ComponentView.registerClass(View);
+    return View;
+  }
+
+  function extendSeriesModel(proto) {
+    var Model = SeriesModel.extend(proto);
+    SeriesModel.registerClass(Model);
+    return Model;
+  }
+
+  function extendChartView(proto) {
+    var View = ChartView.extend(proto);
+    ChartView.registerClass(View);
+    return View;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 PI2$6 = Math.PI * 2;
+  var CMD$3 = PathProxy.CMD;
+  var DEFAULT_SEARCH_SPACE = ['top', 'right', 'bottom', 'left'];
+
+  function getCandidateAnchor(pos, distance$$1, rect, outPt, outDir) {
+    var width = rect.width;
+    var height = rect.height;
+
+    switch (pos) {
+      case 'top':
+        outPt.set(rect.x + width / 2, rect.y - distance$$1);
+        outDir.set(0, -1);
+        break;
+
+      case 'bottom':
+        outPt.set(rect.x + width / 2, rect.y + height + distance$$1);
+        outDir.set(0, 1);
+        break;
+
+      case 'left':
+        outPt.set(rect.x - distance$$1, rect.y + height / 2);
+        outDir.set(-1, 0);
+        break;
+
+      case 'right':
+        outPt.set(rect.x + width + distance$$1, rect.y + height / 2);
+        outDir.set(1, 0);
+        break;
+    }
+  }
+
+  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 ox = x * r + cx;
+    var oy = y * r + cy;
+
+    if (Math.abs(startAngle - endAngle) % PI2$6 < 1e-4) {
+      // Is a circle
+      out[0] = ox;
+      out[1] = oy;
+      return d - r;
+    }
+
+    if (anticlockwise) {
+      var tmp = startAngle;
+      startAngle = normalizeRadian(endAngle);
+      endAngle = normalizeRadian(tmp);
+    } else {
+      startAngle = normalizeRadian(startAngle);
+      endAngle = normalizeRadian(endAngle);
+    }
+
+    if (startAngle > endAngle) {
+      endAngle += PI2$6;
+    }
+
+    var angle = Math.atan2(y, x);
+
+    if (angle < 0) {
+      angle += PI2$6;
+    }
+
+    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;
+    }
+
+    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);
+
+    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 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 projectedLen = dx * dx1 + dy * dy1;
+    var t = projectedLen / lineLen;
+
+    if (limitToEnds) {
+      t = Math.min(Math.max(t, 0), 1);
+    }
+
+    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;
+    }
+
+    if (height < 0) {
+      y1 = y1 + height;
+      height = -height;
+    }
+
+    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 tmpPt = [];
+
+  function nearestPointOnRect(pt, rect, out) {
+    var dist$$1 = projectPointToRect(rect.x, rect.y, rect.width, rect.height, pt.x, pt.y, tmpPt);
+    out.set(tmpPt[0], tmpPt[1]);
+    return dist$$1;
+  }
+  /**
+   * 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;
+
+        case CMD$3.L:
+          d = projectPointToLine(xi, yi, data[i], data[i + 1], x, y, tmpPt, true);
+          xi = data[i++];
+          yi = data[i++];
+          break;
+
+        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;
+
+        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;
+
+        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 旋转
+
+          i += 1;
+          var anticlockwise = !!(1 - data[i++]);
+          x1 = Math.cos(theta) * rx + cx;
+          y1 = Math.sin(theta) * ry + cy; // 不是直接使用 arc 命令
+
+          if (i <= 1) {
+            // 第一个命令起点还未定义
+            x0 = x1;
+            y0 = y1;
+          } // zr 使用scale来模拟椭圆, 这里也对x做一定的缩放
+
+
+          var _x = (x - cx) * ry / rx + cx;
+
+          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;
+
+        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;
+
+        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]);
+      }
+    }
+
+    return minDist;
+  } // Temporal varible for intermediate usage.
+
+
+  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
+   */
+
+  function updateLabelLinePoints(target, labelLineModel) {
+    if (!target) {
+      return;
+    }
+
+    var labelLine = target.getTextGuideLine();
+    var label = target.getTextContent(); // Needs to create text guide in each charts.
+
+    if (!(label && labelLine)) {
+      return;
+    }
+
+    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$$1 = labelLineModel.get('length2') || 0;
+
+    if (anchorPoint) {
+      pt2.copy(anchorPoint);
+    }
+
+    for (var i = 0; i < searchSpace.length; i++) {
+      var candidate = searchSpace[i];
+      getCandidateAnchor(candidate, 0, labelRect, pt0, dir);
+      Point.scaleAndAdd(pt1, pt0, dir, len$$1); // Transform to target coord space.
+
+      pt1.transform(targetInversedTransform); // Note: getBoundingRect will ensure the `path` being created.
+
+      var boundingRect = target.getBoundingRect();
+      var dist$$1 = anchorPoint ? anchorPoint.distance(pt1) : target instanceof Path ? nearestPointOnPath(pt1, target.path, pt2) : nearestPointOnRect(pt1, boundingRect, pt2); // TODO pt2 is in the path
+
+      if (dist$$1 < minDist) {
+        minDist = dist$$1; // Transform back to global space.
+
+        pt1.transform(targetTransform);
+        pt2.transform(targetTransform);
+        pt2.toArray(points[0]);
+        pt1.toArray(points[1]);
+        pt0.toArray(points[2]);
+      }
+    }
+
+    limitTurnAngle(points, labelLineModel.get('minTurnAngle'));
+    labelLine.setShape({
+      points: points
+    });
+  } // Temporal variable for the limitTurnAngle function
+
+
+  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
+   */
+
+  function limitTurnAngle(linePoints, minTurnAngle) {
+    if (!(minTurnAngle <= 180 && minTurnAngle > 0)) {
+      return;
+    }
+
+    minTurnAngle = minTurnAngle / 180 * Math.PI; // The line points can be
+    //      /pt1----pt2 (label)
+    //     /
+    // pt0/
+
+    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();
+
+    if (len1 < 1e-3 || len2 < 1e-3) {
+      return;
+    }
+
+    dir.scale(1 / len1);
+    dir2.scale(1 / len2);
+    var angleCos = dir.dot(dir2);
+    var minTurnAngleCos = Math.cos(minTurnAngle);
+
+    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
+
+      tmpProjPoint.scaleAndAdd(dir2, d / Math.tan(Math.PI - minTurnAngle)); // Limit the new calculated connect point between pt1 and pt2.
+
+      var t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y);
+
+      if (isNaN(t)) {
+        return;
+      }
+
+      if (t < 0) {
+        Point.copy(tmpProjPoint, pt1);
+      } else if (t > 1) {
+        Point.copy(tmpProjPoint, pt2);
+      }
+
+      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
+   */
+
+
+  function limitSurfaceAngle(linePoints, surfaceNormal, maxSurfaceAngle) {
+    if (!(maxSurfaceAngle <= 180 && maxSurfaceAngle > 0)) {
+      return;
+    }
+
+    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();
+
+    if (len1 < 1e-3 || len2 < 1e-3) {
+      return;
+    }
+
+    dir.scale(1 / len1);
+    dir2.scale(1 / len2);
+    var angleCos = dir.dot(surfaceNormal);
+    var maxSurfaceAngleCos = Math.cos(maxSurfaceAngle);
+
+    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 (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 t = pt2.x !== pt1.x ? (tmpProjPoint.x - pt1.x) / (pt2.x - pt1.x) : (tmpProjPoint.y - pt1.y) / (pt2.y - pt1.y);
+
+        if (isNaN(t)) {
+          return;
+        }
+
+        if (t < 0) {
+          Point.copy(tmpProjPoint, pt1);
+        } else if (t > 1) {
+          Point.copy(tmpProjPoint, pt2);
+        }
+      }
+
+      tmpProjPoint.toArray(linePoints[1]);
+    }
+  }
+
+  function setLabelLineState(labelLine, ignore, stateName, stateModel) {
+    var isNormal = stateName === 'normal';
+    var stateObj = isNormal ? labelLine : labelLine.ensureState(stateName); // Make sure display.
+
+    stateObj.ignore = ignore; // Set smooth
+
+    var smooth = stateModel.get('smooth');
+
+    if (smooth && smooth === true) {
+      smooth = 0.3;
+    }
+
+    stateObj.shape = stateObj.shape || {};
+
+    if (smooth > 0) {
+      stateObj.shape.smooth = smooth;
+    }
+
+    var styleObj = stateModel.getModel('lineStyle').getLineStyle();
+    isNormal ? labelLine.useStyle(styleObj) : stateObj.style = styleObj;
+  }
+
+  function buildLabelLinePath(path, shape) {
+    var smooth = shape.smooth;
+    var points = shape.points;
+
+    if (!points) {
+      return;
+    }
+
+    path.moveTo(points[0][0], points[0][1]);
+
+    if (smooth > 0 && points.length >= 3) {
+      var len1 = dist(points[0], points[1]);
+      var len2 = dist(points[1], points[2]);
+
+      if (!len1 || !len2) {
+        path.lineTo(points[1][0], points[1][1]);
+        path.lineTo(points[2][0], points[2][1]);
+        return;
+      }
+
+      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.
+   */
+
+
+  function setLabelLineStyle(targetEl, statesModels, defaultStyle) {
+    var labelLine = targetEl.getTextGuideLine();
+    var label = targetEl.getTextContent();
+
+    if (!label) {
+      // Not show label line if there is no label.
+      if (labelLine) {
+        targetEl.removeTextGuideLine();
+      }
+
+      return;
+    }
+
+    var normalModel = statesModels.normal;
+    var showNormal = normalModel.get('show');
+    var labelIgnoreNormal = label.ignore;
+
+    for (var i = 0; i < DISPLAY_STATES.length; i++) {
+      var stateName = DISPLAY_STATES[i];
+      var stateModel = statesModels[stateName];
+      var isNormal = stateName === 'normal';
+
+      if (stateModel) {
+        var stateShow = stateModel.get('show');
+        var isLabelIgnored = isNormal ? labelIgnoreNormal : retrieve2(label.states[stateName] && label.states[stateName].ignore, labelIgnoreNormal);
+
+        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[stateName];
+
+            if (stateObj) {
+              stateObj.ignore = true;
+            }
+
+            continue;
+          } // Create labelLine if not exists
+
+
+        if (!labelLine) {
+          labelLine = new Polyline();
+          targetEl.setTextGuideLine(labelLine); // Reset state of normal because it's new created.
+          // NOTE: NORMAL should always been the first!
+
+          if (!isNormal && (labelIgnoreNormal || !showNormal)) {
+            setLabelLineState(labelLine, true, 'normal', statesModels.normal);
+          } // Use same state proxy.
+
+
+          if (targetEl.stateProxy) {
+            labelLine.stateProxy = targetEl.stateProxy;
+          }
+        }
+
+        setLabelLineState(labelLine, false, stateName, stateModel);
+      }
+    }
+
+    if (labelLine) {
+      defaults(labelLine.style, defaultStyle); // Not fill.
+
+      labelLine.style.fill = null;
+      var showAbove = normalModel.get('showAbove');
+      var labelLineConfig = targetEl.textGuideLineConfig = targetEl.textGuideLineConfig || {};
+      labelLineConfig.showAbove = showAbove || false; // Custom the buildPath.
+
+      labelLine.buildPath = buildLabelLinePath;
+    }
+  }
+
+  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]);
+    }
+
+    return statesModels;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 prepareLayoutList(input) {
+    var list = [];
+
+    for (var i = 0; i < input.length; i++) {
+      var rawItem = input[i];
+
+      if (rawItem.defaultAttr.ignore) {
+        continue;
+      }
+
+      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 shiftLayout(list, xyDim, sizeDim, minBound, maxBound, balanceShift) {
+    var len = list.length;
+
+    if (len < 2) {
+      return;
+    }
+
+    list.sort(function (a, b) {
+      return a.rect[xyDim] - b.rect[xyDim];
+    });
+    var lastPos = 0;
+    var delta;
+    var adjusted = false;
+    var shifts = [];
+    var totalShifts = 0;
+
+    for (var i = 0; i < len; i++) {
+      var item = list[i];
+      var rect = item.rect;
+      delta = rect[xyDim] - lastPos;
+
+      if (delta < 0) {
+        // shiftForward(i, len, -delta);
+        rect[xyDim] -= delta;
+        item.label[xyDim] -= delta;
+        adjusted = true;
+      }
+
+      var shift = Math.max(-delta, 0);
+      shifts.push(shift);
+      totalShifts += shift;
+      lastPos = rect[xyDim] + rect[sizeDim];
+    }
+
+    if (totalShifts > 0 && balanceShift) {
+      // Shift back to make the distribution more equally.
+      shiftList(-totalShifts / len, 0, len);
+    } // TODO bleedMargin?
+
+
+    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.
+
+    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();
+
+    if (minGap < 0) {
+      squeezeWhenBailout(-minGap);
+    }
+
+    if (maxGap < 0) {
+      squeezeWhenBailout(maxGap);
+    }
+
+    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);
+
+        if (moveFromMaxGap > 0) {
+          shiftList(moveFromMaxGap * moveDir, 0, len);
+          var remained = moveFromMaxGap + gapThisBound;
+
+          if (remained < 0) {
+            squeezeGaps(-remained * moveDir, 1);
+          }
+        } else {
+          squeezeGaps(-gapThisBound * moveDir, 1);
+        }
+      }
+    }
+
+    function shiftList(delta, start, end) {
+      if (delta !== 0) {
+        adjusted = true;
+      }
+
+      for (var i = start; i < end; i++) {
+        var item = list[i];
+        var rect = item.rect;
+        rect[xyDim] += delta;
+        item.label[xyDim] += delta;
+      }
+    } // 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;
+      }
+
+      if (!totalGaps) {
+        return;
+      }
+
+      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);
+        }
+      }
+    }
+    /**
+     * 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;
+
+        if (delta <= 0) {
+          return;
+        }
+      }
+    }
+
+    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.
+   */
+
+
+  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;
+        }
+      }
+
+      el.ignore = true;
+    }
+
+    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.
+
+      globalRect.width -= 0.1;
+      globalRect.height -= 0.1;
+      globalRect.x += 0.05;
+      globalRect.y += 0.05;
+      var obb = labelItem.obb;
+      var overlapped = false;
+
+      for (var j = 0; j < displayedLabels.length; j++) {
+        var existsTextCfg = displayedLabels[j]; // Fast rejection.
+
+        if (!globalRect.intersect(existsTextCfg.rect)) {
+          continue;
+        }
+
+        if (isAxisAligned && existsTextCfg.axisAligned) {
+          // Is overlapped
+          overlapped = true;
+          break;
+        }
+
+        if (!existsTextCfg.obb) {
+          // If self is not axis aligned. But other is.
+          existsTextCfg.obb = new OrientedBoundingRect(existsTextCfg.localRect, existsTextCfg.transform);
+        }
+
+        if (!obb) {
+          // If self is axis aligned. But other is not.
+          obb = new OrientedBoundingRect(localRect, transform);
+        }
+
+        if (obb.intersect(existsTextCfg.obb)) {
+          overlapped = true;
+          break;
+        }
+      } // TODO Callback to determine if this overlap should be handled?
+
+
+      if (overlapped) {
+        hideEl(label);
+        labelLine && hideEl(labelLine);
+      } else {
+        label.attr('ignore', labelItem.defaultAttr.ignore);
+        labelLine && labelLine.attr('ignore', labelItem.defaultAttr.labelGuideIgnore);
+        displayedLabels.push(labelItem);
+      }
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // TODO: move labels out of viewport.
+
+
+  function cloneArr(points) {
+    if (points) {
+      var newPoints = [];
+
+      for (var i = 0; i < points.length; i++) {
+        newPoints.push(points[i].slice());
+      }
+
+      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$$1) {
+    for (var i = 0; i < keys$$1.length; i++) {
+      var key = keys$$1[i];
+
+      if (source[key] != null) {
+        target[key] = source[key];
+      }
+    }
+  }
+
+  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
+     */
+
+
+    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.
+
+      var labelTransform = label.getComputedTransform();
+      var labelRect = label.getBoundingRect().plain();
+      BoundingRect.applyTransform(labelRect, labelRect, labelTransform);
+
+      if (labelTransform) {
+        dummyTransformable.setLocalTransform(labelTransform);
+      } else {
+        // Identity transform.
+        dummyTransformable.x = dummyTransformable.y = dummyTransformable.rotation = dummyTransformable.originX = dummyTransformable.originY = 0;
+        dummyTransformable.scaleX = dummyTransformable.scaleY = 1;
+      }
+
+      var host = label.__hostTarget;
+      var hostRect;
+
+      if (host) {
+        hostRect = host.getBoundingRect().plain();
+        var transform = host.getComputedTransform();
+        BoundingRect.applyTransform(hostRect, hostRect, transform);
+      }
+
+      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.
+       */
+
+      if (!(isFunction(layoutOption) || keys(layoutOption).length)) {
+        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
+
+        if (textEl && !textEl.disableLabelLayout) {
+          _this._addLabel(ecData.dataIndex, ecData.dataType, seriesModel, textEl, layoutOption);
+        }
+      });
+    };
+
+    LabelManager.prototype.updateLayoutConfig = function (api) {
+      var width = api.getWidth();
+      var height = api.getHeight();
+
+      function createDragHandler(el, labelLineModel) {
+        return function () {
+          updateLabelLinePoints(el, labelLineModel);
+        };
+      }
+
+      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 (isFunction(labelItem.layoutOption)) {
+          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;
+
+        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.
+
+          needsUpdateLabelLine = true;
+        } else {
+          label.x = defaultLabelAttr.x;
+          label.setStyle('x', defaultLabelAttr.style.x);
+        }
+
+        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 (layoutOption.labelLinePoints) {
+          var guideLine = hostEl.getTextGuideLine();
+
+          if (guideLine) {
+            guideLine.setShape({
+              points: layoutOption.labelLinePoints
+            }); // Not update
+
+            needsUpdateLabelLine = false;
+          }
+        }
+
+        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 (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;
+        }
+      }
+    };
+
+    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 && !child.forceLabelAnimation) {
+            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 // `forceLabelAnimation` has the highest priority
+      && (el.forceLabelAnimation || !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
+
+            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.
+
+          var prevStates = el.prevStates;
+
+          if (prevStates) {
+            if (indexOf(prevStates, 'select') >= 0) {
+              textEl.attr(layoutStore.oldLayoutSelect);
+            }
+
+            if (indexOf(prevStates, 'emphasis') >= 0) {
+              textEl.attr(layoutStore.oldLayoutEmphasis);
+            }
+          }
+
+          updateProps(textEl, newProps, seriesModel, dataIndex);
+        }
+
+        layoutStore.oldLayout = newProps;
+
+        if (textEl.states.select) {
+          var layoutSelect = layoutStore.oldLayoutSelect = {};
+          extendWithKeys(layoutSelect, newProps, LABEL_LAYOUT_PROPS);
+          extendWithKeys(layoutSelect, textEl.states.select, LABEL_LAYOUT_PROPS);
+        }
+
+        if (textEl.states.emphasis) {
+          var layoutEmphasis = layoutStore.oldLayoutEmphasis = {};
+          extendWithKeys(layoutEmphasis, newProps, LABEL_LAYOUT_PROPS);
+          extendWithKeys(layoutEmphasis, textEl.states.emphasis, LABEL_LAYOUT_PROPS);
+        }
+
+        animateLabelValue(textEl, dataIndex, data, seriesModel, seriesModel);
+      }
+
+      if (guideLine && !guideLine.ignore && !guideLine.invisible) {
+        var layoutStore = labelLineAnimationStore(guideLine);
+        var oldLayout = layoutStore.oldLayout;
+        var newLayout = {
+          points: guideLine.shape.points
+        };
+
+        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);
+        }
+
+        layoutStore.oldLayout = newLayout;
+      }
+    };
+
+    return LabelManager;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 getLabelManager = makeInner();
+
+  function installLabelLayout(registers) {
+    registers.registerUpdateLifecycle('series:beforeupdate', function (ecModel, api, params) {
+      // TODO api provide an namespace that can save stuff per instance
+      var labelManager = getLabelManager(api).labelManager;
+
+      if (!labelManager) {
+        labelManager = getLabelManager(api).labelManager = new LabelManager();
+      }
+
+      labelManager.clearLabels();
+    });
+    registers.registerUpdateLifecycle('series:layoutlabels', function (ecModel, api, params) {
+      var labelManager = getLabelManager(api).labelManager;
+      params.updatedSeries.forEach(function (series) {
+        labelManager.addLabelsOfSeries(api.getViewOfSeriesModel(series));
+      });
+      labelManager.updateLayoutConfig(api);
+      labelManager.layout(api);
+      labelManager.processLabelsOverall();
+    });
+  } // TODO will be treeshaked.
+
+
+  use(installLabelLayout);
+
+  function createDom(id, painter, dpr) {
+    var newDom = platformApi.createCanvas();
+    var width = painter.getWidth();
+    var height = painter.getHeight();
+    var newDomStyle = newDom.style;
+
+    if (newDomStyle) {
+      newDomStyle.position = 'absolute';
+      newDomStyle.left = '0';
+      newDomStyle.top = '0';
+      newDomStyle.width = width + 'px';
+      newDomStyle.height = height + 'px';
+      newDom.setAttribute('data-zr-dom-id', id);
+    }
+
+    newDom.width = width * dpr;
+    newDom.height = height * dpr;
+    return newDom;
+  }
+
+  var Layer = function (_super) {
+    __extends(Layer, _super);
+
+    function Layer(id, painter, dpr) {
+      var _this = _super.call(this) || this;
+
+      _this.motionBlur = false;
+      _this.lastFrameAlpha = 0.7;
+      _this.dpr = 1;
+      _this.virtual = false;
+      _this.config = {};
+      _this.incremental = false;
+      _this.zlevel = 0;
+      _this.maxRepaintRectCount = 5;
+      _this.__dirty = true;
+      _this.__firstTimePaint = true;
+      _this.__used = false;
+      _this.__drawIndex = 0;
+      _this.__startIndex = 0;
+      _this.__endIndex = 0;
+      _this.__prevStartIndex = null;
+      _this.__prevEndIndex = null;
+      var dom;
+      dpr = dpr || devicePixelRatio;
+
+      if (typeof id === 'string') {
+        dom = createDom(id, painter, dpr);
+      } else if (isObject(id)) {
+        dom = id;
+        id = dom.id;
+      }
+
+      _this.id = id;
+      _this.dom = dom;
+      var domStyle = dom.style;
+
+      if (domStyle) {
+        disableUserSelect(dom);
+
+        dom.onselectstart = function () {
+          return false;
+        };
+
+        domStyle.padding = '0';
+        domStyle.margin = '0';
+        domStyle.borderWidth = '0';
+      }
+
+      _this.painter = painter;
+      _this.dpr = dpr;
+      return _this;
+    }
+
+    Layer.prototype.getElementCount = function () {
+      return this.__endIndex - this.__startIndex;
+    };
+
+    Layer.prototype.afterBrush = function () {
+      this.__prevStartIndex = this.__startIndex;
+      this.__prevEndIndex = this.__endIndex;
+    };
+
+    Layer.prototype.initContext = function () {
+      this.ctx = this.dom.getContext('2d');
+      this.ctx.dpr = this.dpr;
+    };
+
+    Layer.prototype.setUnpainted = function () {
+      this.__firstTimePaint = true;
+    };
+
+    Layer.prototype.createBackBuffer = function () {
+      var dpr = this.dpr;
+      this.domBack = createDom('back-' + this.id, this.painter, dpr);
+      this.ctxBack = this.domBack.getContext('2d');
+
+      if (dpr !== 1) {
+        this.ctxBack.scale(dpr, dpr);
+      }
+    };
+
+    Layer.prototype.createRepaintRects = function (displayList, prevList, viewWidth, viewHeight) {
+      if (this.__firstTimePaint) {
+        this.__firstTimePaint = false;
+        return null;
+      }
+
+      var mergedRepaintRects = [];
+      var maxRepaintRectCount = this.maxRepaintRectCount;
+      var full = false;
+      var pendingRect = new BoundingRect(0, 0, 0, 0);
+
+      function addRectToMergePool(rect) {
+        if (!rect.isFinite() || rect.isZero()) {
+          return;
+        }
+
+        if (mergedRepaintRects.length === 0) {
+          var boundingRect = new BoundingRect(0, 0, 0, 0);
+          boundingRect.copy(rect);
+          mergedRepaintRects.push(boundingRect);
+        } else {
+          var isMerged = false;
+          var minDeltaArea = Infinity;
+          var bestRectToMergeIdx = 0;
+
+          for (var i = 0; i < mergedRepaintRects.length; ++i) {
+            var mergedRect = mergedRepaintRects[i];
+
+            if (mergedRect.intersect(rect)) {
+              var pendingRect_1 = new BoundingRect(0, 0, 0, 0);
+              pendingRect_1.copy(mergedRect);
+              pendingRect_1.union(rect);
+              mergedRepaintRects[i] = pendingRect_1;
+              isMerged = true;
+              break;
+            } else if (full) {
+              pendingRect.copy(rect);
+              pendingRect.union(mergedRect);
+              var aArea = rect.width * rect.height;
+              var bArea = mergedRect.width * mergedRect.height;
+              var pendingArea = pendingRect.width * pendingRect.height;
+              var deltaArea = pendingArea - aArea - bArea;
+
+              if (deltaArea < minDeltaArea) {
+                minDeltaArea = deltaArea;
+                bestRectToMergeIdx = i;
+              }
+            }
+          }
+
+          if (full) {
+            mergedRepaintRects[bestRectToMergeIdx].union(rect);
+            isMerged = true;
+          }
+
+          if (!isMerged) {
+            var boundingRect = new BoundingRect(0, 0, 0, 0);
+            boundingRect.copy(rect);
+            mergedRepaintRects.push(boundingRect);
+          }
+
+          if (!full) {
+            full = mergedRepaintRects.length >= maxRepaintRectCount;
+          }
+        }
+      }
+
+      for (var i = this.__startIndex; i < this.__endIndex; ++i) {
+        var el = displayList[i];
+
+        if (el) {
+          var shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true);
+          var prevRect = el.__isRendered && (el.__dirty & REDRAW_BIT || !shouldPaint) ? el.getPrevPaintRect() : null;
+
+          if (prevRect) {
+            addRectToMergePool(prevRect);
+          }
+
+          var curRect = shouldPaint && (el.__dirty & REDRAW_BIT || !el.__isRendered) ? el.getPaintRect() : null;
+
+          if (curRect) {
+            addRectToMergePool(curRect);
+          }
+        }
+      }
+
+      for (var i = this.__prevStartIndex; i < this.__prevEndIndex; ++i) {
+        var el = prevList[i];
+        var shouldPaint = el.shouldBePainted(viewWidth, viewHeight, true, true);
+
+        if (el && (!shouldPaint || !el.__zr) && el.__isRendered) {
+          var prevRect = el.getPrevPaintRect();
+
+          if (prevRect) {
+            addRectToMergePool(prevRect);
+          }
+        }
+      }
+
+      var hasIntersections;
+
+      do {
+        hasIntersections = false;
+
+        for (var i = 0; i < mergedRepaintRects.length;) {
+          if (mergedRepaintRects[i].isZero()) {
+            mergedRepaintRects.splice(i, 1);
+            continue;
+          }
+
+          for (var j = i + 1; j < mergedRepaintRects.length;) {
+            if (mergedRepaintRects[i].intersect(mergedRepaintRects[j])) {
+              hasIntersections = true;
+              mergedRepaintRects[i].union(mergedRepaintRects[j]);
+              mergedRepaintRects.splice(j, 1);
+            } else {
+              j++;
+            }
+          }
+
+          i++;
+        }
+      } while (hasIntersections);
+
+      this._paintRects = mergedRepaintRects;
+      return mergedRepaintRects;
+    };
+
+    Layer.prototype.debugGetPaintRects = function () {
+      return (this._paintRects || []).slice();
+    };
+
+    Layer.prototype.resize = function (width, height) {
+      var dpr = this.dpr;
+      var dom = this.dom;
+      var domStyle = dom.style;
+      var domBack = this.domBack;
+
+      if (domStyle) {
+        domStyle.width = width + 'px';
+        domStyle.height = height + 'px';
+      }
+
+      dom.width = width * dpr;
+      dom.height = height * dpr;
+
+      if (domBack) {
+        domBack.width = width * dpr;
+        domBack.height = height * dpr;
+
+        if (dpr !== 1) {
+          this.ctxBack.scale(dpr, dpr);
+        }
+      }
+    };
+
+    Layer.prototype.clear = function (clearAll, clearColor, repaintRects) {
+      var dom = this.dom;
+      var ctx = this.ctx;
+      var width = dom.width;
+      var height = dom.height;
+      clearColor = clearColor || this.clearColor;
+      var haveMotionBLur = this.motionBlur && !clearAll;
+      var lastFrameAlpha = this.lastFrameAlpha;
+      var dpr = this.dpr;
+      var self = this;
+
+      if (haveMotionBLur) {
+        if (!this.domBack) {
+          this.createBackBuffer();
+        }
+
+        this.ctxBack.globalCompositeOperation = 'copy';
+        this.ctxBack.drawImage(dom, 0, 0, width / dpr, height / dpr);
+      }
+
+      var domBack = this.domBack;
+
+      function doClear(x, y, width, height) {
+        ctx.clearRect(x, y, width, height);
+
+        if (clearColor && clearColor !== 'transparent') {
+          var clearColorGradientOrPattern = void 0;
+
+          if (isGradientObject(clearColor)) {
+            clearColorGradientOrPattern = clearColor.__canvasGradient || getCanvasGradient(ctx, clearColor, {
+              x: 0,
+              y: 0,
+              width: width,
+              height: height
+            });
+            clearColor.__canvasGradient = clearColorGradientOrPattern;
+          } else if (isImagePatternObject(clearColor)) {
+            clearColorGradientOrPattern = createCanvasPattern(ctx, clearColor, {
+              dirty: function () {
+                self.setUnpainted();
+
+                self.__painter.refresh();
+              }
+            });
+          }
+
+          ctx.save();
+          ctx.fillStyle = clearColorGradientOrPattern || clearColor;
+          ctx.fillRect(x, y, width, height);
+          ctx.restore();
+        }
+
+        if (haveMotionBLur) {
+          ctx.save();
+          ctx.globalAlpha = lastFrameAlpha;
+          ctx.drawImage(domBack, x, y, width, height);
+          ctx.restore();
+        }
+      }
+
+      if (!repaintRects || haveMotionBLur) {
+        doClear(0, 0, width, height);
+      } else if (repaintRects.length) {
+        each(repaintRects, function (rect) {
+          doClear(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr);
+        });
+      }
+    };
+
+    return Layer;
+  }(Eventful);
+
+  var HOVER_LAYER_ZLEVEL = 1e5;
+  var CANVAS_ZLEVEL = 314159;
+  var EL_AFTER_INCREMENTAL_INC = 0.01;
+  var INCREMENTAL_INC = 0.001;
+
+  function isLayerValid(layer) {
+    if (!layer) {
+      return false;
+    }
+
+    if (layer.__builtin__) {
+      return true;
+    }
+
+    if (typeof layer.resize !== 'function' || typeof layer.refresh !== 'function') {
+      return false;
+    }
+
+    return true;
+  }
+
+  function createRoot(width, height) {
+    var domRoot = document.createElement('div');
+    domRoot.style.cssText = ['position:relative', 'width:' + width + 'px', 'height:' + height + 'px', 'padding:0', 'margin:0', 'border-width:0'].join(';') + ';';
+    return domRoot;
+  }
+
+  var CanvasPainter = function () {
+    function CanvasPainter(root, storage, opts, id) {
+      this.type = 'canvas';
+      this._zlevelList = [];
+      this._prevDisplayList = [];
+      this._layers = {};
+      this._layerConfig = {};
+      this._needsManuallyCompositing = false;
+      this.type = 'canvas';
+      var singleCanvas = !root.nodeName || root.nodeName.toUpperCase() === 'CANVAS';
+      this._opts = opts = extend({}, opts || {});
+      this.dpr = opts.devicePixelRatio || devicePixelRatio;
+      this._singleCanvas = singleCanvas;
+      this.root = root;
+      var rootStyle = root.style;
+
+      if (rootStyle) {
+        disableUserSelect(root);
+        root.innerHTML = '';
+      }
+
+      this.storage = storage;
+      var zlevelList = this._zlevelList;
+      this._prevDisplayList = [];
+      var layers = this._layers;
+
+      if (!singleCanvas) {
+        this._width = getSize(root, 0, opts);
+        this._height = getSize(root, 1, opts);
+        var domRoot = this._domRoot = createRoot(this._width, this._height);
+        root.appendChild(domRoot);
+      } else {
+        var rootCanvas = root;
+        var width = rootCanvas.width;
+        var height = rootCanvas.height;
+
+        if (opts.width != null) {
+          width = opts.width;
+        }
+
+        if (opts.height != null) {
+          height = opts.height;
+        }
+
+        this.dpr = opts.devicePixelRatio || 1;
+        rootCanvas.width = width * this.dpr;
+        rootCanvas.height = height * this.dpr;
+        this._width = width;
+        this._height = height;
+        var mainLayer = new Layer(rootCanvas, this, this.dpr);
+        mainLayer.__builtin__ = true;
+        mainLayer.initContext();
+        layers[CANVAS_ZLEVEL] = mainLayer;
+        mainLayer.zlevel = CANVAS_ZLEVEL;
+        zlevelList.push(CANVAS_ZLEVEL);
+        this._domRoot = root;
+      }
+    }
+
+    CanvasPainter.prototype.getType = function () {
+      return 'canvas';
+    };
+
+    CanvasPainter.prototype.isSingleCanvas = function () {
+      return this._singleCanvas;
+    };
+
+    CanvasPainter.prototype.getViewportRoot = function () {
+      return this._domRoot;
+    };
+
+    CanvasPainter.prototype.getViewportRootOffset = function () {
+      var viewportRoot = this.getViewportRoot();
+
+      if (viewportRoot) {
+        return {
+          offsetLeft: viewportRoot.offsetLeft || 0,
+          offsetTop: viewportRoot.offsetTop || 0
+        };
+      }
+    };
+
+    CanvasPainter.prototype.refresh = function (paintAll) {
+      var list = this.storage.getDisplayList(true);
+      var prevList = this._prevDisplayList;
+      var zlevelList = this._zlevelList;
+      this._redrawId = Math.random();
+
+      this._paintList(list, prevList, paintAll, this._redrawId);
+
+      for (var i = 0; i < zlevelList.length; i++) {
+        var z = zlevelList[i];
+        var layer = this._layers[z];
+
+        if (!layer.__builtin__ && layer.refresh) {
+          var clearColor = i === 0 ? this._backgroundColor : null;
+          layer.refresh(clearColor);
+        }
+      }
+
+      if (this._opts.useDirtyRect) {
+        this._prevDisplayList = list.slice();
+      }
+
+      return this;
+    };
+
+    CanvasPainter.prototype.refreshHover = function () {
+      this._paintHoverList(this.storage.getDisplayList(false));
+    };
+
+    CanvasPainter.prototype._paintHoverList = function (list) {
+      var len = list.length;
+      var hoverLayer = this._hoverlayer;
+      hoverLayer && hoverLayer.clear();
+
+      if (!len) {
+        return;
+      }
+
+      var scope = {
+        inHover: true,
+        viewWidth: this._width,
+        viewHeight: this._height
+      };
+      var ctx;
+
+      for (var i = 0; i < len; i++) {
+        var el = list[i];
+
+        if (el.__inHover) {
+          if (!hoverLayer) {
+            hoverLayer = this._hoverlayer = this.getLayer(HOVER_LAYER_ZLEVEL);
+          }
+
+          if (!ctx) {
+            ctx = hoverLayer.ctx;
+            ctx.save();
+          }
+
+          brush(ctx, el, scope, i === len - 1);
+        }
+      }
+
+      if (ctx) {
+        ctx.restore();
+      }
+    };
+
+    CanvasPainter.prototype.getHoverLayer = function () {
+      return this.getLayer(HOVER_LAYER_ZLEVEL);
+    };
+
+    CanvasPainter.prototype.paintOne = function (ctx, el) {
+      brushSingle(ctx, el);
+    };
+
+    CanvasPainter.prototype._paintList = function (list, prevList, paintAll, redrawId) {
+      if (this._redrawId !== redrawId) {
+        return;
+      }
+
+      paintAll = paintAll || false;
+
+      this._updateLayerStatus(list);
+
+      var _a = this._doPaintList(list, prevList, paintAll),
+          finished = _a.finished,
+          needsRefreshHover = _a.needsRefreshHover;
+
+      if (this._needsManuallyCompositing) {
+        this._compositeManually();
+      }
+
+      if (needsRefreshHover) {
+        this._paintHoverList(list);
+      }
+
+      if (!finished) {
+        var self_1 = this;
+        requestAnimationFrame$1(function () {
+          self_1._paintList(list, prevList, paintAll, redrawId);
+        });
+      } else {
+        this.eachLayer(function (layer) {
+          layer.afterBrush && layer.afterBrush();
+        });
+      }
+    };
+
+    CanvasPainter.prototype._compositeManually = function () {
+      var ctx = this.getLayer(CANVAS_ZLEVEL).ctx;
+      var width = this._domRoot.width;
+      var height = this._domRoot.height;
+      ctx.clearRect(0, 0, width, height);
+      this.eachBuiltinLayer(function (layer) {
+        if (layer.virtual) {
+          ctx.drawImage(layer.dom, 0, 0, width, height);
+        }
+      });
+    };
+
+    CanvasPainter.prototype._doPaintList = function (list, prevList, paintAll) {
+      var _this = this;
+
+      var layerList = [];
+      var useDirtyRect = this._opts.useDirtyRect;
+
+      for (var zi = 0; zi < this._zlevelList.length; zi++) {
+        var zlevel = this._zlevelList[zi];
+        var layer = this._layers[zlevel];
+
+        if (layer.__builtin__ && layer !== this._hoverlayer && (layer.__dirty || paintAll)) {
+          layerList.push(layer);
+        }
+      }
+
+      var finished = true;
+      var needsRefreshHover = false;
+
+      var _loop_1 = function (k) {
+        var layer = layerList[k];
+        var ctx = layer.ctx;
+        var repaintRects = useDirtyRect && layer.createRepaintRects(list, prevList, this_1._width, this_1._height);
+        var start = paintAll ? layer.__startIndex : layer.__drawIndex;
+        var useTimer = !paintAll && layer.incremental && Date.now;
+        var startTime = useTimer && Date.now();
+        var clearColor = layer.zlevel === this_1._zlevelList[0] ? this_1._backgroundColor : null;
+
+        if (layer.__startIndex === layer.__endIndex) {
+          layer.clear(false, clearColor, repaintRects);
+        } else if (start === layer.__startIndex) {
+          var firstEl = list[start];
+
+          if (!firstEl.incremental || !firstEl.notClear || paintAll) {
+            layer.clear(false, clearColor, repaintRects);
+          }
+        }
+
+        if (start === -1) {
+          console.error('For some unknown reason. drawIndex is -1');
+          start = layer.__startIndex;
+        }
+
+        var i;
+
+        var repaint = function (repaintRect) {
+          var scope = {
+            inHover: false,
+            allClipped: false,
+            prevEl: null,
+            viewWidth: _this._width,
+            viewHeight: _this._height
+          };
+
+          for (i = start; i < layer.__endIndex; i++) {
+            var el = list[i];
+
+            if (el.__inHover) {
+              needsRefreshHover = true;
+            }
+
+            _this._doPaintEl(el, layer, useDirtyRect, repaintRect, scope, i === layer.__endIndex - 1);
+
+            if (useTimer) {
+              var dTime = Date.now() - startTime;
+
+              if (dTime > 15) {
+                break;
+              }
+            }
+          }
+
+          if (scope.prevElClipPaths) {
+            ctx.restore();
+          }
+        };
+
+        if (repaintRects) {
+          if (repaintRects.length === 0) {
+            i = layer.__endIndex;
+          } else {
+            var dpr = this_1.dpr;
+
+            for (var r = 0; r < repaintRects.length; ++r) {
+              var rect = repaintRects[r];
+              ctx.save();
+              ctx.beginPath();
+              ctx.rect(rect.x * dpr, rect.y * dpr, rect.width * dpr, rect.height * dpr);
+              ctx.clip();
+              repaint(rect);
+              ctx.restore();
+            }
+          }
+        } else {
+          ctx.save();
+          repaint();
+          ctx.restore();
+        }
+
+        layer.__drawIndex = i;
+
+        if (layer.__drawIndex < layer.__endIndex) {
+          finished = false;
+        }
+      };
+
+      var this_1 = this;
+
+      for (var k = 0; k < layerList.length; k++) {
+        _loop_1(k);
+      }
+
+      if (env.wxa) {
+        each(this._layers, function (layer) {
+          if (layer && layer.ctx && layer.ctx.draw) {
+            layer.ctx.draw();
+          }
+        });
+      }
+
+      return {
+        finished: finished,
+        needsRefreshHover: needsRefreshHover
+      };
+    };
+
+    CanvasPainter.prototype._doPaintEl = function (el, currentLayer, useDirtyRect, repaintRect, scope, isLast) {
+      var ctx = currentLayer.ctx;
+
+      if (useDirtyRect) {
+        var paintRect = el.getPaintRect();
+
+        if (!repaintRect || paintRect && paintRect.intersect(repaintRect)) {
+          brush(ctx, el, scope, isLast);
+          el.setPrevPaintRect(paintRect);
+        }
+      } else {
+        brush(ctx, el, scope, isLast);
+      }
+    };
+
+    CanvasPainter.prototype.getLayer = function (zlevel, virtual) {
+      if (this._singleCanvas && !this._needsManuallyCompositing) {
+        zlevel = CANVAS_ZLEVEL;
+      }
+
+      var layer = this._layers[zlevel];
+
+      if (!layer) {
+        layer = new Layer('zr_' + zlevel, this, this.dpr);
+        layer.zlevel = zlevel;
+        layer.__builtin__ = true;
+
+        if (this._layerConfig[zlevel]) {
+          merge(layer, this._layerConfig[zlevel], true);
+        } else if (this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC]) {
+          merge(layer, this._layerConfig[zlevel - EL_AFTER_INCREMENTAL_INC], true);
+        }
+
+        if (virtual) {
+          layer.virtual = virtual;
+        }
+
+        this.insertLayer(zlevel, layer);
+        layer.initContext();
+      }
+
+      return layer;
+    };
+
+    CanvasPainter.prototype.insertLayer = function (zlevel, layer) {
+      var layersMap = this._layers;
+      var zlevelList = this._zlevelList;
+      var len = zlevelList.length;
+      var domRoot = this._domRoot;
+      var prevLayer = null;
+      var i = -1;
+
+      if (layersMap[zlevel]) {
+        {
+          logError('ZLevel ' + zlevel + ' has been used already');
+        }
+        return;
+      }
+
+      if (!isLayerValid(layer)) {
+        {
+          logError('Layer of zlevel ' + zlevel + ' is not valid');
+        }
+        return;
+      }
+
+      if (len > 0 && zlevel > zlevelList[0]) {
+        for (i = 0; i < len - 1; i++) {
+          if (zlevelList[i] < zlevel && zlevelList[i + 1] > zlevel) {
+            break;
+          }
+        }
+
+        prevLayer = layersMap[zlevelList[i]];
+      }
+
+      zlevelList.splice(i + 1, 0, zlevel);
+      layersMap[zlevel] = layer;
+
+      if (!layer.virtual) {
+        if (prevLayer) {
+          var prevDom = prevLayer.dom;
+
+          if (prevDom.nextSibling) {
+            domRoot.insertBefore(layer.dom, prevDom.nextSibling);
+          } else {
+            domRoot.appendChild(layer.dom);
+          }
+        } else {
+          if (domRoot.firstChild) {
+            domRoot.insertBefore(layer.dom, domRoot.firstChild);
+          } else {
+            domRoot.appendChild(layer.dom);
+          }
+        }
+      }
+
+      layer.__painter = this;
+    };
+
+    CanvasPainter.prototype.eachLayer = function (cb, context) {
+      var zlevelList = this._zlevelList;
+
+      for (var i = 0; i < zlevelList.length; i++) {
+        var z = zlevelList[i];
+        cb.call(context, this._layers[z], z);
+      }
+    };
+
+    CanvasPainter.prototype.eachBuiltinLayer = function (cb, context) {
+      var zlevelList = this._zlevelList;
+
+      for (var i = 0; i < zlevelList.length; i++) {
+        var z = zlevelList[i];
+        var layer = this._layers[z];
+
+        if (layer.__builtin__) {
+          cb.call(context, layer, z);
+        }
+      }
+    };
+
+    CanvasPainter.prototype.eachOtherLayer = function (cb, context) {
+      var zlevelList = this._zlevelList;
+
+      for (var i = 0; i < zlevelList.length; i++) {
+        var z = zlevelList[i];
+        var layer = this._layers[z];
+
+        if (!layer.__builtin__) {
+          cb.call(context, layer, z);
+        }
+      }
+    };
+
+    CanvasPainter.prototype.getLayers = function () {
+      return this._layers;
+    };
+
+    CanvasPainter.prototype._updateLayerStatus = function (list) {
+      this.eachBuiltinLayer(function (layer, z) {
+        layer.__dirty = layer.__used = false;
+      });
+
+      function updatePrevLayer(idx) {
+        if (prevLayer) {
+          if (prevLayer.__endIndex !== idx) {
+            prevLayer.__dirty = true;
+          }
+
+          prevLayer.__endIndex = idx;
+        }
+      }
+
+      if (this._singleCanvas) {
+        for (var i_1 = 1; i_1 < list.length; i_1++) {
+          var el = list[i_1];
+
+          if (el.zlevel !== list[i_1 - 1].zlevel || el.incremental) {
+            this._needsManuallyCompositing = true;
+            break;
+          }
+        }
+      }
+
+      var prevLayer = null;
+      var incrementalLayerCount = 0;
+      var prevZlevel;
+      var i;
+
+      for (i = 0; i < list.length; i++) {
+        var el = list[i];
+        var zlevel = el.zlevel;
+        var layer = void 0;
+
+        if (prevZlevel !== zlevel) {
+          prevZlevel = zlevel;
+          incrementalLayerCount = 0;
+        }
+
+        if (el.incremental) {
+          layer = this.getLayer(zlevel + INCREMENTAL_INC, this._needsManuallyCompositing);
+          layer.incremental = true;
+          incrementalLayerCount = 1;
+        } else {
+          layer = this.getLayer(zlevel + (incrementalLayerCount > 0 ? EL_AFTER_INCREMENTAL_INC : 0), this._needsManuallyCompositing);
+        }
+
+        if (!layer.__builtin__) {
+          logError('ZLevel ' + zlevel + ' has been used by unkown layer ' + layer.id);
+        }
+
+        if (layer !== prevLayer) {
+          layer.__used = true;
+
+          if (layer.__startIndex !== i) {
+            layer.__dirty = true;
+          }
+
+          layer.__startIndex = i;
+
+          if (!layer.incremental) {
+            layer.__drawIndex = i;
+          } else {
+            layer.__drawIndex = -1;
+          }
+
+          updatePrevLayer(i);
+          prevLayer = layer;
+        }
+
+        if (el.__dirty & REDRAW_BIT && !el.__inHover) {
+          layer.__dirty = true;
+
+          if (layer.incremental && layer.__drawIndex < 0) {
+            layer.__drawIndex = i;
+          }
+        }
+      }
+
+      updatePrevLayer(i);
+      this.eachBuiltinLayer(function (layer, z) {
+        if (!layer.__used && layer.getElementCount() > 0) {
+          layer.__dirty = true;
+          layer.__startIndex = layer.__endIndex = layer.__drawIndex = 0;
+        }
+
+        if (layer.__dirty && layer.__drawIndex < 0) {
+          layer.__drawIndex = layer.__startIndex;
+        }
+      });
+    };
+
+    CanvasPainter.prototype.clear = function () {
+      this.eachBuiltinLayer(this._clearLayer);
+      return this;
+    };
+
+    CanvasPainter.prototype._clearLayer = function (layer) {
+      layer.clear();
+    };
+
+    CanvasPainter.prototype.setBackgroundColor = function (backgroundColor) {
+      this._backgroundColor = backgroundColor;
+      each(this._layers, function (layer) {
+        layer.setUnpainted();
+      });
+    };
+
+    CanvasPainter.prototype.configLayer = function (zlevel, config) {
+      if (config) {
+        var layerConfig = this._layerConfig;
+
+        if (!layerConfig[zlevel]) {
+          layerConfig[zlevel] = config;
+        } else {
+          merge(layerConfig[zlevel], config, true);
+        }
+
+        for (var i = 0; i < this._zlevelList.length; i++) {
+          var _zlevel = this._zlevelList[i];
+
+          if (_zlevel === zlevel || _zlevel === zlevel + EL_AFTER_INCREMENTAL_INC) {
+            var layer = this._layers[_zlevel];
+            merge(layer, layerConfig[zlevel], true);
+          }
+        }
+      }
+    };
+
+    CanvasPainter.prototype.delLayer = function (zlevel) {
+      var layers = this._layers;
+      var zlevelList = this._zlevelList;
+      var layer = layers[zlevel];
+
+      if (!layer) {
+        return;
+      }
+
+      layer.dom.parentNode.removeChild(layer.dom);
+      delete layers[zlevel];
+      zlevelList.splice(indexOf(zlevelList, zlevel), 1);
+    };
+
+    CanvasPainter.prototype.resize = function (width, height) {
+      if (!this._domRoot.style) {
+        if (width == null || height == null) {
+          return;
+        }
+
+        this._width = width;
+        this._height = height;
+        this.getLayer(CANVAS_ZLEVEL).resize(width, height);
+      } else {
+        var domRoot = this._domRoot;
+        domRoot.style.display = 'none';
+        var opts = this._opts;
+        var root = this.root;
+        width != null && (opts.width = width);
+        height != null && (opts.height = height);
+        width = getSize(root, 0, opts);
+        height = getSize(root, 1, opts);
+        domRoot.style.display = '';
+
+        if (this._width !== width || height !== this._height) {
+          domRoot.style.width = width + 'px';
+          domRoot.style.height = height + 'px';
+
+          for (var id in this._layers) {
+            if (this._layers.hasOwnProperty(id)) {
+              this._layers[id].resize(width, height);
+            }
+          }
+
+          this.refresh(true);
+        }
+
+        this._width = width;
+        this._height = height;
+      }
+
+      return this;
+    };
+
+    CanvasPainter.prototype.clearLayer = function (zlevel) {
+      var layer = this._layers[zlevel];
+
+      if (layer) {
+        layer.clear();
+      }
+    };
+
+    CanvasPainter.prototype.dispose = function () {
+      this.root.innerHTML = '';
+      this.root = this.storage = this._domRoot = this._layers = null;
+    };
+
+    CanvasPainter.prototype.getRenderedCanvas = function (opts) {
+      opts = opts || {};
+
+      if (this._singleCanvas && !this._compositeManually) {
+        return this._layers[CANVAS_ZLEVEL].dom;
+      }
+
+      var imageLayer = new Layer('image', this, opts.pixelRatio || this.dpr);
+      imageLayer.initContext();
+      imageLayer.clear(false, opts.backgroundColor || this._backgroundColor);
+      var ctx = imageLayer.ctx;
+
+      if (opts.pixelRatio <= this.dpr) {
+        this.refresh();
+        var width_1 = imageLayer.dom.width;
+        var height_1 = imageLayer.dom.height;
+        this.eachLayer(function (layer) {
+          if (layer.__builtin__) {
+            ctx.drawImage(layer.dom, 0, 0, width_1, height_1);
+          } else if (layer.renderToCanvas) {
+            ctx.save();
+            layer.renderToCanvas(ctx);
+            ctx.restore();
+          }
+        });
+      } else {
+        var scope = {
+          inHover: false,
+          viewWidth: this._width,
+          viewHeight: this._height
+        };
+        var displayList = this.storage.getDisplayList(true);
+
+        for (var i = 0, len = displayList.length; i < len; i++) {
+          var el = displayList[i];
+          brush(ctx, el, scope, i === len - 1);
+        }
+      }
+
+      return imageLayer.dom;
+    };
+
+    CanvasPainter.prototype.getWidth = function () {
+      return this._width;
+    };
+
+    CanvasPainter.prototype.getHeight = function () {
+      return this._height;
+    };
+
+    return CanvasPainter;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install(registers) {
+    registers.registerPainter('canvas', CanvasPainter);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * This module is imported by echarts directly.
+   *
+   * Notice:
+   * Always keep this file exists for backward compatibility.
+   * Because before 4.1.0, dataset is an optional component,
+   * some users may import this module manually.
+   */
+
+
+  var DatasetModel =
+  /** @class */
+  function (_super) {
+    __extends(DatasetModel, _super);
+
+    function DatasetModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = 'dataset';
+      return _this;
+    }
+
+    DatasetModel.prototype.init = function (option, parentModel, ecModel) {
+      _super.prototype.init.call(this, option, parentModel, ecModel);
+
+      this._sourceManager = new SourceManager(this);
+      disableTransformOptionMerge(this);
+    };
+
+    DatasetModel.prototype.mergeOption = function (newOption, ecModel) {
+      _super.prototype.mergeOption.call(this, newOption, ecModel);
+
+      disableTransformOptionMerge(this);
+    };
+
+    DatasetModel.prototype.optionUpdated = function () {
+      this._sourceManager.dirty();
+    };
+
+    DatasetModel.prototype.getSourceManager = function () {
+      return this._sourceManager;
+    };
+
+    DatasetModel.type = 'dataset';
+    DatasetModel.defaultOption = {
+      seriesLayoutBy: SERIES_LAYOUT_BY_COLUMN
+    };
+    return DatasetModel;
+  }(ComponentModel);
+
+  var DatasetView =
+  /** @class */
+  function (_super) {
+    __extends(DatasetView, _super);
+
+    function DatasetView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = 'dataset';
+      return _this;
+    }
+
+    DatasetView.type = 'dataset';
+    return DatasetView;
+  }(ComponentView);
+
+  function install$1(registers) {
+    registers.registerComponentModel(DatasetModel);
+    registers.registerComponentView(DatasetView);
+  }
+
+  use([install, install$1]); // TODO: Compatitable with the following code
+  // import echarts from 'echarts/lib/echarts.js'
+  // TODO remove
+
+  use(installLabelLayout);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 samplers = {
+    average: function (frame) {
+      var sum = 0;
+      var count = 0;
+
+      for (var i = 0; i < frame.length; i++) {
+        if (!isNaN(frame[i])) {
+          sum += frame[i];
+          count++;
+        }
+      } // Return NaN if count is 0
+
+
+      return count === 0 ? NaN : sum / count;
+    },
+    sum: function (frame) {
+      var sum = 0;
+
+      for (var i = 0; i < frame.length; i++) {
+        // Ignore NaN
+        sum += frame[i] || 0;
+      }
+
+      return sum;
+    },
+    max: function (frame) {
+      var max = -Infinity;
+
+      for (var i = 0; i < frame.length; i++) {
+        frame[i] > max && (max = frame[i]);
+      } // NaN will cause illegal axis extent.
+
+
+      return isFinite(max) ? max : NaN;
+    },
+    min: function (frame) {
+      var min = Infinity;
+
+      for (var i = 0; i < frame.length; i++) {
+        frame[i] < min && (min = frame[i]);
+      } // NaN will cause illegal axis extent.
+
+
+      return isFinite(min) ? min : NaN;
+    },
+    // TODO
+    // Median
+    nearest: function (frame) {
+      return frame[0];
+    }
+  };
+
+  var indexSampler = function (frame) {
+    return Math.round(frame.length / 2);
+  };
+
+  function dataSample(seriesType) {
+    return {
+      seriesType: seriesType,
+      // FIXME:TS never used, so comment it
+      // modifyOutputEnd: true,
+      reset: function (seriesModel, ecModel, api) {
+        var data = seriesModel.getData();
+        var sampling = seriesModel.get('sampling');
+        var coordSys = seriesModel.coordinateSystem;
+        var count = data.count(); // Only cartesian2d support down sampling. Disable it when there is few data.
+
+        if (count > 10 && coordSys.type === 'cartesian2d' && sampling) {
+          var baseAxis = coordSys.getBaseAxis();
+          var valueAxis = coordSys.getOtherAxis(baseAxis);
+          var extent = baseAxis.getExtent();
+          var dpr = api.getDevicePixelRatio(); // Coordinste system has been resized
+
+          var size = Math.abs(extent[1] - extent[0]) * (dpr || 1);
+          var rate = Math.round(count / size);
+
+          if (isFinite(rate) && rate > 1) {
+            if (sampling === 'lttb') {
+              seriesModel.setData(data.lttbDownSample(data.mapDimension(valueAxis.dim), 1 / rate));
+            }
+
+            var sampler = void 0;
+
+            if (isString(sampling)) {
+              sampler = samplers[sampling];
+            } else if (isFunction(sampling)) {
+              sampler = sampling;
+            }
+
+            if (sampler) {
+              // Only support sample the first dim mapped from value axis.
+              seriesModel.setData(data.downSample(data.mapDimension(valueAxis.dim), 1 / rate, sampler, indexSampler));
+            }
+          }
+        }
+      }
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 BaseBarSeriesModel =
+  /** @class */
+  function (_super) {
+    __extends(BaseBarSeriesModel, _super);
+
+    function BaseBarSeriesModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = BaseBarSeriesModel.type;
+      return _this;
+    }
+
+    BaseBarSeriesModel.prototype.getInitialData = function (option, ecModel) {
+      return createSeriesData(null, this, {
+        useEncodeDefaulter: true
+      });
+    };
+
+    BaseBarSeriesModel.prototype.getMarkerPosition = function (value) {
+      var coordSys = this.coordinateSystem;
+
+      if (coordSys && coordSys.clampData) {
+        // PENDING if clamp ?
+        var pt = coordSys.dataToPoint(coordSys.clampData(value));
+        var data = this.getData();
+        var offset = data.getLayout('offset');
+        var size = data.getLayout('size');
+        var offsetIndex = coordSys.getBaseAxis().isHorizontal() ? 0 : 1;
+        pt[offsetIndex] += offset + size / 2;
+        return pt;
+      }
+
+      return [NaN, NaN];
+    };
+
+    BaseBarSeriesModel.type = 'series.__base_bar__';
+    BaseBarSeriesModel.defaultOption = {
+      // zlevel: 0,
+      z: 2,
+      coordinateSystem: 'cartesian2d',
+      legendHoverLink: true,
+      // stack: null
+      // Cartesian coordinate system
+      // xAxisIndex: 0,
+      // yAxisIndex: 0,
+      barMinHeight: 0,
+      barMinAngle: 0,
+      // cursor: null,
+      large: false,
+      largeThreshold: 400,
+      progressive: 3e3,
+      progressiveChunkMode: 'mod'
+    };
+    return BaseBarSeriesModel;
+  }(SeriesModel);
+
+  SeriesModel.registerClass(BaseBarSeriesModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 BarSeriesModel =
+  /** @class */
+  function (_super) {
+    __extends(BarSeriesModel, _super);
+
+    function BarSeriesModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = BarSeriesModel.type;
+      return _this;
+    }
+
+    BarSeriesModel.prototype.getInitialData = function () {
+      return createSeriesData(null, this, {
+        useEncodeDefaulter: true,
+        createInvertedIndices: !!this.get('realtimeSort', true) || null
+      });
+    };
+    /**
+     * @override
+     */
+
+
+    BarSeriesModel.prototype.getProgressive = function () {
+      // Do not support progressive in normal mode.
+      return this.get('large') ? this.get('progressive') : false;
+    };
+    /**
+     * @override
+     */
+
+
+    BarSeriesModel.prototype.getProgressiveThreshold = function () {
+      // Do not support progressive in normal mode.
+      var progressiveThreshold = this.get('progressiveThreshold');
+      var largeThreshold = this.get('largeThreshold');
+
+      if (largeThreshold > progressiveThreshold) {
+        progressiveThreshold = largeThreshold;
+      }
+
+      return progressiveThreshold;
+    };
+
+    BarSeriesModel.prototype.brushSelector = function (dataIndex, data, selectors) {
+      return selectors.rect(data.getItemLayout(dataIndex));
+    };
+
+    BarSeriesModel.type = 'series.bar';
+    BarSeriesModel.dependencies = ['grid', 'polar'];
+    BarSeriesModel.defaultOption = inheritDefaultOption(BaseBarSeriesModel.defaultOption, {
+      // If clipped
+      // Only available on cartesian2d
+      clip: true,
+      roundCap: false,
+      showBackground: false,
+      backgroundStyle: {
+        color: 'rgba(180, 180, 180, 0.2)',
+        borderColor: null,
+        borderWidth: 0,
+        borderType: 'solid',
+        borderRadius: 0,
+        shadowBlur: 0,
+        shadowColor: null,
+        shadowOffsetX: 0,
+        shadowOffsetY: 0,
+        opacity: 1
+      },
+      select: {
+        itemStyle: {
+          borderColor: '#212121'
+        }
+      },
+      realtimeSort: false
+    });
+    return BarSeriesModel;
+  }(BaseBarSeriesModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 createGridClipPath(cartesian, hasAnimation, seriesModel, done, during) {
+    var rect = cartesian.getArea();
+    var x = rect.x;
+    var y = rect.y;
+    var width = rect.width;
+    var height = rect.height;
+    var lineWidth = seriesModel.get(['lineStyle', 'width']) || 2; // Expand the clip path a bit to avoid the border is clipped and looks thinner
+
+    x -= lineWidth / 2;
+    y -= lineWidth / 2;
+    width += lineWidth;
+    height += lineWidth; // fix: https://github.com/apache/incubator-echarts/issues/11369
+
+    x = Math.floor(x);
+    width = Math.round(width);
+    var clipPath = new Rect({
+      shape: {
+        x: x,
+        y: y,
+        width: width,
+        height: height
+      }
+    });
+
+    if (hasAnimation) {
+      var baseAxis = cartesian.getBaseAxis();
+      var isHorizontal = baseAxis.isHorizontal();
+      var isAxisInversed = baseAxis.inverse;
+
+      if (isHorizontal) {
+        if (isAxisInversed) {
+          clipPath.shape.x += width;
+        }
+
+        clipPath.shape.width = 0;
+      } else {
+        if (!isAxisInversed) {
+          clipPath.shape.y += height;
+        }
+
+        clipPath.shape.height = 0;
+      }
+
+      var duringCb = isFunction(during) ? function (percent) {
+        during(percent, clipPath);
+      } : null;
+      initProps(clipPath, {
+        shape: {
+          width: width,
+          height: height,
+          x: x,
+          y: y
+        }
+      }, seriesModel, null, done, duringCb);
+    }
+
+    return clipPath;
+  }
+
+  function createPolarClipPath(polar, hasAnimation, seriesModel) {
+    var sectorArea = polar.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent.
+
+    var r0 = round(sectorArea.r0, 1);
+    var r = round(sectorArea.r, 1);
+    var clipPath = new Sector({
+      shape: {
+        cx: round(polar.cx, 1),
+        cy: round(polar.cy, 1),
+        r0: r0,
+        r: r,
+        startAngle: sectorArea.startAngle,
+        endAngle: sectorArea.endAngle,
+        clockwise: sectorArea.clockwise
+      }
+    });
+
+    if (hasAnimation) {
+      var isRadial = polar.getBaseAxis().dim === 'angle';
+
+      if (isRadial) {
+        clipPath.shape.endAngle = sectorArea.startAngle;
+      } else {
+        clipPath.shape.r = r0;
+      }
+
+      initProps(clipPath, {
+        shape: {
+          endAngle: sectorArea.endAngle,
+          r: r
+        }
+      }, seriesModel);
+    }
+
+    return clipPath;
+  }
+
+  function createClipPath(coordSys, hasAnimation, seriesModel, done, during) {
+    if (!coordSys) {
+      return null;
+    } else if (coordSys.type === 'polar') {
+      return createPolarClipPath(coordSys, hasAnimation, seriesModel);
+    } else if (coordSys.type === 'cartesian2d') {
+      return createGridClipPath(coordSys, hasAnimation, seriesModel, done, during);
+    }
+
+    return null;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Sausage: similar to sector, but have half circle on both sides
+   */
+
+
+  var SausageShape =
+  /** @class */
+  function () {
+    function SausageShape() {
+      this.cx = 0;
+      this.cy = 0;
+      this.r0 = 0;
+      this.r = 0;
+      this.startAngle = 0;
+      this.endAngle = Math.PI * 2;
+      this.clockwise = true;
+    }
+
+    return SausageShape;
+  }();
+
+  var SausagePath =
+  /** @class */
+  function (_super) {
+    __extends(SausagePath, _super);
+
+    function SausagePath(opts) {
+      var _this = _super.call(this, opts) || this;
+
+      _this.type = 'sausage';
+      return _this;
+    }
+
+    SausagePath.prototype.getDefaultShape = function () {
+      return new SausageShape();
+    };
+
+    SausagePath.prototype.buildPath = function (ctx, shape) {
+      var cx = shape.cx;
+      var cy = shape.cy;
+      var r0 = Math.max(shape.r0 || 0, 0);
+      var r = Math.max(shape.r, 0);
+      var dr = (r - r0) * 0.5;
+      var rCenter = r0 + dr;
+      var startAngle = shape.startAngle;
+      var endAngle = shape.endAngle;
+      var clockwise = shape.clockwise;
+      var PI2 = Math.PI * 2;
+      var lessThanCircle = clockwise ? endAngle - startAngle < PI2 : startAngle - endAngle < PI2;
+
+      if (!lessThanCircle) {
+        // Normalize angles
+        startAngle = endAngle - (clockwise ? PI2 : -PI2);
+      }
+
+      var unitStartX = Math.cos(startAngle);
+      var unitStartY = Math.sin(startAngle);
+      var unitEndX = Math.cos(endAngle);
+      var unitEndY = Math.sin(endAngle);
+
+      if (lessThanCircle) {
+        ctx.moveTo(unitStartX * r0 + cx, unitStartY * r0 + cy);
+        ctx.arc(unitStartX * rCenter + cx, unitStartY * rCenter + cy, dr, -Math.PI + startAngle, startAngle, !clockwise);
+      } else {
+        ctx.moveTo(unitStartX * r + cx, unitStartY * r + cy);
+      }
+
+      ctx.arc(cx, cy, r, startAngle, endAngle, !clockwise);
+      ctx.arc(unitEndX * rCenter + cx, unitEndY * rCenter + cy, dr, endAngle - Math.PI * 2, endAngle - Math.PI, !clockwise);
+
+      if (r0 !== 0) {
+        ctx.arc(cx, cy, r0, endAngle, startAngle, clockwise);
+      } // ctx.closePath();
+
+    };
+
+    return SausagePath;
+  }(Path);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 isCoordinateSystemType(coordSys, type) {
+    return coordSys.type === type;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * @return label string. Not null/undefined
+   */
+
+
+  function getDefaultLabel(data, dataIndex) {
+    var labelDims = data.mapDimensionsAll('defaultedLabel');
+    var len = labelDims.length; // Simple optimization (in lots of cases, label dims length is 1)
+
+    if (len === 1) {
+      var rawVal = retrieveRawValue(data, dataIndex, labelDims[0]);
+      return rawVal != null ? rawVal + '' : null;
+    } else if (len) {
+      var vals = [];
+
+      for (var i = 0; i < labelDims.length; i++) {
+        vals.push(retrieveRawValue(data, dataIndex, labelDims[i]));
+      }
+
+      return vals.join(' ');
+    }
+  }
+
+  function getDefaultInterpolatedLabel(data, interpolatedValue) {
+    var labelDims = data.mapDimensionsAll('defaultedLabel');
+
+    if (!isArray(interpolatedValue)) {
+      return interpolatedValue + '';
+    }
+
+    var vals = [];
+
+    for (var i = 0; i < labelDims.length; i++) {
+      var dimIndex = data.getDimensionIndex(labelDims[i]);
+
+      if (dimIndex >= 0) {
+        vals.push(interpolatedValue[dimIndex]);
+      }
+    }
+
+    return vals.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.
+  */
+
+  /**
+   * AUTO-GENERATED FILE. DO NOT MODIFY.
+   */
+
+  /*
+  * 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 createSectorCalculateTextPosition(positionMapping, opts) {
+    opts = opts || {};
+    var isRoundCap = opts.isRoundCap;
+    return function (out, opts, boundingRect) {
+      var textPosition = opts.position;
+
+      if (!textPosition || textPosition instanceof Array) {
+        return calculateTextPosition(out, opts, boundingRect);
+      }
+
+      var mappedSectorPosition = positionMapping(textPosition);
+      var distance = opts.distance != null ? opts.distance : 5;
+      var sector = this.shape;
+      var cx = sector.cx;
+      var cy = sector.cy;
+      var r = sector.r;
+      var r0 = sector.r0;
+      var middleR = (r + r0) / 2;
+      var startAngle = sector.startAngle;
+      var endAngle = sector.endAngle;
+      var middleAngle = (startAngle + endAngle) / 2;
+      var extraDist = isRoundCap ? Math.abs(r - r0) / 2 : 0;
+      var mathCos = Math.cos;
+      var mathSin = Math.sin; // base position: top-left
+
+      var x = cx + r * mathCos(startAngle);
+      var y = cy + r * mathSin(startAngle);
+      var textAlign = 'left';
+      var textVerticalAlign = 'top';
+
+      switch (mappedSectorPosition) {
+        case 'startArc':
+          x = cx + (r0 - distance) * mathCos(middleAngle);
+          y = cy + (r0 - distance) * mathSin(middleAngle);
+          textAlign = 'center';
+          textVerticalAlign = 'top';
+          break;
+
+        case 'insideStartArc':
+          x = cx + (r0 + distance) * mathCos(middleAngle);
+          y = cy + (r0 + distance) * mathSin(middleAngle);
+          textAlign = 'center';
+          textVerticalAlign = 'bottom';
+          break;
+
+        case 'startAngle':
+          x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, distance + extraDist, false);
+          y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, distance + extraDist, false);
+          textAlign = 'right';
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'insideStartAngle':
+          x = cx + middleR * mathCos(startAngle) + adjustAngleDistanceX(startAngle, -distance + extraDist, false);
+          y = cy + middleR * mathSin(startAngle) + adjustAngleDistanceY(startAngle, -distance + extraDist, false);
+          textAlign = 'left';
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'middle':
+          x = cx + middleR * mathCos(middleAngle);
+          y = cy + middleR * mathSin(middleAngle);
+          textAlign = 'center';
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'endArc':
+          x = cx + (r + distance) * mathCos(middleAngle);
+          y = cy + (r + distance) * mathSin(middleAngle);
+          textAlign = 'center';
+          textVerticalAlign = 'bottom';
+          break;
+
+        case 'insideEndArc':
+          x = cx + (r - distance) * mathCos(middleAngle);
+          y = cy + (r - distance) * mathSin(middleAngle);
+          textAlign = 'center';
+          textVerticalAlign = 'top';
+          break;
+
+        case 'endAngle':
+          x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, distance + extraDist, true);
+          y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, distance + extraDist, true);
+          textAlign = 'left';
+          textVerticalAlign = 'middle';
+          break;
+
+        case 'insideEndAngle':
+          x = cx + middleR * mathCos(endAngle) + adjustAngleDistanceX(endAngle, -distance + extraDist, true);
+          y = cy + middleR * mathSin(endAngle) + adjustAngleDistanceY(endAngle, -distance + extraDist, true);
+          textAlign = 'right';
+          textVerticalAlign = 'middle';
+          break;
+
+        default:
+          return calculateTextPosition(out, opts, boundingRect);
+      }
+
+      out = out || {};
+      out.x = x;
+      out.y = y;
+      out.align = textAlign;
+      out.verticalAlign = textVerticalAlign;
+      return out;
+    };
+  }
+
+  function setSectorTextRotation(sector, textPosition, positionMapping, rotateType) {
+    if (isNumber(rotateType)) {
+      // user-set rotation
+      sector.setTextConfig({
+        rotation: rotateType
+      });
+      return;
+    } else if (isArray(textPosition)) {
+      // user-set position, use 0 as auto rotation
+      sector.setTextConfig({
+        rotation: 0
+      });
+      return;
+    }
+
+    var shape = sector.shape;
+    var startAngle = shape.clockwise ? shape.startAngle : shape.endAngle;
+    var endAngle = shape.clockwise ? shape.endAngle : shape.startAngle;
+    var middleAngle = (startAngle + endAngle) / 2;
+    var anchorAngle;
+    var mappedSectorPosition = positionMapping(textPosition);
+
+    switch (mappedSectorPosition) {
+      case 'startArc':
+      case 'insideStartArc':
+      case 'middle':
+      case 'insideEndArc':
+      case 'endArc':
+        anchorAngle = middleAngle;
+        break;
+
+      case 'startAngle':
+      case 'insideStartAngle':
+        anchorAngle = startAngle;
+        break;
+
+      case 'endAngle':
+      case 'insideEndAngle':
+        anchorAngle = endAngle;
+        break;
+
+      default:
+        sector.setTextConfig({
+          rotation: 0
+        });
+        return;
+    }
+
+    var rotate = Math.PI * 1.5 - anchorAngle;
+    /**
+     * TODO: labels with rotate > Math.PI / 2 should be rotate another
+     * half round flipped to increase readability. However, only middle
+     * position supports this for now, because in other positions, the
+     * anchor point is not at the center of the text, so the positions
+     * after rotating is not as expected.
+     */
+
+    if (mappedSectorPosition === 'middle' && rotate > Math.PI / 2 && rotate < Math.PI * 1.5) {
+      rotate -= Math.PI;
+    }
+
+    sector.setTextConfig({
+      rotation: rotate
+    });
+  }
+
+  function adjustAngleDistanceX(angle, distance, isEnd) {
+    return distance * Math.sin(angle) * (isEnd ? -1 : 1);
+  }
+
+  function adjustAngleDistanceY(angle, distance, isEnd) {
+    return distance * Math.cos(angle) * (isEnd ? 1 : -1);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 mathMax$5 = Math.max;
+  var mathMin$5 = Math.min;
+
+  function getClipArea(coord, data) {
+    var coordSysClipArea = coord.getArea && coord.getArea();
+
+    if (isCoordinateSystemType(coord, 'cartesian2d')) {
+      var baseAxis = coord.getBaseAxis(); // When boundaryGap is false or using time axis. bar may exceed the grid.
+      // We should not clip this part.
+      // See test/bar2.html
+
+      if (baseAxis.type !== 'category' || !baseAxis.onBand) {
+        var expandWidth = data.getLayout('bandWidth');
+
+        if (baseAxis.isHorizontal()) {
+          coordSysClipArea.x -= expandWidth;
+          coordSysClipArea.width += expandWidth * 2;
+        } else {
+          coordSysClipArea.y -= expandWidth;
+          coordSysClipArea.height += expandWidth * 2;
+        }
+      }
+    }
+
+    return coordSysClipArea;
+  }
+
+  var BarView =
+  /** @class */
+  function (_super) {
+    __extends(BarView, _super);
+
+    function BarView() {
+      var _this = _super.call(this) || this;
+
+      _this.type = BarView.type;
+      _this._isFirstFrame = true;
+      return _this;
+    }
+
+    BarView.prototype.render = function (seriesModel, ecModel, api, payload) {
+      this._model = seriesModel;
+
+      this._removeOnRenderedListener(api);
+
+      this._updateDrawMode(seriesModel);
+
+      var coordinateSystemType = seriesModel.get('coordinateSystem');
+
+      if (coordinateSystemType === 'cartesian2d' || coordinateSystemType === 'polar') {
+        // Clear previously rendered progressive elements.
+        this._progressiveEls = null;
+        this._isLargeDraw ? this._renderLarge(seriesModel, ecModel, api) : this._renderNormal(seriesModel, ecModel, api, payload);
+      } else {
+        warn('Only cartesian2d and polar supported for bar.');
+      }
+    };
+
+    BarView.prototype.incrementalPrepareRender = function (seriesModel) {
+      this._clear();
+
+      this._updateDrawMode(seriesModel); // incremental also need to clip, otherwise might be overlow.
+      // But must not set clip in each frame, otherwise all of the children will be marked redraw.
+
+
+      this._updateLargeClip(seriesModel);
+    };
+
+    BarView.prototype.incrementalRender = function (params, seriesModel) {
+      // Reset
+      this._progressiveEls = []; // Do not support progressive in normal mode.
+
+      this._incrementalRenderLarge(params, seriesModel);
+    };
+
+    BarView.prototype.eachRendered = function (cb) {
+      traverseElements(this._progressiveEls || this.group, cb);
+    };
+
+    BarView.prototype._updateDrawMode = function (seriesModel) {
+      var isLargeDraw = seriesModel.pipelineContext.large;
+
+      if (this._isLargeDraw == null || isLargeDraw !== this._isLargeDraw) {
+        this._isLargeDraw = isLargeDraw;
+
+        this._clear();
+      }
+    };
+
+    BarView.prototype._renderNormal = function (seriesModel, ecModel, api, payload) {
+      var group = this.group;
+      var data = seriesModel.getData();
+      var oldData = this._data;
+      var coord = seriesModel.coordinateSystem;
+      var baseAxis = coord.getBaseAxis();
+      var isHorizontalOrRadial;
+
+      if (coord.type === 'cartesian2d') {
+        isHorizontalOrRadial = baseAxis.isHorizontal();
+      } else if (coord.type === 'polar') {
+        isHorizontalOrRadial = baseAxis.dim === 'angle';
+      }
+
+      var animationModel = seriesModel.isAnimationEnabled() ? seriesModel : null;
+      var realtimeSortCfg = shouldRealtimeSort(seriesModel, coord);
+
+      if (realtimeSortCfg) {
+        this._enableRealtimeSort(realtimeSortCfg, data, api);
+      }
+
+      var needsClip = seriesModel.get('clip', true) || realtimeSortCfg;
+      var coordSysClipArea = getClipArea(coord, data); // If there is clipPath created in large mode. Remove it.
+
+      group.removeClipPath(); // We don't use clipPath in normal mode because we needs a perfect animation
+      // And don't want the label are clipped.
+
+      var roundCap = seriesModel.get('roundCap', true);
+      var drawBackground = seriesModel.get('showBackground', true);
+      var backgroundModel = seriesModel.getModel('backgroundStyle');
+      var barBorderRadius = backgroundModel.get('borderRadius') || 0;
+      var bgEls = [];
+      var oldBgEls = this._backgroundEls;
+      var isInitSort = payload && payload.isInitSort;
+      var isChangeOrder = payload && payload.type === 'changeAxisOrder';
+
+      function createBackground(dataIndex) {
+        var bgLayout = getLayout[coord.type](data, dataIndex);
+        var bgEl = createBackgroundEl(coord, isHorizontalOrRadial, bgLayout);
+        bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius.
+
+        if (coord.type === 'cartesian2d') {
+          bgEl.setShape('r', barBorderRadius);
+        }
+
+        bgEls[dataIndex] = bgEl;
+        return bgEl;
+      }
+
+      data.diff(oldData).add(function (dataIndex) {
+        var itemModel = data.getItemModel(dataIndex);
+        var layout = getLayout[coord.type](data, dataIndex, itemModel);
+
+        if (drawBackground) {
+          createBackground(dataIndex);
+        } // If dataZoom in filteMode: 'empty', the baseValue can be set as NaN in "axisProxy".
+
+
+        if (!data.hasValue(dataIndex) || !isValidLayout[coord.type](layout)) {
+          return;
+        }
+
+        var isClipped = false;
+
+        if (needsClip) {
+          // Clip will modify the layout params.
+          // And return a boolean to determine if the shape are fully clipped.
+          isClipped = clip[coord.type](coordSysClipArea, layout);
+        }
+
+        var el = elementCreator[coord.type](seriesModel, data, dataIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, false, roundCap);
+
+        if (realtimeSortCfg) {
+          /**
+           * Force label animation because even if the element is
+           * ignored because it's clipped, it may not be clipped after
+           * changing order. Then, if not using forceLabelAnimation,
+           * the label animation was never started, in which case,
+           * the label will be the final value and doesn't have label
+           * animation.
+           */
+          el.forceLabelAnimation = true;
+        }
+
+        updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
+
+        if (isInitSort) {
+          el.attr({
+            shape: layout
+          });
+        } else if (realtimeSortCfg) {
+          updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, dataIndex, isHorizontalOrRadial, false, false);
+        } else {
+          initProps(el, {
+            shape: layout
+          }, seriesModel, dataIndex);
+        }
+
+        data.setItemGraphicEl(dataIndex, el);
+        group.add(el);
+        el.ignore = isClipped;
+      }).update(function (newIndex, oldIndex) {
+        var itemModel = data.getItemModel(newIndex);
+        var layout = getLayout[coord.type](data, newIndex, itemModel);
+
+        if (drawBackground) {
+          var bgEl = void 0;
+
+          if (oldBgEls.length === 0) {
+            bgEl = createBackground(oldIndex);
+          } else {
+            bgEl = oldBgEls[oldIndex];
+            bgEl.useStyle(backgroundModel.getItemStyle()); // Only cartesian2d support borderRadius.
+
+            if (coord.type === 'cartesian2d') {
+              bgEl.setShape('r', barBorderRadius);
+            }
+
+            bgEls[newIndex] = bgEl;
+          }
+
+          var bgLayout = getLayout[coord.type](data, newIndex);
+          var shape = createBackgroundShape(isHorizontalOrRadial, bgLayout, coord);
+          updateProps(bgEl, {
+            shape: shape
+          }, animationModel, newIndex);
+        }
+
+        var el = oldData.getItemGraphicEl(oldIndex);
+
+        if (!data.hasValue(newIndex) || !isValidLayout[coord.type](layout)) {
+          group.remove(el);
+          return;
+        }
+
+        var isClipped = false;
+
+        if (needsClip) {
+          isClipped = clip[coord.type](coordSysClipArea, layout);
+
+          if (isClipped) {
+            group.remove(el);
+          }
+        }
+
+        if (!el) {
+          el = elementCreator[coord.type](seriesModel, data, newIndex, layout, isHorizontalOrRadial, animationModel, baseAxis.model, !!el, roundCap);
+        } else {
+          saveOldStyle(el);
+        }
+
+        if (realtimeSortCfg) {
+          el.forceLabelAnimation = true;
+        }
+
+        if (isChangeOrder) {
+          var textEl = el.getTextContent();
+
+          if (textEl) {
+            var labelInnerStore = labelInner(textEl);
+
+            if (labelInnerStore.prevValue != null) {
+              /**
+               * Set preValue to be value so that no new label
+               * should be started, otherwise, it will take a full
+               * `animationDurationUpdate` time to finish the
+               * animation, which is not expected.
+               */
+              labelInnerStore.prevValue = labelInnerStore.value;
+            }
+          }
+        } // Not change anything if only order changed.
+        // Especially not change label.
+        else {
+            updateStyle(el, data, newIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, coord.type === 'polar');
+          }
+
+        if (isInitSort) {
+          el.attr({
+            shape: layout
+          });
+        } else if (realtimeSortCfg) {
+          updateRealtimeAnimation(realtimeSortCfg, animationModel, el, layout, newIndex, isHorizontalOrRadial, true, isChangeOrder);
+        } else {
+          updateProps(el, {
+            shape: layout
+          }, seriesModel, newIndex, null);
+        }
+
+        data.setItemGraphicEl(newIndex, el);
+        el.ignore = isClipped;
+        group.add(el);
+      }).remove(function (dataIndex) {
+        var el = oldData.getItemGraphicEl(dataIndex);
+        el && removeElementWithFadeOut(el, seriesModel, dataIndex);
+      }).execute();
+      var bgGroup = this._backgroundGroup || (this._backgroundGroup = new Group());
+      bgGroup.removeAll();
+
+      for (var i = 0; i < bgEls.length; ++i) {
+        bgGroup.add(bgEls[i]);
+      }
+
+      group.add(bgGroup);
+      this._backgroundEls = bgEls;
+      this._data = data;
+    };
+
+    BarView.prototype._renderLarge = function (seriesModel, ecModel, api) {
+      this._clear();
+
+      createLarge(seriesModel, this.group);
+
+      this._updateLargeClip(seriesModel);
+    };
+
+    BarView.prototype._incrementalRenderLarge = function (params, seriesModel) {
+      this._removeBackground();
+
+      createLarge(seriesModel, this.group, this._progressiveEls, true);
+    };
+
+    BarView.prototype._updateLargeClip = function (seriesModel) {
+      // Use clipPath in large mode.
+      var clipPath = seriesModel.get('clip', true) && createClipPath(seriesModel.coordinateSystem, false, seriesModel);
+      var group = this.group;
+
+      if (clipPath) {
+        group.setClipPath(clipPath);
+      } else {
+        group.removeClipPath();
+      }
+    };
+
+    BarView.prototype._enableRealtimeSort = function (realtimeSortCfg, data, api) {
+      var _this = this; // If no data in the first frame, wait for data to initSort
+
+
+      if (!data.count()) {
+        return;
+      }
+
+      var baseAxis = realtimeSortCfg.baseAxis;
+
+      if (this._isFirstFrame) {
+        this._dispatchInitSort(data, realtimeSortCfg, api);
+
+        this._isFirstFrame = false;
+      } else {
+        var orderMapping_1 = function (idx) {
+          var el = data.getItemGraphicEl(idx);
+          var shape = el && el.shape;
+          return shape && // The result should be consistent with the initial sort by data value.
+          // Do not support the case that both positive and negative exist.
+          Math.abs(baseAxis.isHorizontal() ? shape.height : shape.width) // If data is NaN, shape.xxx may be NaN, so use || 0 here in case
+          || 0;
+        };
+
+        this._onRendered = function () {
+          _this._updateSortWithinSameData(data, orderMapping_1, baseAxis, api);
+        };
+
+        api.getZr().on('rendered', this._onRendered);
+      }
+    };
+
+    BarView.prototype._dataSort = function (data, baseAxis, orderMapping) {
+      var info = [];
+      data.each(data.mapDimension(baseAxis.dim), function (ordinalNumber, dataIdx) {
+        var mappedValue = orderMapping(dataIdx);
+        mappedValue = mappedValue == null ? NaN : mappedValue;
+        info.push({
+          dataIndex: dataIdx,
+          mappedValue: mappedValue,
+          ordinalNumber: ordinalNumber
+        });
+      });
+      info.sort(function (a, b) {
+        // If NaN, it will be treated as min val.
+        return b.mappedValue - a.mappedValue;
+      });
+      return {
+        ordinalNumbers: map(info, function (item) {
+          return item.ordinalNumber;
+        })
+      };
+    };
+
+    BarView.prototype._isOrderChangedWithinSameData = function (data, orderMapping, baseAxis) {
+      var scale = baseAxis.scale;
+      var ordinalDataDim = data.mapDimension(baseAxis.dim);
+      var lastValue = Number.MAX_VALUE;
+
+      for (var tickNum = 0, len = scale.getOrdinalMeta().categories.length; tickNum < len; ++tickNum) {
+        var rawIdx = data.rawIndexOf(ordinalDataDim, scale.getRawOrdinalNumber(tickNum));
+        var value = rawIdx < 0 // If some tick have no bar, the tick will be treated as min.
+        ? Number.MIN_VALUE // PENDING: if dataZoom on baseAxis exits, is it a performance issue?
+        : orderMapping(data.indexOfRawIndex(rawIdx));
+
+        if (value > lastValue) {
+          return true;
+        }
+
+        lastValue = value;
+      }
+
+      return false;
+    };
+    /*
+     * Consider the case when A and B changed order, whose representing
+     * bars are both out of sight, we don't wish to trigger reorder action
+     * as long as the order in the view doesn't change.
+     */
+
+
+    BarView.prototype._isOrderDifferentInView = function (orderInfo, baseAxis) {
+      var scale = baseAxis.scale;
+      var extent = scale.getExtent();
+      var tickNum = Math.max(0, extent[0]);
+      var tickMax = Math.min(extent[1], scale.getOrdinalMeta().categories.length - 1);
+
+      for (; tickNum <= tickMax; ++tickNum) {
+        if (orderInfo.ordinalNumbers[tickNum] !== scale.getRawOrdinalNumber(tickNum)) {
+          return true;
+        }
+      }
+    };
+
+    BarView.prototype._updateSortWithinSameData = function (data, orderMapping, baseAxis, api) {
+      if (!this._isOrderChangedWithinSameData(data, orderMapping, baseAxis)) {
+        return;
+      }
+
+      var sortInfo = this._dataSort(data, baseAxis, orderMapping);
+
+      if (this._isOrderDifferentInView(sortInfo, baseAxis)) {
+        this._removeOnRenderedListener(api);
+
+        api.dispatchAction({
+          type: 'changeAxisOrder',
+          componentType: baseAxis.dim + 'Axis',
+          axisId: baseAxis.index,
+          sortInfo: sortInfo
+        });
+      }
+    };
+
+    BarView.prototype._dispatchInitSort = function (data, realtimeSortCfg, api) {
+      var baseAxis = realtimeSortCfg.baseAxis;
+
+      var sortResult = this._dataSort(data, baseAxis, function (dataIdx) {
+        return data.get(data.mapDimension(realtimeSortCfg.otherAxis.dim), dataIdx);
+      });
+
+      api.dispatchAction({
+        type: 'changeAxisOrder',
+        componentType: baseAxis.dim + 'Axis',
+        isInitSort: true,
+        axisId: baseAxis.index,
+        sortInfo: sortResult
+      });
+    };
+
+    BarView.prototype.remove = function (ecModel, api) {
+      this._clear(this._model);
+
+      this._removeOnRenderedListener(api);
+    };
+
+    BarView.prototype.dispose = function (ecModel, api) {
+      this._removeOnRenderedListener(api);
+    };
+
+    BarView.prototype._removeOnRenderedListener = function (api) {
+      if (this._onRendered) {
+        api.getZr().off('rendered', this._onRendered);
+        this._onRendered = null;
+      }
+    };
+
+    BarView.prototype._clear = function (model) {
+      var group = this.group;
+      var data = this._data;
+
+      if (model && model.isAnimationEnabled() && data && !this._isLargeDraw) {
+        this._removeBackground();
+
+        this._backgroundEls = [];
+        data.eachItemGraphicEl(function (el) {
+          removeElementWithFadeOut(el, model, getECData(el).dataIndex);
+        });
+      } else {
+        group.removeAll();
+      }
+
+      this._data = null;
+      this._isFirstFrame = true;
+    };
+
+    BarView.prototype._removeBackground = function () {
+      this.group.remove(this._backgroundGroup);
+      this._backgroundGroup = null;
+    };
+
+    BarView.type = 'bar';
+    return BarView;
+  }(ChartView);
+
+  var clip = {
+    cartesian2d: function (coordSysBoundingRect, layout) {
+      var signWidth = layout.width < 0 ? -1 : 1;
+      var signHeight = layout.height < 0 ? -1 : 1; // Needs positive width and height
+
+      if (signWidth < 0) {
+        layout.x += layout.width;
+        layout.width = -layout.width;
+      }
+
+      if (signHeight < 0) {
+        layout.y += layout.height;
+        layout.height = -layout.height;
+      }
+
+      var coordSysX2 = coordSysBoundingRect.x + coordSysBoundingRect.width;
+      var coordSysY2 = coordSysBoundingRect.y + coordSysBoundingRect.height;
+      var x = mathMax$5(layout.x, coordSysBoundingRect.x);
+      var x2 = mathMin$5(layout.x + layout.width, coordSysX2);
+      var y = mathMax$5(layout.y, coordSysBoundingRect.y);
+      var y2 = mathMin$5(layout.y + layout.height, coordSysY2);
+      var xClipped = x2 < x;
+      var yClipped = y2 < y; // When xClipped or yClipped, the element will be marked as `ignore`.
+      // But we should also place the element at the edge of the coord sys bounding rect.
+      // Beause if data changed and the bar show again, its transition animaiton
+      // will begin at this place.
+
+      layout.x = xClipped && x > coordSysX2 ? x2 : x;
+      layout.y = yClipped && y > coordSysY2 ? y2 : y;
+      layout.width = xClipped ? 0 : x2 - x;
+      layout.height = yClipped ? 0 : y2 - y; // Reverse back
+
+      if (signWidth < 0) {
+        layout.x += layout.width;
+        layout.width = -layout.width;
+      }
+
+      if (signHeight < 0) {
+        layout.y += layout.height;
+        layout.height = -layout.height;
+      }
+
+      return xClipped || yClipped;
+    },
+    polar: function (coordSysClipArea, layout) {
+      var signR = layout.r0 <= layout.r ? 1 : -1; // Make sure r is larger than r0
+
+      if (signR < 0) {
+        var tmp = layout.r;
+        layout.r = layout.r0;
+        layout.r0 = tmp;
+      }
+
+      var r = mathMin$5(layout.r, coordSysClipArea.r);
+      var r0 = mathMax$5(layout.r0, coordSysClipArea.r0);
+      layout.r = r;
+      layout.r0 = r0;
+      var clipped = r - r0 < 0; // Reverse back
+
+      if (signR < 0) {
+        var tmp = layout.r;
+        layout.r = layout.r0;
+        layout.r0 = tmp;
+      }
+
+      return clipped;
+    }
+  };
+  var elementCreator = {
+    cartesian2d: function (seriesModel, data, newIndex, layout, isHorizontal, animationModel, axisModel, isUpdate, roundCap) {
+      var rect = new Rect({
+        shape: extend({}, layout),
+        z2: 1
+      });
+      rect.__dataIndex = newIndex;
+      rect.name = 'item';
+
+      if (animationModel) {
+        var rectShape = rect.shape;
+        var animateProperty = isHorizontal ? 'height' : 'width';
+        rectShape[animateProperty] = 0;
+      }
+
+      return rect;
+    },
+    polar: function (seriesModel, data, newIndex, layout, isRadial, animationModel, axisModel, isUpdate, roundCap) {
+      var ShapeClass = !isRadial && roundCap ? SausagePath : Sector;
+      var sector = new ShapeClass({
+        shape: layout,
+        z2: 1
+      });
+      sector.name = 'item';
+      var positionMap = createPolarPositionMapping(isRadial);
+      sector.calculateTextPosition = createSectorCalculateTextPosition(positionMap, {
+        isRoundCap: ShapeClass === SausagePath
+      }); // Animation
+
+      if (animationModel) {
+        var sectorShape = sector.shape;
+        var animateProperty = isRadial ? 'r' : 'endAngle';
+        var animateTarget = {};
+        sectorShape[animateProperty] = isRadial ? 0 : layout.startAngle;
+        animateTarget[animateProperty] = layout[animateProperty];
+        (isUpdate ? updateProps : initProps)(sector, {
+          shape: animateTarget // __value: typeof dataValue === 'string' ? parseInt(dataValue, 10) : dataValue
+
+        }, animationModel);
+      }
+
+      return sector;
+    }
+  };
+
+  function shouldRealtimeSort(seriesModel, coordSys) {
+    var realtimeSortOption = seriesModel.get('realtimeSort', true);
+    var baseAxis = coordSys.getBaseAxis();
+    {
+      if (realtimeSortOption) {
+        if (baseAxis.type !== 'category') {
+          warn('`realtimeSort` will not work because this bar series is not based on a category axis.');
+        }
+
+        if (coordSys.type !== 'cartesian2d') {
+          warn('`realtimeSort` will not work because this bar series is not on cartesian2d.');
+        }
+      }
+    }
+
+    if (realtimeSortOption && baseAxis.type === 'category' && coordSys.type === 'cartesian2d') {
+      return {
+        baseAxis: baseAxis,
+        otherAxis: coordSys.getOtherAxis(baseAxis)
+      };
+    }
+  }
+
+  function updateRealtimeAnimation(realtimeSortCfg, seriesAnimationModel, el, layout, newIndex, isHorizontal, isUpdate, isChangeOrder) {
+    var seriesTarget;
+    var axisTarget;
+
+    if (isHorizontal) {
+      axisTarget = {
+        x: layout.x,
+        width: layout.width
+      };
+      seriesTarget = {
+        y: layout.y,
+        height: layout.height
+      };
+    } else {
+      axisTarget = {
+        y: layout.y,
+        height: layout.height
+      };
+      seriesTarget = {
+        x: layout.x,
+        width: layout.width
+      };
+    }
+
+    if (!isChangeOrder) {
+      // Keep the original growth animation if only axis order changed.
+      // Not start a new animation.
+      (isUpdate ? updateProps : initProps)(el, {
+        shape: seriesTarget
+      }, seriesAnimationModel, newIndex, null);
+    }
+
+    var axisAnimationModel = seriesAnimationModel ? realtimeSortCfg.baseAxis.model : null;
+    (isUpdate ? updateProps : initProps)(el, {
+      shape: axisTarget
+    }, axisAnimationModel, newIndex);
+  }
+
+  function checkPropertiesNotValid(obj, props) {
+    for (var i = 0; i < props.length; i++) {
+      if (!isFinite(obj[props[i]])) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  var rectPropties = ['x', 'y', 'width', 'height'];
+  var polarPropties = ['cx', 'cy', 'r', 'startAngle', 'endAngle'];
+  var isValidLayout = {
+    cartesian2d: function (layout) {
+      return !checkPropertiesNotValid(layout, rectPropties);
+    },
+    polar: function (layout) {
+      return !checkPropertiesNotValid(layout, polarPropties);
+    }
+  };
+  var getLayout = {
+    // itemModel is only used to get borderWidth, which is not needed
+    // when calculating bar background layout.
+    cartesian2d: function (data, dataIndex, itemModel) {
+      var layout = data.getItemLayout(dataIndex);
+      var fixedLineWidth = itemModel ? getLineWidth(itemModel, layout) : 0; // fix layout with lineWidth
+
+      var signX = layout.width > 0 ? 1 : -1;
+      var signY = layout.height > 0 ? 1 : -1;
+      return {
+        x: layout.x + signX * fixedLineWidth / 2,
+        y: layout.y + signY * fixedLineWidth / 2,
+        width: layout.width - signX * fixedLineWidth,
+        height: layout.height - signY * fixedLineWidth
+      };
+    },
+    polar: function (data, dataIndex, itemModel) {
+      var layout = data.getItemLayout(dataIndex);
+      return {
+        cx: layout.cx,
+        cy: layout.cy,
+        r0: layout.r0,
+        r: layout.r,
+        startAngle: layout.startAngle,
+        endAngle: layout.endAngle,
+        clockwise: layout.clockwise
+      };
+    }
+  };
+
+  function isZeroOnPolar(layout) {
+    return layout.startAngle != null && layout.endAngle != null && layout.startAngle === layout.endAngle;
+  }
+
+  function createPolarPositionMapping(isRadial) {
+    return function (isRadial) {
+      var arcOrAngle = isRadial ? 'Arc' : 'Angle';
+      return function (position) {
+        switch (position) {
+          case 'start':
+          case 'insideStart':
+          case 'end':
+          case 'insideEnd':
+            return position + arcOrAngle;
+
+          default:
+            return position;
+        }
+      };
+    }(isRadial);
+  }
+
+  function updateStyle(el, data, dataIndex, itemModel, layout, seriesModel, isHorizontalOrRadial, isPolar) {
+    var style = data.getItemVisual(dataIndex, 'style');
+
+    if (!isPolar) {
+      el.setShape('r', itemModel.get(['itemStyle', 'borderRadius']) || 0);
+    }
+
+    el.useStyle(style);
+    var cursorStyle = itemModel.getShallow('cursor');
+    cursorStyle && el.attr('cursor', cursorStyle);
+    var labelPositionOutside = isPolar ? isHorizontalOrRadial ? layout.r >= layout.r0 ? 'endArc' : 'startArc' : layout.endAngle >= layout.startAngle ? 'endAngle' : 'startAngle' : isHorizontalOrRadial ? layout.height >= 0 ? 'bottom' : 'top' : layout.width >= 0 ? 'right' : 'left';
+    var labelStatesModels = getLabelStatesModels(itemModel);
+    setLabelStyle(el, labelStatesModels, {
+      labelFetcher: seriesModel,
+      labelDataIndex: dataIndex,
+      defaultText: getDefaultLabel(seriesModel.getData(), dataIndex),
+      inheritColor: style.fill,
+      defaultOpacity: style.opacity,
+      defaultOutsidePosition: labelPositionOutside
+    });
+    var label = el.getTextContent();
+
+    if (isPolar && label) {
+      var position = itemModel.get(['label', 'position']);
+      el.textConfig.inside = position === 'middle' ? true : null;
+      setSectorTextRotation(el, position === 'outside' ? labelPositionOutside : position, createPolarPositionMapping(isHorizontalOrRadial), itemModel.get(['label', 'rotate']));
+    }
+
+    setLabelValueAnimation(label, labelStatesModels, seriesModel.getRawValue(dataIndex), function (value) {
+      return getDefaultInterpolatedLabel(data, value);
+    });
+    var emphasisModel = itemModel.getModel(['emphasis']);
+    toggleHoverEmphasis(el, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled'));
+    setStatesStylesFromModel(el, itemModel);
+
+    if (isZeroOnPolar(layout)) {
+      el.style.fill = 'none';
+      el.style.stroke = 'none';
+      each(el.states, function (state) {
+        if (state.style) {
+          state.style.fill = state.style.stroke = 'none';
+        }
+      });
+    }
+  } // In case width or height are too small.
+
+
+  function getLineWidth(itemModel, rawLayout) {
+    // Has no border.
+    var borderColor = itemModel.get(['itemStyle', 'borderColor']);
+
+    if (!borderColor || borderColor === 'none') {
+      return 0;
+    }
+
+    var lineWidth = itemModel.get(['itemStyle', 'borderWidth']) || 0; // width or height may be NaN for empty data
+
+    var width = isNaN(rawLayout.width) ? Number.MAX_VALUE : Math.abs(rawLayout.width);
+    var height = isNaN(rawLayout.height) ? Number.MAX_VALUE : Math.abs(rawLayout.height);
+    return Math.min(lineWidth, width, height);
+  }
+
+  var LagePathShape =
+  /** @class */
+  function () {
+    function LagePathShape() {}
+
+    return LagePathShape;
+  }();
+
+  var LargePath =
+  /** @class */
+  function (_super) {
+    __extends(LargePath, _super);
+
+    function LargePath(opts) {
+      var _this = _super.call(this, opts) || this;
+
+      _this.type = 'largeBar';
+      return _this;
+    }
+
+    LargePath.prototype.getDefaultShape = function () {
+      return new LagePathShape();
+    };
+
+    LargePath.prototype.buildPath = function (ctx, shape) {
+      // Drawing lines is more efficient than drawing
+      // a whole line or drawing rects.
+      var points = shape.points;
+      var baseDimIdx = this.baseDimIdx;
+      var valueDimIdx = 1 - this.baseDimIdx;
+      var startPoint = [];
+      var size = [];
+      var barWidth = this.barWidth;
+
+      for (var i = 0; i < points.length; i += 3) {
+        size[baseDimIdx] = barWidth;
+        size[valueDimIdx] = points[i + 2];
+        startPoint[baseDimIdx] = points[i + baseDimIdx];
+        startPoint[valueDimIdx] = points[i + valueDimIdx];
+        ctx.rect(startPoint[0], startPoint[1], size[0], size[1]);
+      }
+    };
+
+    return LargePath;
+  }(Path);
+
+  function createLarge(seriesModel, group, progressiveEls, incremental) {
+    // TODO support polar
+    var data = seriesModel.getData();
+    var baseDimIdx = data.getLayout('valueAxisHorizontal') ? 1 : 0;
+    var largeDataIndices = data.getLayout('largeDataIndices');
+    var barWidth = data.getLayout('size');
+    var backgroundModel = seriesModel.getModel('backgroundStyle');
+    var bgPoints = data.getLayout('largeBackgroundPoints');
+
+    if (bgPoints) {
+      var bgEl = new LargePath({
+        shape: {
+          points: bgPoints
+        },
+        incremental: !!incremental,
+        silent: true,
+        z2: 0
+      });
+      bgEl.baseDimIdx = baseDimIdx;
+      bgEl.largeDataIndices = largeDataIndices;
+      bgEl.barWidth = barWidth;
+      bgEl.useStyle(backgroundModel.getItemStyle());
+      group.add(bgEl);
+      progressiveEls && progressiveEls.push(bgEl);
+    }
+
+    var el = new LargePath({
+      shape: {
+        points: data.getLayout('largePoints')
+      },
+      incremental: !!incremental,
+      z2: 1
+    });
+    el.baseDimIdx = baseDimIdx;
+    el.largeDataIndices = largeDataIndices;
+    el.barWidth = barWidth;
+    group.add(el);
+    el.useStyle(data.getVisual('style')); // Enable tooltip and user mouse/touch event handlers.
+
+    getECData(el).seriesIndex = seriesModel.seriesIndex;
+
+    if (!seriesModel.get('silent')) {
+      el.on('mousedown', largePathUpdateDataIndex);
+      el.on('mousemove', largePathUpdateDataIndex);
+    }
+
+    progressiveEls && progressiveEls.push(el);
+  } // Use throttle to avoid frequently traverse to find dataIndex.
+
+
+  var largePathUpdateDataIndex = throttle(function (event) {
+    var largePath = this;
+    var dataIndex = largePathFindDataIndex(largePath, event.offsetX, event.offsetY);
+    getECData(largePath).dataIndex = dataIndex >= 0 ? dataIndex : null;
+  }, 30, false);
+
+  function largePathFindDataIndex(largePath, x, y) {
+    var baseDimIdx = largePath.baseDimIdx;
+    var valueDimIdx = 1 - baseDimIdx;
+    var points = largePath.shape.points;
+    var largeDataIndices = largePath.largeDataIndices;
+    var startPoint = [];
+    var size = [];
+    var barWidth = largePath.barWidth;
+
+    for (var i = 0, len = points.length / 3; i < len; i++) {
+      var ii = i * 3;
+      size[baseDimIdx] = barWidth;
+      size[valueDimIdx] = points[ii + 2];
+      startPoint[baseDimIdx] = points[ii + baseDimIdx];
+      startPoint[valueDimIdx] = points[ii + valueDimIdx];
+
+      if (size[valueDimIdx] < 0) {
+        startPoint[valueDimIdx] += size[valueDimIdx];
+        size[valueDimIdx] = -size[valueDimIdx];
+      }
+
+      if (x >= startPoint[0] && x <= startPoint[0] + size[0] && y >= startPoint[1] && y <= startPoint[1] + size[1]) {
+        return largeDataIndices[i];
+      }
+    }
+
+    return -1;
+  }
+
+  function createBackgroundShape(isHorizontalOrRadial, layout, coord) {
+    if (isCoordinateSystemType(coord, 'cartesian2d')) {
+      var rectShape = layout;
+      var coordLayout = coord.getArea();
+      return {
+        x: isHorizontalOrRadial ? rectShape.x : coordLayout.x,
+        y: isHorizontalOrRadial ? coordLayout.y : rectShape.y,
+        width: isHorizontalOrRadial ? rectShape.width : coordLayout.width,
+        height: isHorizontalOrRadial ? coordLayout.height : rectShape.height
+      };
+    } else {
+      var coordLayout = coord.getArea();
+      var sectorShape = layout;
+      return {
+        cx: coordLayout.cx,
+        cy: coordLayout.cy,
+        r0: isHorizontalOrRadial ? coordLayout.r0 : sectorShape.r0,
+        r: isHorizontalOrRadial ? coordLayout.r : sectorShape.r,
+        startAngle: isHorizontalOrRadial ? sectorShape.startAngle : 0,
+        endAngle: isHorizontalOrRadial ? sectorShape.endAngle : Math.PI * 2
+      };
+    }
+  }
+
+  function createBackgroundEl(coord, isHorizontalOrRadial, layout) {
+    var ElementClz = coord.type === 'polar' ? Sector : Rect;
+    return new ElementClz({
+      shape: createBackgroundShape(isHorizontalOrRadial, layout, coord),
+      silent: true,
+      z2: 0
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install$2(registers) {
+    registers.registerChartView(BarView);
+    registers.registerSeriesModel(BarSeriesModel);
+    registers.registerLayout(registers.PRIORITY.VISUAL.LAYOUT, curry(layout, 'bar')); // Do layout after other overall layout, which can preapre some informations.
+
+    registers.registerLayout(registers.PRIORITY.VISUAL.PROGRESSIVE_LAYOUT, createProgressiveLayout('bar')); // Down sample after filter
+
+    registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('bar'));
+    /**
+     * @payload
+     * @property {string} [componentType=series]
+     * @property {number} [dx]
+     * @property {number} [dy]
+     * @property {number} [zoom]
+     * @property {number} [originX]
+     * @property {number} [originY]
+     */
+
+    registers.registerAction({
+      type: 'changeAxisOrder',
+      event: 'changeAxisOrder',
+      update: 'update'
+    }, function (payload, ecModel) {
+      var componentType = payload.componentType || 'series';
+      ecModel.eachComponent({
+        mainType: componentType,
+        query: payload
+      }, function (componentModel) {
+        if (payload.sortInfo) {
+          componentModel.axis.setCategorySortInfo(payload.sortInfo);
+        }
+      });
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+
+  use(install$2);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 LineSeriesModel =
+  /** @class */
+  function (_super) {
+    __extends(LineSeriesModel, _super);
+
+    function LineSeriesModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = LineSeriesModel.type;
+      _this.hasSymbolVisual = true;
+      return _this;
+    }
+
+    LineSeriesModel.prototype.getInitialData = function (option) {
+      {
+        var coordSys = option.coordinateSystem;
+
+        if (coordSys !== 'polar' && coordSys !== 'cartesian2d') {
+          throw new Error('Line not support coordinateSystem besides cartesian and polar');
+        }
+      }
+      return createSeriesData(null, this, {
+        useEncodeDefaulter: true
+      });
+    };
+
+    LineSeriesModel.prototype.getLegendIcon = function (opt) {
+      var group = new Group();
+      var line = createSymbol('line', 0, opt.itemHeight / 2, opt.itemWidth, 0, opt.lineStyle.stroke, false);
+      group.add(line);
+      line.setStyle(opt.lineStyle);
+      var visualType = this.getData().getVisual('symbol');
+      var visualRotate = this.getData().getVisual('symbolRotate');
+      var symbolType = visualType === 'none' ? 'circle' : visualType; // Symbol size is 80% when there is a line
+
+      var size = opt.itemHeight * 0.8;
+      var symbol = createSymbol(symbolType, (opt.itemWidth - size) / 2, (opt.itemHeight - size) / 2, size, size, opt.itemStyle.fill);
+      group.add(symbol);
+      symbol.setStyle(opt.itemStyle);
+      var symbolRotate = opt.iconRotate === 'inherit' ? visualRotate : opt.iconRotate || 0;
+      symbol.rotation = symbolRotate * Math.PI / 180;
+      symbol.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]);
+
+      if (symbolType.indexOf('empty') > -1) {
+        symbol.style.stroke = symbol.style.fill;
+        symbol.style.fill = '#fff';
+        symbol.style.lineWidth = 2;
+      }
+
+      return group;
+    };
+
+    LineSeriesModel.type = 'series.line';
+    LineSeriesModel.dependencies = ['grid', 'polar'];
+    LineSeriesModel.defaultOption = {
+      // zlevel: 0,
+      z: 3,
+      coordinateSystem: 'cartesian2d',
+      legendHoverLink: true,
+      clip: true,
+      label: {
+        position: 'top'
+      },
+      // itemStyle: {
+      // },
+      endLabel: {
+        show: false,
+        valueAnimation: true,
+        distance: 8
+      },
+      lineStyle: {
+        width: 2,
+        type: 'solid'
+      },
+      emphasis: {
+        scale: true
+      },
+      // areaStyle: {
+      // origin of areaStyle. Valid values:
+      // `'auto'/null/undefined`: from axisLine to data
+      // `'start'`: from min to data
+      // `'end'`: from data to max
+      // origin: 'auto'
+      // },
+      // false, 'start', 'end', 'middle'
+      step: false,
+      // Disabled if step is true
+      smooth: false,
+      smoothMonotone: null,
+      symbol: 'emptyCircle',
+      symbolSize: 4,
+      symbolRotate: null,
+      showSymbol: true,
+      // `false`: follow the label interval strategy.
+      // `true`: show all symbols.
+      // `'auto'`: If possible, show all symbols, otherwise
+      //           follow the label interval strategy.
+      showAllSymbol: 'auto',
+      // Whether to connect break point.
+      connectNulls: false,
+      // Sampling for large data. Can be: 'average', 'max', 'min', 'sum', 'lttb'.
+      sampling: 'none',
+      animationEasing: 'linear',
+      // Disable progressive
+      progressive: 0,
+      hoverLayerThreshold: Infinity,
+      universalTransition: {
+        divideShape: 'clone'
+      },
+      triggerLineEvent: false
+    };
+    return LineSeriesModel;
+  }(SeriesModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 Symbol$1 =
+  /** @class */
+  function (_super) {
+    __extends(Symbol, _super);
+
+    function Symbol(data, idx, seriesScope, opts) {
+      var _this = _super.call(this) || this;
+
+      _this.updateData(data, idx, seriesScope, opts);
+
+      return _this;
+    }
+
+    Symbol.prototype._createSymbol = function (symbolType, data, idx, symbolSize, keepAspect) {
+      // Remove paths created before
+      this.removeAll(); // let symbolPath = createSymbol(
+      //     symbolType, -0.5, -0.5, 1, 1, color
+      // );
+      // If width/height are set too small (e.g., set to 1) on ios10
+      // and macOS Sierra, a circle stroke become a rect, no matter what
+      // the scale is set. So we set width/height as 2. See #4150.
+
+      var symbolPath = createSymbol(symbolType, -1, -1, 2, 2, null, keepAspect);
+      symbolPath.attr({
+        z2: 100,
+        culling: true,
+        scaleX: symbolSize[0] / 2,
+        scaleY: symbolSize[1] / 2
+      }); // Rewrite drift method
+
+      symbolPath.drift = driftSymbol;
+      this._symbolType = symbolType;
+      this.add(symbolPath);
+    };
+    /**
+     * Stop animation
+     * @param {boolean} toLastFrame
+     */
+
+
+    Symbol.prototype.stopSymbolAnimation = function (toLastFrame) {
+      this.childAt(0).stopAnimation(null, toLastFrame);
+    };
+
+    Symbol.prototype.getSymbolType = function () {
+      return this._symbolType;
+    };
+    /**
+     * FIXME:
+     * Caution: This method breaks the encapsulation of this module,
+     * but it indeed brings convenience. So do not use the method
+     * unless you detailedly know all the implements of `Symbol`,
+     * especially animation.
+     *
+     * Get symbol path element.
+     */
+
+
+    Symbol.prototype.getSymbolPath = function () {
+      return this.childAt(0);
+    };
+    /**
+     * Highlight symbol
+     */
+
+
+    Symbol.prototype.highlight = function () {
+      enterEmphasis(this.childAt(0));
+    };
+    /**
+     * Downplay symbol
+     */
+
+
+    Symbol.prototype.downplay = function () {
+      leaveEmphasis(this.childAt(0));
+    };
+    /**
+     * @param {number} zlevel
+     * @param {number} z
+     */
+
+
+    Symbol.prototype.setZ = function (zlevel, z) {
+      var symbolPath = this.childAt(0);
+      symbolPath.zlevel = zlevel;
+      symbolPath.z = z;
+    };
+
+    Symbol.prototype.setDraggable = function (draggable, hasCursorOption) {
+      var symbolPath = this.childAt(0);
+      symbolPath.draggable = draggable;
+      symbolPath.cursor = !hasCursorOption && draggable ? 'move' : symbolPath.cursor;
+    };
+    /**
+     * Update symbol properties
+     */
+
+
+    Symbol.prototype.updateData = function (data, idx, seriesScope, opts) {
+      this.silent = false;
+      var symbolType = data.getItemVisual(idx, 'symbol') || 'circle';
+      var seriesModel = data.hostModel;
+      var symbolSize = Symbol.getSymbolSize(data, idx);
+      var isInit = symbolType !== this._symbolType;
+      var disableAnimation = opts && opts.disableAnimation;
+
+      if (isInit) {
+        var keepAspect = data.getItemVisual(idx, 'symbolKeepAspect');
+
+        this._createSymbol(symbolType, data, idx, symbolSize, keepAspect);
+      } else {
+        var symbolPath = this.childAt(0);
+        symbolPath.silent = false;
+        var target = {
+          scaleX: symbolSize[0] / 2,
+          scaleY: symbolSize[1] / 2
+        };
+        disableAnimation ? symbolPath.attr(target) : updateProps(symbolPath, target, seriesModel, idx);
+        saveOldStyle(symbolPath);
+      }
+
+      this._updateCommon(data, idx, symbolSize, seriesScope, opts);
+
+      if (isInit) {
+        var symbolPath = this.childAt(0);
+
+        if (!disableAnimation) {
+          var target = {
+            scaleX: this._sizeX,
+            scaleY: this._sizeY,
+            style: {
+              // Always fadeIn. Because it has fadeOut animation when symbol is removed..
+              opacity: symbolPath.style.opacity
+            }
+          };
+          symbolPath.scaleX = symbolPath.scaleY = 0;
+          symbolPath.style.opacity = 0;
+          initProps(symbolPath, target, seriesModel, idx);
+        }
+      }
+
+      if (disableAnimation) {
+        // Must stop leave transition manually if don't call initProps or updateProps.
+        this.childAt(0).stopAnimation('leave');
+      }
+    };
+
+    Symbol.prototype._updateCommon = function (data, idx, symbolSize, seriesScope, opts) {
+      var symbolPath = this.childAt(0);
+      var seriesModel = data.hostModel;
+      var emphasisItemStyle;
+      var blurItemStyle;
+      var selectItemStyle;
+      var focus;
+      var blurScope;
+      var emphasisDisabled;
+      var labelStatesModels;
+      var hoverScale;
+      var cursorStyle;
+
+      if (seriesScope) {
+        emphasisItemStyle = seriesScope.emphasisItemStyle;
+        blurItemStyle = seriesScope.blurItemStyle;
+        selectItemStyle = seriesScope.selectItemStyle;
+        focus = seriesScope.focus;
+        blurScope = seriesScope.blurScope;
+        labelStatesModels = seriesScope.labelStatesModels;
+        hoverScale = seriesScope.hoverScale;
+        cursorStyle = seriesScope.cursorStyle;
+        emphasisDisabled = seriesScope.emphasisDisabled;
+      }
+
+      if (!seriesScope || data.hasItemOption) {
+        var itemModel = seriesScope && seriesScope.itemModel ? seriesScope.itemModel : data.getItemModel(idx);
+        var emphasisModel = itemModel.getModel('emphasis');
+        emphasisItemStyle = emphasisModel.getModel('itemStyle').getItemStyle();
+        selectItemStyle = itemModel.getModel(['select', 'itemStyle']).getItemStyle();
+        blurItemStyle = itemModel.getModel(['blur', 'itemStyle']).getItemStyle();
+        focus = emphasisModel.get('focus');
+        blurScope = emphasisModel.get('blurScope');
+        emphasisDisabled = emphasisModel.get('disabled');
+        labelStatesModels = getLabelStatesModels(itemModel);
+        hoverScale = emphasisModel.getShallow('scale');
+        cursorStyle = itemModel.getShallow('cursor');
+      }
+
+      var symbolRotate = data.getItemVisual(idx, 'symbolRotate');
+      symbolPath.attr('rotation', (symbolRotate || 0) * Math.PI / 180 || 0);
+      var symbolOffset = normalizeSymbolOffset(data.getItemVisual(idx, 'symbolOffset'), symbolSize);
+
+      if (symbolOffset) {
+        symbolPath.x = symbolOffset[0];
+        symbolPath.y = symbolOffset[1];
+      }
+
+      cursorStyle && symbolPath.attr('cursor', cursorStyle);
+      var symbolStyle = data.getItemVisual(idx, 'style');
+      var visualColor = symbolStyle.fill;
+
+      if (symbolPath instanceof ZRImage) {
+        var pathStyle = symbolPath.style;
+        symbolPath.useStyle(extend({
+          // TODO other properties like x, y ?
+          image: pathStyle.image,
+          x: pathStyle.x,
+          y: pathStyle.y,
+          width: pathStyle.width,
+          height: pathStyle.height
+        }, symbolStyle));
+      } else {
+        if (symbolPath.__isEmptyBrush) {
+          // fill and stroke will be swapped if it's empty.
+          // So we cloned a new style to avoid it affecting the original style in visual storage.
+          // TODO Better implementation. No empty logic!
+          symbolPath.useStyle(extend({}, symbolStyle));
+        } else {
+          symbolPath.useStyle(symbolStyle);
+        } // Disable decal because symbol scale will been applied on the decal.
+
+
+        symbolPath.style.decal = null;
+        symbolPath.setColor(visualColor, opts && opts.symbolInnerColor);
+        symbolPath.style.strokeNoScale = true;
+      }
+
+      var liftZ = data.getItemVisual(idx, 'liftZ');
+      var z2Origin = this._z2;
+
+      if (liftZ != null) {
+        if (z2Origin == null) {
+          this._z2 = symbolPath.z2;
+          symbolPath.z2 += liftZ;
+        }
+      } else if (z2Origin != null) {
+        symbolPath.z2 = z2Origin;
+        this._z2 = null;
+      }
+
+      var useNameLabel = opts && opts.useNameLabel;
+      setLabelStyle(symbolPath, labelStatesModels, {
+        labelFetcher: seriesModel,
+        labelDataIndex: idx,
+        defaultText: getLabelDefaultText,
+        inheritColor: visualColor,
+        defaultOpacity: symbolStyle.opacity
+      }); // Do not execute util needed.
+
+      function getLabelDefaultText(idx) {
+        return useNameLabel ? data.getName(idx) : getDefaultLabel(data, idx);
+      }
+
+      this._sizeX = symbolSize[0] / 2;
+      this._sizeY = symbolSize[1] / 2;
+      var emphasisState = symbolPath.ensureState('emphasis');
+      emphasisState.style = emphasisItemStyle;
+      symbolPath.ensureState('select').style = selectItemStyle;
+      symbolPath.ensureState('blur').style = blurItemStyle;
+
+      if (hoverScale) {
+        var scaleRatio = Math.max(isNumber(hoverScale) ? hoverScale : 1.1, 3 / this._sizeY);
+        emphasisState.scaleX = this._sizeX * scaleRatio;
+        emphasisState.scaleY = this._sizeY * scaleRatio;
+      }
+
+      this.setSymbolScale(1);
+      toggleHoverEmphasis(this, focus, blurScope, emphasisDisabled);
+    };
+
+    Symbol.prototype.setSymbolScale = function (scale) {
+      this.scaleX = this.scaleY = scale;
+    };
+
+    Symbol.prototype.fadeOut = function (cb, seriesModel, opt) {
+      var symbolPath = this.childAt(0);
+      var dataIndex = getECData(this).dataIndex;
+      var animationOpt = opt && opt.animation; // Avoid mistaken hover when fading out
+
+      this.silent = symbolPath.silent = true; // Not show text when animating
+
+      if (opt && opt.fadeLabel) {
+        var textContent = symbolPath.getTextContent();
+
+        if (textContent) {
+          removeElement(textContent, {
+            style: {
+              opacity: 0
+            }
+          }, seriesModel, {
+            dataIndex: dataIndex,
+            removeOpt: animationOpt,
+            cb: function () {
+              symbolPath.removeTextContent();
+            }
+          });
+        }
+      } else {
+        symbolPath.removeTextContent();
+      }
+
+      removeElement(symbolPath, {
+        style: {
+          opacity: 0
+        },
+        scaleX: 0,
+        scaleY: 0
+      }, seriesModel, {
+        dataIndex: dataIndex,
+        cb: cb,
+        removeOpt: animationOpt
+      });
+    };
+
+    Symbol.getSymbolSize = function (data, idx) {
+      return normalizeSymbolSize(data.getItemVisual(idx, 'symbolSize'));
+    };
+
+    return Symbol;
+  }(Group);
+
+  function driftSymbol(dx, dy) {
+    this.parent.drift(dx, dy);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 symbolNeedsDraw(data, point, idx, opt) {
+    return point && !isNaN(point[0]) && !isNaN(point[1]) && !(opt.isIgnore && opt.isIgnore(idx)) // We do not set clipShape on group, because it will cut part of
+    // the symbol element shape. We use the same clip shape here as
+    // the line clip.
+    && !(opt.clipShape && !opt.clipShape.contain(point[0], point[1])) && data.getItemVisual(idx, 'symbol') !== 'none';
+  }
+
+  function normalizeUpdateOpt(opt) {
+    if (opt != null && !isObject(opt)) {
+      opt = {
+        isIgnore: opt
+      };
+    }
+
+    return opt || {};
+  }
+
+  function makeSeriesScope(data) {
+    var seriesModel = data.hostModel;
+    var emphasisModel = seriesModel.getModel('emphasis');
+    return {
+      emphasisItemStyle: emphasisModel.getModel('itemStyle').getItemStyle(),
+      blurItemStyle: seriesModel.getModel(['blur', 'itemStyle']).getItemStyle(),
+      selectItemStyle: seriesModel.getModel(['select', 'itemStyle']).getItemStyle(),
+      focus: emphasisModel.get('focus'),
+      blurScope: emphasisModel.get('blurScope'),
+      emphasisDisabled: emphasisModel.get('disabled'),
+      hoverScale: emphasisModel.get('scale'),
+      labelStatesModels: getLabelStatesModels(seriesModel),
+      cursorStyle: seriesModel.get('cursor')
+    };
+  }
+
+  var SymbolDraw =
+  /** @class */
+  function () {
+    function SymbolDraw(SymbolCtor) {
+      this.group = new Group();
+      this._SymbolCtor = SymbolCtor || Symbol$1;
+    }
+    /**
+     * Update symbols draw by new data
+     */
+
+
+    SymbolDraw.prototype.updateData = function (data, opt) {
+      // Remove progressive els.
+      this._progressiveEls = null;
+      opt = normalizeUpdateOpt(opt);
+      var group = this.group;
+      var seriesModel = data.hostModel;
+      var oldData = this._data;
+      var SymbolCtor = this._SymbolCtor;
+      var disableAnimation = opt.disableAnimation;
+      var seriesScope = makeSeriesScope(data);
+      var symbolUpdateOpt = {
+        disableAnimation: disableAnimation
+      };
+
+      var getSymbolPoint = opt.getSymbolPoint || function (idx) {
+        return data.getItemLayout(idx);
+      }; // There is no oldLineData only when first rendering or switching from
+      // stream mode to normal mode, where previous elements should be removed.
+
+
+      if (!oldData) {
+        group.removeAll();
+      }
+
+      data.diff(oldData).add(function (newIdx) {
+        var point = getSymbolPoint(newIdx);
+
+        if (symbolNeedsDraw(data, point, newIdx, opt)) {
+          var symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt);
+          symbolEl.setPosition(point);
+          data.setItemGraphicEl(newIdx, symbolEl);
+          group.add(symbolEl);
+        }
+      }).update(function (newIdx, oldIdx) {
+        var symbolEl = oldData.getItemGraphicEl(oldIdx);
+        var point = getSymbolPoint(newIdx);
+
+        if (!symbolNeedsDraw(data, point, newIdx, opt)) {
+          group.remove(symbolEl);
+          return;
+        }
+
+        var newSymbolType = data.getItemVisual(newIdx, 'symbol') || 'circle';
+        var oldSymbolType = symbolEl && symbolEl.getSymbolType && symbolEl.getSymbolType();
+
+        if (!symbolEl // Create a new if symbol type changed.
+        || oldSymbolType && oldSymbolType !== newSymbolType) {
+          group.remove(symbolEl);
+          symbolEl = new SymbolCtor(data, newIdx, seriesScope, symbolUpdateOpt);
+          symbolEl.setPosition(point);
+        } else {
+          symbolEl.updateData(data, newIdx, seriesScope, symbolUpdateOpt);
+          var target = {
+            x: point[0],
+            y: point[1]
+          };
+          disableAnimation ? symbolEl.attr(target) : updateProps(symbolEl, target, seriesModel);
+        } // Add back
+
+
+        group.add(symbolEl);
+        data.setItemGraphicEl(newIdx, symbolEl);
+      }).remove(function (oldIdx) {
+        var el = oldData.getItemGraphicEl(oldIdx);
+        el && el.fadeOut(function () {
+          group.remove(el);
+        }, seriesModel);
+      }).execute();
+      this._getSymbolPoint = getSymbolPoint;
+      this._data = data;
+    };
+
+    SymbolDraw.prototype.updateLayout = function () {
+      var _this = this;
+
+      var data = this._data;
+
+      if (data) {
+        // Not use animation
+        data.eachItemGraphicEl(function (el, idx) {
+          var point = _this._getSymbolPoint(idx);
+
+          el.setPosition(point);
+          el.markRedraw();
+        });
+      }
+    };
+
+    SymbolDraw.prototype.incrementalPrepareUpdate = function (data) {
+      this._seriesScope = makeSeriesScope(data);
+      this._data = null;
+      this.group.removeAll();
+    };
+    /**
+     * Update symbols draw by new data
+     */
+
+
+    SymbolDraw.prototype.incrementalUpdate = function (taskParams, data, opt) {
+      // Clear
+      this._progressiveEls = [];
+      opt = normalizeUpdateOpt(opt);
+
+      function updateIncrementalAndHover(el) {
+        if (!el.isGroup) {
+          el.incremental = true;
+          el.ensureState('emphasis').hoverLayer = true;
+        }
+      }
+
+      for (var idx = taskParams.start; idx < taskParams.end; idx++) {
+        var point = data.getItemLayout(idx);
+
+        if (symbolNeedsDraw(data, point, idx, opt)) {
+          var el = new this._SymbolCtor(data, idx, this._seriesScope);
+          el.traverse(updateIncrementalAndHover);
+          el.setPosition(point);
+          this.group.add(el);
+          data.setItemGraphicEl(idx, el);
+
+          this._progressiveEls.push(el);
+        }
+      }
+    };
+
+    SymbolDraw.prototype.eachRendered = function (cb) {
+      traverseElements(this._progressiveEls || this.group, cb);
+    };
+
+    SymbolDraw.prototype.remove = function (enableAnimation) {
+      var group = this.group;
+      var data = this._data; // Incremental model do not have this._data.
+
+      if (data && enableAnimation) {
+        data.eachItemGraphicEl(function (el) {
+          el.fadeOut(function () {
+            group.remove(el);
+          }, data.hostModel);
+        });
+      } else {
+        group.removeAll();
+      }
+    };
+
+    return SymbolDraw;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 prepareDataCoordInfo(coordSys, data, valueOrigin) {
+    var baseAxis = coordSys.getBaseAxis();
+    var valueAxis = coordSys.getOtherAxis(baseAxis);
+    var valueStart = getValueStart(valueAxis, valueOrigin);
+    var baseAxisDim = baseAxis.dim;
+    var valueAxisDim = valueAxis.dim;
+    var valueDim = data.mapDimension(valueAxisDim);
+    var baseDim = data.mapDimension(baseAxisDim);
+    var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;
+    var dims = map(coordSys.dimensions, function (coordDim) {
+      return data.mapDimension(coordDim);
+    });
+    var stacked = false;
+    var stackResultDim = data.getCalculationInfo('stackResultDimension');
+
+    if (isDimensionStacked(data, dims[0]
+    /*, dims[1]*/
+    )) {
+      // jshint ignore:line
+      stacked = true;
+      dims[0] = stackResultDim;
+    }
+
+    if (isDimensionStacked(data, dims[1]
+    /*, dims[0]*/
+    )) {
+      // jshint ignore:line
+      stacked = true;
+      dims[1] = stackResultDim;
+    }
+
+    return {
+      dataDimsForPoint: dims,
+      valueStart: valueStart,
+      valueAxisDim: valueAxisDim,
+      baseAxisDim: baseAxisDim,
+      stacked: !!stacked,
+      valueDim: valueDim,
+      baseDim: baseDim,
+      baseDataOffset: baseDataOffset,
+      stackedOverDimension: data.getCalculationInfo('stackedOverDimension')
+    };
+  }
+
+  function getValueStart(valueAxis, valueOrigin) {
+    var valueStart = 0;
+    var extent = valueAxis.scale.getExtent();
+
+    if (valueOrigin === 'start') {
+      valueStart = extent[0];
+    } else if (valueOrigin === 'end') {
+      valueStart = extent[1];
+    } // If origin is specified as a number, use it as
+    // valueStart directly
+    else if (isNumber(valueOrigin) && !isNaN(valueOrigin)) {
+        valueStart = valueOrigin;
+      } // auto
+      else {
+          // Both positive
+          if (extent[0] > 0) {
+            valueStart = extent[0];
+          } // Both negative
+          else if (extent[1] < 0) {
+              valueStart = extent[1];
+            } // If is one positive, and one negative, onZero shall be true
+
+        }
+
+    return valueStart;
+  }
+
+  function getStackedOnPoint(dataCoordInfo, coordSys, data, idx) {
+    var value = NaN;
+
+    if (dataCoordInfo.stacked) {
+      value = data.get(data.getCalculationInfo('stackedOverDimension'), idx);
+    }
+
+    if (isNaN(value)) {
+      value = dataCoordInfo.valueStart;
+    }
+
+    var baseDataOffset = dataCoordInfo.baseDataOffset;
+    var stackedData = [];
+    stackedData[baseDataOffset] = data.get(dataCoordInfo.baseDim, idx);
+    stackedData[1 - baseDataOffset] = value;
+    return coordSys.dataToPoint(stackedData);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 diffData(oldData, newData) {
+    var diffResult = [];
+    newData.diff(oldData).add(function (idx) {
+      diffResult.push({
+        cmd: '+',
+        idx: idx
+      });
+    }).update(function (newIdx, oldIdx) {
+      diffResult.push({
+        cmd: '=',
+        idx: oldIdx,
+        idx1: newIdx
+      });
+    }).remove(function (idx) {
+      diffResult.push({
+        cmd: '-',
+        idx: idx
+      });
+    }).execute();
+    return diffResult;
+  }
+
+  function lineAnimationDiff(oldData, newData, oldStackedOnPoints, newStackedOnPoints, oldCoordSys, newCoordSys, oldValueOrigin, newValueOrigin) {
+    var diff = diffData(oldData, newData); // let newIdList = newData.mapArray(newData.getId);
+    // let oldIdList = oldData.mapArray(oldData.getId);
+    // convertToIntId(newIdList, oldIdList);
+    // // FIXME One data ?
+    // diff = arrayDiff(oldIdList, newIdList);
+
+    var currPoints = [];
+    var nextPoints = []; // Points for stacking base line
+
+    var currStackedPoints = [];
+    var nextStackedPoints = [];
+    var status = [];
+    var sortedIndices = [];
+    var rawIndices = [];
+    var newDataOldCoordInfo = prepareDataCoordInfo(oldCoordSys, newData, oldValueOrigin); // const oldDataNewCoordInfo = prepareDataCoordInfo(newCoordSys, oldData, newValueOrigin);
+
+    var oldPoints = oldData.getLayout('points') || [];
+    var newPoints = newData.getLayout('points') || [];
+
+    for (var i = 0; i < diff.length; i++) {
+      var diffItem = diff[i];
+      var pointAdded = true;
+      var oldIdx2 = void 0;
+      var newIdx2 = void 0; // FIXME, animation is not so perfect when dataZoom window moves fast
+      // Which is in case remvoing or add more than one data in the tail or head
+
+      switch (diffItem.cmd) {
+        case '=':
+          oldIdx2 = diffItem.idx * 2;
+          newIdx2 = diffItem.idx1 * 2;
+          var currentX = oldPoints[oldIdx2];
+          var currentY = oldPoints[oldIdx2 + 1];
+          var nextX = newPoints[newIdx2];
+          var nextY = newPoints[newIdx2 + 1]; // If previous data is NaN, use next point directly
+
+          if (isNaN(currentX) || isNaN(currentY)) {
+            currentX = nextX;
+            currentY = nextY;
+          }
+
+          currPoints.push(currentX, currentY);
+          nextPoints.push(nextX, nextY);
+          currStackedPoints.push(oldStackedOnPoints[oldIdx2], oldStackedOnPoints[oldIdx2 + 1]);
+          nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]);
+          rawIndices.push(newData.getRawIndex(diffItem.idx1));
+          break;
+
+        case '+':
+          var newIdx = diffItem.idx;
+          var newDataDimsForPoint = newDataOldCoordInfo.dataDimsForPoint;
+          var oldPt = oldCoordSys.dataToPoint([newData.get(newDataDimsForPoint[0], newIdx), newData.get(newDataDimsForPoint[1], newIdx)]);
+          newIdx2 = newIdx * 2;
+          currPoints.push(oldPt[0], oldPt[1]);
+          nextPoints.push(newPoints[newIdx2], newPoints[newIdx2 + 1]);
+          var stackedOnPoint = getStackedOnPoint(newDataOldCoordInfo, oldCoordSys, newData, newIdx);
+          currStackedPoints.push(stackedOnPoint[0], stackedOnPoint[1]);
+          nextStackedPoints.push(newStackedOnPoints[newIdx2], newStackedOnPoints[newIdx2 + 1]);
+          rawIndices.push(newData.getRawIndex(newIdx));
+          break;
+
+        case '-':
+          pointAdded = false;
+      } // Original indices
+
+
+      if (pointAdded) {
+        status.push(diffItem);
+        sortedIndices.push(sortedIndices.length);
+      }
+    } // Diff result may be crossed if all items are changed
+    // Sort by data index
+
+
+    sortedIndices.sort(function (a, b) {
+      return rawIndices[a] - rawIndices[b];
+    });
+    var len = currPoints.length;
+    var sortedCurrPoints = createFloat32Array(len);
+    var sortedNextPoints = createFloat32Array(len);
+    var sortedCurrStackedPoints = createFloat32Array(len);
+    var sortedNextStackedPoints = createFloat32Array(len);
+    var sortedStatus = [];
+
+    for (var i = 0; i < sortedIndices.length; i++) {
+      var idx = sortedIndices[i];
+      var i2 = i * 2;
+      var idx2 = idx * 2;
+      sortedCurrPoints[i2] = currPoints[idx2];
+      sortedCurrPoints[i2 + 1] = currPoints[idx2 + 1];
+      sortedNextPoints[i2] = nextPoints[idx2];
+      sortedNextPoints[i2 + 1] = nextPoints[idx2 + 1];
+      sortedCurrStackedPoints[i2] = currStackedPoints[idx2];
+      sortedCurrStackedPoints[i2 + 1] = currStackedPoints[idx2 + 1];
+      sortedNextStackedPoints[i2] = nextStackedPoints[idx2];
+      sortedNextStackedPoints[i2 + 1] = nextStackedPoints[idx2 + 1];
+      sortedStatus[i] = status[idx];
+    }
+
+    return {
+      current: sortedCurrPoints,
+      next: sortedNextPoints,
+      stackedOnCurrent: sortedCurrStackedPoints,
+      stackedOnNext: sortedNextStackedPoints,
+      status: sortedStatus
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 mathMin$6 = Math.min;
+  var mathMax$6 = Math.max;
+
+  function isPointNull$1(x, y) {
+    return isNaN(x) || isNaN(y);
+  }
+  /**
+   * Draw smoothed line in non-monotone, in may cause undesired curve in extreme
+   * situations. This should be used when points are non-monotone neither in x or
+   * y dimension.
+   */
+
+
+  function drawSegment(ctx, points, start, segLen, allLen, dir, smooth, smoothMonotone, connectNulls) {
+    var prevX;
+    var prevY;
+    var cpx0;
+    var cpy0;
+    var cpx1;
+    var cpy1;
+    var idx = start;
+    var k = 0;
+
+    for (; k < segLen; k++) {
+      var x = points[idx * 2];
+      var y = points[idx * 2 + 1];
+
+      if (idx >= allLen || idx < 0) {
+        break;
+      }
+
+      if (isPointNull$1(x, y)) {
+        if (connectNulls) {
+          idx += dir;
+          continue;
+        }
+
+        break;
+      }
+
+      if (idx === start) {
+        ctx[dir > 0 ? 'moveTo' : 'lineTo'](x, y);
+        cpx0 = x;
+        cpy0 = y;
+      } else {
+        var dx = x - prevX;
+        var dy = y - prevY; // Ignore tiny segment.
+
+        if (dx * dx + dy * dy < 0.5) {
+          idx += dir;
+          continue;
+        }
+
+        if (smooth > 0) {
+          var nextIdx = idx + dir;
+          var nextX = points[nextIdx * 2];
+          var nextY = points[nextIdx * 2 + 1]; // Ignore duplicate point
+
+          while (nextX === x && nextY === y && k < segLen) {
+            k++;
+            nextIdx += dir;
+            idx += dir;
+            nextX = points[nextIdx * 2];
+            nextY = points[nextIdx * 2 + 1];
+            x = points[idx * 2];
+            y = points[idx * 2 + 1];
+            dx = x - prevX;
+            dy = y - prevY;
+          }
+
+          var tmpK = k + 1;
+
+          if (connectNulls) {
+            // Find next point not null
+            while (isPointNull$1(nextX, nextY) && tmpK < segLen) {
+              tmpK++;
+              nextIdx += dir;
+              nextX = points[nextIdx * 2];
+              nextY = points[nextIdx * 2 + 1];
+            }
+          }
+
+          var ratioNextSeg = 0.5;
+          var vx = 0;
+          var vy = 0;
+          var nextCpx0 = void 0;
+          var nextCpy0 = void 0; // Is last point
+
+          if (tmpK >= segLen || isPointNull$1(nextX, nextY)) {
+            cpx1 = x;
+            cpy1 = y;
+          } else {
+            vx = nextX - prevX;
+            vy = nextY - prevY;
+            var dx0 = x - prevX;
+            var dx1 = nextX - x;
+            var dy0 = y - prevY;
+            var dy1 = nextY - y;
+            var lenPrevSeg = void 0;
+            var lenNextSeg = void 0;
+
+            if (smoothMonotone === 'x') {
+              lenPrevSeg = Math.abs(dx0);
+              lenNextSeg = Math.abs(dx1);
+              var dir_1 = vx > 0 ? 1 : -1;
+              cpx1 = x - dir_1 * lenPrevSeg * smooth;
+              cpy1 = y;
+              nextCpx0 = x + dir_1 * lenNextSeg * smooth;
+              nextCpy0 = y;
+            } else if (smoothMonotone === 'y') {
+              lenPrevSeg = Math.abs(dy0);
+              lenNextSeg = Math.abs(dy1);
+              var dir_2 = vy > 0 ? 1 : -1;
+              cpx1 = x;
+              cpy1 = y - dir_2 * lenPrevSeg * smooth;
+              nextCpx0 = x;
+              nextCpy0 = y + dir_2 * lenNextSeg * smooth;
+            } else {
+              lenPrevSeg = Math.sqrt(dx0 * dx0 + dy0 * dy0);
+              lenNextSeg = Math.sqrt(dx1 * dx1 + dy1 * dy1); // Use ratio of seg length
+
+              ratioNextSeg = lenNextSeg / (lenNextSeg + lenPrevSeg);
+              cpx1 = x - vx * smooth * (1 - ratioNextSeg);
+              cpy1 = y - vy * smooth * (1 - ratioNextSeg); // cp0 of next segment
+
+              nextCpx0 = x + vx * smooth * ratioNextSeg;
+              nextCpy0 = y + vy * smooth * ratioNextSeg; // Smooth constraint between point and next point.
+              // Avoid exceeding extreme after smoothing.
+
+              nextCpx0 = mathMin$6(nextCpx0, mathMax$6(nextX, x));
+              nextCpy0 = mathMin$6(nextCpy0, mathMax$6(nextY, y));
+              nextCpx0 = mathMax$6(nextCpx0, mathMin$6(nextX, x));
+              nextCpy0 = mathMax$6(nextCpy0, mathMin$6(nextY, y)); // Reclaculate cp1 based on the adjusted cp0 of next seg.
+
+              vx = nextCpx0 - x;
+              vy = nextCpy0 - y;
+              cpx1 = x - vx * lenPrevSeg / lenNextSeg;
+              cpy1 = y - vy * lenPrevSeg / lenNextSeg; // Smooth constraint between point and prev point.
+              // Avoid exceeding extreme after smoothing.
+
+              cpx1 = mathMin$6(cpx1, mathMax$6(prevX, x));
+              cpy1 = mathMin$6(cpy1, mathMax$6(prevY, y));
+              cpx1 = mathMax$6(cpx1, mathMin$6(prevX, x));
+              cpy1 = mathMax$6(cpy1, mathMin$6(prevY, y)); // Adjust next cp0 again.
+
+              vx = x - cpx1;
+              vy = y - cpy1;
+              nextCpx0 = x + vx * lenNextSeg / lenPrevSeg;
+              nextCpy0 = y + vy * lenNextSeg / lenPrevSeg;
+            }
+          }
+
+          ctx.bezierCurveTo(cpx0, cpy0, cpx1, cpy1, x, y);
+          cpx0 = nextCpx0;
+          cpy0 = nextCpy0;
+        } else {
+          ctx.lineTo(x, y);
+        }
+      }
+
+      prevX = x;
+      prevY = y;
+      idx += dir;
+    }
+
+    return k;
+  }
+
+  var ECPolylineShape =
+  /** @class */
+  function () {
+    function ECPolylineShape() {
+      this.smooth = 0;
+      this.smoothConstraint = true;
+    }
+
+    return ECPolylineShape;
+  }();
+
+  var ECPolyline =
+  /** @class */
+  function (_super) {
+    __extends(ECPolyline, _super);
+
+    function ECPolyline(opts) {
+      var _this = _super.call(this, opts) || this;
+
+      _this.type = 'ec-polyline';
+      return _this;
+    }
+
+    ECPolyline.prototype.getDefaultStyle = function () {
+      return {
+        stroke: '#000',
+        fill: null
+      };
+    };
+
+    ECPolyline.prototype.getDefaultShape = function () {
+      return new ECPolylineShape();
+    };
+
+    ECPolyline.prototype.buildPath = function (ctx, shape) {
+      var points = shape.points;
+      var i = 0;
+      var len = points.length / 2; // const result = getBoundingBox(points, shape.smoothConstraint);
+
+      if (shape.connectNulls) {
+        // Must remove first and last null values avoid draw error in polygon
+        for (; len > 0; len--) {
+          if (!isPointNull$1(points[len * 2 - 2], points[len * 2 - 1])) {
+            break;
+          }
+        }
+
+        for (; i < len; i++) {
+          if (!isPointNull$1(points[i * 2], points[i * 2 + 1])) {
+            break;
+          }
+        }
+      }
+
+      while (i < len) {
+        i += drawSegment(ctx, points, i, len, len, 1, shape.smooth, shape.smoothMonotone, shape.connectNulls) + 1;
+      }
+    };
+
+    ECPolyline.prototype.getPointOn = function (xOrY, dim) {
+      if (!this.path) {
+        this.createPathProxy();
+        this.buildPath(this.path, this.shape);
+      }
+
+      var path = this.path;
+      var data = path.data;
+      var CMD = PathProxy.CMD;
+      var x0;
+      var y0;
+      var isDimX = dim === 'x';
+      var roots = [];
+
+      for (var i = 0; i < data.length;) {
+        var cmd = data[i++];
+        var x = void 0;
+        var y = void 0;
+        var x2 = void 0;
+        var y2 = void 0;
+        var x3 = void 0;
+        var y3 = void 0;
+        var t = void 0;
+
+        switch (cmd) {
+          case CMD.M:
+            x0 = data[i++];
+            y0 = data[i++];
+            break;
+
+          case CMD.L:
+            x = data[i++];
+            y = data[i++];
+            t = isDimX ? (xOrY - x0) / (x - x0) : (xOrY - y0) / (y - y0);
+
+            if (t <= 1 && t >= 0) {
+              var val = isDimX ? (y - y0) * t + y0 : (x - x0) * t + x0;
+              return isDimX ? [xOrY, val] : [val, xOrY];
+            }
+
+            x0 = x;
+            y0 = y;
+            break;
+
+          case CMD.C:
+            x = data[i++];
+            y = data[i++];
+            x2 = data[i++];
+            y2 = data[i++];
+            x3 = data[i++];
+            y3 = data[i++];
+            var nRoot = isDimX ? cubicRootAt(x0, x, x2, x3, xOrY, roots) : cubicRootAt(y0, y, y2, y3, xOrY, roots);
+
+            if (nRoot > 0) {
+              for (var i_1 = 0; i_1 < nRoot; i_1++) {
+                var t_1 = roots[i_1];
+
+                if (t_1 <= 1 && t_1 >= 0) {
+                  var val = isDimX ? cubicAt(y0, y, y2, y3, t_1) : cubicAt(x0, x, x2, x3, t_1);
+                  return isDimX ? [xOrY, val] : [val, xOrY];
+                }
+              }
+            }
+
+            x0 = x3;
+            y0 = y3;
+            break;
+        }
+      }
+    };
+
+    return ECPolyline;
+  }(Path);
+
+  var ECPolygonShape =
+  /** @class */
+  function (_super) {
+    __extends(ECPolygonShape, _super);
+
+    function ECPolygonShape() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    return ECPolygonShape;
+  }(ECPolylineShape);
+
+  var ECPolygon =
+  /** @class */
+  function (_super) {
+    __extends(ECPolygon, _super);
+
+    function ECPolygon(opts) {
+      var _this = _super.call(this, opts) || this;
+
+      _this.type = 'ec-polygon';
+      return _this;
+    }
+
+    ECPolygon.prototype.getDefaultShape = function () {
+      return new ECPolygonShape();
+    };
+
+    ECPolygon.prototype.buildPath = function (ctx, shape) {
+      var points = shape.points;
+      var stackedOnPoints = shape.stackedOnPoints;
+      var i = 0;
+      var len = points.length / 2;
+      var smoothMonotone = shape.smoothMonotone;
+
+      if (shape.connectNulls) {
+        // Must remove first and last null values avoid draw error in polygon
+        for (; len > 0; len--) {
+          if (!isPointNull$1(points[len * 2 - 2], points[len * 2 - 1])) {
+            break;
+          }
+        }
+
+        for (; i < len; i++) {
+          if (!isPointNull$1(points[i * 2], points[i * 2 + 1])) {
+            break;
+          }
+        }
+      }
+
+      while (i < len) {
+        var k = drawSegment(ctx, points, i, len, len, 1, shape.smooth, smoothMonotone, shape.connectNulls);
+        drawSegment(ctx, stackedOnPoints, i + k - 1, k, len, -1, shape.stackedOnSmooth, smoothMonotone, shape.connectNulls);
+        i += k + 1;
+        ctx.closePath();
+      }
+    };
+
+    return ECPolygon;
+  }(Path);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 isPointsSame(points1, points2) {
+    if (points1.length !== points2.length) {
+      return;
+    }
+
+    for (var i = 0; i < points1.length; i++) {
+      if (points1[i] !== points2[i]) {
+        return;
+      }
+    }
+
+    return true;
+  }
+
+  function bboxFromPoints(points) {
+    var minX = Infinity;
+    var minY = Infinity;
+    var maxX = -Infinity;
+    var maxY = -Infinity;
+
+    for (var i = 0; i < points.length;) {
+      var x = points[i++];
+      var y = points[i++];
+
+      if (!isNaN(x)) {
+        minX = Math.min(x, minX);
+        maxX = Math.max(x, maxX);
+      }
+
+      if (!isNaN(y)) {
+        minY = Math.min(y, minY);
+        maxY = Math.max(y, maxY);
+      }
+    }
+
+    return [[minX, minY], [maxX, maxY]];
+  }
+
+  function getBoundingDiff(points1, points2) {
+    var _a = bboxFromPoints(points1),
+        min1 = _a[0],
+        max1 = _a[1];
+
+    var _b = bboxFromPoints(points2),
+        min2 = _b[0],
+        max2 = _b[1]; // Get a max value from each corner of two boundings.
+
+
+    return Math.max(Math.abs(min1[0] - min2[0]), Math.abs(min1[1] - min2[1]), Math.abs(max1[0] - max2[0]), Math.abs(max1[1] - max2[1]));
+  }
+
+  function getSmooth(smooth) {
+    return isNumber(smooth) ? smooth : smooth ? 0.5 : 0;
+  }
+
+  function getStackedOnPoints(coordSys, data, dataCoordInfo) {
+    if (!dataCoordInfo.valueDim) {
+      return [];
+    }
+
+    var len = data.count();
+    var points = createFloat32Array(len * 2);
+
+    for (var idx = 0; idx < len; idx++) {
+      var pt = getStackedOnPoint(dataCoordInfo, coordSys, data, idx);
+      points[idx * 2] = pt[0];
+      points[idx * 2 + 1] = pt[1];
+    }
+
+    return points;
+  }
+
+  function turnPointsIntoStep(points, coordSys, stepTurnAt, connectNulls) {
+    var baseAxis = coordSys.getBaseAxis();
+    var baseIndex = baseAxis.dim === 'x' || baseAxis.dim === 'radius' ? 0 : 1;
+    var stepPoints = [];
+    var i = 0;
+    var stepPt = [];
+    var pt = [];
+    var nextPt = [];
+    var filteredPoints = [];
+
+    if (connectNulls) {
+      for (i = 0; i < points.length; i += 2) {
+        if (!isNaN(points[i]) && !isNaN(points[i + 1])) {
+          filteredPoints.push(points[i], points[i + 1]);
+        }
+      }
+
+      points = filteredPoints;
+    }
+
+    for (i = 0; i < points.length - 2; i += 2) {
+      nextPt[0] = points[i + 2];
+      nextPt[1] = points[i + 3];
+      pt[0] = points[i];
+      pt[1] = points[i + 1];
+      stepPoints.push(pt[0], pt[1]);
+
+      switch (stepTurnAt) {
+        case 'end':
+          stepPt[baseIndex] = nextPt[baseIndex];
+          stepPt[1 - baseIndex] = pt[1 - baseIndex];
+          stepPoints.push(stepPt[0], stepPt[1]);
+          break;
+
+        case 'middle':
+          var middle = (pt[baseIndex] + nextPt[baseIndex]) / 2;
+          var stepPt2 = [];
+          stepPt[baseIndex] = stepPt2[baseIndex] = middle;
+          stepPt[1 - baseIndex] = pt[1 - baseIndex];
+          stepPt2[1 - baseIndex] = nextPt[1 - baseIndex];
+          stepPoints.push(stepPt[0], stepPt[1]);
+          stepPoints.push(stepPt2[0], stepPt2[1]);
+          break;
+
+        default:
+          // default is start
+          stepPt[baseIndex] = pt[baseIndex];
+          stepPt[1 - baseIndex] = nextPt[1 - baseIndex];
+          stepPoints.push(stepPt[0], stepPt[1]);
+      }
+    } // Last points
+
+
+    stepPoints.push(points[i++], points[i++]);
+    return stepPoints;
+  }
+  /**
+   * Clip color stops to edge. Avoid creating too large gradients.
+   * Which may lead to blurry when GPU acceleration is enabled. See #15680
+   *
+   * The stops has been sorted from small to large.
+   */
+
+
+  function clipColorStops(colorStops, maxSize) {
+    var newColorStops = [];
+    var len = colorStops.length; // coord will always < 0 in prevOutOfRangeColorStop.
+
+    var prevOutOfRangeColorStop;
+    var prevInRangeColorStop;
+
+    function lerpStop(stop0, stop1, clippedCoord) {
+      var coord0 = stop0.coord;
+      var p = (clippedCoord - coord0) / (stop1.coord - coord0);
+      var color = lerp$1(p, [stop0.color, stop1.color]);
+      return {
+        coord: clippedCoord,
+        color: color
+      };
+    }
+
+    for (var i = 0; i < len; i++) {
+      var stop_1 = colorStops[i];
+      var coord = stop_1.coord;
+
+      if (coord < 0) {
+        prevOutOfRangeColorStop = stop_1;
+      } else if (coord > maxSize) {
+        if (prevInRangeColorStop) {
+          newColorStops.push(lerpStop(prevInRangeColorStop, stop_1, maxSize));
+        } else if (prevOutOfRangeColorStop) {
+          // If there are two stops and coord range is between these two stops
+          newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0), lerpStop(prevOutOfRangeColorStop, stop_1, maxSize));
+        } // All following stop will be out of range. So just ignore them.
+
+
+        break;
+      } else {
+        if (prevOutOfRangeColorStop) {
+          newColorStops.push(lerpStop(prevOutOfRangeColorStop, stop_1, 0)); // Reset
+
+          prevOutOfRangeColorStop = null;
+        }
+
+        newColorStops.push(stop_1);
+        prevInRangeColorStop = stop_1;
+      }
+    }
+
+    return newColorStops;
+  }
+
+  function getVisualGradient(data, coordSys, api) {
+    var visualMetaList = data.getVisual('visualMeta');
+
+    if (!visualMetaList || !visualMetaList.length || !data.count()) {
+      // When data.count() is 0, gradient range can not be calculated.
+      return;
+    }
+
+    if (coordSys.type !== 'cartesian2d') {
+      {
+        console.warn('Visual map on line style is only supported on cartesian2d.');
+      }
+      return;
+    }
+
+    var coordDim;
+    var visualMeta;
+
+    for (var i = visualMetaList.length - 1; i >= 0; i--) {
+      var dimInfo = data.getDimensionInfo(visualMetaList[i].dimension);
+      coordDim = dimInfo && dimInfo.coordDim; // Can only be x or y
+
+      if (coordDim === 'x' || coordDim === 'y') {
+        visualMeta = visualMetaList[i];
+        break;
+      }
+    }
+
+    if (!visualMeta) {
+      {
+        console.warn('Visual map on line style only support x or y dimension.');
+      }
+      return;
+    } // If the area to be rendered is bigger than area defined by LinearGradient,
+    // the canvas spec prescribes that the color of the first stop and the last
+    // stop should be used. But if two stops are added at offset 0, in effect
+    // browsers use the color of the second stop to render area outside
+    // LinearGradient. So we can only infinitesimally extend area defined in
+    // LinearGradient to render `outerColors`.
+
+
+    var axis = coordSys.getAxis(coordDim); // dataToCoord mapping may not be linear, but must be monotonic.
+
+    var colorStops = map(visualMeta.stops, function (stop) {
+      // offset will be calculated later.
+      return {
+        coord: axis.toGlobalCoord(axis.dataToCoord(stop.value)),
+        color: stop.color
+      };
+    });
+    var stopLen = colorStops.length;
+    var outerColors = visualMeta.outerColors.slice();
+
+    if (stopLen && colorStops[0].coord > colorStops[stopLen - 1].coord) {
+      colorStops.reverse();
+      outerColors.reverse();
+    }
+
+    var colorStopsInRange = clipColorStops(colorStops, coordDim === 'x' ? api.getWidth() : api.getHeight());
+    var inRangeStopLen = colorStopsInRange.length;
+
+    if (!inRangeStopLen && stopLen) {
+      // All stops are out of range. All will be the same color.
+      return colorStops[0].coord < 0 ? outerColors[1] ? outerColors[1] : colorStops[stopLen - 1].color : outerColors[0] ? outerColors[0] : colorStops[0].color;
+    }
+
+    var tinyExtent = 10; // Arbitrary value: 10px
+
+    var minCoord = colorStopsInRange[0].coord - tinyExtent;
+    var maxCoord = colorStopsInRange[inRangeStopLen - 1].coord + tinyExtent;
+    var coordSpan = maxCoord - minCoord;
+
+    if (coordSpan < 1e-3) {
+      return 'transparent';
+    }
+
+    each(colorStopsInRange, function (stop) {
+      stop.offset = (stop.coord - minCoord) / coordSpan;
+    });
+    colorStopsInRange.push({
+      // NOTE: inRangeStopLen may still be 0 if stoplen is zero.
+      offset: inRangeStopLen ? colorStopsInRange[inRangeStopLen - 1].offset : 0.5,
+      color: outerColors[1] || 'transparent'
+    });
+    colorStopsInRange.unshift({
+      offset: inRangeStopLen ? colorStopsInRange[0].offset : 0.5,
+      color: outerColors[0] || 'transparent'
+    });
+    var gradient = new LinearGradient(0, 0, 0, 0, colorStopsInRange, true);
+    gradient[coordDim] = minCoord;
+    gradient[coordDim + '2'] = maxCoord;
+    return gradient;
+  }
+
+  function getIsIgnoreFunc(seriesModel, data, coordSys) {
+    var showAllSymbol = seriesModel.get('showAllSymbol');
+    var isAuto = showAllSymbol === 'auto';
+
+    if (showAllSymbol && !isAuto) {
+      return;
+    }
+
+    var categoryAxis = coordSys.getAxesByScale('ordinal')[0];
+
+    if (!categoryAxis) {
+      return;
+    } // Note that category label interval strategy might bring some weird effect
+    // in some scenario: users may wonder why some of the symbols are not
+    // displayed. So we show all symbols as possible as we can.
+
+
+    if (isAuto // Simplify the logic, do not determine label overlap here.
+    && canShowAllSymbolForCategory(categoryAxis, data)) {
+      return;
+    } // Otherwise follow the label interval strategy on category axis.
+
+
+    var categoryDataDim = data.mapDimension(categoryAxis.dim);
+    var labelMap = {};
+    each(categoryAxis.getViewLabels(), function (labelItem) {
+      var ordinalNumber = categoryAxis.scale.getRawOrdinalNumber(labelItem.tickValue);
+      labelMap[ordinalNumber] = 1;
+    });
+    return function (dataIndex) {
+      return !labelMap.hasOwnProperty(data.get(categoryDataDim, dataIndex));
+    };
+  }
+
+  function canShowAllSymbolForCategory(categoryAxis, data) {
+    // In mose cases, line is monotonous on category axis, and the label size
+    // is close with each other. So we check the symbol size and some of the
+    // label size alone with the category axis to estimate whether all symbol
+    // can be shown without overlap.
+    var axisExtent = categoryAxis.getExtent();
+    var availSize = Math.abs(axisExtent[1] - axisExtent[0]) / categoryAxis.scale.count();
+    isNaN(availSize) && (availSize = 0); // 0/0 is NaN.
+    // Sampling some points, max 5.
+
+    var dataLen = data.count();
+    var step = Math.max(1, Math.round(dataLen / 5));
+
+    for (var dataIndex = 0; dataIndex < dataLen; dataIndex += step) {
+      if (Symbol$1.getSymbolSize(data, dataIndex // Only for cartesian, where `isHorizontal` exists.
+      )[categoryAxis.isHorizontal() ? 1 : 0] // Empirical number
+      * 1.5 > availSize) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  function isPointNull(x, y) {
+    return isNaN(x) || isNaN(y);
+  }
+
+  function getLastIndexNotNull(points) {
+    var len = points.length / 2;
+
+    for (; len > 0; len--) {
+      if (!isPointNull(points[len * 2 - 2], points[len * 2 - 1])) {
+        break;
+      }
+    }
+
+    return len - 1;
+  }
+
+  function getPointAtIndex(points, idx) {
+    return [points[idx * 2], points[idx * 2 + 1]];
+  }
+
+  function getIndexRange(points, xOrY, dim) {
+    var len = points.length / 2;
+    var dimIdx = dim === 'x' ? 0 : 1;
+    var a;
+    var b;
+    var prevIndex = 0;
+    var nextIndex = -1;
+
+    for (var i = 0; i < len; i++) {
+      b = points[i * 2 + dimIdx];
+
+      if (isNaN(b) || isNaN(points[i * 2 + 1 - dimIdx])) {
+        continue;
+      }
+
+      if (i === 0) {
+        a = b;
+        continue;
+      }
+
+      if (a <= xOrY && b >= xOrY || a >= xOrY && b <= xOrY) {
+        nextIndex = i;
+        break;
+      }
+
+      prevIndex = i;
+      a = b;
+    }
+
+    return {
+      range: [prevIndex, nextIndex],
+      t: (xOrY - a) / (b - a)
+    };
+  }
+
+  function anyStateShowEndLabel(seriesModel) {
+    if (seriesModel.get(['endLabel', 'show'])) {
+      return true;
+    }
+
+    for (var i = 0; i < SPECIAL_STATES.length; i++) {
+      if (seriesModel.get([SPECIAL_STATES[i], 'endLabel', 'show'])) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  function createLineClipPath(lineView, coordSys, hasAnimation, seriesModel) {
+    if (isCoordinateSystemType(coordSys, 'cartesian2d')) {
+      var endLabelModel_1 = seriesModel.getModel('endLabel');
+      var valueAnimation_1 = endLabelModel_1.get('valueAnimation');
+      var data_1 = seriesModel.getData();
+      var labelAnimationRecord_1 = {
+        lastFrameIndex: 0
+      };
+      var during = anyStateShowEndLabel(seriesModel) ? function (percent, clipRect) {
+        lineView._endLabelOnDuring(percent, clipRect, data_1, labelAnimationRecord_1, valueAnimation_1, endLabelModel_1, coordSys);
+      } : null;
+      var isHorizontal = coordSys.getBaseAxis().isHorizontal();
+      var clipPath = createGridClipPath(coordSys, hasAnimation, seriesModel, function () {
+        var endLabel = lineView._endLabel;
+
+        if (endLabel && hasAnimation) {
+          if (labelAnimationRecord_1.originalX != null) {
+            endLabel.attr({
+              x: labelAnimationRecord_1.originalX,
+              y: labelAnimationRecord_1.originalY
+            });
+          }
+        }
+      }, during); // Expand clip shape to avoid clipping when line value exceeds axis
+
+      if (!seriesModel.get('clip', true)) {
+        var rectShape = clipPath.shape;
+        var expandSize = Math.max(rectShape.width, rectShape.height);
+
+        if (isHorizontal) {
+          rectShape.y -= expandSize;
+          rectShape.height += expandSize * 2;
+        } else {
+          rectShape.x -= expandSize;
+          rectShape.width += expandSize * 2;
+        }
+      } // Set to the final frame. To make sure label layout is right.
+
+
+      if (during) {
+        during(1, clipPath);
+      }
+
+      return clipPath;
+    } else {
+      {
+        if (seriesModel.get(['endLabel', 'show'])) {
+          console.warn('endLabel is not supported for lines in polar systems.');
+        }
+      }
+      return createPolarClipPath(coordSys, hasAnimation, seriesModel);
+    }
+  }
+
+  function getEndLabelStateSpecified(endLabelModel, coordSys) {
+    var baseAxis = coordSys.getBaseAxis();
+    var isHorizontal = baseAxis.isHorizontal();
+    var isBaseInversed = baseAxis.inverse;
+    var align = isHorizontal ? isBaseInversed ? 'right' : 'left' : 'center';
+    var verticalAlign = isHorizontal ? 'middle' : isBaseInversed ? 'top' : 'bottom';
+    return {
+      normal: {
+        align: endLabelModel.get('align') || align,
+        verticalAlign: endLabelModel.get('verticalAlign') || verticalAlign
+      }
+    };
+  }
+
+  var LineView =
+  /** @class */
+  function (_super) {
+    __extends(LineView, _super);
+
+    function LineView() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    LineView.prototype.init = function () {
+      var lineGroup = new Group();
+      var symbolDraw = new SymbolDraw();
+      this.group.add(symbolDraw.group);
+      this._symbolDraw = symbolDraw;
+      this._lineGroup = lineGroup;
+    };
+
+    LineView.prototype.render = function (seriesModel, ecModel, api) {
+      var _this = this;
+
+      var coordSys = seriesModel.coordinateSystem;
+      var group = this.group;
+      var data = seriesModel.getData();
+      var lineStyleModel = seriesModel.getModel('lineStyle');
+      var areaStyleModel = seriesModel.getModel('areaStyle');
+      var points = data.getLayout('points') || [];
+      var isCoordSysPolar = coordSys.type === 'polar';
+      var prevCoordSys = this._coordSys;
+      var symbolDraw = this._symbolDraw;
+      var polyline = this._polyline;
+      var polygon = this._polygon;
+      var lineGroup = this._lineGroup;
+      var hasAnimation = seriesModel.get('animation');
+      var isAreaChart = !areaStyleModel.isEmpty();
+      var valueOrigin = areaStyleModel.get('origin');
+      var dataCoordInfo = prepareDataCoordInfo(coordSys, data, valueOrigin);
+      var stackedOnPoints = isAreaChart && getStackedOnPoints(coordSys, data, dataCoordInfo);
+      var showSymbol = seriesModel.get('showSymbol');
+      var connectNulls = seriesModel.get('connectNulls');
+      var isIgnoreFunc = showSymbol && !isCoordSysPolar && getIsIgnoreFunc(seriesModel, data, coordSys); // Remove temporary symbols
+
+      var oldData = this._data;
+      oldData && oldData.eachItemGraphicEl(function (el, idx) {
+        if (el.__temp) {
+          group.remove(el);
+          oldData.setItemGraphicEl(idx, null);
+        }
+      }); // Remove previous created symbols if showSymbol changed to false
+
+      if (!showSymbol) {
+        symbolDraw.remove();
+      }
+
+      group.add(lineGroup); // FIXME step not support polar
+
+      var step = !isCoordSysPolar ? seriesModel.get('step') : false;
+      var clipShapeForSymbol;
+
+      if (coordSys && coordSys.getArea && seriesModel.get('clip', true)) {
+        clipShapeForSymbol = coordSys.getArea(); // Avoid float number rounding error for symbol on the edge of axis extent.
+        // See #7913 and `test/dataZoom-clip.html`.
+
+        if (clipShapeForSymbol.width != null) {
+          clipShapeForSymbol.x -= 0.1;
+          clipShapeForSymbol.y -= 0.1;
+          clipShapeForSymbol.width += 0.2;
+          clipShapeForSymbol.height += 0.2;
+        } else if (clipShapeForSymbol.r0) {
+          clipShapeForSymbol.r0 -= 0.5;
+          clipShapeForSymbol.r += 0.5;
+        }
+      }
+
+      this._clipShapeForSymbol = clipShapeForSymbol;
+      var visualColor = getVisualGradient(data, coordSys, api) || data.getVisual('style')[data.getVisual('drawType')]; // Initialization animation or coordinate system changed
+
+      if (!(polyline && prevCoordSys.type === coordSys.type && step === this._step)) {
+        showSymbol && symbolDraw.updateData(data, {
+          isIgnore: isIgnoreFunc,
+          clipShape: clipShapeForSymbol,
+          disableAnimation: true,
+          getSymbolPoint: function (idx) {
+            return [points[idx * 2], points[idx * 2 + 1]];
+          }
+        });
+        hasAnimation && this._initSymbolLabelAnimation(data, coordSys, clipShapeForSymbol);
+
+        if (step) {
+          // TODO If stacked series is not step
+          points = turnPointsIntoStep(points, coordSys, step, connectNulls);
+
+          if (stackedOnPoints) {
+            stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step, connectNulls);
+          }
+        }
+
+        polyline = this._newPolyline(points);
+
+        if (isAreaChart) {
+          polygon = this._newPolygon(points, stackedOnPoints);
+        } // If areaStyle is removed
+        else if (polygon) {
+            lineGroup.remove(polygon);
+            polygon = this._polygon = null;
+          } // NOTE: Must update _endLabel before setClipPath.
+
+
+        if (!isCoordSysPolar) {
+          this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor));
+        }
+
+        lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel));
+      } else {
+        if (isAreaChart && !polygon) {
+          // If areaStyle is added
+          polygon = this._newPolygon(points, stackedOnPoints);
+        } else if (polygon && !isAreaChart) {
+          // If areaStyle is removed
+          lineGroup.remove(polygon);
+          polygon = this._polygon = null;
+        } // NOTE: Must update _endLabel before setClipPath.
+
+
+        if (!isCoordSysPolar) {
+          this._initOrUpdateEndLabel(seriesModel, coordSys, convertToColorString(visualColor));
+        } // Update clipPath
+
+
+        var oldClipPath = lineGroup.getClipPath();
+
+        if (oldClipPath) {
+          var newClipPath = createLineClipPath(this, coordSys, false, seriesModel);
+          initProps(oldClipPath, {
+            shape: newClipPath.shape
+          }, seriesModel);
+        } else {
+          lineGroup.setClipPath(createLineClipPath(this, coordSys, true, seriesModel));
+        } // Always update, or it is wrong in the case turning on legend
+        // because points are not changed
+
+
+        showSymbol && symbolDraw.updateData(data, {
+          isIgnore: isIgnoreFunc,
+          clipShape: clipShapeForSymbol,
+          disableAnimation: true,
+          getSymbolPoint: function (idx) {
+            return [points[idx * 2], points[idx * 2 + 1]];
+          }
+        }); // In the case data zoom triggerred refreshing frequently
+        // Data may not change if line has a category axis. So it should animate nothing
+
+        if (!isPointsSame(this._stackedOnPoints, stackedOnPoints) || !isPointsSame(this._points, points)) {
+          if (hasAnimation) {
+            this._doUpdateAnimation(data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls);
+          } else {
+            // Not do it in update with animation
+            if (step) {
+              // TODO If stacked series is not step
+              points = turnPointsIntoStep(points, coordSys, step, connectNulls);
+
+              if (stackedOnPoints) {
+                stackedOnPoints = turnPointsIntoStep(stackedOnPoints, coordSys, step, connectNulls);
+              }
+            }
+
+            polyline.setShape({
+              points: points
+            });
+            polygon && polygon.setShape({
+              points: points,
+              stackedOnPoints: stackedOnPoints
+            });
+          }
+        }
+      }
+
+      var emphasisModel = seriesModel.getModel('emphasis');
+      var focus = emphasisModel.get('focus');
+      var blurScope = emphasisModel.get('blurScope');
+      var emphasisDisabled = emphasisModel.get('disabled');
+      polyline.useStyle(defaults( // Use color in lineStyle first
+      lineStyleModel.getLineStyle(), {
+        fill: 'none',
+        stroke: visualColor,
+        lineJoin: 'bevel'
+      }));
+      setStatesStylesFromModel(polyline, seriesModel, 'lineStyle');
+
+      if (polyline.style.lineWidth > 0 && seriesModel.get(['emphasis', 'lineStyle', 'width']) === 'bolder') {
+        var emphasisLineStyle = polyline.getState('emphasis').style;
+        emphasisLineStyle.lineWidth = +polyline.style.lineWidth + 1;
+      } // Needs seriesIndex for focus
+
+
+      getECData(polyline).seriesIndex = seriesModel.seriesIndex;
+      toggleHoverEmphasis(polyline, focus, blurScope, emphasisDisabled);
+      var smooth = getSmooth(seriesModel.get('smooth'));
+      var smoothMonotone = seriesModel.get('smoothMonotone');
+      polyline.setShape({
+        smooth: smooth,
+        smoothMonotone: smoothMonotone,
+        connectNulls: connectNulls
+      });
+
+      if (polygon) {
+        var stackedOnSeries = data.getCalculationInfo('stackedOnSeries');
+        var stackedOnSmooth = 0;
+        polygon.useStyle(defaults(areaStyleModel.getAreaStyle(), {
+          fill: visualColor,
+          opacity: 0.7,
+          lineJoin: 'bevel',
+          decal: data.getVisual('style').decal
+        }));
+
+        if (stackedOnSeries) {
+          stackedOnSmooth = getSmooth(stackedOnSeries.get('smooth'));
+        }
+
+        polygon.setShape({
+          smooth: smooth,
+          stackedOnSmooth: stackedOnSmooth,
+          smoothMonotone: smoothMonotone,
+          connectNulls: connectNulls
+        });
+        setStatesStylesFromModel(polygon, seriesModel, 'areaStyle'); // Needs seriesIndex for focus
+
+        getECData(polygon).seriesIndex = seriesModel.seriesIndex;
+        toggleHoverEmphasis(polygon, focus, blurScope, emphasisDisabled);
+      }
+
+      var changePolyState = function (toState) {
+        _this._changePolyState(toState);
+      };
+
+      data.eachItemGraphicEl(function (el) {
+        // Switch polyline / polygon state if element changed its state.
+        el && (el.onHoverStateChange = changePolyState);
+      });
+      this._polyline.onHoverStateChange = changePolyState;
+      this._data = data; // Save the coordinate system for transition animation when data changed
+
+      this._coordSys = coordSys;
+      this._stackedOnPoints = stackedOnPoints;
+      this._points = points;
+      this._step = step;
+      this._valueOrigin = valueOrigin;
+
+      if (seriesModel.get('triggerLineEvent')) {
+        this.packEventData(seriesModel, polyline);
+        polygon && this.packEventData(seriesModel, polygon);
+      }
+    };
+
+    LineView.prototype.packEventData = function (seriesModel, el) {
+      getECData(el).eventData = {
+        componentType: 'series',
+        componentSubType: 'line',
+        componentIndex: seriesModel.componentIndex,
+        seriesIndex: seriesModel.seriesIndex,
+        seriesName: seriesModel.name,
+        seriesType: 'line'
+      };
+    };
+
+    LineView.prototype.highlight = function (seriesModel, ecModel, api, payload) {
+      var data = seriesModel.getData();
+      var dataIndex = queryDataIndex(data, payload);
+
+      this._changePolyState('emphasis');
+
+      if (!(dataIndex instanceof Array) && dataIndex != null && dataIndex >= 0) {
+        var points = data.getLayout('points');
+        var symbol = data.getItemGraphicEl(dataIndex);
+
+        if (!symbol) {
+          // Create a temporary symbol if it is not exists
+          var x = points[dataIndex * 2];
+          var y = points[dataIndex * 2 + 1];
+
+          if (isNaN(x) || isNaN(y)) {
+            // Null data
+            return;
+          } // fix #11360: should't draw symbol outside clipShapeForSymbol
+
+
+          if (this._clipShapeForSymbol && !this._clipShapeForSymbol.contain(x, y)) {
+            return;
+          }
+
+          var zlevel = seriesModel.get('zlevel');
+          var z = seriesModel.get('z');
+          symbol = new Symbol$1(data, dataIndex);
+          symbol.x = x;
+          symbol.y = y;
+          symbol.setZ(zlevel, z); // ensure label text of the temporary symbol is in front of line and area polygon
+
+          var symbolLabel = symbol.getSymbolPath().getTextContent();
+
+          if (symbolLabel) {
+            symbolLabel.zlevel = zlevel;
+            symbolLabel.z = z;
+            symbolLabel.z2 = this._polyline.z2 + 1;
+          }
+
+          symbol.__temp = true;
+          data.setItemGraphicEl(dataIndex, symbol); // Stop scale animation
+
+          symbol.stopSymbolAnimation(true);
+          this.group.add(symbol);
+        }
+
+        symbol.highlight();
+      } else {
+        // Highlight whole series
+        ChartView.prototype.highlight.call(this, seriesModel, ecModel, api, payload);
+      }
+    };
+
+    LineView.prototype.downplay = function (seriesModel, ecModel, api, payload) {
+      var data = seriesModel.getData();
+      var dataIndex = queryDataIndex(data, payload);
+
+      this._changePolyState('normal');
+
+      if (dataIndex != null && dataIndex >= 0) {
+        var symbol = data.getItemGraphicEl(dataIndex);
+
+        if (symbol) {
+          if (symbol.__temp) {
+            data.setItemGraphicEl(dataIndex, null);
+            this.group.remove(symbol);
+          } else {
+            symbol.downplay();
+          }
+        }
+      } else {
+        // FIXME
+        // can not downplay completely.
+        // Downplay whole series
+        ChartView.prototype.downplay.call(this, seriesModel, ecModel, api, payload);
+      }
+    };
+
+    LineView.prototype._changePolyState = function (toState) {
+      var polygon = this._polygon;
+      setStatesFlag(this._polyline, toState);
+      polygon && setStatesFlag(polygon, toState);
+    };
+
+    LineView.prototype._newPolyline = function (points) {
+      var polyline = this._polyline; // Remove previous created polyline
+
+      if (polyline) {
+        this._lineGroup.remove(polyline);
+      }
+
+      polyline = new ECPolyline({
+        shape: {
+          points: points
+        },
+        segmentIgnoreThreshold: 2,
+        z2: 10
+      });
+
+      this._lineGroup.add(polyline);
+
+      this._polyline = polyline;
+      return polyline;
+    };
+
+    LineView.prototype._newPolygon = function (points, stackedOnPoints) {
+      var polygon = this._polygon; // Remove previous created polygon
+
+      if (polygon) {
+        this._lineGroup.remove(polygon);
+      }
+
+      polygon = new ECPolygon({
+        shape: {
+          points: points,
+          stackedOnPoints: stackedOnPoints
+        },
+        segmentIgnoreThreshold: 2
+      });
+
+      this._lineGroup.add(polygon);
+
+      this._polygon = polygon;
+      return polygon;
+    };
+
+    LineView.prototype._initSymbolLabelAnimation = function (data, coordSys, clipShape) {
+      var isHorizontalOrRadial;
+      var isCoordSysPolar;
+      var baseAxis = coordSys.getBaseAxis();
+      var isAxisInverse = baseAxis.inverse;
+
+      if (coordSys.type === 'cartesian2d') {
+        isHorizontalOrRadial = baseAxis.isHorizontal();
+        isCoordSysPolar = false;
+      } else if (coordSys.type === 'polar') {
+        isHorizontalOrRadial = baseAxis.dim === 'angle';
+        isCoordSysPolar = true;
+      }
+
+      var seriesModel = data.hostModel;
+      var seriesDuration = seriesModel.get('animationDuration');
+
+      if (isFunction(seriesDuration)) {
+        seriesDuration = seriesDuration(null);
+      }
+
+      var seriesDalay = seriesModel.get('animationDelay') || 0;
+      var seriesDalayValue = isFunction(seriesDalay) ? seriesDalay(null) : seriesDalay;
+      data.eachItemGraphicEl(function (symbol, idx) {
+        var el = symbol;
+
+        if (el) {
+          var point = [symbol.x, symbol.y];
+          var start = void 0;
+          var end = void 0;
+          var current = void 0;
+
+          if (clipShape) {
+            if (isCoordSysPolar) {
+              var polarClip = clipShape;
+              var coord = coordSys.pointToCoord(point);
+
+              if (isHorizontalOrRadial) {
+                start = polarClip.startAngle;
+                end = polarClip.endAngle;
+                current = -coord[1] / 180 * Math.PI;
+              } else {
+                start = polarClip.r0;
+                end = polarClip.r;
+                current = coord[0];
+              }
+            } else {
+              var gridClip = clipShape;
+
+              if (isHorizontalOrRadial) {
+                start = gridClip.x;
+                end = gridClip.x + gridClip.width;
+                current = symbol.x;
+              } else {
+                start = gridClip.y + gridClip.height;
+                end = gridClip.y;
+                current = symbol.y;
+              }
+            }
+          }
+
+          var ratio = end === start ? 0 : (current - start) / (end - start);
+
+          if (isAxisInverse) {
+            ratio = 1 - ratio;
+          }
+
+          var delay = isFunction(seriesDalay) ? seriesDalay(idx) : seriesDuration * ratio + seriesDalayValue;
+          var symbolPath = el.getSymbolPath();
+          var text = symbolPath.getTextContent();
+          el.attr({
+            scaleX: 0,
+            scaleY: 0
+          });
+          el.animateTo({
+            scaleX: 1,
+            scaleY: 1
+          }, {
+            duration: 200,
+            setToFinal: true,
+            delay: delay
+          });
+
+          if (text) {
+            text.animateFrom({
+              style: {
+                opacity: 0
+              }
+            }, {
+              duration: 300,
+              delay: delay
+            });
+          }
+
+          symbolPath.disableLabelAnimation = true;
+        }
+      });
+    };
+
+    LineView.prototype._initOrUpdateEndLabel = function (seriesModel, coordSys, inheritColor) {
+      var endLabelModel = seriesModel.getModel('endLabel');
+
+      if (anyStateShowEndLabel(seriesModel)) {
+        var data_2 = seriesModel.getData();
+        var polyline = this._polyline; // series may be filtered.
+
+        var points = data_2.getLayout('points');
+
+        if (!points) {
+          polyline.removeTextContent();
+          this._endLabel = null;
+          return;
+        }
+
+        var endLabel = this._endLabel;
+
+        if (!endLabel) {
+          endLabel = this._endLabel = new ZRText({
+            z2: 200 // should be higher than item symbol
+
+          });
+          endLabel.ignoreClip = true;
+          polyline.setTextContent(this._endLabel);
+          polyline.disableLabelAnimation = true;
+        } // Find last non-NaN data to display data
+
+
+        var dataIndex = getLastIndexNotNull(points);
+
+        if (dataIndex >= 0) {
+          setLabelStyle(polyline, getLabelStatesModels(seriesModel, 'endLabel'), {
+            inheritColor: inheritColor,
+            labelFetcher: seriesModel,
+            labelDataIndex: dataIndex,
+            defaultText: function (dataIndex, opt, interpolatedValue) {
+              return interpolatedValue != null ? getDefaultInterpolatedLabel(data_2, interpolatedValue) : getDefaultLabel(data_2, dataIndex);
+            },
+            enableTextSetter: true
+          }, getEndLabelStateSpecified(endLabelModel, coordSys));
+          polyline.textConfig.position = null;
+        }
+      } else if (this._endLabel) {
+        this._polyline.removeTextContent();
+
+        this._endLabel = null;
+      }
+    };
+
+    LineView.prototype._endLabelOnDuring = function (percent, clipRect, data, animationRecord, valueAnimation, endLabelModel, coordSys) {
+      var endLabel = this._endLabel;
+      var polyline = this._polyline;
+
+      if (endLabel) {
+        // NOTE: Don't remove percent < 1. percent === 1 means the first frame during render.
+        // The label is not prepared at this time.
+        if (percent < 1 && animationRecord.originalX == null) {
+          animationRecord.originalX = endLabel.x;
+          animationRecord.originalY = endLabel.y;
+        }
+
+        var points = data.getLayout('points');
+        var seriesModel = data.hostModel;
+        var connectNulls = seriesModel.get('connectNulls');
+        var precision = endLabelModel.get('precision');
+        var distance = endLabelModel.get('distance') || 0;
+        var baseAxis = coordSys.getBaseAxis();
+        var isHorizontal = baseAxis.isHorizontal();
+        var isBaseInversed = baseAxis.inverse;
+        var clipShape = clipRect.shape;
+        var xOrY = isBaseInversed ? isHorizontal ? clipShape.x : clipShape.y + clipShape.height : isHorizontal ? clipShape.x + clipShape.width : clipShape.y;
+        var distanceX = (isHorizontal ? distance : 0) * (isBaseInversed ? -1 : 1);
+        var distanceY = (isHorizontal ? 0 : -distance) * (isBaseInversed ? -1 : 1);
+        var dim = isHorizontal ? 'x' : 'y';
+        var dataIndexRange = getIndexRange(points, xOrY, dim);
+        var indices = dataIndexRange.range;
+        var diff = indices[1] - indices[0];
+        var value = void 0;
+
+        if (diff >= 1) {
+          // diff > 1 && connectNulls, which is on the null data.
+          if (diff > 1 && !connectNulls) {
+            var pt = getPointAtIndex(points, indices[0]);
+            endLabel.attr({
+              x: pt[0] + distanceX,
+              y: pt[1] + distanceY
+            });
+            valueAnimation && (value = seriesModel.getRawValue(indices[0]));
+          } else {
+            var pt = polyline.getPointOn(xOrY, dim);
+            pt && endLabel.attr({
+              x: pt[0] + distanceX,
+              y: pt[1] + distanceY
+            });
+            var startValue = seriesModel.getRawValue(indices[0]);
+            var endValue = seriesModel.getRawValue(indices[1]);
+            valueAnimation && (value = interpolateRawValues(data, precision, startValue, endValue, dataIndexRange.t));
+          }
+
+          animationRecord.lastFrameIndex = indices[0];
+        } else {
+          // If diff <= 0, which is the range is not found(Include NaN)
+          // Choose the first point or last point.
+          var idx = percent === 1 || animationRecord.lastFrameIndex > 0 ? indices[0] : 0;
+          var pt = getPointAtIndex(points, idx);
+          valueAnimation && (value = seriesModel.getRawValue(idx));
+          endLabel.attr({
+            x: pt[0] + distanceX,
+            y: pt[1] + distanceY
+          });
+        }
+
+        if (valueAnimation) {
+          labelInner(endLabel).setLabelText(value);
+        }
+      }
+    };
+    /**
+     * @private
+     */
+    // FIXME Two value axis
+
+
+    LineView.prototype._doUpdateAnimation = function (data, stackedOnPoints, coordSys, api, step, valueOrigin, connectNulls) {
+      var polyline = this._polyline;
+      var polygon = this._polygon;
+      var seriesModel = data.hostModel;
+      var diff = lineAnimationDiff(this._data, data, this._stackedOnPoints, stackedOnPoints, this._coordSys, coordSys, this._valueOrigin, valueOrigin);
+      var current = diff.current;
+      var stackedOnCurrent = diff.stackedOnCurrent;
+      var next = diff.next;
+      var stackedOnNext = diff.stackedOnNext;
+
+      if (step) {
+        // TODO If stacked series is not step
+        current = turnPointsIntoStep(diff.current, coordSys, step, connectNulls);
+        stackedOnCurrent = turnPointsIntoStep(diff.stackedOnCurrent, coordSys, step, connectNulls);
+        next = turnPointsIntoStep(diff.next, coordSys, step, connectNulls);
+        stackedOnNext = turnPointsIntoStep(diff.stackedOnNext, coordSys, step, connectNulls);
+      } // Don't apply animation if diff is large.
+      // For better result and avoid memory explosion problems like
+      // https://github.com/apache/incubator-echarts/issues/12229
+
+
+      if (getBoundingDiff(current, next) > 3000 || polygon && getBoundingDiff(stackedOnCurrent, stackedOnNext) > 3000) {
+        polyline.stopAnimation();
+        polyline.setShape({
+          points: next
+        });
+
+        if (polygon) {
+          polygon.stopAnimation();
+          polygon.setShape({
+            points: next,
+            stackedOnPoints: stackedOnNext
+          });
+        }
+
+        return;
+      }
+
+      polyline.shape.__points = diff.current;
+      polyline.shape.points = current;
+      var target = {
+        shape: {
+          points: next
+        }
+      }; // Also animate the original points.
+      // If points reference is changed when turning into step line.
+
+      if (diff.current !== current) {
+        target.shape.__points = diff.next;
+      } // Stop previous animation.
+
+
+      polyline.stopAnimation();
+      updateProps(polyline, target, seriesModel);
+
+      if (polygon) {
+        polygon.setShape({
+          // Reuse the points with polyline.
+          points: current,
+          stackedOnPoints: stackedOnCurrent
+        });
+        polygon.stopAnimation();
+        updateProps(polygon, {
+          shape: {
+            stackedOnPoints: stackedOnNext
+          }
+        }, seriesModel); // If use attr directly in updateProps.
+
+        if (polyline.shape.points !== polygon.shape.points) {
+          polygon.shape.points = polyline.shape.points;
+        }
+      }
+
+      var updatedDataInfo = [];
+      var diffStatus = diff.status;
+
+      for (var i = 0; i < diffStatus.length; i++) {
+        var cmd = diffStatus[i].cmd;
+
+        if (cmd === '=') {
+          var el = data.getItemGraphicEl(diffStatus[i].idx1);
+
+          if (el) {
+            updatedDataInfo.push({
+              el: el,
+              ptIdx: i // Index of points
+
+            });
+          }
+        }
+      }
+
+      if (polyline.animators && polyline.animators.length) {
+        polyline.animators[0].during(function () {
+          polygon && polygon.dirtyShape();
+          var points = polyline.shape.__points;
+
+          for (var i = 0; i < updatedDataInfo.length; i++) {
+            var el = updatedDataInfo[i].el;
+            var offset = updatedDataInfo[i].ptIdx * 2;
+            el.x = points[offset];
+            el.y = points[offset + 1];
+            el.markRedraw();
+          }
+        });
+      }
+    };
+
+    LineView.prototype.remove = function (ecModel) {
+      var group = this.group;
+      var oldData = this._data;
+
+      this._lineGroup.removeAll();
+
+      this._symbolDraw.remove(true); // Remove temporary created elements when highlighting
+
+
+      oldData && oldData.eachItemGraphicEl(function (el, idx) {
+        if (el.__temp) {
+          group.remove(el);
+          oldData.setItemGraphicEl(idx, null);
+        }
+      });
+      this._polyline = this._polygon = this._coordSys = this._points = this._stackedOnPoints = this._endLabel = this._data = null;
+    };
+
+    LineView.type = 'line';
+    return LineView;
+  }(ChartView);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 pointsLayout(seriesType, forceStoreInTypedArray) {
+    return {
+      seriesType: seriesType,
+      plan: createRenderPlanner(),
+      reset: function (seriesModel) {
+        var data = seriesModel.getData();
+        var coordSys = seriesModel.coordinateSystem;
+        var pipelineContext = seriesModel.pipelineContext;
+        var useTypedArray = forceStoreInTypedArray || pipelineContext.large;
+
+        if (!coordSys) {
+          return;
+        }
+
+        var dims = map(coordSys.dimensions, function (dim) {
+          return data.mapDimension(dim);
+        }).slice(0, 2);
+        var dimLen = dims.length;
+        var stackResultDim = data.getCalculationInfo('stackResultDimension');
+
+        if (isDimensionStacked(data, dims[0])) {
+          dims[0] = stackResultDim;
+        }
+
+        if (isDimensionStacked(data, dims[1])) {
+          dims[1] = stackResultDim;
+        }
+
+        var store = data.getStore();
+        var dimIdx0 = data.getDimensionIndex(dims[0]);
+        var dimIdx1 = data.getDimensionIndex(dims[1]);
+        return dimLen && {
+          progress: function (params, data) {
+            var segCount = params.end - params.start;
+            var points = useTypedArray && createFloat32Array(segCount * dimLen);
+            var tmpIn = [];
+            var tmpOut = [];
+
+            for (var i = params.start, offset = 0; i < params.end; i++) {
+              var point = void 0;
+
+              if (dimLen === 1) {
+                var x = store.get(dimIdx0, i); // NOTE: Make sure the second parameter is null to use default strategy.
+
+                point = coordSys.dataToPoint(x, null, tmpOut);
+              } else {
+                tmpIn[0] = store.get(dimIdx0, i);
+                tmpIn[1] = store.get(dimIdx1, i); // Let coordinate system to handle the NaN data.
+
+                point = coordSys.dataToPoint(tmpIn, null, tmpOut);
+              }
+
+              if (useTypedArray) {
+                points[offset++] = point[0];
+                points[offset++] = point[1];
+              } else {
+                data.setItemLayout(i, point.slice());
+              }
+            }
+
+            useTypedArray && data.setLayout('points', points);
+          }
+        };
+      }
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install$3(registers) {
+    registers.registerChartView(LineView);
+    registers.registerSeriesModel(LineSeriesModel);
+    registers.registerLayout(pointsLayout('line', true));
+    registers.registerVisual({
+      seriesType: 'line',
+      reset: function (seriesModel) {
+        var data = seriesModel.getData(); // Visual coding for legend
+
+        var lineStyle = seriesModel.getModel('lineStyle').getLineStyle();
+
+        if (lineStyle && !lineStyle.stroke) {
+          // Fill in visual should be palette color if
+          // has color callback
+          lineStyle.stroke = data.getVisual('style').fill;
+        }
+
+        data.setVisual('legendLineStyle', lineStyle);
+      }
+    }); // Down sample after filter
+
+    registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, dataSample('line'));
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+
+  use(install$3);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 PI2$7 = Math.PI * 2;
+  var RADIAN = Math.PI / 180;
+
+  function getViewRect(seriesModel, api) {
+    return getLayoutRect(seriesModel.getBoxLayoutParams(), {
+      width: api.getWidth(),
+      height: api.getHeight()
+    });
+  }
+
+  function getBasicPieLayout(seriesModel, api) {
+    var viewRect = getViewRect(seriesModel, api);
+    var center = seriesModel.get('center');
+    var radius = seriesModel.get('radius');
+
+    if (!isArray(radius)) {
+      radius = [0, radius];
+    }
+
+    if (!isArray(center)) {
+      center = [center, center];
+    }
+
+    var width = parsePercent$1(viewRect.width, api.getWidth());
+    var height = parsePercent$1(viewRect.height, api.getHeight());
+    var size = Math.min(width, height);
+    var cx = parsePercent$1(center[0], width) + viewRect.x;
+    var cy = parsePercent$1(center[1], height) + viewRect.y;
+    var r0 = parsePercent$1(radius[0], size / 2);
+    var r = parsePercent$1(radius[1], size / 2);
+    return {
+      cx: cx,
+      cy: cy,
+      r0: r0,
+      r: r
+    };
+  }
+
+  function pieLayout(seriesType, ecModel, api) {
+    ecModel.eachSeriesByType(seriesType, function (seriesModel) {
+      var data = seriesModel.getData();
+      var valueDim = data.mapDimension('value');
+      var viewRect = getViewRect(seriesModel, api);
+
+      var _a = getBasicPieLayout(seriesModel, api),
+          cx = _a.cx,
+          cy = _a.cy,
+          r = _a.r,
+          r0 = _a.r0;
+
+      var startAngle = -seriesModel.get('startAngle') * RADIAN;
+      var minAngle = seriesModel.get('minAngle') * RADIAN;
+      var validDataCount = 0;
+      data.each(valueDim, function (value) {
+        !isNaN(value) && validDataCount++;
+      });
+      var sum = data.getSum(valueDim); // Sum may be 0
+
+      var unitRadian = Math.PI / (sum || validDataCount) * 2;
+      var clockwise = seriesModel.get('clockwise');
+      var roseType = seriesModel.get('roseType');
+      var stillShowZeroSum = seriesModel.get('stillShowZeroSum'); // [0...max]
+
+      var extent = data.getDataExtent(valueDim);
+      extent[0] = 0; // In the case some sector angle is smaller than minAngle
+
+      var restAngle = PI2$7;
+      var valueSumLargerThanMinAngle = 0;
+      var currentAngle = startAngle;
+      var dir = clockwise ? 1 : -1;
+      data.setLayout({
+        viewRect: viewRect,
+        r: r
+      });
+      data.each(valueDim, function (value, idx) {
+        var angle;
+
+        if (isNaN(value)) {
+          data.setItemLayout(idx, {
+            angle: NaN,
+            startAngle: NaN,
+            endAngle: NaN,
+            clockwise: clockwise,
+            cx: cx,
+            cy: cy,
+            r0: r0,
+            r: roseType ? NaN : r
+          });
+          return;
+        } // FIXME 兼容 2.0 但是 roseType 是 area 的时候才是这样?
+
+
+        if (roseType !== 'area') {
+          angle = sum === 0 && stillShowZeroSum ? unitRadian : value * unitRadian;
+        } else {
+          angle = PI2$7 / validDataCount;
+        }
+
+        if (angle < minAngle) {
+          angle = minAngle;
+          restAngle -= minAngle;
+        } else {
+          valueSumLargerThanMinAngle += value;
+        }
+
+        var endAngle = currentAngle + dir * angle;
+        data.setItemLayout(idx, {
+          angle: angle,
+          startAngle: currentAngle,
+          endAngle: endAngle,
+          clockwise: clockwise,
+          cx: cx,
+          cy: cy,
+          r0: r0,
+          r: roseType ? linearMap(value, extent, [r0, r]) : r
+        });
+        currentAngle = endAngle;
+      }); // Some sector is constrained by minAngle
+      // Rest sectors needs recalculate angle
+
+      if (restAngle < PI2$7 && validDataCount) {
+        // Average the angle if rest angle is not enough after all angles is
+        // Constrained by minAngle
+        if (restAngle <= 1e-3) {
+          var angle_1 = PI2$7 / validDataCount;
+          data.each(valueDim, function (value, idx) {
+            if (!isNaN(value)) {
+              var layout_1 = data.getItemLayout(idx);
+              layout_1.angle = angle_1;
+              layout_1.startAngle = startAngle + dir * idx * angle_1;
+              layout_1.endAngle = startAngle + dir * (idx + 1) * angle_1;
+            }
+          });
+        } else {
+          unitRadian = restAngle / valueSumLargerThanMinAngle;
+          currentAngle = startAngle;
+          data.each(valueDim, function (value, idx) {
+            if (!isNaN(value)) {
+              var layout_2 = data.getItemLayout(idx);
+              var angle = layout_2.angle === minAngle ? minAngle : value * unitRadian;
+              layout_2.startAngle = currentAngle;
+              layout_2.endAngle = currentAngle + dir * angle;
+              currentAngle += dir * angle;
+            }
+          });
+        }
+      }
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 dataFilter(seriesType) {
+    return {
+      seriesType: seriesType,
+      reset: function (seriesModel, ecModel) {
+        var legendModels = ecModel.findComponents({
+          mainType: 'legend'
+        });
+
+        if (!legendModels || !legendModels.length) {
+          return;
+        }
+
+        var data = seriesModel.getData();
+        data.filterSelf(function (idx) {
+          var name = data.getName(idx); // If in any legend component the status is not selected.
+
+          for (var i = 0; i < legendModels.length; i++) {
+            // @ts-ignore FIXME: LegendModel
+            if (!legendModels[i].isSelected(name)) {
+              return false;
+            }
+          }
+
+          return true;
+        });
+      }
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // FIXME emphasis label position is not same with normal label position
+
+
+  var RADIAN$1 = Math.PI / 180;
+
+  function adjustSingleSide(list, cx, cy, r, dir, viewWidth, viewHeight, viewLeft, viewTop, farthestX) {
+    if (list.length < 2) {
+      return;
+    }
+
+    function recalculateXOnSemiToAlignOnEllipseCurve(semi) {
+      var rB = semi.rB;
+      var rB2 = rB * rB;
+
+      for (var i = 0; i < semi.list.length; i++) {
+        var item = semi.list[i];
+        var dy = Math.abs(item.label.y - cy); // horizontal r is always same with original r because x is not changed.
+
+        var rA = r + item.len;
+        var rA2 = rA * rA; // Use ellipse implicit function to calculate x
+
+        var dx = Math.sqrt((1 - Math.abs(dy * dy / rB2)) * rA2);
+        var newX = cx + (dx + item.len2) * dir;
+        var deltaX = newX - item.label.x;
+        var newTargetWidth = item.targetTextWidth - deltaX * dir; // text x is changed, so need to recalculate width.
+
+        constrainTextWidth(item, newTargetWidth, true);
+        item.label.x = newX;
+      }
+    } // Adjust X based on the shifted y. Make tight labels aligned on an ellipse curve.
+
+
+    function recalculateX(items) {
+      // Extremes of
+      var topSemi = {
+        list: [],
+        maxY: 0
+      };
+      var bottomSemi = {
+        list: [],
+        maxY: 0
+      };
+
+      for (var i = 0; i < items.length; i++) {
+        if (items[i].labelAlignTo !== 'none') {
+          continue;
+        }
+
+        var item = items[i];
+        var semi = item.label.y > cy ? bottomSemi : topSemi;
+        var dy = Math.abs(item.label.y - cy);
+
+        if (dy >= semi.maxY) {
+          var dx = item.label.x - cx - item.len2 * dir; // horizontal r is always same with original r because x is not changed.
+
+          var rA = r + item.len; // Canculate rB based on the topest / bottemest label.
+
+          var rB = Math.abs(dx) < rA ? Math.sqrt(dy * dy / (1 - dx * dx / rA / rA)) : rA;
+          semi.rB = rB;
+          semi.maxY = dy;
+        }
+
+        semi.list.push(item);
+      }
+
+      recalculateXOnSemiToAlignOnEllipseCurve(topSemi);
+      recalculateXOnSemiToAlignOnEllipseCurve(bottomSemi);
+    }
+
+    var len = list.length;
+
+    for (var i = 0; i < len; i++) {
+      if (list[i].position === 'outer' && list[i].labelAlignTo === 'labelLine') {
+        var dx = list[i].label.x - farthestX;
+        list[i].linePoints[1][0] += dx;
+        list[i].label.x = farthestX;
+      }
+    }
+
+    if (shiftLayoutOnY(list, viewTop, viewTop + viewHeight)) {
+      recalculateX(list);
+    }
+  }
+
+  function avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop) {
+    var leftList = [];
+    var rightList = [];
+    var leftmostX = Number.MAX_VALUE;
+    var rightmostX = -Number.MAX_VALUE;
+
+    for (var i = 0; i < labelLayoutList.length; i++) {
+      var label = labelLayoutList[i].label;
+
+      if (isPositionCenter(labelLayoutList[i])) {
+        continue;
+      }
+
+      if (label.x < cx) {
+        leftmostX = Math.min(leftmostX, label.x);
+        leftList.push(labelLayoutList[i]);
+      } else {
+        rightmostX = Math.max(rightmostX, label.x);
+        rightList.push(labelLayoutList[i]);
+      }
+    }
+
+    for (var i = 0; i < labelLayoutList.length; i++) {
+      var layout = labelLayoutList[i];
+
+      if (!isPositionCenter(layout) && layout.linePoints) {
+        if (layout.labelStyleWidth != null) {
+          continue;
+        }
+
+        var label = layout.label;
+        var linePoints = layout.linePoints;
+        var targetTextWidth = void 0;
+
+        if (layout.labelAlignTo === 'edge') {
+          if (label.x < cx) {
+            targetTextWidth = linePoints[2][0] - layout.labelDistance - viewLeft - layout.edgeDistance;
+          } else {
+            targetTextWidth = viewLeft + viewWidth - layout.edgeDistance - linePoints[2][0] - layout.labelDistance;
+          }
+        } else if (layout.labelAlignTo === 'labelLine') {
+          if (label.x < cx) {
+            targetTextWidth = leftmostX - viewLeft - layout.bleedMargin;
+          } else {
+            targetTextWidth = viewLeft + viewWidth - rightmostX - layout.bleedMargin;
+          }
+        } else {
+          if (label.x < cx) {
+            targetTextWidth = label.x - viewLeft - layout.bleedMargin;
+          } else {
+            targetTextWidth = viewLeft + viewWidth - label.x - layout.bleedMargin;
+          }
+        }
+
+        layout.targetTextWidth = targetTextWidth;
+        constrainTextWidth(layout, targetTextWidth);
+      }
+    }
+
+    adjustSingleSide(rightList, cx, cy, r, 1, viewWidth, viewHeight, viewLeft, viewTop, rightmostX);
+    adjustSingleSide(leftList, cx, cy, r, -1, viewWidth, viewHeight, viewLeft, viewTop, leftmostX);
+
+    for (var i = 0; i < labelLayoutList.length; i++) {
+      var layout = labelLayoutList[i];
+
+      if (!isPositionCenter(layout) && layout.linePoints) {
+        var label = layout.label;
+        var linePoints = layout.linePoints;
+        var isAlignToEdge = layout.labelAlignTo === 'edge';
+        var padding = label.style.padding;
+        var paddingH = padding ? padding[1] + padding[3] : 0; // textRect.width already contains paddingH if bgColor is set
+
+        var extraPaddingH = label.style.backgroundColor ? 0 : paddingH;
+        var realTextWidth = layout.rect.width + extraPaddingH;
+        var dist = linePoints[1][0] - linePoints[2][0];
+
+        if (isAlignToEdge) {
+          if (label.x < cx) {
+            linePoints[2][0] = viewLeft + layout.edgeDistance + realTextWidth + layout.labelDistance;
+          } else {
+            linePoints[2][0] = viewLeft + viewWidth - layout.edgeDistance - realTextWidth - layout.labelDistance;
+          }
+        } else {
+          if (label.x < cx) {
+            linePoints[2][0] = label.x + layout.labelDistance;
+          } else {
+            linePoints[2][0] = label.x - layout.labelDistance;
+          }
+
+          linePoints[1][0] = linePoints[2][0] + dist;
+        }
+
+        linePoints[1][1] = linePoints[2][1] = label.y;
+      }
+    }
+  }
+  /**
+   * Set max width of each label, and then wrap each label to the max width.
+   *
+   * @param layout label layout
+   * @param availableWidth max width for the label to display
+   * @param forceRecalculate recaculate the text layout even if the current width
+   * is smaller than `availableWidth`. This is useful when the text was previously
+   * wrapped by calling `constrainTextWidth` but now `availableWidth` changed, in
+   * which case, previous wrapping should be redo.
+   */
+
+
+  function constrainTextWidth(layout, availableWidth, forceRecalculate) {
+    if (forceRecalculate === void 0) {
+      forceRecalculate = false;
+    }
+
+    if (layout.labelStyleWidth != null) {
+      // User-defined style.width has the highest priority.
+      return;
+    }
+
+    var label = layout.label;
+    var style = label.style;
+    var textRect = layout.rect;
+    var bgColor = style.backgroundColor;
+    var padding = style.padding;
+    var paddingH = padding ? padding[1] + padding[3] : 0;
+    var overflow = style.overflow; // textRect.width already contains paddingH if bgColor is set
+
+    var oldOuterWidth = textRect.width + (bgColor ? 0 : paddingH);
+
+    if (availableWidth < oldOuterWidth || forceRecalculate) {
+      var oldHeight = textRect.height;
+
+      if (overflow && overflow.match('break')) {
+        // Temporarily set background to be null to calculate
+        // the bounding box without backgroud.
+        label.setStyle('backgroundColor', null); // Set constraining width
+
+        label.setStyle('width', availableWidth - paddingH); // This is the real bounding box of the text without padding
+
+        var innerRect = label.getBoundingRect();
+        label.setStyle('width', Math.ceil(innerRect.width));
+        label.setStyle('backgroundColor', bgColor);
+      } else {
+        var availableInnerWidth = availableWidth - paddingH;
+        var newWidth = availableWidth < oldOuterWidth // Current text is too wide, use `availableWidth` as max width.
+        ? availableInnerWidth : // Current available width is enough, but the text may have
+        // already been wrapped with a smaller available width.
+        forceRecalculate ? availableInnerWidth > layout.unconstrainedWidth // Current available is larger than text width,
+        // so don't constrain width (otherwise it may have
+        // empty space in the background).
+        ? null // Current available is smaller than text width, so
+        // use the current available width as constraining
+        // width.
+        : availableInnerWidth : // Current available width is enough, so no need to
+        // constrain.
+        null;
+        label.setStyle('width', newWidth);
+      }
+
+      var newRect = label.getBoundingRect();
+      textRect.width = newRect.width;
+      var margin = (label.style.margin || 0) + 2.1;
+      textRect.height = newRect.height + margin;
+      textRect.y -= (textRect.height - oldHeight) / 2;
+    }
+  }
+
+  function isPositionCenter(sectorShape) {
+    // Not change x for center label
+    return sectorShape.position === 'center';
+  }
+
+  function pieLabelLayout(seriesModel) {
+    var data = seriesModel.getData();
+    var labelLayoutList = [];
+    var cx;
+    var cy;
+    var hasLabelRotate = false;
+    var minShowLabelRadian = (seriesModel.get('minShowLabelAngle') || 0) * RADIAN$1;
+    var viewRect = data.getLayout('viewRect');
+    var r = data.getLayout('r');
+    var viewWidth = viewRect.width;
+    var viewLeft = viewRect.x;
+    var viewTop = viewRect.y;
+    var viewHeight = viewRect.height;
+
+    function setNotShow(el) {
+      el.ignore = true;
+    }
+
+    function isLabelShown(label) {
+      if (!label.ignore) {
+        return true;
+      }
+
+      for (var key in label.states) {
+        if (label.states[key].ignore === false) {
+          return true;
+        }
+      }
+
+      return false;
+    }
+
+    data.each(function (idx) {
+      var sector = data.getItemGraphicEl(idx);
+      var sectorShape = sector.shape;
+      var label = sector.getTextContent();
+      var labelLine = sector.getTextGuideLine();
+      var itemModel = data.getItemModel(idx);
+      var labelModel = itemModel.getModel('label'); // Use position in normal or emphasis
+
+      var labelPosition = labelModel.get('position') || itemModel.get(['emphasis', 'label', 'position']);
+      var labelDistance = labelModel.get('distanceToLabelLine');
+      var labelAlignTo = labelModel.get('alignTo');
+      var edgeDistance = parsePercent$1(labelModel.get('edgeDistance'), viewWidth);
+      var bleedMargin = labelModel.get('bleedMargin');
+      var labelLineModel = itemModel.getModel('labelLine');
+      var labelLineLen = labelLineModel.get('length');
+      labelLineLen = parsePercent$1(labelLineLen, viewWidth);
+      var labelLineLen2 = labelLineModel.get('length2');
+      labelLineLen2 = parsePercent$1(labelLineLen2, viewWidth);
+
+      if (Math.abs(sectorShape.endAngle - sectorShape.startAngle) < minShowLabelRadian) {
+        each(label.states, setNotShow);
+        label.ignore = true;
+        return;
+      }
+
+      if (!isLabelShown(label)) {
+        return;
+      }
+
+      var midAngle = (sectorShape.startAngle + sectorShape.endAngle) / 2;
+      var nx = Math.cos(midAngle);
+      var ny = Math.sin(midAngle);
+      var textX;
+      var textY;
+      var linePoints;
+      var textAlign;
+      cx = sectorShape.cx;
+      cy = sectorShape.cy;
+      var isLabelInside = labelPosition === 'inside' || labelPosition === 'inner';
+
+      if (labelPosition === 'center') {
+        textX = sectorShape.cx;
+        textY = sectorShape.cy;
+        textAlign = 'center';
+      } else {
+        var x1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * nx : sectorShape.r * nx) + cx;
+        var y1 = (isLabelInside ? (sectorShape.r + sectorShape.r0) / 2 * ny : sectorShape.r * ny) + cy;
+        textX = x1 + nx * 3;
+        textY = y1 + ny * 3;
+
+        if (!isLabelInside) {
+          // For roseType
+          var x2 = x1 + nx * (labelLineLen + r - sectorShape.r);
+          var y2 = y1 + ny * (labelLineLen + r - sectorShape.r);
+          var x3 = x2 + (nx < 0 ? -1 : 1) * labelLineLen2;
+          var y3 = y2;
+
+          if (labelAlignTo === 'edge') {
+            // Adjust textX because text align of edge is opposite
+            textX = nx < 0 ? viewLeft + edgeDistance : viewLeft + viewWidth - edgeDistance;
+          } else {
+            textX = x3 + (nx < 0 ? -labelDistance : labelDistance);
+          }
+
+          textY = y3;
+          linePoints = [[x1, y1], [x2, y2], [x3, y3]];
+        }
+
+        textAlign = isLabelInside ? 'center' : labelAlignTo === 'edge' ? nx > 0 ? 'right' : 'left' : nx > 0 ? 'left' : 'right';
+      }
+
+      var PI = Math.PI;
+      var labelRotate = 0;
+      var rotate = labelModel.get('rotate');
+
+      if (isNumber(rotate)) {
+        labelRotate = rotate * (PI / 180);
+      } else if (labelPosition === 'center') {
+        labelRotate = 0;
+      } else if (rotate === 'radial' || rotate === true) {
+        var radialAngle = nx < 0 ? -midAngle + PI : -midAngle;
+        labelRotate = radialAngle;
+      } else if (rotate === 'tangential' && labelPosition !== 'outside' && labelPosition !== 'outer') {
+        var rad = Math.atan2(nx, ny);
+
+        if (rad < 0) {
+          rad = PI * 2 + rad;
+        }
+
+        var isDown = ny > 0;
+
+        if (isDown) {
+          rad = PI + rad;
+        }
+
+        labelRotate = rad - PI;
+      }
+
+      hasLabelRotate = !!labelRotate;
+      label.x = textX;
+      label.y = textY;
+      label.rotation = labelRotate;
+      label.setStyle({
+        verticalAlign: 'middle'
+      }); // Not sectorShape the inside label
+
+      if (!isLabelInside) {
+        var textRect = label.getBoundingRect().clone();
+        textRect.applyTransform(label.getComputedTransform()); // Text has a default 1px stroke. Exclude this.
+
+        var margin = (label.style.margin || 0) + 2.1;
+        textRect.y -= margin / 2;
+        textRect.height += margin;
+        labelLayoutList.push({
+          label: label,
+          labelLine: labelLine,
+          position: labelPosition,
+          len: labelLineLen,
+          len2: labelLineLen2,
+          minTurnAngle: labelLineModel.get('minTurnAngle'),
+          maxSurfaceAngle: labelLineModel.get('maxSurfaceAngle'),
+          surfaceNormal: new Point(nx, ny),
+          linePoints: linePoints,
+          textAlign: textAlign,
+          labelDistance: labelDistance,
+          labelAlignTo: labelAlignTo,
+          edgeDistance: edgeDistance,
+          bleedMargin: bleedMargin,
+          rect: textRect,
+          unconstrainedWidth: textRect.width,
+          labelStyleWidth: label.style.width
+        });
+      } else {
+        label.setStyle({
+          align: textAlign
+        });
+        var selectState = label.states.select;
+
+        if (selectState) {
+          selectState.x += label.x;
+          selectState.y += label.y;
+        }
+      }
+
+      sector.setTextConfig({
+        inside: isLabelInside
+      });
+    });
+
+    if (!hasLabelRotate && seriesModel.get('avoidLabelOverlap')) {
+      avoidOverlap(labelLayoutList, cx, cy, r, viewWidth, viewHeight, viewLeft, viewTop);
+    }
+
+    for (var i = 0; i < labelLayoutList.length; i++) {
+      var layout = labelLayoutList[i];
+      var label = layout.label;
+      var labelLine = layout.labelLine;
+      var notShowLabel = isNaN(label.x) || isNaN(label.y);
+
+      if (label) {
+        label.setStyle({
+          align: layout.textAlign
+        });
+
+        if (notShowLabel) {
+          each(label.states, setNotShow);
+          label.ignore = true;
+        }
+
+        var selectState = label.states.select;
+
+        if (selectState) {
+          selectState.x += label.x;
+          selectState.y += label.y;
+        }
+      }
+
+      if (labelLine) {
+        var linePoints = layout.linePoints;
+
+        if (notShowLabel || !linePoints) {
+          each(labelLine.states, setNotShow);
+          labelLine.ignore = true;
+        } else {
+          limitTurnAngle(linePoints, layout.minTurnAngle);
+          limitSurfaceAngle(linePoints, layout.surfaceNormal, layout.maxSurfaceAngle);
+          labelLine.setShape({
+            points: linePoints
+          }); // Set the anchor to the midpoint of sector
+
+          label.__hostTarget.textGuideLineConfig = {
+            anchor: new Point(linePoints[0][0], linePoints[0][1])
+          };
+        }
+      }
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 getSectorCornerRadius(model, shape, zeroIfNull) {
+    var cornerRadius = model.get('borderRadius');
+
+    if (cornerRadius == null) {
+      return zeroIfNull ? {
+        cornerRadius: 0
+      } : null;
+    }
+
+    if (!isArray(cornerRadius)) {
+      cornerRadius = [cornerRadius, cornerRadius, cornerRadius, cornerRadius];
+    }
+
+    var dr = Math.abs(shape.r || 0 - shape.r0 || 0);
+    return {
+      cornerRadius: map(cornerRadius, function (cr) {
+        return parsePercent(cr, dr);
+      })
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Piece of pie including Sector, Label, LabelLine
+   */
+
+
+  var PiePiece =
+  /** @class */
+  function (_super) {
+    __extends(PiePiece, _super);
+
+    function PiePiece(data, idx, startAngle) {
+      var _this = _super.call(this) || this;
+
+      _this.z2 = 2;
+      var text = new ZRText();
+
+      _this.setTextContent(text);
+
+      _this.updateData(data, idx, startAngle, true);
+
+      return _this;
+    }
+
+    PiePiece.prototype.updateData = function (data, idx, startAngle, firstCreate) {
+      var sector = this;
+      var seriesModel = data.hostModel;
+      var itemModel = data.getItemModel(idx);
+      var emphasisModel = itemModel.getModel('emphasis');
+      var layout = data.getItemLayout(idx); // cornerRadius & innerCornerRadius doesn't exist in the item layout. Use `0` if null value is specified.
+      // see `setItemLayout` in `pieLayout.ts`.
+
+      var sectorShape = extend(getSectorCornerRadius(itemModel.getModel('itemStyle'), layout, true), layout); // Ignore NaN data.
+
+      if (isNaN(sectorShape.startAngle)) {
+        // Use NaN shape to avoid drawing shape.
+        sector.setShape(sectorShape);
+        return;
+      }
+
+      if (firstCreate) {
+        sector.setShape(sectorShape);
+        var animationType = seriesModel.getShallow('animationType');
+
+        if (seriesModel.ecModel.ssr) {
+          // Use scale animation in SSR mode(opacity?)
+          // Because CSS SVG animation doesn't support very customized shape animation.
+          initProps(sector, {
+            scaleX: 0,
+            scaleY: 0
+          }, seriesModel, {
+            dataIndex: idx,
+            isFrom: true
+          });
+          sector.originX = sectorShape.cx;
+          sector.originY = sectorShape.cy;
+        } else if (animationType === 'scale') {
+          sector.shape.r = layout.r0;
+          initProps(sector, {
+            shape: {
+              r: layout.r
+            }
+          }, seriesModel, idx);
+        } // Expansion
+        else {
+            if (startAngle != null) {
+              sector.setShape({
+                startAngle: startAngle,
+                endAngle: startAngle
+              });
+              initProps(sector, {
+                shape: {
+                  startAngle: layout.startAngle,
+                  endAngle: layout.endAngle
+                }
+              }, seriesModel, idx);
+            } else {
+              sector.shape.endAngle = layout.startAngle;
+              updateProps(sector, {
+                shape: {
+                  endAngle: layout.endAngle
+                }
+              }, seriesModel, idx);
+            }
+          }
+      } else {
+        saveOldStyle(sector); // Transition animation from the old shape
+
+        updateProps(sector, {
+          shape: sectorShape
+        }, seriesModel, idx);
+      }
+
+      sector.useStyle(data.getItemVisual(idx, 'style'));
+      setStatesStylesFromModel(sector, itemModel);
+      var midAngle = (layout.startAngle + layout.endAngle) / 2;
+      var offset = seriesModel.get('selectedOffset');
+      var dx = Math.cos(midAngle) * offset;
+      var dy = Math.sin(midAngle) * offset;
+      var cursorStyle = itemModel.getShallow('cursor');
+      cursorStyle && sector.attr('cursor', cursorStyle);
+
+      this._updateLabel(seriesModel, data, idx);
+
+      sector.ensureState('emphasis').shape = extend({
+        r: layout.r + (emphasisModel.get('scale') ? emphasisModel.get('scaleSize') || 0 : 0)
+      }, getSectorCornerRadius(emphasisModel.getModel('itemStyle'), layout));
+      extend(sector.ensureState('select'), {
+        x: dx,
+        y: dy,
+        shape: getSectorCornerRadius(itemModel.getModel(['select', 'itemStyle']), layout)
+      });
+      extend(sector.ensureState('blur'), {
+        shape: getSectorCornerRadius(itemModel.getModel(['blur', 'itemStyle']), layout)
+      });
+      var labelLine = sector.getTextGuideLine();
+      var labelText = sector.getTextContent();
+      labelLine && extend(labelLine.ensureState('select'), {
+        x: dx,
+        y: dy
+      }); // TODO: needs dx, dy in zrender?
+
+      extend(labelText.ensureState('select'), {
+        x: dx,
+        y: dy
+      });
+      toggleHoverEmphasis(this, emphasisModel.get('focus'), emphasisModel.get('blurScope'), emphasisModel.get('disabled'));
+    };
+
+    PiePiece.prototype._updateLabel = function (seriesModel, data, idx) {
+      var sector = this;
+      var itemModel = data.getItemModel(idx);
+      var labelLineModel = itemModel.getModel('labelLine');
+      var style = data.getItemVisual(idx, 'style');
+      var visualColor = style && style.fill;
+      var visualOpacity = style && style.opacity;
+      setLabelStyle(sector, getLabelStatesModels(itemModel), {
+        labelFetcher: data.hostModel,
+        labelDataIndex: idx,
+        inheritColor: visualColor,
+        defaultOpacity: visualOpacity,
+        defaultText: seriesModel.getFormattedLabel(idx, 'normal') || data.getName(idx)
+      });
+      var labelText = sector.getTextContent(); // Set textConfig on sector.
+
+      sector.setTextConfig({
+        // reset position, rotation
+        position: null,
+        rotation: null
+      }); // Make sure update style on labelText after setLabelStyle.
+      // Because setLabelStyle will replace a new style on it.
+
+      labelText.attr({
+        z2: 10
+      });
+      var labelPosition = seriesModel.get(['label', 'position']);
+
+      if (labelPosition !== 'outside' && labelPosition !== 'outer') {
+        sector.removeTextGuideLine();
+      } else {
+        var polyline = this.getTextGuideLine();
+
+        if (!polyline) {
+          polyline = new Polyline();
+          this.setTextGuideLine(polyline);
+        } // Default use item visual color
+
+
+        setLabelLineStyle(this, getLabelLineStatesModels(itemModel), {
+          stroke: visualColor,
+          opacity: retrieve3(labelLineModel.get(['lineStyle', 'opacity']), visualOpacity, 1)
+        });
+      }
+    };
+
+    return PiePiece;
+  }(Sector); // Pie view
+
+
+  var PieView =
+  /** @class */
+  function (_super) {
+    __extends(PieView, _super);
+
+    function PieView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.ignoreLabelLineUpdate = true;
+      return _this;
+    }
+
+    PieView.prototype.render = function (seriesModel, ecModel, api, payload) {
+      var data = seriesModel.getData();
+      var oldData = this._data;
+      var group = this.group;
+      var startAngle; // First render
+
+      if (!oldData && data.count() > 0) {
+        var shape = data.getItemLayout(0);
+
+        for (var s = 1; isNaN(shape && shape.startAngle) && s < data.count(); ++s) {
+          shape = data.getItemLayout(s);
+        }
+
+        if (shape) {
+          startAngle = shape.startAngle;
+        }
+      } // remove empty-circle if it exists
+
+
+      if (this._emptyCircleSector) {
+        group.remove(this._emptyCircleSector);
+      } // when all data are filtered, show lightgray empty circle
+
+
+      if (data.count() === 0 && seriesModel.get('showEmptyCircle')) {
+        var sector = new Sector({
+          shape: getBasicPieLayout(seriesModel, api)
+        });
+        sector.useStyle(seriesModel.getModel('emptyCircleStyle').getItemStyle());
+        this._emptyCircleSector = sector;
+        group.add(sector);
+      }
+
+      data.diff(oldData).add(function (idx) {
+        var piePiece = new PiePiece(data, idx, startAngle);
+        data.setItemGraphicEl(idx, piePiece);
+        group.add(piePiece);
+      }).update(function (newIdx, oldIdx) {
+        var piePiece = oldData.getItemGraphicEl(oldIdx);
+        piePiece.updateData(data, newIdx, startAngle);
+        piePiece.off('click');
+        group.add(piePiece);
+        data.setItemGraphicEl(newIdx, piePiece);
+      }).remove(function (idx) {
+        var piePiece = oldData.getItemGraphicEl(idx);
+        removeElementWithFadeOut(piePiece, seriesModel, idx);
+      }).execute();
+      pieLabelLayout(seriesModel); // Always use initial animation.
+
+      if (seriesModel.get('animationTypeUpdate') !== 'expansion') {
+        this._data = data;
+      }
+    };
+
+    PieView.prototype.dispose = function () {};
+
+    PieView.prototype.containPoint = function (point, seriesModel) {
+      var data = seriesModel.getData();
+      var itemLayout = data.getItemLayout(0);
+
+      if (itemLayout) {
+        var dx = point[0] - itemLayout.cx;
+        var dy = point[1] - itemLayout.cy;
+        var radius = Math.sqrt(dx * dx + dy * dy);
+        return radius <= itemLayout.r && radius >= itemLayout.r0;
+      }
+    };
+
+    PieView.type = 'pie';
+    return PieView;
+  }(ChartView);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * [Usage]:
+   * (1)
+   * createListSimply(seriesModel, ['value']);
+   * (2)
+   * createListSimply(seriesModel, {
+   *     coordDimensions: ['value'],
+   *     dimensionsCount: 5
+   * });
+   */
+
+
+  function createSeriesDataSimply(seriesModel, opt, nameList) {
+    opt = isArray(opt) && {
+      coordDimensions: opt
+    } || extend({
+      encodeDefine: seriesModel.getEncode()
+    }, opt);
+    var source = seriesModel.getSource();
+    var dimensions = prepareSeriesDataSchema(source, opt).dimensions;
+    var list = new SeriesData(dimensions, seriesModel);
+    list.initData(source, nameList);
+    return list;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * LegendVisualProvider is an bridge that pick encoded color from data and
+   * provide to the legend component.
+   */
+
+
+  var LegendVisualProvider =
+  /** @class */
+  function () {
+    function LegendVisualProvider( // Function to get data after filtered. It stores all the encoding info
+    getDataWithEncodedVisual, // Function to get raw data before filtered.
+    getRawData) {
+      this._getDataWithEncodedVisual = getDataWithEncodedVisual;
+      this._getRawData = getRawData;
+    }
+
+    LegendVisualProvider.prototype.getAllNames = function () {
+      var rawData = this._getRawData(); // We find the name from the raw data. In case it's filtered by the legend component.
+      // Normally, the name can be found in rawData, but can't be found in filtered data will display as gray.
+
+
+      return rawData.mapArray(rawData.getName);
+    };
+
+    LegendVisualProvider.prototype.containName = function (name) {
+      var rawData = this._getRawData();
+
+      return rawData.indexOfName(name) >= 0;
+    };
+
+    LegendVisualProvider.prototype.indexOfName = function (name) {
+      // Only get data when necessary.
+      // Because LegendVisualProvider constructor may be new in the stage that data is not prepared yet.
+      // Invoking Series#getData immediately will throw an error.
+      var dataWithEncodedVisual = this._getDataWithEncodedVisual();
+
+      return dataWithEncodedVisual.indexOfName(name);
+    };
+
+    LegendVisualProvider.prototype.getItemVisual = function (dataIndex, key) {
+      // Get encoded visual properties from final filtered data.
+      var dataWithEncodedVisual = this._getDataWithEncodedVisual();
+
+      return dataWithEncodedVisual.getItemVisual(dataIndex, key);
+    };
+
+    return LegendVisualProvider;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 PieSeriesModel =
+  /** @class */
+  function (_super) {
+    __extends(PieSeriesModel, _super);
+
+    function PieSeriesModel() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+    /**
+     * @overwrite
+     */
+
+
+    PieSeriesModel.prototype.init = function (option) {
+      _super.prototype.init.apply(this, arguments); // Enable legend selection for each data item
+      // Use a function instead of direct access because data reference may changed
+
+
+      this.legendVisualProvider = new LegendVisualProvider(bind(this.getData, this), bind(this.getRawData, this));
+
+      this._defaultLabelLine(option);
+    };
+    /**
+     * @overwrite
+     */
+
+
+    PieSeriesModel.prototype.mergeOption = function () {
+      _super.prototype.mergeOption.apply(this, arguments);
+    };
+    /**
+     * @overwrite
+     */
+
+
+    PieSeriesModel.prototype.getInitialData = function () {
+      return createSeriesDataSimply(this, {
+        coordDimensions: ['value'],
+        encodeDefaulter: curry(makeSeriesEncodeForNameBased, this)
+      });
+    };
+    /**
+     * @overwrite
+     */
+
+
+    PieSeriesModel.prototype.getDataParams = function (dataIndex) {
+      var data = this.getData();
+
+      var params = _super.prototype.getDataParams.call(this, dataIndex); // FIXME toFixed?
+
+
+      var valueList = [];
+      data.each(data.mapDimension('value'), function (value) {
+        valueList.push(value);
+      });
+      params.percent = getPercentWithPrecision(valueList, dataIndex, data.hostModel.get('percentPrecision'));
+      params.$vars.push('percent');
+      return params;
+    };
+
+    PieSeriesModel.prototype._defaultLabelLine = function (option) {
+      // Extend labelLine emphasis
+      defaultEmphasis(option, 'labelLine', ['show']);
+      var labelLineNormalOpt = option.labelLine;
+      var labelLineEmphasisOpt = option.emphasis.labelLine; // Not show label line if `label.normal.show = false`
+
+      labelLineNormalOpt.show = labelLineNormalOpt.show && option.label.show;
+      labelLineEmphasisOpt.show = labelLineEmphasisOpt.show && option.emphasis.label.show;
+    };
+
+    PieSeriesModel.type = 'series.pie';
+    PieSeriesModel.defaultOption = {
+      // zlevel: 0,
+      z: 2,
+      legendHoverLink: true,
+      colorBy: 'data',
+      // 默认全局居中
+      center: ['50%', '50%'],
+      radius: [0, '75%'],
+      // 默认顺时针
+      clockwise: true,
+      startAngle: 90,
+      // 最小角度改为0
+      minAngle: 0,
+      // If the angle of a sector less than `minShowLabelAngle`,
+      // the label will not be displayed.
+      minShowLabelAngle: 0,
+      // 选中时扇区偏移量
+      selectedOffset: 10,
+      // 选择模式,默认关闭,可选single,multiple
+      // selectedMode: false,
+      // 南丁格尔玫瑰图模式,'radius'(半径) | 'area'(面积)
+      // roseType: null,
+      percentPrecision: 2,
+      // If still show when all data zero.
+      stillShowZeroSum: true,
+      // cursor: null,
+      left: 0,
+      top: 0,
+      right: 0,
+      bottom: 0,
+      width: null,
+      height: null,
+      label: {
+        // color: 'inherit',
+        // If rotate around circle
+        rotate: 0,
+        show: true,
+        overflow: 'truncate',
+        // 'outer', 'inside', 'center'
+        position: 'outer',
+        // 'none', 'labelLine', 'edge'. Works only when position is 'outer'
+        alignTo: 'none',
+        // Closest distance between label and chart edge.
+        // Works only position is 'outer' and alignTo is 'edge'.
+        edgeDistance: '25%',
+        // Works only position is 'outer' and alignTo is not 'edge'.
+        bleedMargin: 10,
+        // Distance between text and label line.
+        distanceToLabelLine: 5 // formatter: 标签文本格式器,同Tooltip.formatter,不支持异步回调
+        // 默认使用全局文本样式,详见TEXTSTYLE
+        // distance: 当position为inner时有效,为label位置到圆心的距离与圆半径(环状图为内外半径和)的比例系数
+
+      },
+      // Enabled when label.normal.position is 'outer'
+      labelLine: {
+        show: true,
+        // 引导线两段中的第一段长度
+        length: 15,
+        // 引导线两段中的第二段长度
+        length2: 15,
+        smooth: false,
+        minTurnAngle: 90,
+        maxSurfaceAngle: 90,
+        lineStyle: {
+          // color: 各异,
+          width: 1,
+          type: 'solid'
+        }
+      },
+      itemStyle: {
+        borderWidth: 1,
+        borderJoin: 'round'
+      },
+      showEmptyCircle: true,
+      emptyCircleStyle: {
+        color: 'lightgray',
+        opacity: 1
+      },
+      labelLayout: {
+        // Hide the overlapped label.
+        hideOverlap: true
+      },
+      emphasis: {
+        scale: true,
+        scaleSize: 5
+      },
+      // If use strategy to avoid label overlapping
+      avoidLabelOverlap: true,
+      // Animation type. Valid values: expansion, scale
+      animationType: 'expansion',
+      animationDuration: 1000,
+      // Animation type when update. Valid values: transition, expansion
+      animationTypeUpdate: 'transition',
+      animationEasingUpdate: 'cubicInOut',
+      animationDurationUpdate: 500,
+      animationEasing: 'cubicInOut'
+    };
+    return PieSeriesModel;
+  }(SeriesModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 negativeDataFilter(seriesType) {
+    return {
+      seriesType: seriesType,
+      reset: function (seriesModel, ecModel) {
+        var data = seriesModel.getData();
+        data.filterSelf(function (idx) {
+          // handle negative value condition
+          var valueDim = data.mapDimension('value');
+          var curValue = data.get(valueDim, idx);
+
+          if (isNumber(curValue) && !isNaN(curValue) && curValue < 0) {
+            return false;
+          }
+
+          return true;
+        });
+      }
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install$4(registers) {
+    registers.registerChartView(PieView);
+    registers.registerSeriesModel(PieSeriesModel);
+    createLegacyDataSelectAction('pie', registers.registerAction);
+    registers.registerLayout(curry(pieLayout, 'pie'));
+    registers.registerProcessor(dataFilter('pie'));
+    registers.registerProcessor(negativeDataFilter('pie'));
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+
+  use(install$4);
+  /*
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * 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.
+   */
+
+  /*
+  * 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 GridModel =
+  /** @class */
+  function (_super) {
+    __extends(GridModel, _super);
+
+    function GridModel() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    GridModel.type = 'grid';
+    GridModel.dependencies = ['xAxis', 'yAxis'];
+    GridModel.layoutMode = 'box';
+    GridModel.defaultOption = {
+      show: false,
+      // zlevel: 0,
+      z: 0,
+      left: '10%',
+      top: 60,
+      right: '10%',
+      bottom: 70,
+      // If grid size contain label
+      containLabel: false,
+      // width: {totalWidth} - left - right,
+      // height: {totalHeight} - top - bottom,
+      backgroundColor: 'rgba(0,0,0,0)',
+      borderWidth: 1,
+      borderColor: '#ccc'
+    };
+    return GridModel;
+  }(ComponentModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 CartesianAxisModel =
+  /** @class */
+  function (_super) {
+    __extends(CartesianAxisModel, _super);
+
+    function CartesianAxisModel() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+
+    CartesianAxisModel.prototype.getCoordSysModel = function () {
+      return this.getReferringComponents('grid', SINGLE_REFERRING).models[0];
+    };
+
+    CartesianAxisModel.type = 'cartesian2dAxis';
+    return CartesianAxisModel;
+  }(ComponentModel);
+
+  mixin(CartesianAxisModel, AxisModelCommonMixin);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 defaultOption = {
+    show: true,
+    // zlevel: 0,
+    z: 0,
+    // Inverse the axis.
+    inverse: false,
+    // Axis name displayed.
+    name: '',
+    // 'start' | 'middle' | 'end'
+    nameLocation: 'end',
+    // By degree. By default auto rotate by nameLocation.
+    nameRotate: null,
+    nameTruncate: {
+      maxWidth: null,
+      ellipsis: '...',
+      placeholder: '.'
+    },
+    // Use global text style by default.
+    nameTextStyle: {},
+    // The gap between axisName and axisLine.
+    nameGap: 15,
+    // Default `false` to support tooltip.
+    silent: false,
+    // Default `false` to avoid legacy user event listener fail.
+    triggerEvent: false,
+    tooltip: {
+      show: false
+    },
+    axisPointer: {},
+    axisLine: {
+      show: true,
+      onZero: true,
+      onZeroAxisIndex: null,
+      lineStyle: {
+        color: '#6E7079',
+        width: 1,
+        type: 'solid'
+      },
+      // The arrow at both ends the the axis.
+      symbol: ['none', 'none'],
+      symbolSize: [10, 15]
+    },
+    axisTick: {
+      show: true,
+      // Whether axisTick is inside the grid or outside the grid.
+      inside: false,
+      // The length of axisTick.
+      length: 5,
+      lineStyle: {
+        width: 1
+      }
+    },
+    axisLabel: {
+      show: true,
+      // Whether axisLabel is inside the grid or outside the grid.
+      inside: false,
+      rotate: 0,
+      // true | false | null/undefined (auto)
+      showMinLabel: null,
+      // true | false | null/undefined (auto)
+      showMaxLabel: null,
+      margin: 8,
+      // formatter: null,
+      fontSize: 12
+    },
+    splitLine: {
+      show: true,
+      lineStyle: {
+        color: ['#E0E6F1'],
+        width: 1,
+        type: 'solid'
+      }
+    },
+    splitArea: {
+      show: false,
+      areaStyle: {
+        color: ['rgba(250,250,250,0.2)', 'rgba(210,219,238,0.2)']
+      }
+    }
+  };
+  var categoryAxis = merge({
+    // The gap at both ends of the axis. For categoryAxis, boolean.
+    boundaryGap: true,
+    // Set false to faster category collection.
+    deduplication: null,
+    // splitArea: {
+    // show: false
+    // },
+    splitLine: {
+      show: false
+    },
+    axisTick: {
+      // If tick is align with label when boundaryGap is true
+      alignWithLabel: false,
+      interval: 'auto'
+    },
+    axisLabel: {
+      interval: 'auto'
+    }
+  }, defaultOption);
+  var valueAxis = merge({
+    boundaryGap: [0, 0],
+    axisLine: {
+      // Not shown when other axis is categoryAxis in cartesian
+      show: 'auto'
+    },
+    axisTick: {
+      // Not shown when other axis is categoryAxis in cartesian
+      show: 'auto'
+    },
+    // TODO
+    // min/max: [30, datamin, 60] or [20, datamin] or [datamin, 60]
+    splitNumber: 5,
+    minorTick: {
+      // Minor tick, not available for cateogry axis.
+      show: false,
+      // Split number of minor ticks. The value should be in range of (0, 100)
+      splitNumber: 5,
+      // Lenght of minor tick
+      length: 3,
+      // Line style
+      lineStyle: {// Default to be same with axisTick
+      }
+    },
+    minorSplitLine: {
+      show: false,
+      lineStyle: {
+        color: '#F4F7FD',
+        width: 1
+      }
+    }
+  }, defaultOption);
+  var timeAxis = merge({
+    splitNumber: 6,
+    axisLabel: {
+      // To eliminate labels that are not nice
+      showMinLabel: false,
+      showMaxLabel: false,
+      rich: {
+        primary: {
+          fontWeight: 'bold'
+        }
+      }
+    },
+    splitLine: {
+      show: false
+    }
+  }, valueAxis);
+  var logAxis = defaults({
+    logBase: 10
+  }, valueAxis);
+  var axisDefault = {
+    category: categoryAxis,
+    value: valueAxis,
+    time: timeAxis,
+    log: logAxis
+  };
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 AXIS_TYPES = {
+    value: 1,
+    category: 1,
+    time: 1,
+    log: 1
+  };
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Generate sub axis model class
+   * @param axisName 'x' 'y' 'radius' 'angle' 'parallel' ...
+   */
+
+  function axisModelCreator(registers, axisName, BaseAxisModelClass, extraDefaultOption) {
+    each(AXIS_TYPES, function (v, axisType) {
+      var defaultOption = merge(merge({}, axisDefault[axisType], true), extraDefaultOption, true);
+
+      var AxisModel =
+      /** @class */
+      function (_super) {
+        __extends(AxisModel, _super);
+
+        function AxisModel() {
+          var _this = _super !== null && _super.apply(this, arguments) || this;
+
+          _this.type = axisName + 'Axis.' + axisType;
+          return _this;
+        }
+
+        AxisModel.prototype.mergeDefaultAndTheme = function (option, ecModel) {
+          var layoutMode = fetchLayoutMode(this);
+          var inputPositionParams = layoutMode ? getLayoutParams(option) : {};
+          var themeModel = ecModel.getTheme();
+          merge(option, themeModel.get(axisType + 'Axis'));
+          merge(option, this.getDefaultOption());
+          option.type = getAxisType(option);
+
+          if (layoutMode) {
+            mergeLayoutParam(option, inputPositionParams, layoutMode);
+          }
+        };
+
+        AxisModel.prototype.optionUpdated = function () {
+          var thisOption = this.option;
+
+          if (thisOption.type === 'category') {
+            this.__ordinalMeta = OrdinalMeta.createByAxisModel(this);
+          }
+        };
+        /**
+         * Should not be called before all of 'getInitailData' finished.
+         * Because categories are collected during initializing data.
+         */
+
+
+        AxisModel.prototype.getCategories = function (rawData) {
+          var option = this.option; // FIXME
+          // warning if called before all of 'getInitailData' finished.
+
+          if (option.type === 'category') {
+            if (rawData) {
+              return option.data;
+            }
+
+            return this.__ordinalMeta.categories;
+          }
+        };
+
+        AxisModel.prototype.getOrdinalMeta = function () {
+          return this.__ordinalMeta;
+        };
+
+        AxisModel.type = axisName + 'Axis.' + axisType;
+        AxisModel.defaultOption = defaultOption;
+        return AxisModel;
+      }(BaseAxisModelClass);
+
+      registers.registerComponentModel(AxisModel);
+    });
+    registers.registerSubTypeDefaulter(axisName + 'Axis', getAxisType);
+  }
+
+  function getAxisType(option) {
+    // Default axis with data is category axis
+    return option.type || (option.data ? 'category' : 'value');
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 Cartesian =
+  /** @class */
+  function () {
+    function Cartesian(name) {
+      this.type = 'cartesian';
+      this._dimList = [];
+      this._axes = {};
+      this.name = name || '';
+    }
+
+    Cartesian.prototype.getAxis = function (dim) {
+      return this._axes[dim];
+    };
+
+    Cartesian.prototype.getAxes = function () {
+      return map(this._dimList, function (dim) {
+        return this._axes[dim];
+      }, this);
+    };
+
+    Cartesian.prototype.getAxesByScale = function (scaleType) {
+      scaleType = scaleType.toLowerCase();
+      return filter(this.getAxes(), function (axis) {
+        return axis.scale.type === scaleType;
+      });
+    };
+
+    Cartesian.prototype.addAxis = function (axis) {
+      var dim = axis.dim;
+      this._axes[dim] = axis;
+
+      this._dimList.push(dim);
+    };
+
+    return Cartesian;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 cartesian2DDimensions = ['x', 'y'];
+
+  function canCalculateAffineTransform(scale$$1) {
+    return scale$$1.type === 'interval' || scale$$1.type === 'time';
+  }
+
+  var Cartesian2D =
+  /** @class */
+  function (_super) {
+    __extends(Cartesian2D, _super);
+
+    function Cartesian2D() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = 'cartesian2d';
+      _this.dimensions = cartesian2DDimensions;
+      return _this;
+    }
+    /**
+     * Calculate an affine transform matrix if two axes are time or value.
+     * It's mainly for accelartion on the large time series data.
+     */
+
+
+    Cartesian2D.prototype.calcAffineTransform = function () {
+      this._transform = this._invTransform = null;
+      var xAxisScale = this.getAxis('x').scale;
+      var yAxisScale = this.getAxis('y').scale;
+
+      if (!canCalculateAffineTransform(xAxisScale) || !canCalculateAffineTransform(yAxisScale)) {
+        return;
+      }
+
+      var xScaleExtent = xAxisScale.getExtent();
+      var yScaleExtent = yAxisScale.getExtent();
+      var start = this.dataToPoint([xScaleExtent[0], yScaleExtent[0]]);
+      var end = this.dataToPoint([xScaleExtent[1], yScaleExtent[1]]);
+      var xScaleSpan = xScaleExtent[1] - xScaleExtent[0];
+      var yScaleSpan = yScaleExtent[1] - yScaleExtent[0];
+
+      if (!xScaleSpan || !yScaleSpan) {
+        return;
+      } // Accelerate data to point calculation on the special large time series data.
+
+
+      var scaleX = (end[0] - start[0]) / xScaleSpan;
+      var scaleY = (end[1] - start[1]) / yScaleSpan;
+      var translateX = start[0] - xScaleExtent[0] * scaleX;
+      var translateY = start[1] - yScaleExtent[0] * scaleY;
+      var m = this._transform = [scaleX, 0, 0, scaleY, translateX, translateY];
+      this._invTransform = invert([], m);
+    };
+    /**
+     * Base axis will be used on stacking.
+     */
+
+
+    Cartesian2D.prototype.getBaseAxis = function () {
+      return this.getAxesByScale('ordinal')[0] || this.getAxesByScale('time')[0] || this.getAxis('x');
+    };
+
+    Cartesian2D.prototype.containPoint = function (point) {
+      var axisX = this.getAxis('x');
+      var axisY = this.getAxis('y');
+      return axisX.contain(axisX.toLocalCoord(point[0])) && axisY.contain(axisY.toLocalCoord(point[1]));
+    };
+
+    Cartesian2D.prototype.containData = function (data) {
+      return this.getAxis('x').containData(data[0]) && this.getAxis('y').containData(data[1]);
+    };
+
+    Cartesian2D.prototype.containZone = function (data1, data2) {
+      var zoneDiag1 = this.dataToPoint(data1);
+      var zoneDiag2 = this.dataToPoint(data2);
+      var area = this.getArea();
+      var zone = new BoundingRect(zoneDiag1[0], zoneDiag1[1], zoneDiag2[0] - zoneDiag1[0], zoneDiag2[1] - zoneDiag1[1]);
+      return area.intersect(zone);
+    };
+
+    Cartesian2D.prototype.dataToPoint = function (data, clamp, out) {
+      out = out || [];
+      var xVal = data[0];
+      var yVal = data[1]; // Fast path
+
+      if (this._transform // It's supported that if data is like `[Inifity, 123]`, where only Y pixel calculated.
+      && xVal != null && isFinite(xVal) && yVal != null && isFinite(yVal)) {
+        return applyTransform(out, data, this._transform);
+      }
+
+      var xAxis = this.getAxis('x');
+      var yAxis = this.getAxis('y');
+      out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(xVal, clamp));
+      out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(yVal, clamp));
+      return out;
+    };
+
+    Cartesian2D.prototype.clampData = function (data, out) {
+      var xScale = this.getAxis('x').scale;
+      var yScale = this.getAxis('y').scale;
+      var xAxisExtent = xScale.getExtent();
+      var yAxisExtent = yScale.getExtent();
+      var x = xScale.parse(data[0]);
+      var y = yScale.parse(data[1]);
+      out = out || [];
+      out[0] = Math.min(Math.max(Math.min(xAxisExtent[0], xAxisExtent[1]), x), Math.max(xAxisExtent[0], xAxisExtent[1]));
+      out[1] = Math.min(Math.max(Math.min(yAxisExtent[0], yAxisExtent[1]), y), Math.max(yAxisExtent[0], yAxisExtent[1]));
+      return out;
+    };
+
+    Cartesian2D.prototype.pointToData = function (point, clamp) {
+      var out = [];
+
+      if (this._invTransform) {
+        return applyTransform(out, point, this._invTransform);
+      }
+
+      var xAxis = this.getAxis('x');
+      var yAxis = this.getAxis('y');
+      out[0] = xAxis.coordToData(xAxis.toLocalCoord(point[0]), clamp);
+      out[1] = yAxis.coordToData(yAxis.toLocalCoord(point[1]), clamp);
+      return out;
+    };
+
+    Cartesian2D.prototype.getOtherAxis = function (axis) {
+      return this.getAxis(axis.dim === 'x' ? 'y' : 'x');
+    };
+    /**
+     * Get rect area of cartesian.
+     * Area will have a contain function to determine if a point is in the coordinate system.
+     */
+
+
+    Cartesian2D.prototype.getArea = function () {
+      var xExtent = this.getAxis('x').getGlobalExtent();
+      var yExtent = this.getAxis('y').getGlobalExtent();
+      var x = Math.min(xExtent[0], xExtent[1]);
+      var y = Math.min(yExtent[0], yExtent[1]);
+      var width = Math.max(xExtent[0], xExtent[1]) - x;
+      var height = Math.max(yExtent[0], yExtent[1]) - y;
+      return new BoundingRect(x, y, width, height);
+    };
+
+    return Cartesian2D;
+  }(Cartesian);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 Axis2D =
+  /** @class */
+  function (_super) {
+    __extends(Axis2D, _super);
+
+    function Axis2D(dim, scale, coordExtent, axisType, position) {
+      var _this = _super.call(this, dim, scale, coordExtent) || this;
+      /**
+       * Index of axis, can be used as key
+       * Injected outside.
+       */
+
+
+      _this.index = 0;
+      _this.type = axisType || 'value';
+      _this.position = position || 'bottom';
+      return _this;
+    }
+
+    Axis2D.prototype.isHorizontal = function () {
+      var position = this.position;
+      return position === 'top' || position === 'bottom';
+    };
+    /**
+     * Each item cooresponds to this.getExtent(), which
+     * means globalExtent[0] may greater than globalExtent[1],
+     * unless `asc` is input.
+     *
+     * @param {boolean} [asc]
+     * @return {Array.<number>}
+     */
+
+
+    Axis2D.prototype.getGlobalExtent = function (asc) {
+      var ret = this.getExtent();
+      ret[0] = this.toGlobalCoord(ret[0]);
+      ret[1] = this.toGlobalCoord(ret[1]);
+      asc && ret[0] > ret[1] && ret.reverse();
+      return ret;
+    };
+
+    Axis2D.prototype.pointToData = function (point, clamp) {
+      return this.coordToData(this.toLocalCoord(point[this.dim === 'x' ? 0 : 1]), clamp);
+    };
+    /**
+     * Set ordinalSortInfo
+     * @param info new OrdinalSortInfo
+     */
+
+
+    Axis2D.prototype.setCategorySortInfo = function (info) {
+      if (this.type !== 'category') {
+        return false;
+      }
+
+      this.model.option.categorySortInfo = info;
+      this.scale.setSortInfo(info);
+    };
+
+    return Axis2D;
+  }(Axis);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Can only be called after coordinate system creation stage.
+   * (Can be called before coordinate system update stage).
+   */
+
+
+  function layout$1(gridModel, axisModel, opt) {
+    opt = opt || {};
+    var grid = gridModel.coordinateSystem;
+    var axis = axisModel.axis;
+    var layout = {};
+    var otherAxisOnZeroOf = axis.getAxesOnZeroOf()[0];
+    var rawAxisPosition = axis.position;
+    var axisPosition = otherAxisOnZeroOf ? 'onZero' : rawAxisPosition;
+    var axisDim = axis.dim;
+    var rect = grid.getRect();
+    var rectBound = [rect.x, rect.x + rect.width, rect.y, rect.y + rect.height];
+    var idx = {
+      left: 0,
+      right: 1,
+      top: 0,
+      bottom: 1,
+      onZero: 2
+    };
+    var axisOffset = axisModel.get('offset') || 0;
+    var posBound = axisDim === 'x' ? [rectBound[2] - axisOffset, rectBound[3] + axisOffset] : [rectBound[0] - axisOffset, rectBound[1] + axisOffset];
+
+    if (otherAxisOnZeroOf) {
+      var onZeroCoord = otherAxisOnZeroOf.toGlobalCoord(otherAxisOnZeroOf.dataToCoord(0));
+      posBound[idx.onZero] = Math.max(Math.min(onZeroCoord, posBound[1]), posBound[0]);
+    } // Axis position
+
+
+    layout.position = [axisDim === 'y' ? posBound[idx[axisPosition]] : rectBound[0], axisDim === 'x' ? posBound[idx[axisPosition]] : rectBound[3]]; // Axis rotation
+
+    layout.rotation = Math.PI / 2 * (axisDim === 'x' ? 0 : 1); // Tick and label direction, x y is axisDim
+
+    var dirMap = {
+      top: -1,
+      bottom: 1,
+      left: -1,
+      right: 1
+    };
+    layout.labelDirection = layout.tickDirection = layout.nameDirection = dirMap[rawAxisPosition];
+    layout.labelOffset = otherAxisOnZeroOf ? posBound[idx[rawAxisPosition]] - posBound[idx.onZero] : 0;
+
+    if (axisModel.get(['axisTick', 'inside'])) {
+      layout.tickDirection = -layout.tickDirection;
+    }
+
+    if (retrieve(opt.labelInside, axisModel.get(['axisLabel', 'inside']))) {
+      layout.labelDirection = -layout.labelDirection;
+    } // Special label rotation
+
+
+    var labelRotate = axisModel.get(['axisLabel', 'rotate']);
+    layout.labelRotate = axisPosition === 'top' ? -labelRotate : labelRotate; // Over splitLine and splitArea
+
+    layout.z2 = 1;
+    return layout;
+  }
+
+  function isCartesian2DSeries(seriesModel) {
+    return seriesModel.get('coordinateSystem') === 'cartesian2d';
+  }
+
+  function findAxisModels(seriesModel) {
+    var axisModelMap = {
+      xAxisModel: null,
+      yAxisModel: null
+    };
+    each(axisModelMap, function (v, key) {
+      var axisType = key.replace(/Model$/, '');
+      var axisModel = seriesModel.getReferringComponents(axisType, SINGLE_REFERRING).models[0];
+      {
+        if (!axisModel) {
+          throw new Error(axisType + ' "' + retrieve3(seriesModel.get(axisType + 'Index'), seriesModel.get(axisType + 'Id'), 0) + '" not found');
+        }
+      }
+      axisModelMap[key] = axisModel;
+    });
+    return axisModelMap;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 mathLog$1 = Math.log;
+
+  function alignScaleTicks(scale, axisModel, alignToScale) {
+    var intervalScaleProto = IntervalScale.prototype; // NOTE: There is a precondition for log scale  here:
+    // In log scale we store _interval and _extent of exponent value.
+    // So if we use the method of InternalScale to set/get these data.
+    // It process the exponent value, which is linear and what we want here.
+
+    var alignToTicks = intervalScaleProto.getTicks.call(alignToScale);
+    var alignToNicedTicks = intervalScaleProto.getTicks.call(alignToScale, true);
+    var alignToSplitNumber = alignToTicks.length - 1;
+    var alignToInterval = intervalScaleProto.getInterval.call(alignToScale);
+    var scaleExtent = getScaleExtent(scale, axisModel);
+    var rawExtent = scaleExtent.extent;
+    var isMinFixed = scaleExtent.fixMin;
+    var isMaxFixed = scaleExtent.fixMax;
+
+    if (scale.type === 'log') {
+      var logBase = mathLog$1(scale.base);
+      rawExtent = [mathLog$1(rawExtent[0]) / logBase, mathLog$1(rawExtent[1]) / logBase];
+    }
+
+    scale.setExtent(rawExtent[0], rawExtent[1]);
+    scale.calcNiceExtent({
+      splitNumber: alignToSplitNumber,
+      fixMin: isMinFixed,
+      fixMax: isMaxFixed
+    });
+    var extent = intervalScaleProto.getExtent.call(scale); // Need to update the rawExtent.
+    // Because value in rawExtent may be not parsed. e.g. 'dataMin', 'dataMax'
+
+    if (isMinFixed) {
+      rawExtent[0] = extent[0];
+    }
+
+    if (isMaxFixed) {
+      rawExtent[1] = extent[1];
+    }
+
+    var interval = intervalScaleProto.getInterval.call(scale);
+    var min = rawExtent[0];
+    var max = rawExtent[1];
+
+    if (isMinFixed && isMaxFixed) {
+      // User set min, max, divide to get new interval
+      interval = (max - min) / alignToSplitNumber;
+    } else if (isMinFixed) {
+      max = rawExtent[0] + interval * alignToSplitNumber; // User set min, expand extent on the other side
+
+      while (max < rawExtent[1] && isFinite(max) && isFinite(rawExtent[1])) {
+        interval = increaseInterval(interval);
+        max = rawExtent[0] + interval * alignToSplitNumber;
+      }
+    } else if (isMaxFixed) {
+      // User set max, expand extent on the other side
+      min = rawExtent[1] - interval * alignToSplitNumber;
+
+      while (min > rawExtent[0] && isFinite(min) && isFinite(rawExtent[0])) {
+        interval = increaseInterval(interval);
+        min = rawExtent[1] - interval * alignToSplitNumber;
+      }
+    } else {
+      var nicedSplitNumber = scale.getTicks().length - 1;
+
+      if (nicedSplitNumber > alignToSplitNumber) {
+        interval = increaseInterval(interval);
+      }
+
+      var range = interval * alignToSplitNumber;
+      max = Math.ceil(rawExtent[1] / interval) * interval;
+      min = round(max - range); // Not change the result that crossing zero.
+
+      if (min < 0 && rawExtent[0] >= 0) {
+        min = 0;
+        max = round(range);
+      } else if (max > 0 && rawExtent[1] <= 0) {
+        max = 0;
+        min = -round(range);
+      }
+    } // Adjust min, max based on the extent of alignTo. When min or max is set in alignTo scale
+
+
+    var t0 = (alignToTicks[0].value - alignToNicedTicks[0].value) / alignToInterval;
+    var t1 = (alignToTicks[alignToSplitNumber].value - alignToNicedTicks[alignToSplitNumber].value) / alignToInterval; // NOTE: Must in setExtent -> setInterval -> setNiceExtent order.
+
+    intervalScaleProto.setExtent.call(scale, min + interval * t0, max + interval * t1);
+    intervalScaleProto.setInterval.call(scale, interval);
+
+    if (t0 || t1) {
+      intervalScaleProto.setNiceExtent.call(scale, min + interval, max - interval);
+    }
+
+    {
+      var ticks = intervalScaleProto.getTicks.call(scale);
+
+      if (ticks[1] && (!isValueNice(interval) || getPrecisionSafe(ticks[1].value) > getPrecisionSafe(interval))) {
+        warn( // eslint-disable-next-line
+        "The ticks may be not readable when set min: " + axisModel.get('min') + ", max: " + axisModel.get('max') + " and alignTicks: true");
+      }
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Grid is a region which contains at most 4 cartesian systems
+   *
+   * TODO Default cartesian
+   */
+
+
+  var Grid =
+  /** @class */
+  function () {
+    function Grid(gridModel, ecModel, api) {
+      // FIXME:TS where used (different from registered type 'cartesian2d')?
+      this.type = 'grid';
+      this._coordsMap = {};
+      this._coordsList = [];
+      this._axesMap = {};
+      this._axesList = [];
+      this.axisPointerEnabled = true;
+      this.dimensions = cartesian2DDimensions;
+
+      this._initCartesian(gridModel, ecModel, api);
+
+      this.model = gridModel;
+    }
+
+    Grid.prototype.getRect = function () {
+      return this._rect;
+    };
+
+    Grid.prototype.update = function (ecModel, api) {
+      var axesMap = this._axesMap;
+
+      this._updateScale(ecModel, this.model);
+
+      function updateAxisTicks(axes) {
+        var alignTo; // Axis is added in order of axisIndex.
+
+        var axesIndices = keys(axes);
+        var len = axesIndices.length;
+
+        if (!len) {
+          return;
+        }
+
+        var axisNeedsAlign = []; // Process once and calculate the ticks for those don't use alignTicks.
+
+        for (var i = len - 1; i >= 0; i--) {
+          var idx = +axesIndices[i]; // Convert to number.
+
+          var axis = axes[idx];
+          var model = axis.model;
+          var scale = axis.scale;
+
+          if ( // Only value and log axis without interval support alignTicks.
+          isIntervalOrLogScale(scale) && model.get('alignTicks') && model.get('interval') == null) {
+            axisNeedsAlign.push(axis);
+          } else {
+            niceScaleExtent(scale, model);
+
+            if (isIntervalOrLogScale(scale)) {
+              // Can only align to interval or log axis.
+              alignTo = axis;
+            }
+          }
+        } // All axes has set alignTicks. Pick the first one.
+        // PENDING. Should we find the axis that both set interval, min, max and align to this one?
+
+
+        if (axisNeedsAlign.length) {
+          if (!alignTo) {
+            alignTo = axisNeedsAlign.pop();
+            niceScaleExtent(alignTo.scale, alignTo.model);
+          }
+
+          each(axisNeedsAlign, function (axis) {
+            alignScaleTicks(axis.scale, axis.model, alignTo.scale);
+          });
+        }
+      }
+
+      updateAxisTicks(axesMap.x);
+      updateAxisTicks(axesMap.y); // Key: axisDim_axisIndex, value: boolean, whether onZero target.
+
+      var onZeroRecords = {};
+      each(axesMap.x, function (xAxis) {
+        fixAxisOnZero(axesMap, 'y', xAxis, onZeroRecords);
+      });
+      each(axesMap.y, function (yAxis) {
+        fixAxisOnZero(axesMap, 'x', yAxis, onZeroRecords);
+      }); // Resize again if containLabel is enabled
+      // FIXME It may cause getting wrong grid size in data processing stage
+
+      this.resize(this.model, api);
+    };
+    /**
+     * Resize the grid
+     */
+
+
+    Grid.prototype.resize = function (gridModel, api, ignoreContainLabel) {
+      var boxLayoutParams = gridModel.getBoxLayoutParams();
+      var isContainLabel = !ignoreContainLabel && gridModel.get('containLabel');
+      var gridRect = getLayoutRect(boxLayoutParams, {
+        width: api.getWidth(),
+        height: api.getHeight()
+      });
+      this._rect = gridRect;
+      var axesList = this._axesList;
+      adjustAxes(); // Minus label size
+
+      if (isContainLabel) {
+        each(axesList, function (axis) {
+          if (!axis.model.get(['axisLabel', 'inside'])) {
+            var labelUnionRect = estimateLabelUnionRect(axis);
+
+            if (labelUnionRect) {
+              var dim = axis.isHorizontal() ? 'height' : 'width';
+              var margin = axis.model.get(['axisLabel', 'margin']);
+              gridRect[dim] -= labelUnionRect[dim] + margin;
+
+              if (axis.position === 'top') {
+                gridRect.y += labelUnionRect.height + margin;
+              } else if (axis.position === 'left') {
+                gridRect.x += labelUnionRect.width + margin;
+              }
+            }
+          }
+        });
+        adjustAxes();
+      }
+
+      each(this._coordsList, function (coord) {
+        // Calculate affine matrix to accelerate the data to point transform.
+        // If all the axes scales are time or value.
+        coord.calcAffineTransform();
+      });
+
+      function adjustAxes() {
+        each(axesList, function (axis) {
+          var isHorizontal = axis.isHorizontal();
+          var extent = isHorizontal ? [0, gridRect.width] : [0, gridRect.height];
+          var idx = axis.inverse ? 1 : 0;
+          axis.setExtent(extent[idx], extent[1 - idx]);
+          updateAxisTransform(axis, isHorizontal ? gridRect.x : gridRect.y);
+        });
+      }
+    };
+
+    Grid.prototype.getAxis = function (dim, axisIndex) {
+      var axesMapOnDim = this._axesMap[dim];
+
+      if (axesMapOnDim != null) {
+        return axesMapOnDim[axisIndex || 0];
+      }
+    };
+
+    Grid.prototype.getAxes = function () {
+      return this._axesList.slice();
+    };
+
+    Grid.prototype.getCartesian = function (xAxisIndex, yAxisIndex) {
+      if (xAxisIndex != null && yAxisIndex != null) {
+        var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
+        return this._coordsMap[key];
+      }
+
+      if (isObject(xAxisIndex)) {
+        yAxisIndex = xAxisIndex.yAxisIndex;
+        xAxisIndex = xAxisIndex.xAxisIndex;
+      }
+
+      for (var i = 0, coordList = this._coordsList; i < coordList.length; i++) {
+        if (coordList[i].getAxis('x').index === xAxisIndex || coordList[i].getAxis('y').index === yAxisIndex) {
+          return coordList[i];
+        }
+      }
+    };
+
+    Grid.prototype.getCartesians = function () {
+      return this._coordsList.slice();
+    };
+    /**
+     * @implements
+     */
+
+
+    Grid.prototype.convertToPixel = function (ecModel, finder, value) {
+      var target = this._findConvertTarget(finder);
+
+      return target.cartesian ? target.cartesian.dataToPoint(value) : target.axis ? target.axis.toGlobalCoord(target.axis.dataToCoord(value)) : null;
+    };
+    /**
+     * @implements
+     */
+
+
+    Grid.prototype.convertFromPixel = function (ecModel, finder, value) {
+      var target = this._findConvertTarget(finder);
+
+      return target.cartesian ? target.cartesian.pointToData(value) : target.axis ? target.axis.coordToData(target.axis.toLocalCoord(value)) : null;
+    };
+
+    Grid.prototype._findConvertTarget = function (finder) {
+      var seriesModel = finder.seriesModel;
+      var xAxisModel = finder.xAxisModel || seriesModel && seriesModel.getReferringComponents('xAxis', SINGLE_REFERRING).models[0];
+      var yAxisModel = finder.yAxisModel || seriesModel && seriesModel.getReferringComponents('yAxis', SINGLE_REFERRING).models[0];
+      var gridModel = finder.gridModel;
+      var coordsList = this._coordsList;
+      var cartesian;
+      var axis;
+
+      if (seriesModel) {
+        cartesian = seriesModel.coordinateSystem;
+        indexOf(coordsList, cartesian) < 0 && (cartesian = null);
+      } else if (xAxisModel && yAxisModel) {
+        cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
+      } else if (xAxisModel) {
+        axis = this.getAxis('x', xAxisModel.componentIndex);
+      } else if (yAxisModel) {
+        axis = this.getAxis('y', yAxisModel.componentIndex);
+      } // Lowest priority.
+      else if (gridModel) {
+          var grid = gridModel.coordinateSystem;
+
+          if (grid === this) {
+            cartesian = this._coordsList[0];
+          }
+        }
+
+      return {
+        cartesian: cartesian,
+        axis: axis
+      };
+    };
+    /**
+     * @implements
+     */
+
+
+    Grid.prototype.containPoint = function (point) {
+      var coord = this._coordsList[0];
+
+      if (coord) {
+        return coord.containPoint(point);
+      }
+    };
+    /**
+     * Initialize cartesian coordinate systems
+     */
+
+
+    Grid.prototype._initCartesian = function (gridModel, ecModel, api) {
+      var _this = this;
+
+      var grid = this;
+      var axisPositionUsed = {
+        left: false,
+        right: false,
+        top: false,
+        bottom: false
+      };
+      var axesMap = {
+        x: {},
+        y: {}
+      };
+      var axesCount = {
+        x: 0,
+        y: 0
+      }; /// Create axis
+
+      ecModel.eachComponent('xAxis', createAxisCreator('x'), this);
+      ecModel.eachComponent('yAxis', createAxisCreator('y'), this);
+
+      if (!axesCount.x || !axesCount.y) {
+        // Roll back when there no either x or y axis
+        this._axesMap = {};
+        this._axesList = [];
+        return;
+      }
+
+      this._axesMap = axesMap; /// Create cartesian2d
+
+      each(axesMap.x, function (xAxis, xAxisIndex) {
+        each(axesMap.y, function (yAxis, yAxisIndex) {
+          var key = 'x' + xAxisIndex + 'y' + yAxisIndex;
+          var cartesian = new Cartesian2D(key);
+          cartesian.master = _this;
+          cartesian.model = gridModel;
+          _this._coordsMap[key] = cartesian;
+
+          _this._coordsList.push(cartesian);
+
+          cartesian.addAxis(xAxis);
+          cartesian.addAxis(yAxis);
+        });
+      });
+
+      function createAxisCreator(dimName) {
+        return function (axisModel, idx) {
+          if (!isAxisUsedInTheGrid(axisModel, gridModel)) {
+            return;
+          }
+
+          var axisPosition = axisModel.get('position');
+
+          if (dimName === 'x') {
+            // Fix position
+            if (axisPosition !== 'top' && axisPosition !== 'bottom') {
+              // Default bottom of X
+              axisPosition = axisPositionUsed.bottom ? 'top' : 'bottom';
+            }
+          } else {
+            // Fix position
+            if (axisPosition !== 'left' && axisPosition !== 'right') {
+              // Default left of Y
+              axisPosition = axisPositionUsed.left ? 'right' : 'left';
+            }
+          }
+
+          axisPositionUsed[axisPosition] = true;
+          var axis = new Axis2D(dimName, createScaleByModel(axisModel), [0, 0], axisModel.get('type'), axisPosition);
+          var isCategory = axis.type === 'category';
+          axis.onBand = isCategory && axisModel.get('boundaryGap');
+          axis.inverse = axisModel.get('inverse'); // Inject axis into axisModel
+
+          axisModel.axis = axis; // Inject axisModel into axis
+
+          axis.model = axisModel; // Inject grid info axis
+
+          axis.grid = grid; // Index of axis, can be used as key
+
+          axis.index = idx;
+
+          grid._axesList.push(axis);
+
+          axesMap[dimName][idx] = axis;
+          axesCount[dimName]++;
+        };
+      }
+    };
+    /**
+     * Update cartesian properties from series.
+     */
+
+
+    Grid.prototype._updateScale = function (ecModel, gridModel) {
+      // Reset scale
+      each(this._axesList, function (axis) {
+        axis.scale.setExtent(Infinity, -Infinity);
+
+        if (axis.type === 'category') {
+          var categorySortInfo = axis.model.get('categorySortInfo');
+          axis.scale.setSortInfo(categorySortInfo);
+        }
+      });
+      ecModel.eachSeries(function (seriesModel) {
+        if (isCartesian2DSeries(seriesModel)) {
+          var axesModelMap = findAxisModels(seriesModel);
+          var xAxisModel = axesModelMap.xAxisModel;
+          var yAxisModel = axesModelMap.yAxisModel;
+
+          if (!isAxisUsedInTheGrid(xAxisModel, gridModel) || !isAxisUsedInTheGrid(yAxisModel, gridModel)) {
+            return;
+          }
+
+          var cartesian = this.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
+          var data = seriesModel.getData();
+          var xAxis = cartesian.getAxis('x');
+          var yAxis = cartesian.getAxis('y');
+          unionExtent(data, xAxis);
+          unionExtent(data, yAxis);
+        }
+      }, this);
+
+      function unionExtent(data, axis) {
+        each(getDataDimensionsOnAxis(data, axis.dim), function (dim) {
+          axis.scale.unionExtentFromData(data, dim);
+        });
+      }
+    };
+    /**
+     * @param dim 'x' or 'y' or 'auto' or null/undefined
+     */
+
+
+    Grid.prototype.getTooltipAxes = function (dim) {
+      var baseAxes = [];
+      var otherAxes = [];
+      each(this.getCartesians(), function (cartesian) {
+        var baseAxis = dim != null && dim !== 'auto' ? cartesian.getAxis(dim) : cartesian.getBaseAxis();
+        var otherAxis = cartesian.getOtherAxis(baseAxis);
+        indexOf(baseAxes, baseAxis) < 0 && baseAxes.push(baseAxis);
+        indexOf(otherAxes, otherAxis) < 0 && otherAxes.push(otherAxis);
+      });
+      return {
+        baseAxes: baseAxes,
+        otherAxes: otherAxes
+      };
+    };
+
+    Grid.create = function (ecModel, api) {
+      var grids = [];
+      ecModel.eachComponent('grid', function (gridModel, idx) {
+        var grid = new Grid(gridModel, ecModel, api);
+        grid.name = 'grid_' + idx; // dataSampling requires axis extent, so resize
+        // should be performed in create stage.
+
+        grid.resize(gridModel, api, true);
+        gridModel.coordinateSystem = grid;
+        grids.push(grid);
+      }); // Inject the coordinateSystems into seriesModel
+
+      ecModel.eachSeries(function (seriesModel) {
+        if (!isCartesian2DSeries(seriesModel)) {
+          return;
+        }
+
+        var axesModelMap = findAxisModels(seriesModel);
+        var xAxisModel = axesModelMap.xAxisModel;
+        var yAxisModel = axesModelMap.yAxisModel;
+        var gridModel = xAxisModel.getCoordSysModel();
+        {
+          if (!gridModel) {
+            throw new Error('Grid "' + retrieve3(xAxisModel.get('gridIndex'), xAxisModel.get('gridId'), 0) + '" not found');
+          }
+
+          if (xAxisModel.getCoordSysModel() !== yAxisModel.getCoordSysModel()) {
+            throw new Error('xAxis and yAxis must use the same grid');
+          }
+        }
+        var grid = gridModel.coordinateSystem;
+        seriesModel.coordinateSystem = grid.getCartesian(xAxisModel.componentIndex, yAxisModel.componentIndex);
+      });
+      return grids;
+    }; // For deciding which dimensions to use when creating list data
+
+
+    Grid.dimensions = cartesian2DDimensions;
+    return Grid;
+  }();
+  /**
+   * Check if the axis is used in the specified grid.
+   */
+
+
+  function isAxisUsedInTheGrid(axisModel, gridModel) {
+    return axisModel.getCoordSysModel() === gridModel;
+  }
+
+  function fixAxisOnZero(axesMap, otherAxisDim, axis, // Key: see `getOnZeroRecordKey`
+  onZeroRecords) {
+    axis.getAxesOnZeroOf = function () {
+      // TODO: onZero of multiple axes.
+      return otherAxisOnZeroOf ? [otherAxisOnZeroOf] : [];
+    }; // onZero can not be enabled in these two situations:
+    // 1. When any other axis is a category axis.
+    // 2. When no axis is cross 0 point.
+
+
+    var otherAxes = axesMap[otherAxisDim];
+    var otherAxisOnZeroOf;
+    var axisModel = axis.model;
+    var onZero = axisModel.get(['axisLine', 'onZero']);
+    var onZeroAxisIndex = axisModel.get(['axisLine', 'onZeroAxisIndex']);
+
+    if (!onZero) {
+      return;
+    } // If target axis is specified.
+
+
+    if (onZeroAxisIndex != null) {
+      if (canOnZeroToAxis(otherAxes[onZeroAxisIndex])) {
+        otherAxisOnZeroOf = otherAxes[onZeroAxisIndex];
+      }
+    } else {
+      // Find the first available other axis.
+      for (var idx in otherAxes) {
+        if (otherAxes.hasOwnProperty(idx) && canOnZeroToAxis(otherAxes[idx]) // Consider that two Y axes on one value axis,
+        // if both onZero, the two Y axes overlap.
+        && !onZeroRecords[getOnZeroRecordKey(otherAxes[idx])]) {
+          otherAxisOnZeroOf = otherAxes[idx];
+          break;
+        }
+      }
+    }
+
+    if (otherAxisOnZeroOf) {
+      onZeroRecords[getOnZeroRecordKey(otherAxisOnZeroOf)] = true;
+    }
+
+    function getOnZeroRecordKey(axis) {
+      return axis.dim + '_' + axis.index;
+    }
+  }
+
+  function canOnZeroToAxis(axis) {
+    return axis && axis.type !== 'category' && axis.type !== 'time' && ifAxisCrossZero(axis);
+  }
+
+  function updateAxisTransform(axis, coordBase) {
+    var axisExtent = axis.getExtent();
+    var axisExtentSum = axisExtent[0] + axisExtent[1]; // Fast transform
+
+    axis.toGlobalCoord = axis.dim === 'x' ? function (coord) {
+      return coord + coordBase;
+    } : function (coord) {
+      return axisExtentSum - coord + coordBase;
+    };
+    axis.toLocalCoord = axis.dim === 'x' ? function (coord) {
+      return coord - coordBase;
+    } : function (coord) {
+      return axisExtentSum - coord + coordBase;
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 PI$4 = Math.PI;
+  /**
+   * A final axis is translated and rotated from a "standard axis".
+   * So opt.position and opt.rotation is required.
+   *
+   * A standard axis is and axis from [0, 0] to [0, axisExtent[1]],
+   * for example: (0, 0) ------------> (0, 50)
+   *
+   * nameDirection or tickDirection or labelDirection is 1 means tick
+   * or label is below the standard axis, whereas is -1 means above
+   * the standard axis. labelOffset means offset between label and axis,
+   * which is useful when 'onZero', where axisLabel is in the grid and
+   * label in outside grid.
+   *
+   * Tips: like always,
+   * positive rotation represents anticlockwise, and negative rotation
+   * represents clockwise.
+   * The direction of position coordinate is the same as the direction
+   * of screen coordinate.
+   *
+   * Do not need to consider axis 'inverse', which is auto processed by
+   * axis extent.
+   */
+
+  var AxisBuilder =
+  /** @class */
+  function () {
+    function AxisBuilder(axisModel, opt) {
+      this.group = new Group();
+      this.opt = opt;
+      this.axisModel = axisModel; // Default value
+
+      defaults(opt, {
+        labelOffset: 0,
+        nameDirection: 1,
+        tickDirection: 1,
+        labelDirection: 1,
+        silent: true,
+        handleAutoShown: function () {
+          return true;
+        }
+      }); // FIXME Not use a seperate text group?
+
+      var transformGroup = new Group({
+        x: opt.position[0],
+        y: opt.position[1],
+        rotation: opt.rotation
+      }); // this.group.add(transformGroup);
+      // this._transformGroup = transformGroup;
+
+      transformGroup.updateTransform();
+      this._transformGroup = transformGroup;
+    }
+
+    AxisBuilder.prototype.hasBuilder = function (name) {
+      return !!builders[name];
+    };
+
+    AxisBuilder.prototype.add = function (name) {
+      builders[name](this.opt, this.axisModel, this.group, this._transformGroup);
+    };
+
+    AxisBuilder.prototype.getGroup = function () {
+      return this.group;
+    };
+
+    AxisBuilder.innerTextLayout = function (axisRotation, textRotation, direction) {
+      var rotationDiff = remRadian(textRotation - axisRotation);
+      var textAlign;
+      var textVerticalAlign;
+
+      if (isRadianAroundZero(rotationDiff)) {
+        // Label is parallel with axis line.
+        textVerticalAlign = direction > 0 ? 'top' : 'bottom';
+        textAlign = 'center';
+      } else if (isRadianAroundZero(rotationDiff - PI$4)) {
+        // Label is inverse parallel with axis line.
+        textVerticalAlign = direction > 0 ? 'bottom' : 'top';
+        textAlign = 'center';
+      } else {
+        textVerticalAlign = 'middle';
+
+        if (rotationDiff > 0 && rotationDiff < PI$4) {
+          textAlign = direction > 0 ? 'right' : 'left';
+        } else {
+          textAlign = direction > 0 ? 'left' : 'right';
+        }
+      }
+
+      return {
+        rotation: rotationDiff,
+        textAlign: textAlign,
+        textVerticalAlign: textVerticalAlign
+      };
+    };
+
+    AxisBuilder.makeAxisEventDataBase = function (axisModel) {
+      var eventData = {
+        componentType: axisModel.mainType,
+        componentIndex: axisModel.componentIndex
+      };
+      eventData[axisModel.mainType + 'Index'] = axisModel.componentIndex;
+      return eventData;
+    };
+
+    AxisBuilder.isLabelSilent = function (axisModel) {
+      var tooltipOpt = axisModel.get('tooltip');
+      return axisModel.get('silent') // Consider mouse cursor, add these restrictions.
+      || !(axisModel.get('triggerEvent') || tooltipOpt && tooltipOpt.show);
+    };
+
+    return AxisBuilder;
+  }();
+
+  var builders = {
+    axisLine: function (opt, axisModel, group, transformGroup) {
+      var shown = axisModel.get(['axisLine', 'show']);
+
+      if (shown === 'auto' && opt.handleAutoShown) {
+        shown = opt.handleAutoShown('axisLine');
+      }
+
+      if (!shown) {
+        return;
+      }
+
+      var extent = axisModel.axis.getExtent();
+      var matrix = transformGroup.transform;
+      var pt1 = [extent[0], 0];
+      var pt2 = [extent[1], 0];
+
+      if (matrix) {
+        applyTransform(pt1, pt1, matrix);
+        applyTransform(pt2, pt2, matrix);
+      }
+
+      var lineStyle = extend({
+        lineCap: 'round'
+      }, axisModel.getModel(['axisLine', 'lineStyle']).getLineStyle());
+      var line = new Line({
+        // Id for animation
+        subPixelOptimize: true,
+        shape: {
+          x1: pt1[0],
+          y1: pt1[1],
+          x2: pt2[0],
+          y2: pt2[1]
+        },
+        style: lineStyle,
+        strokeContainThreshold: opt.strokeContainThreshold || 5,
+        silent: true,
+        z2: 1
+      });
+      line.anid = 'line';
+      group.add(line);
+      var arrows = axisModel.get(['axisLine', 'symbol']);
+
+      if (arrows != null) {
+        var arrowSize = axisModel.get(['axisLine', 'symbolSize']);
+
+        if (isString(arrows)) {
+          // Use the same arrow for start and end point
+          arrows = [arrows, arrows];
+        }
+
+        if (isString(arrowSize) || isNumber(arrowSize)) {
+          // Use the same size for width and height
+          arrowSize = [arrowSize, arrowSize];
+        }
+
+        var arrowOffset = normalizeSymbolOffset(axisModel.get(['axisLine', 'symbolOffset']) || 0, arrowSize);
+        var symbolWidth_1 = arrowSize[0];
+        var symbolHeight_1 = arrowSize[1];
+        each([{
+          rotate: opt.rotation + Math.PI / 2,
+          offset: arrowOffset[0],
+          r: 0
+        }, {
+          rotate: opt.rotation - Math.PI / 2,
+          offset: arrowOffset[1],
+          r: Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1]))
+        }], function (point, index) {
+          if (arrows[index] !== 'none' && arrows[index] != null) {
+            var symbol = createSymbol(arrows[index], -symbolWidth_1 / 2, -symbolHeight_1 / 2, symbolWidth_1, symbolHeight_1, lineStyle.stroke, true); // Calculate arrow position with offset
+
+            var r = point.r + point.offset;
+            symbol.attr({
+              rotation: point.rotate,
+              x: pt1[0] + r * Math.cos(opt.rotation),
+              y: pt1[1] - r * Math.sin(opt.rotation),
+              silent: true,
+              z2: 11
+            });
+            group.add(symbol);
+          }
+        });
+      }
+    },
+    axisTickLabel: function (opt, axisModel, group, transformGroup) {
+      var ticksEls = buildAxisMajorTicks(group, transformGroup, axisModel, opt);
+      var labelEls = buildAxisLabel(group, transformGroup, axisModel, opt);
+      fixMinMaxLabelShow(axisModel, labelEls, ticksEls);
+      buildAxisMinorTicks(group, transformGroup, axisModel, opt.tickDirection); // This bit fixes the label overlap issue for the time chart.
+      // See https://github.com/apache/echarts/issues/14266 for more.
+
+      if (axisModel.get(['axisLabel', 'hideOverlap'])) {
+        var labelList = prepareLayoutList(map(labelEls, function (label) {
+          return {
+            label: label,
+            priority: label.z2,
+            defaultAttr: {
+              ignore: label.ignore
+            }
+          };
+        }));
+        hideOverlap(labelList);
+      }
+    },
+    axisName: function (opt, axisModel, group, transformGroup) {
+      var name = retrieve(opt.axisName, axisModel.get('name'));
+
+      if (!name) {
+        return;
+      }
+
+      var nameLocation = axisModel.get('nameLocation');
+      var nameDirection = opt.nameDirection;
+      var textStyleModel = axisModel.getModel('nameTextStyle');
+      var gap = axisModel.get('nameGap') || 0;
+      var extent = axisModel.axis.getExtent();
+      var gapSignal = extent[0] > extent[1] ? -1 : 1;
+      var pos = [nameLocation === 'start' ? extent[0] - gapSignal * gap : nameLocation === 'end' ? extent[1] + gapSignal * gap : (extent[0] + extent[1]) / 2, // Reuse labelOffset.
+      isNameLocationCenter(nameLocation) ? opt.labelOffset + nameDirection * gap : 0];
+      var labelLayout;
+      var nameRotation = axisModel.get('nameRotate');
+
+      if (nameRotation != null) {
+        nameRotation = nameRotation * PI$4 / 180; // To radian.
+      }
+
+      var axisNameAvailableWidth;
+
+      if (isNameLocationCenter(nameLocation)) {
+        labelLayout = AxisBuilder.innerTextLayout(opt.rotation, nameRotation != null ? nameRotation : opt.rotation, // Adapt to axis.
+        nameDirection);
+      } else {
+        labelLayout = endTextLayout(opt.rotation, nameLocation, nameRotation || 0, extent);
+        axisNameAvailableWidth = opt.axisNameAvailableWidth;
+
+        if (axisNameAvailableWidth != null) {
+          axisNameAvailableWidth = Math.abs(axisNameAvailableWidth / Math.sin(labelLayout.rotation));
+          !isFinite(axisNameAvailableWidth) && (axisNameAvailableWidth = null);
+        }
+      }
+
+      var textFont = textStyleModel.getFont();
+      var truncateOpt = axisModel.get('nameTruncate', true) || {};
+      var ellipsis = truncateOpt.ellipsis;
+      var maxWidth = retrieve(opt.nameTruncateMaxWidth, truncateOpt.maxWidth, axisNameAvailableWidth);
+      var textEl = new ZRText({
+        x: pos[0],
+        y: pos[1],
+        rotation: labelLayout.rotation,
+        silent: AxisBuilder.isLabelSilent(axisModel),
+        style: createTextStyle(textStyleModel, {
+          text: name,
+          font: textFont,
+          overflow: 'truncate',
+          width: maxWidth,
+          ellipsis: ellipsis,
+          fill: textStyleModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']),
+          align: textStyleModel.get('align') || labelLayout.textAlign,
+          verticalAlign: textStyleModel.get('verticalAlign') || labelLayout.textVerticalAlign
+        }),
+        z2: 1
+      });
+      setTooltipConfig({
+        el: textEl,
+        componentModel: axisModel,
+        itemName: name
+      });
+      textEl.__fullText = name; // Id for animation
+
+      textEl.anid = 'name';
+
+      if (axisModel.get('triggerEvent')) {
+        var eventData = AxisBuilder.makeAxisEventDataBase(axisModel);
+        eventData.targetType = 'axisName';
+        eventData.name = name;
+        getECData(textEl).eventData = eventData;
+      } // FIXME
+
+
+      transformGroup.add(textEl);
+      textEl.updateTransform();
+      group.add(textEl);
+      textEl.decomposeTransform();
+    }
+  };
+
+  function endTextLayout(rotation, textPosition, textRotate, extent) {
+    var rotationDiff = remRadian(textRotate - rotation);
+    var textAlign;
+    var textVerticalAlign;
+    var inverse = extent[0] > extent[1];
+    var onLeft = textPosition === 'start' && !inverse || textPosition !== 'start' && inverse;
+
+    if (isRadianAroundZero(rotationDiff - PI$4 / 2)) {
+      textVerticalAlign = onLeft ? 'bottom' : 'top';
+      textAlign = 'center';
+    } else if (isRadianAroundZero(rotationDiff - PI$4 * 1.5)) {
+      textVerticalAlign = onLeft ? 'top' : 'bottom';
+      textAlign = 'center';
+    } else {
+      textVerticalAlign = 'middle';
+
+      if (rotationDiff < PI$4 * 1.5 && rotationDiff > PI$4 / 2) {
+        textAlign = onLeft ? 'left' : 'right';
+      } else {
+        textAlign = onLeft ? 'right' : 'left';
+      }
+    }
+
+    return {
+      rotation: rotationDiff,
+      textAlign: textAlign,
+      textVerticalAlign: textVerticalAlign
+    };
+  }
+
+  function fixMinMaxLabelShow(axisModel, labelEls, tickEls) {
+    if (shouldShowAllLabels(axisModel.axis)) {
+      return;
+    } // If min or max are user set, we need to check
+    // If the tick on min(max) are overlap on their neighbour tick
+    // If they are overlapped, we need to hide the min(max) tick label
+
+
+    var showMinLabel = axisModel.get(['axisLabel', 'showMinLabel']);
+    var showMaxLabel = axisModel.get(['axisLabel', 'showMaxLabel']); // FIXME
+    // Have not consider onBand yet, where tick els is more than label els.
+
+    labelEls = labelEls || [];
+    tickEls = tickEls || [];
+    var firstLabel = labelEls[0];
+    var nextLabel = labelEls[1];
+    var lastLabel = labelEls[labelEls.length - 1];
+    var prevLabel = labelEls[labelEls.length - 2];
+    var firstTick = tickEls[0];
+    var nextTick = tickEls[1];
+    var lastTick = tickEls[tickEls.length - 1];
+    var prevTick = tickEls[tickEls.length - 2];
+
+    if (showMinLabel === false) {
+      ignoreEl(firstLabel);
+      ignoreEl(firstTick);
+    } else if (isTwoLabelOverlapped(firstLabel, nextLabel)) {
+      if (showMinLabel) {
+        ignoreEl(nextLabel);
+        ignoreEl(nextTick);
+      } else {
+        ignoreEl(firstLabel);
+        ignoreEl(firstTick);
+      }
+    }
+
+    if (showMaxLabel === false) {
+      ignoreEl(lastLabel);
+      ignoreEl(lastTick);
+    } else if (isTwoLabelOverlapped(prevLabel, lastLabel)) {
+      if (showMaxLabel) {
+        ignoreEl(prevLabel);
+        ignoreEl(prevTick);
+      } else {
+        ignoreEl(lastLabel);
+        ignoreEl(lastTick);
+      }
+    }
+  }
+
+  function ignoreEl(el) {
+    el && (el.ignore = true);
+  }
+
+  function isTwoLabelOverlapped(current, next) {
+    // current and next has the same rotation.
+    var firstRect = current && current.getBoundingRect().clone();
+    var nextRect = next && next.getBoundingRect().clone();
+
+    if (!firstRect || !nextRect) {
+      return;
+    } // When checking intersect of two rotated labels, we use mRotationBack
+    // to avoid that boundingRect is enlarge when using `boundingRect.applyTransform`.
+
+
+    var mRotationBack = identity([]);
+    rotate(mRotationBack, mRotationBack, -current.rotation);
+    firstRect.applyTransform(mul$1([], mRotationBack, current.getLocalTransform()));
+    nextRect.applyTransform(mul$1([], mRotationBack, next.getLocalTransform()));
+    return firstRect.intersect(nextRect);
+  }
+
+  function isNameLocationCenter(nameLocation) {
+    return nameLocation === 'middle' || nameLocation === 'center';
+  }
+
+  function createTicks(ticksCoords, tickTransform, tickEndCoord, tickLineStyle, anidPrefix) {
+    var tickEls = [];
+    var pt1 = [];
+    var pt2 = [];
+
+    for (var i = 0; i < ticksCoords.length; i++) {
+      var tickCoord = ticksCoords[i].coord;
+      pt1[0] = tickCoord;
+      pt1[1] = 0;
+      pt2[0] = tickCoord;
+      pt2[1] = tickEndCoord;
+
+      if (tickTransform) {
+        applyTransform(pt1, pt1, tickTransform);
+        applyTransform(pt2, pt2, tickTransform);
+      } // Tick line, Not use group transform to have better line draw
+
+
+      var tickEl = new Line({
+        subPixelOptimize: true,
+        shape: {
+          x1: pt1[0],
+          y1: pt1[1],
+          x2: pt2[0],
+          y2: pt2[1]
+        },
+        style: tickLineStyle,
+        z2: 2,
+        autoBatch: true,
+        silent: true
+      });
+      tickEl.anid = anidPrefix + '_' + ticksCoords[i].tickValue;
+      tickEls.push(tickEl);
+    }
+
+    return tickEls;
+  }
+
+  function buildAxisMajorTicks(group, transformGroup, axisModel, opt) {
+    var axis = axisModel.axis;
+    var tickModel = axisModel.getModel('axisTick');
+    var shown = tickModel.get('show');
+
+    if (shown === 'auto' && opt.handleAutoShown) {
+      shown = opt.handleAutoShown('axisTick');
+    }
+
+    if (!shown || axis.scale.isBlank()) {
+      return;
+    }
+
+    var lineStyleModel = tickModel.getModel('lineStyle');
+    var tickEndCoord = opt.tickDirection * tickModel.get('length');
+    var ticksCoords = axis.getTicksCoords();
+    var ticksEls = createTicks(ticksCoords, transformGroup.transform, tickEndCoord, defaults(lineStyleModel.getLineStyle(), {
+      stroke: axisModel.get(['axisLine', 'lineStyle', 'color'])
+    }), 'ticks');
+
+    for (var i = 0; i < ticksEls.length; i++) {
+      group.add(ticksEls[i]);
+    }
+
+    return ticksEls;
+  }
+
+  function buildAxisMinorTicks(group, transformGroup, axisModel, tickDirection) {
+    var axis = axisModel.axis;
+    var minorTickModel = axisModel.getModel('minorTick');
+
+    if (!minorTickModel.get('show') || axis.scale.isBlank()) {
+      return;
+    }
+
+    var minorTicksCoords = axis.getMinorTicksCoords();
+
+    if (!minorTicksCoords.length) {
+      return;
+    }
+
+    var lineStyleModel = minorTickModel.getModel('lineStyle');
+    var tickEndCoord = tickDirection * minorTickModel.get('length');
+    var minorTickLineStyle = defaults(lineStyleModel.getLineStyle(), defaults(axisModel.getModel('axisTick').getLineStyle(), {
+      stroke: axisModel.get(['axisLine', 'lineStyle', 'color'])
+    }));
+
+    for (var i = 0; i < minorTicksCoords.length; i++) {
+      var minorTicksEls = createTicks(minorTicksCoords[i], transformGroup.transform, tickEndCoord, minorTickLineStyle, 'minorticks_' + i);
+
+      for (var k = 0; k < minorTicksEls.length; k++) {
+        group.add(minorTicksEls[k]);
+      }
+    }
+  }
+
+  function buildAxisLabel(group, transformGroup, axisModel, opt) {
+    var axis = axisModel.axis;
+    var show = retrieve(opt.axisLabelShow, axisModel.get(['axisLabel', 'show']));
+
+    if (!show || axis.scale.isBlank()) {
+      return;
+    }
+
+    var labelModel = axisModel.getModel('axisLabel');
+    var labelMargin = labelModel.get('margin');
+    var labels = axis.getViewLabels(); // Special label rotate.
+
+    var labelRotation = (retrieve(opt.labelRotate, labelModel.get('rotate')) || 0) * PI$4 / 180;
+    var labelLayout = AxisBuilder.innerTextLayout(opt.rotation, labelRotation, opt.labelDirection);
+    var rawCategoryData = axisModel.getCategories && axisModel.getCategories(true);
+    var labelEls = [];
+    var silent = AxisBuilder.isLabelSilent(axisModel);
+    var triggerEvent = axisModel.get('triggerEvent');
+    each(labels, function (labelItem, index) {
+      var tickValue = axis.scale.type === 'ordinal' ? axis.scale.getRawOrdinalNumber(labelItem.tickValue) : labelItem.tickValue;
+      var formattedLabel = labelItem.formattedLabel;
+      var rawLabel = labelItem.rawLabel;
+      var itemLabelModel = labelModel;
+
+      if (rawCategoryData && rawCategoryData[tickValue]) {
+        var rawCategoryItem = rawCategoryData[tickValue];
+
+        if (isObject(rawCategoryItem) && rawCategoryItem.textStyle) {
+          itemLabelModel = new Model(rawCategoryItem.textStyle, labelModel, axisModel.ecModel);
+        }
+      }
+
+      var textColor = itemLabelModel.getTextColor() || axisModel.get(['axisLine', 'lineStyle', 'color']);
+      var tickCoord = axis.dataToCoord(tickValue);
+      var textEl = new ZRText({
+        x: tickCoord,
+        y: opt.labelOffset + opt.labelDirection * labelMargin,
+        rotation: labelLayout.rotation,
+        silent: silent,
+        z2: 10 + (labelItem.level || 0),
+        style: createTextStyle(itemLabelModel, {
+          text: formattedLabel,
+          align: itemLabelModel.getShallow('align', true) || labelLayout.textAlign,
+          verticalAlign: itemLabelModel.getShallow('verticalAlign', true) || itemLabelModel.getShallow('baseline', true) || labelLayout.textVerticalAlign,
+          fill: isFunction(textColor) ? textColor( // (1) In category axis with data zoom, tick is not the original
+          // index of axis.data. So tick should not be exposed to user
+          // in category axis.
+          // (2) Compatible with previous version, which always use formatted label as
+          // input. But in interval scale the formatted label is like '223,445', which
+          // maked user repalce ','. So we modify it to return original val but remain
+          // it as 'string' to avoid error in replacing.
+          axis.type === 'category' ? rawLabel : axis.type === 'value' ? tickValue + '' : tickValue, index) : textColor
+        })
+      });
+      textEl.anid = 'label_' + tickValue; // Pack data for mouse event
+
+      if (triggerEvent) {
+        var eventData = AxisBuilder.makeAxisEventDataBase(axisModel);
+        eventData.targetType = 'axisLabel';
+        eventData.value = rawLabel;
+        eventData.tickIndex = index;
+
+        if (axis.type === 'category') {
+          eventData.dataIndex = tickValue;
+        }
+
+        getECData(textEl).eventData = eventData;
+      } // FIXME
+
+
+      transformGroup.add(textEl);
+      textEl.updateTransform();
+      labelEls.push(textEl);
+      group.add(textEl);
+      textEl.decomposeTransform();
+    });
+    return labelEls;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // allAxesInfo should be updated when setOption performed.
+
+
+  function collect(ecModel, api) {
+    var result = {
+      /**
+       * key: makeKey(axis.model)
+       * value: {
+       *      axis,
+       *      coordSys,
+       *      axisPointerModel,
+       *      triggerTooltip,
+       *      involveSeries,
+       *      snap,
+       *      seriesModels,
+       *      seriesDataCount
+       * }
+       */
+      axesInfo: {},
+      seriesInvolved: false,
+
+      /**
+       * key: makeKey(coordSys.model)
+       * value: Object: key makeKey(axis.model), value: axisInfo
+       */
+      coordSysAxesInfo: {},
+      coordSysMap: {}
+    };
+    collectAxesInfo(result, ecModel, api); // Check seriesInvolved for performance, in case too many series in some chart.
+
+    result.seriesInvolved && collectSeriesInfo(result, ecModel);
+    return result;
+  }
+
+  function collectAxesInfo(result, ecModel, api) {
+    var globalTooltipModel = ecModel.getComponent('tooltip');
+    var globalAxisPointerModel = ecModel.getComponent('axisPointer'); // links can only be set on global.
+
+    var linksOption = globalAxisPointerModel.get('link', true) || [];
+    var linkGroups = []; // Collect axes info.
+
+    each(api.getCoordinateSystems(), function (coordSys) {
+      // Some coordinate system do not support axes, like geo.
+      if (!coordSys.axisPointerEnabled) {
+        return;
+      }
+
+      var coordSysKey = makeKey(coordSys.model);
+      var axesInfoInCoordSys = result.coordSysAxesInfo[coordSysKey] = {};
+      result.coordSysMap[coordSysKey] = coordSys; // Set tooltip (like 'cross') is a convienent way to show axisPointer
+      // for user. So we enable seting tooltip on coordSys model.
+
+      var coordSysModel = coordSys.model;
+      var baseTooltipModel = coordSysModel.getModel('tooltip', globalTooltipModel);
+      each(coordSys.getAxes(), curry(saveTooltipAxisInfo, false, null)); // If axis tooltip used, choose tooltip axis for each coordSys.
+      // Notice this case: coordSys is `grid` but not `cartesian2D` here.
+
+      if (coordSys.getTooltipAxes && globalTooltipModel // If tooltip.showContent is set as false, tooltip will not
+      // show but axisPointer will show as normal.
+      && baseTooltipModel.get('show')) {
+        // Compatible with previous logic. But series.tooltip.trigger: 'axis'
+        // or series.data[n].tooltip.trigger: 'axis' are not support any more.
+        var triggerAxis = baseTooltipModel.get('trigger') === 'axis';
+        var cross = baseTooltipModel.get(['axisPointer', 'type']) === 'cross';
+        var tooltipAxes = coordSys.getTooltipAxes(baseTooltipModel.get(['axisPointer', 'axis']));
+
+        if (triggerAxis || cross) {
+          each(tooltipAxes.baseAxes, curry(saveTooltipAxisInfo, cross ? 'cross' : true, triggerAxis));
+        }
+
+        if (cross) {
+          each(tooltipAxes.otherAxes, curry(saveTooltipAxisInfo, 'cross', false));
+        }
+      } // fromTooltip: true | false | 'cross'
+      // triggerTooltip: true | false | null
+
+
+      function saveTooltipAxisInfo(fromTooltip, triggerTooltip, axis) {
+        var axisPointerModel = axis.model.getModel('axisPointer', globalAxisPointerModel);
+        var axisPointerShow = axisPointerModel.get('show');
+
+        if (!axisPointerShow || axisPointerShow === 'auto' && !fromTooltip && !isHandleTrigger(axisPointerModel)) {
+          return;
+        }
+
+        if (triggerTooltip == null) {
+          triggerTooltip = axisPointerModel.get('triggerTooltip');
+        }
+
+        axisPointerModel = fromTooltip ? makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) : axisPointerModel;
+        var snap = axisPointerModel.get('snap');
+        var axisKey = makeKey(axis.model);
+        var involveSeries = triggerTooltip || snap || axis.type === 'category'; // If result.axesInfo[key] exist, override it (tooltip has higher priority).
+
+        var axisInfo = result.axesInfo[axisKey] = {
+          key: axisKey,
+          axis: axis,
+          coordSys: coordSys,
+          axisPointerModel: axisPointerModel,
+          triggerTooltip: triggerTooltip,
+          involveSeries: involveSeries,
+          snap: snap,
+          useHandle: isHandleTrigger(axisPointerModel),
+          seriesModels: [],
+          linkGroup: null
+        };
+        axesInfoInCoordSys[axisKey] = axisInfo;
+        result.seriesInvolved = result.seriesInvolved || involveSeries;
+        var groupIndex = getLinkGroupIndex(linksOption, axis);
+
+        if (groupIndex != null) {
+          var linkGroup = linkGroups[groupIndex] || (linkGroups[groupIndex] = {
+            axesInfo: {}
+          });
+          linkGroup.axesInfo[axisKey] = axisInfo;
+          linkGroup.mapper = linksOption[groupIndex].mapper;
+          axisInfo.linkGroup = linkGroup;
+        }
+      }
+    });
+  }
+
+  function makeAxisPointerModel(axis, baseTooltipModel, globalAxisPointerModel, ecModel, fromTooltip, triggerTooltip) {
+    var tooltipAxisPointerModel = baseTooltipModel.getModel('axisPointer');
+    var fields = ['type', 'snap', 'lineStyle', 'shadowStyle', 'label', 'animation', 'animationDurationUpdate', 'animationEasingUpdate', 'z'];
+    var volatileOption = {};
+    each(fields, function (field) {
+      volatileOption[field] = clone(tooltipAxisPointerModel.get(field));
+    }); // category axis do not auto snap, otherwise some tick that do not
+    // has value can not be hovered. value/time/log axis default snap if
+    // triggered from tooltip and trigger tooltip.
+
+    volatileOption.snap = axis.type !== 'category' && !!triggerTooltip; // Compatibel with previous behavior, tooltip axis do not show label by default.
+    // Only these properties can be overrided from tooltip to axisPointer.
+
+    if (tooltipAxisPointerModel.get('type') === 'cross') {
+      volatileOption.type = 'line';
+    }
+
+    var labelOption = volatileOption.label || (volatileOption.label = {}); // Follow the convention, do not show label when triggered by tooltip by default.
+
+    labelOption.show == null && (labelOption.show = false);
+
+    if (fromTooltip === 'cross') {
+      // When 'cross', both axes show labels.
+      var tooltipAxisPointerLabelShow = tooltipAxisPointerModel.get(['label', 'show']);
+      labelOption.show = tooltipAxisPointerLabelShow != null ? tooltipAxisPointerLabelShow : true; // If triggerTooltip, this is a base axis, which should better not use cross style
+      // (cross style is dashed by default)
+
+      if (!triggerTooltip) {
+        var crossStyle = volatileOption.lineStyle = tooltipAxisPointerModel.get('crossStyle');
+        crossStyle && defaults(labelOption, crossStyle.textStyle);
+      }
+    }
+
+    return axis.model.getModel('axisPointer', new Model(volatileOption, globalAxisPointerModel, ecModel));
+  }
+
+  function collectSeriesInfo(result, ecModel) {
+    // Prepare data for axis trigger
+    ecModel.eachSeries(function (seriesModel) {
+      // Notice this case: this coordSys is `cartesian2D` but not `grid`.
+      var coordSys = seriesModel.coordinateSystem;
+      var seriesTooltipTrigger = seriesModel.get(['tooltip', 'trigger'], true);
+      var seriesTooltipShow = seriesModel.get(['tooltip', 'show'], true);
+
+      if (!coordSys || seriesTooltipTrigger === 'none' || seriesTooltipTrigger === false || seriesTooltipTrigger === 'item' || seriesTooltipShow === false || seriesModel.get(['axisPointer', 'show'], true) === false) {
+        return;
+      }
+
+      each(result.coordSysAxesInfo[makeKey(coordSys.model)], function (axisInfo) {
+        var axis = axisInfo.axis;
+
+        if (coordSys.getAxis(axis.dim) === axis) {
+          axisInfo.seriesModels.push(seriesModel);
+          axisInfo.seriesDataCount == null && (axisInfo.seriesDataCount = 0);
+          axisInfo.seriesDataCount += seriesModel.getData().count();
+        }
+      });
+    });
+  }
+  /**
+   * For example:
+   * {
+   *     axisPointer: {
+   *         links: [{
+   *             xAxisIndex: [2, 4],
+   *             yAxisIndex: 'all'
+   *         }, {
+   *             xAxisId: ['a5', 'a7'],
+   *             xAxisName: 'xxx'
+   *         }]
+   *     }
+   * }
+   */
+
+
+  function getLinkGroupIndex(linksOption, axis) {
+    var axisModel = axis.model;
+    var dim = axis.dim;
+
+    for (var i = 0; i < linksOption.length; i++) {
+      var linkOption = linksOption[i] || {};
+
+      if (checkPropInLink(linkOption[dim + 'AxisId'], axisModel.id) || checkPropInLink(linkOption[dim + 'AxisIndex'], axisModel.componentIndex) || checkPropInLink(linkOption[dim + 'AxisName'], axisModel.name)) {
+        return i;
+      }
+    }
+  }
+
+  function checkPropInLink(linkPropValue, axisPropValue) {
+    return linkPropValue === 'all' || isArray(linkPropValue) && indexOf(linkPropValue, axisPropValue) >= 0 || linkPropValue === axisPropValue;
+  }
+
+  function fixValue(axisModel) {
+    var axisInfo = getAxisInfo(axisModel);
+
+    if (!axisInfo) {
+      return;
+    }
+
+    var axisPointerModel = axisInfo.axisPointerModel;
+    var scale = axisInfo.axis.scale;
+    var option = axisPointerModel.option;
+    var status = axisPointerModel.get('status');
+    var value = axisPointerModel.get('value'); // Parse init value for category and time axis.
+
+    if (value != null) {
+      value = scale.parse(value);
+    }
+
+    var useHandle = isHandleTrigger(axisPointerModel); // If `handle` used, `axisPointer` will always be displayed, so value
+    // and status should be initialized.
+
+    if (status == null) {
+      option.status = useHandle ? 'show' : 'hide';
+    }
+
+    var extent = scale.getExtent().slice();
+    extent[0] > extent[1] && extent.reverse();
+
+    if ( // Pick a value on axis when initializing.
+    value == null // If both `handle` and `dataZoom` are used, value may be out of axis extent,
+    // where we should re-pick a value to keep `handle` displaying normally.
+    || value > extent[1]) {
+      // Make handle displayed on the end of the axis when init, which looks better.
+      value = extent[1];
+    }
+
+    if (value < extent[0]) {
+      value = extent[0];
+    }
+
+    option.value = value;
+
+    if (useHandle) {
+      option.status = axisInfo.axis.scale.isBlank() ? 'hide' : 'show';
+    }
+  }
+
+  function getAxisInfo(axisModel) {
+    var coordSysAxesInfo = (axisModel.ecModel.getComponent('axisPointer') || {}).coordSysAxesInfo;
+    return coordSysAxesInfo && coordSysAxesInfo.axesInfo[makeKey(axisModel)];
+  }
+
+  function getAxisPointerModel(axisModel) {
+    var axisInfo = getAxisInfo(axisModel);
+    return axisInfo && axisInfo.axisPointerModel;
+  }
+
+  function isHandleTrigger(axisPointerModel) {
+    return !!axisPointerModel.get(['handle', 'show']);
+  }
+  /**
+   * @param {module:echarts/model/Model} model
+   * @return {string} unique key
+   */
+
+
+  function makeKey(model) {
+    return model.type + '||' + model.id;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 axisPointerClazz = {};
+  /**
+   * Base class of AxisView.
+   */
+
+  var AxisView =
+  /** @class */
+  function (_super) {
+    __extends(AxisView, _super);
+
+    function AxisView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = AxisView.type;
+      return _this;
+    }
+    /**
+     * @override
+     */
+
+
+    AxisView.prototype.render = function (axisModel, ecModel, api, payload) {
+      // FIXME
+      // This process should proformed after coordinate systems updated
+      // (axis scale updated), and should be performed each time update.
+      // So put it here temporarily, although it is not appropriate to
+      // put a model-writing procedure in `view`.
+      this.axisPointerClass && fixValue(axisModel);
+
+      _super.prototype.render.apply(this, arguments);
+
+      this._doUpdateAxisPointerClass(axisModel, api, true);
+    };
+    /**
+     * Action handler.
+     */
+
+
+    AxisView.prototype.updateAxisPointer = function (axisModel, ecModel, api, payload) {
+      this._doUpdateAxisPointerClass(axisModel, api, false);
+    };
+    /**
+     * @override
+     */
+
+
+    AxisView.prototype.remove = function (ecModel, api) {
+      var axisPointer = this._axisPointer;
+      axisPointer && axisPointer.remove(api);
+    };
+    /**
+     * @override
+     */
+
+
+    AxisView.prototype.dispose = function (ecModel, api) {
+      this._disposeAxisPointer(api);
+
+      _super.prototype.dispose.apply(this, arguments);
+    };
+
+    AxisView.prototype._doUpdateAxisPointerClass = function (axisModel, api, forceRender) {
+      var Clazz = AxisView.getAxisPointerClass(this.axisPointerClass);
+
+      if (!Clazz) {
+        return;
+      }
+
+      var axisPointerModel = getAxisPointerModel(axisModel);
+      axisPointerModel ? (this._axisPointer || (this._axisPointer = new Clazz())).render(axisModel, axisPointerModel, api, forceRender) : this._disposeAxisPointer(api);
+    };
+
+    AxisView.prototype._disposeAxisPointer = function (api) {
+      this._axisPointer && this._axisPointer.dispose(api);
+      this._axisPointer = null;
+    };
+
+    AxisView.registerAxisPointerClass = function (type, clazz) {
+      {
+        if (axisPointerClazz[type]) {
+          throw new Error('axisPointer ' + type + ' exists');
+        }
+      }
+      axisPointerClazz[type] = clazz;
+    };
+
+    AxisView.getAxisPointerClass = function (type) {
+      return type && axisPointerClazz[type];
+    };
+
+    AxisView.type = 'axis';
+    return AxisView;
+  }(ComponentView);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$6 = makeInner();
+
+  function rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel) {
+    var axis = axisModel.axis;
+
+    if (axis.scale.isBlank()) {
+      return;
+    } // TODO: TYPE
+
+
+    var splitAreaModel = axisModel.getModel('splitArea');
+    var areaStyleModel = splitAreaModel.getModel('areaStyle');
+    var areaColors = areaStyleModel.get('color');
+    var gridRect = gridModel.coordinateSystem.getRect();
+    var ticksCoords = axis.getTicksCoords({
+      tickModel: splitAreaModel,
+      clamp: true
+    });
+
+    if (!ticksCoords.length) {
+      return;
+    } // For Making appropriate splitArea animation, the color and anid
+    // should be corresponding to previous one if possible.
+
+
+    var areaColorsLen = areaColors.length;
+    var lastSplitAreaColors = inner$6(axisView).splitAreaColors;
+    var newSplitAreaColors = createHashMap();
+    var colorIndex = 0;
+
+    if (lastSplitAreaColors) {
+      for (var i = 0; i < ticksCoords.length; i++) {
+        var cIndex = lastSplitAreaColors.get(ticksCoords[i].tickValue);
+
+        if (cIndex != null) {
+          colorIndex = (cIndex + (areaColorsLen - 1) * i) % areaColorsLen;
+          break;
+        }
+      }
+    }
+
+    var prev = axis.toGlobalCoord(ticksCoords[0].coord);
+    var areaStyle = areaStyleModel.getAreaStyle();
+    areaColors = isArray(areaColors) ? areaColors : [areaColors];
+
+    for (var i = 1; i < ticksCoords.length; i++) {
+      var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);
+      var x = void 0;
+      var y = void 0;
+      var width = void 0;
+      var height = void 0;
+
+      if (axis.isHorizontal()) {
+        x = prev;
+        y = gridRect.y;
+        width = tickCoord - x;
+        height = gridRect.height;
+        prev = x + width;
+      } else {
+        x = gridRect.x;
+        y = prev;
+        width = gridRect.width;
+        height = tickCoord - y;
+        prev = y + height;
+      }
+
+      var tickValue = ticksCoords[i - 1].tickValue;
+      tickValue != null && newSplitAreaColors.set(tickValue, colorIndex);
+      axisGroup.add(new Rect({
+        anid: tickValue != null ? 'area_' + tickValue : null,
+        shape: {
+          x: x,
+          y: y,
+          width: width,
+          height: height
+        },
+        style: defaults({
+          fill: areaColors[colorIndex]
+        }, areaStyle),
+        autoBatch: true,
+        silent: true
+      }));
+      colorIndex = (colorIndex + 1) % areaColorsLen;
+    }
+
+    inner$6(axisView).splitAreaColors = newSplitAreaColors;
+  }
+
+  function rectCoordAxisHandleRemove(axisView) {
+    inner$6(axisView).splitAreaColors = null;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 axisBuilderAttrs = ['axisLine', 'axisTickLabel', 'axisName'];
+  var selfBuilderAttrs = ['splitArea', 'splitLine', 'minorSplitLine'];
+
+  var CartesianAxisView =
+  /** @class */
+  function (_super) {
+    __extends(CartesianAxisView, _super);
+
+    function CartesianAxisView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = CartesianAxisView.type;
+      _this.axisPointerClass = 'CartesianAxisPointer';
+      return _this;
+    }
+    /**
+     * @override
+     */
+
+
+    CartesianAxisView.prototype.render = function (axisModel, ecModel, api, payload) {
+      this.group.removeAll();
+      var oldAxisGroup = this._axisGroup;
+      this._axisGroup = new Group();
+      this.group.add(this._axisGroup);
+
+      if (!axisModel.get('show')) {
+        return;
+      }
+
+      var gridModel = axisModel.getCoordSysModel();
+      var layout = layout$1(gridModel, axisModel);
+      var axisBuilder = new AxisBuilder(axisModel, extend({
+        handleAutoShown: function (elementType) {
+          var cartesians = gridModel.coordinateSystem.getCartesians();
+
+          for (var i = 0; i < cartesians.length; i++) {
+            if (isIntervalOrLogScale(cartesians[i].getOtherAxis(axisModel.axis).scale)) {
+              // Still show axis tick or axisLine if other axis is value / log
+              return true;
+            }
+          } // Not show axisTick or axisLine if other axis is category / time
+
+
+          return false;
+        }
+      }, layout));
+      each(axisBuilderAttrs, axisBuilder.add, axisBuilder);
+
+      this._axisGroup.add(axisBuilder.getGroup());
+
+      each(selfBuilderAttrs, function (name) {
+        if (axisModel.get([name, 'show'])) {
+          axisElementBuilders[name](this, this._axisGroup, axisModel, gridModel);
+        }
+      }, this); // THIS is a special case for bar racing chart.
+      // Update the axis label from the natural initial layout to
+      // sorted layout should has no animation.
+
+      var isInitialSortFromBarRacing = payload && payload.type === 'changeAxisOrder' && payload.isInitSort;
+
+      if (!isInitialSortFromBarRacing) {
+        groupTransition(oldAxisGroup, this._axisGroup, axisModel);
+      }
+
+      _super.prototype.render.call(this, axisModel, ecModel, api, payload);
+    };
+
+    CartesianAxisView.prototype.remove = function () {
+      rectCoordAxisHandleRemove(this);
+    };
+
+    CartesianAxisView.type = 'cartesianAxis';
+    return CartesianAxisView;
+  }(AxisView);
+
+  var axisElementBuilders = {
+    splitLine: function (axisView, axisGroup, axisModel, gridModel) {
+      var axis = axisModel.axis;
+
+      if (axis.scale.isBlank()) {
+        return;
+      }
+
+      var splitLineModel = axisModel.getModel('splitLine');
+      var lineStyleModel = splitLineModel.getModel('lineStyle');
+      var lineColors = lineStyleModel.get('color');
+      lineColors = isArray(lineColors) ? lineColors : [lineColors];
+      var gridRect = gridModel.coordinateSystem.getRect();
+      var isHorizontal = axis.isHorizontal();
+      var lineCount = 0;
+      var ticksCoords = axis.getTicksCoords({
+        tickModel: splitLineModel
+      });
+      var p1 = [];
+      var p2 = [];
+      var lineStyle = lineStyleModel.getLineStyle();
+
+      for (var i = 0; i < ticksCoords.length; i++) {
+        var tickCoord = axis.toGlobalCoord(ticksCoords[i].coord);
+
+        if (isHorizontal) {
+          p1[0] = tickCoord;
+          p1[1] = gridRect.y;
+          p2[0] = tickCoord;
+          p2[1] = gridRect.y + gridRect.height;
+        } else {
+          p1[0] = gridRect.x;
+          p1[1] = tickCoord;
+          p2[0] = gridRect.x + gridRect.width;
+          p2[1] = tickCoord;
+        }
+
+        var colorIndex = lineCount++ % lineColors.length;
+        var tickValue = ticksCoords[i].tickValue;
+        axisGroup.add(new Line({
+          anid: tickValue != null ? 'line_' + ticksCoords[i].tickValue : null,
+          subPixelOptimize: true,
+          autoBatch: true,
+          shape: {
+            x1: p1[0],
+            y1: p1[1],
+            x2: p2[0],
+            y2: p2[1]
+          },
+          style: defaults({
+            stroke: lineColors[colorIndex]
+          }, lineStyle),
+          silent: true
+        }));
+      }
+    },
+    minorSplitLine: function (axisView, axisGroup, axisModel, gridModel) {
+      var axis = axisModel.axis;
+      var minorSplitLineModel = axisModel.getModel('minorSplitLine');
+      var lineStyleModel = minorSplitLineModel.getModel('lineStyle');
+      var gridRect = gridModel.coordinateSystem.getRect();
+      var isHorizontal = axis.isHorizontal();
+      var minorTicksCoords = axis.getMinorTicksCoords();
+
+      if (!minorTicksCoords.length) {
+        return;
+      }
+
+      var p1 = [];
+      var p2 = [];
+      var lineStyle = lineStyleModel.getLineStyle();
+
+      for (var i = 0; i < minorTicksCoords.length; i++) {
+        for (var k = 0; k < minorTicksCoords[i].length; k++) {
+          var tickCoord = axis.toGlobalCoord(minorTicksCoords[i][k].coord);
+
+          if (isHorizontal) {
+            p1[0] = tickCoord;
+            p1[1] = gridRect.y;
+            p2[0] = tickCoord;
+            p2[1] = gridRect.y + gridRect.height;
+          } else {
+            p1[0] = gridRect.x;
+            p1[1] = tickCoord;
+            p2[0] = gridRect.x + gridRect.width;
+            p2[1] = tickCoord;
+          }
+
+          axisGroup.add(new Line({
+            anid: 'minor_line_' + minorTicksCoords[i][k].tickValue,
+            subPixelOptimize: true,
+            autoBatch: true,
+            shape: {
+              x1: p1[0],
+              y1: p1[1],
+              x2: p2[0],
+              y2: p2[1]
+            },
+            style: lineStyle,
+            silent: true
+          }));
+        }
+      }
+    },
+    splitArea: function (axisView, axisGroup, axisModel, gridModel) {
+      rectCoordAxisBuildSplitArea(axisView, axisGroup, axisModel, gridModel);
+    }
+  };
+
+  var CartesianXAxisView =
+  /** @class */
+  function (_super) {
+    __extends(CartesianXAxisView, _super);
+
+    function CartesianXAxisView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = CartesianXAxisView.type;
+      return _this;
+    }
+
+    CartesianXAxisView.type = 'xAxis';
+    return CartesianXAxisView;
+  }(CartesianAxisView);
+
+  var CartesianYAxisView =
+  /** @class */
+  function (_super) {
+    __extends(CartesianYAxisView, _super);
+
+    function CartesianYAxisView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = CartesianXAxisView.type;
+      return _this;
+    }
+
+    CartesianYAxisView.type = 'yAxis';
+    return CartesianYAxisView;
+  }(CartesianAxisView);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 GridView =
+  /** @class */
+  function (_super) {
+    __extends(GridView, _super);
+
+    function GridView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = 'grid';
+      return _this;
+    }
+
+    GridView.prototype.render = function (gridModel, ecModel) {
+      this.group.removeAll();
+
+      if (gridModel.get('show')) {
+        this.group.add(new Rect({
+          shape: gridModel.coordinateSystem.getRect(),
+          style: defaults({
+            fill: gridModel.get('backgroundColor')
+          }, gridModel.getItemStyle()),
+          silent: true,
+          z2: -1
+        }));
+      }
+    };
+
+    GridView.type = 'grid';
+    return GridView;
+  }(ComponentView);
+
+  var extraOption = {
+    // gridIndex: 0,
+    // gridId: '',
+    offset: 0
+  };
+
+  function install$5(registers) {
+    registers.registerComponentView(GridView);
+    registers.registerComponentModel(GridModel);
+    registers.registerCoordinateSystem('cartesian2d', Grid);
+    axisModelCreator(registers, 'x', CartesianAxisModel, extraOption);
+    axisModelCreator(registers, 'y', CartesianAxisModel, extraOption);
+    registers.registerComponentView(CartesianXAxisView);
+    registers.registerComponentView(CartesianYAxisView);
+    registers.registerPreprocessor(function (option) {
+      // Only create grid when need
+      if (option.xAxis && option.yAxis && !option.grid) {
+        option.grid = {};
+      }
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+
+  use(install$5);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 TitleModel =
+  /** @class */
+  function (_super) {
+    __extends(TitleModel, _super);
+
+    function TitleModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = TitleModel.type;
+      _this.layoutMode = {
+        type: 'box',
+        ignoreSize: true
+      };
+      return _this;
+    }
+
+    TitleModel.type = 'title';
+    TitleModel.defaultOption = {
+      // zlevel: 0,
+      z: 6,
+      show: true,
+      text: '',
+      target: 'blank',
+      subtext: '',
+      subtarget: 'blank',
+      left: 0,
+      top: 0,
+      backgroundColor: 'rgba(0,0,0,0)',
+      borderColor: '#ccc',
+      borderWidth: 0,
+      padding: 5,
+      itemGap: 10,
+      textStyle: {
+        fontSize: 18,
+        fontWeight: 'bold',
+        color: '#464646'
+      },
+      subtextStyle: {
+        fontSize: 12,
+        color: '#6E7079'
+      }
+    };
+    return TitleModel;
+  }(ComponentModel); // View
+
+
+  var TitleView =
+  /** @class */
+  function (_super) {
+    __extends(TitleView, _super);
+
+    function TitleView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = TitleView.type;
+      return _this;
+    }
+
+    TitleView.prototype.render = function (titleModel, ecModel, api) {
+      this.group.removeAll();
+
+      if (!titleModel.get('show')) {
+        return;
+      }
+
+      var group = this.group;
+      var textStyleModel = titleModel.getModel('textStyle');
+      var subtextStyleModel = titleModel.getModel('subtextStyle');
+      var textAlign = titleModel.get('textAlign');
+      var textVerticalAlign = retrieve2(titleModel.get('textBaseline'), titleModel.get('textVerticalAlign'));
+      var textEl = new ZRText({
+        style: createTextStyle(textStyleModel, {
+          text: titleModel.get('text'),
+          fill: textStyleModel.getTextColor()
+        }, {
+          disableBox: true
+        }),
+        z2: 10
+      });
+      var textRect = textEl.getBoundingRect();
+      var subText = titleModel.get('subtext');
+      var subTextEl = new ZRText({
+        style: createTextStyle(subtextStyleModel, {
+          text: subText,
+          fill: subtextStyleModel.getTextColor(),
+          y: textRect.height + titleModel.get('itemGap'),
+          verticalAlign: 'top'
+        }, {
+          disableBox: true
+        }),
+        z2: 10
+      });
+      var link = titleModel.get('link');
+      var sublink = titleModel.get('sublink');
+      var triggerEvent = titleModel.get('triggerEvent', true);
+      textEl.silent = !link && !triggerEvent;
+      subTextEl.silent = !sublink && !triggerEvent;
+
+      if (link) {
+        textEl.on('click', function () {
+          windowOpen(link, '_' + titleModel.get('target'));
+        });
+      }
+
+      if (sublink) {
+        subTextEl.on('click', function () {
+          windowOpen(sublink, '_' + titleModel.get('subtarget'));
+        });
+      }
+
+      getECData(textEl).eventData = getECData(subTextEl).eventData = triggerEvent ? {
+        componentType: 'title',
+        componentIndex: titleModel.componentIndex
+      } : null;
+      group.add(textEl);
+      subText && group.add(subTextEl); // If no subText, but add subTextEl, there will be an empty line.
+
+      var groupRect = group.getBoundingRect();
+      var layoutOption = titleModel.getBoxLayoutParams();
+      layoutOption.width = groupRect.width;
+      layoutOption.height = groupRect.height;
+      var layoutRect = getLayoutRect(layoutOption, {
+        width: api.getWidth(),
+        height: api.getHeight()
+      }, titleModel.get('padding')); // Adjust text align based on position
+
+      if (!textAlign) {
+        // Align left if title is on the left. center and right is same
+        textAlign = titleModel.get('left') || titleModel.get('right'); // @ts-ignore
+
+        if (textAlign === 'middle') {
+          textAlign = 'center';
+        } // Adjust layout by text align
+
+
+        if (textAlign === 'right') {
+          layoutRect.x += layoutRect.width;
+        } else if (textAlign === 'center') {
+          layoutRect.x += layoutRect.width / 2;
+        }
+      }
+
+      if (!textVerticalAlign) {
+        textVerticalAlign = titleModel.get('top') || titleModel.get('bottom'); // @ts-ignore
+
+        if (textVerticalAlign === 'center') {
+          textVerticalAlign = 'middle';
+        }
+
+        if (textVerticalAlign === 'bottom') {
+          layoutRect.y += layoutRect.height;
+        } else if (textVerticalAlign === 'middle') {
+          layoutRect.y += layoutRect.height / 2;
+        }
+
+        textVerticalAlign = textVerticalAlign || 'top';
+      }
+
+      group.x = layoutRect.x;
+      group.y = layoutRect.y;
+      group.markRedraw();
+      var alignStyle = {
+        align: textAlign,
+        verticalAlign: textVerticalAlign
+      };
+      textEl.setStyle(alignStyle);
+      subTextEl.setStyle(alignStyle); // Render background
+      // Get groupRect again because textAlign has been changed
+
+      groupRect = group.getBoundingRect();
+      var padding = layoutRect.margin;
+      var style = titleModel.getItemStyle(['color', 'opacity']);
+      style.fill = titleModel.get('backgroundColor');
+      var rect = new Rect({
+        shape: {
+          x: groupRect.x - padding[3],
+          y: groupRect.y - padding[0],
+          width: groupRect.width + padding[1] + padding[3],
+          height: groupRect.height + padding[0] + padding[2],
+          r: titleModel.get('borderRadius')
+        },
+        style: style,
+        subPixelOptimize: true,
+        silent: true
+      });
+      group.add(rect);
+    };
+
+    TitleView.type = 'title';
+    return TitleView;
+  }(ComponentView);
+
+  function install$6(registers) {
+    registers.registerComponentModel(TitleModel);
+    registers.registerComponentView(TitleView);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+
+  use(install$6);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 getDefaultSelectorOptions = function (ecModel, type) {
+    if (type === 'all') {
+      return {
+        type: 'all',
+        title: ecModel.getLocaleModel().get(['legend', 'selector', 'all'])
+      };
+    } else if (type === 'inverse') {
+      return {
+        type: 'inverse',
+        title: ecModel.getLocaleModel().get(['legend', 'selector', 'inverse'])
+      };
+    }
+  };
+
+  var LegendModel =
+  /** @class */
+  function (_super) {
+    __extends(LegendModel, _super);
+
+    function LegendModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = LegendModel.type;
+      _this.layoutMode = {
+        type: 'box',
+        // legend.width/height are maxWidth/maxHeight actually,
+        // whereas realy width/height is calculated by its content.
+        // (Setting {left: 10, right: 10} does not make sense).
+        // So consider the case:
+        // `setOption({legend: {left: 10});`
+        // then `setOption({legend: {right: 10});`
+        // The previous `left` should be cleared by setting `ignoreSize`.
+        ignoreSize: true
+      };
+      return _this;
+    }
+
+    LegendModel.prototype.init = function (option, parentModel, ecModel) {
+      this.mergeDefaultAndTheme(option, ecModel);
+      option.selected = option.selected || {};
+
+      this._updateSelector(option);
+    };
+
+    LegendModel.prototype.mergeOption = function (option, ecModel) {
+      _super.prototype.mergeOption.call(this, option, ecModel);
+
+      this._updateSelector(option);
+    };
+
+    LegendModel.prototype._updateSelector = function (option) {
+      var selector = option.selector;
+      var ecModel = this.ecModel;
+
+      if (selector === true) {
+        selector = option.selector = ['all', 'inverse'];
+      }
+
+      if (isArray(selector)) {
+        each(selector, function (item, index) {
+          isString(item) && (item = {
+            type: item
+          });
+          selector[index] = merge(item, getDefaultSelectorOptions(ecModel, item.type));
+        });
+      }
+    };
+
+    LegendModel.prototype.optionUpdated = function () {
+      this._updateData(this.ecModel);
+
+      var legendData = this._data; // If selectedMode is single, try to select one
+
+      if (legendData[0] && this.get('selectedMode') === 'single') {
+        var hasSelected = false; // If has any selected in option.selected
+
+        for (var i = 0; i < legendData.length; i++) {
+          var name_1 = legendData[i].get('name');
+
+          if (this.isSelected(name_1)) {
+            // Force to unselect others
+            this.select(name_1);
+            hasSelected = true;
+            break;
+          }
+        } // Try select the first if selectedMode is single
+
+
+        !hasSelected && this.select(legendData[0].get('name'));
+      }
+    };
+
+    LegendModel.prototype._updateData = function (ecModel) {
+      var potentialData = [];
+      var availableNames = [];
+      ecModel.eachRawSeries(function (seriesModel) {
+        var seriesName = seriesModel.name;
+        availableNames.push(seriesName);
+        var isPotential;
+
+        if (seriesModel.legendVisualProvider) {
+          var provider = seriesModel.legendVisualProvider;
+          var names = provider.getAllNames();
+
+          if (!ecModel.isSeriesFiltered(seriesModel)) {
+            availableNames = availableNames.concat(names);
+          }
+
+          if (names.length) {
+            potentialData = potentialData.concat(names);
+          } else {
+            isPotential = true;
+          }
+        } else {
+          isPotential = true;
+        }
+
+        if (isPotential && isNameSpecified(seriesModel)) {
+          potentialData.push(seriesModel.name);
+        }
+      });
+      /**
+       * @type {Array.<string>}
+       * @private
+       */
+
+      this._availableNames = availableNames; // If legend.data not specified in option, use availableNames as data,
+      // which is convinient for user preparing option.
+
+      var rawData = this.get('data') || potentialData;
+      var legendData = map(rawData, function (dataItem) {
+        // Can be string or number
+        if (isString(dataItem) || isNumber(dataItem)) {
+          dataItem = {
+            name: dataItem
+          };
+        }
+
+        return new Model(dataItem, this, this.ecModel);
+      }, this);
+      /**
+       * @type {Array.<module:echarts/model/Model>}
+       * @private
+       */
+
+      this._data = legendData;
+    };
+
+    LegendModel.prototype.getData = function () {
+      return this._data;
+    };
+
+    LegendModel.prototype.select = function (name) {
+      var selected = this.option.selected;
+      var selectedMode = this.get('selectedMode');
+
+      if (selectedMode === 'single') {
+        var data = this._data;
+        each(data, function (dataItem) {
+          selected[dataItem.get('name')] = false;
+        });
+      }
+
+      selected[name] = true;
+    };
+
+    LegendModel.prototype.unSelect = function (name) {
+      if (this.get('selectedMode') !== 'single') {
+        this.option.selected[name] = false;
+      }
+    };
+
+    LegendModel.prototype.toggleSelected = function (name) {
+      var selected = this.option.selected; // Default is true
+
+      if (!selected.hasOwnProperty(name)) {
+        selected[name] = true;
+      }
+
+      this[selected[name] ? 'unSelect' : 'select'](name);
+    };
+
+    LegendModel.prototype.allSelect = function () {
+      var data = this._data;
+      var selected = this.option.selected;
+      each(data, function (dataItem) {
+        selected[dataItem.get('name', true)] = true;
+      });
+    };
+
+    LegendModel.prototype.inverseSelect = function () {
+      var data = this._data;
+      var selected = this.option.selected;
+      each(data, function (dataItem) {
+        var name = dataItem.get('name', true); // Initially, default value is true
+
+        if (!selected.hasOwnProperty(name)) {
+          selected[name] = true;
+        }
+
+        selected[name] = !selected[name];
+      });
+    };
+
+    LegendModel.prototype.isSelected = function (name) {
+      var selected = this.option.selected;
+      return !(selected.hasOwnProperty(name) && !selected[name]) && indexOf(this._availableNames, name) >= 0;
+    };
+
+    LegendModel.prototype.getOrient = function () {
+      return this.get('orient') === 'vertical' ? {
+        index: 1,
+        name: 'vertical'
+      } : {
+        index: 0,
+        name: 'horizontal'
+      };
+    };
+
+    LegendModel.type = 'legend.plain';
+    LegendModel.dependencies = ['series'];
+    LegendModel.defaultOption = {
+      // zlevel: 0,
+      z: 4,
+      show: true,
+      orient: 'horizontal',
+      left: 'center',
+      // right: 'center',
+      top: 0,
+      // bottom: null,
+      align: 'auto',
+      backgroundColor: 'rgba(0,0,0,0)',
+      borderColor: '#ccc',
+      borderRadius: 0,
+      borderWidth: 0,
+      padding: 5,
+      itemGap: 10,
+      itemWidth: 25,
+      itemHeight: 14,
+      symbolRotate: 'inherit',
+      symbolKeepAspect: true,
+      inactiveColor: '#ccc',
+      inactiveBorderColor: '#ccc',
+      inactiveBorderWidth: 'auto',
+      itemStyle: {
+        color: 'inherit',
+        opacity: 'inherit',
+        borderColor: 'inherit',
+        borderWidth: 'auto',
+        borderCap: 'inherit',
+        borderJoin: 'inherit',
+        borderDashOffset: 'inherit',
+        borderMiterLimit: 'inherit'
+      },
+      lineStyle: {
+        width: 'auto',
+        color: 'inherit',
+        inactiveColor: '#ccc',
+        inactiveWidth: 2,
+        opacity: 'inherit',
+        type: 'inherit',
+        cap: 'inherit',
+        join: 'inherit',
+        dashOffset: 'inherit',
+        miterLimit: 'inherit'
+      },
+      textStyle: {
+        color: '#333'
+      },
+      selectedMode: true,
+      selector: false,
+      selectorLabel: {
+        show: true,
+        borderRadius: 10,
+        padding: [3, 5, 3, 5],
+        fontSize: 12,
+        fontFamily: 'sans-serif',
+        color: '#666',
+        borderWidth: 1,
+        borderColor: '#666'
+      },
+      emphasis: {
+        selectorLabel: {
+          show: true,
+          color: '#eee',
+          backgroundColor: '#666'
+        }
+      },
+      selectorPosition: 'auto',
+      selectorItemGap: 7,
+      selectorButtonGap: 10,
+      tooltip: {
+        show: false
+      }
+    };
+    return LegendModel;
+  }(ComponentModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // @ts-nocheck
+
+  /**
+   * Layout list like component.
+   * It will box layout each items in group of component and then position the whole group in the viewport
+   * @param {module:zrender/group/Group} group
+   * @param {module:echarts/model/Component} componentModel
+   * @param {module:echarts/ExtensionAPI}
+   */
+
+
+  function makeBackground(rect, componentModel) {
+    var padding = normalizeCssArray$1(componentModel.get('padding'));
+    var style = componentModel.getItemStyle(['color', 'opacity']);
+    style.fill = componentModel.get('backgroundColor');
+    rect = new Rect({
+      shape: {
+        x: rect.x - padding[3],
+        y: rect.y - padding[0],
+        width: rect.width + padding[1] + padding[3],
+        height: rect.height + padding[0] + padding[2],
+        r: componentModel.get('borderRadius')
+      },
+      style: style,
+      silent: true,
+      z2: -1
+    }); // FIXME
+    // `subPixelOptimizeRect` may bring some gap between edge of viewpart
+    // and background rect when setting like `left: 0`, `top: 0`.
+    // graphic.subPixelOptimizeRect(rect);
+
+    return rect;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 curry$1 = curry;
+  var each$3 = each;
+  var Group$2 = Group;
+
+  var LegendView =
+  /** @class */
+  function (_super) {
+    __extends(LegendView, _super);
+
+    function LegendView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = LegendView.type;
+      _this.newlineDisabled = false;
+      return _this;
+    }
+
+    LegendView.prototype.init = function () {
+      this.group.add(this._contentGroup = new Group$2());
+      this.group.add(this._selectorGroup = new Group$2());
+      this._isFirstRender = true;
+    };
+    /**
+     * @protected
+     */
+
+
+    LegendView.prototype.getContentGroup = function () {
+      return this._contentGroup;
+    };
+    /**
+     * @protected
+     */
+
+
+    LegendView.prototype.getSelectorGroup = function () {
+      return this._selectorGroup;
+    };
+    /**
+     * @override
+     */
+
+
+    LegendView.prototype.render = function (legendModel, ecModel, api) {
+      var isFirstRender = this._isFirstRender;
+      this._isFirstRender = false;
+      this.resetInner();
+
+      if (!legendModel.get('show', true)) {
+        return;
+      }
+
+      var itemAlign = legendModel.get('align');
+      var orient = legendModel.get('orient');
+
+      if (!itemAlign || itemAlign === 'auto') {
+        itemAlign = legendModel.get('left') === 'right' && orient === 'vertical' ? 'right' : 'left';
+      } // selector has been normalized to an array in model
+
+
+      var selector = legendModel.get('selector', true);
+      var selectorPosition = legendModel.get('selectorPosition', true);
+
+      if (selector && (!selectorPosition || selectorPosition === 'auto')) {
+        selectorPosition = orient === 'horizontal' ? 'end' : 'start';
+      }
+
+      this.renderInner(itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition); // Perform layout.
+
+      var positionInfo = legendModel.getBoxLayoutParams();
+      var viewportSize = {
+        width: api.getWidth(),
+        height: api.getHeight()
+      };
+      var padding = legendModel.get('padding');
+      var maxSize = getLayoutRect(positionInfo, viewportSize, padding);
+      var mainRect = this.layoutInner(legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition); // Place mainGroup, based on the calculated `mainRect`.
+
+      var layoutRect = getLayoutRect(defaults({
+        width: mainRect.width,
+        height: mainRect.height
+      }, positionInfo), viewportSize, padding);
+      this.group.x = layoutRect.x - mainRect.x;
+      this.group.y = layoutRect.y - mainRect.y;
+      this.group.markRedraw(); // Render background after group is layout.
+
+      this.group.add(this._backgroundEl = makeBackground(mainRect, legendModel));
+    };
+
+    LegendView.prototype.resetInner = function () {
+      this.getContentGroup().removeAll();
+      this._backgroundEl && this.group.remove(this._backgroundEl);
+      this.getSelectorGroup().removeAll();
+    };
+
+    LegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) {
+      var contentGroup = this.getContentGroup();
+      var legendDrawnMap = createHashMap();
+      var selectMode = legendModel.get('selectedMode');
+      var excludeSeriesId = [];
+      ecModel.eachRawSeries(function (seriesModel) {
+        !seriesModel.get('legendHoverLink') && excludeSeriesId.push(seriesModel.id);
+      });
+      each$3(legendModel.getData(), function (legendItemModel, dataIndex) {
+        var name = legendItemModel.get('name'); // Use empty string or \n as a newline string
+
+        if (!this.newlineDisabled && (name === '' || name === '\n')) {
+          var g = new Group$2(); // @ts-ignore
+
+          g.newline = true;
+          contentGroup.add(g);
+          return;
+        } // Representitive series.
+
+
+        var seriesModel = ecModel.getSeriesByName(name)[0];
+
+        if (legendDrawnMap.get(name)) {
+          // Have been drawed
+          return;
+        } // Legend to control series.
+
+
+        if (seriesModel) {
+          var data = seriesModel.getData();
+          var lineVisualStyle = data.getVisual('legendLineStyle') || {};
+          var legendIcon = data.getVisual('legendIcon');
+          /**
+           * `data.getVisual('style')` may be the color from the register
+           * in series. For example, for line series,
+           */
+
+          var style = data.getVisual('style');
+
+          var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, style, legendIcon, selectMode, api);
+
+          itemGroup.on('click', curry$1(dispatchSelectAction, name, null, api, excludeSeriesId)).on('mouseover', curry$1(dispatchHighlightAction, seriesModel.name, null, api, excludeSeriesId)).on('mouseout', curry$1(dispatchDownplayAction, seriesModel.name, null, api, excludeSeriesId));
+          legendDrawnMap.set(name, true);
+        } else {
+          // Legend to control data. In pie and funnel.
+          ecModel.eachRawSeries(function (seriesModel) {
+            // In case multiple series has same data name
+            if (legendDrawnMap.get(name)) {
+              return;
+            }
+
+            if (seriesModel.legendVisualProvider) {
+              var provider = seriesModel.legendVisualProvider;
+
+              if (!provider.containName(name)) {
+                return;
+              }
+
+              var idx = provider.indexOfName(name);
+              var style = provider.getItemVisual(idx, 'style');
+              var legendIcon = provider.getItemVisual(idx, 'legendIcon');
+              var colorArr = parse(style.fill); // Color may be set to transparent in visualMap when data is out of range.
+              // Do not show nothing.
+
+              if (colorArr && colorArr[3] === 0) {
+                colorArr[3] = 0.2; // TODO color is set to 0, 0, 0, 0. Should show correct RGBA
+
+                style = extend(extend({}, style), {
+                  fill: stringify(colorArr, 'rgba')
+                });
+              }
+
+              var itemGroup = this._createItem(seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, {}, style, legendIcon, selectMode, api); // FIXME: consider different series has items with the same name.
+
+
+              itemGroup.on('click', curry$1(dispatchSelectAction, null, name, api, excludeSeriesId)) // Should not specify the series name, consider legend controls
+              // more than one pie series.
+              .on('mouseover', curry$1(dispatchHighlightAction, null, name, api, excludeSeriesId)).on('mouseout', curry$1(dispatchDownplayAction, null, name, api, excludeSeriesId));
+              legendDrawnMap.set(name, true);
+            }
+          }, this);
+        }
+
+        {
+          if (!legendDrawnMap.get(name)) {
+            console.warn(name + ' series not exists. Legend data should be same with series name or data name.');
+          }
+        }
+      }, this);
+
+      if (selector) {
+        this._createSelector(selector, legendModel, api, orient, selectorPosition);
+      }
+    };
+
+    LegendView.prototype._createSelector = function (selector, legendModel, api, orient, selectorPosition) {
+      var selectorGroup = this.getSelectorGroup();
+      each$3(selector, function createSelectorButton(selectorItem) {
+        var type = selectorItem.type;
+        var labelText = new ZRText({
+          style: {
+            x: 0,
+            y: 0,
+            align: 'center',
+            verticalAlign: 'middle'
+          },
+          onclick: function () {
+            api.dispatchAction({
+              type: type === 'all' ? 'legendAllSelect' : 'legendInverseSelect'
+            });
+          }
+        });
+        selectorGroup.add(labelText);
+        var labelModel = legendModel.getModel('selectorLabel');
+        var emphasisLabelModel = legendModel.getModel(['emphasis', 'selectorLabel']);
+        setLabelStyle(labelText, {
+          normal: labelModel,
+          emphasis: emphasisLabelModel
+        }, {
+          defaultText: selectorItem.title
+        });
+        enableHoverEmphasis(labelText);
+      });
+    };
+
+    LegendView.prototype._createItem = function (seriesModel, name, dataIndex, legendItemModel, legendModel, itemAlign, lineVisualStyle, itemVisualStyle, legendIcon, selectMode, api) {
+      var drawType = seriesModel.visualDrawType;
+      var itemWidth = legendModel.get('itemWidth');
+      var itemHeight = legendModel.get('itemHeight');
+      var isSelected = legendModel.isSelected(name);
+      var iconRotate = legendItemModel.get('symbolRotate');
+      var symbolKeepAspect = legendItemModel.get('symbolKeepAspect');
+      var legendIconType = legendItemModel.get('icon');
+      legendIcon = legendIconType || legendIcon || 'roundRect';
+      var style = getLegendStyle(legendIcon, legendItemModel, lineVisualStyle, itemVisualStyle, drawType, isSelected, api);
+      var itemGroup = new Group$2();
+      var textStyleModel = legendItemModel.getModel('textStyle');
+
+      if (isFunction(seriesModel.getLegendIcon) && (!legendIconType || legendIconType === 'inherit')) {
+        // Series has specific way to define legend icon
+        itemGroup.add(seriesModel.getLegendIcon({
+          itemWidth: itemWidth,
+          itemHeight: itemHeight,
+          icon: legendIcon,
+          iconRotate: iconRotate,
+          itemStyle: style.itemStyle,
+          lineStyle: style.lineStyle,
+          symbolKeepAspect: symbolKeepAspect
+        }));
+      } else {
+        // Use default legend icon policy for most series
+        var rotate = legendIconType === 'inherit' && seriesModel.getData().getVisual('symbol') ? iconRotate === 'inherit' ? seriesModel.getData().getVisual('symbolRotate') : iconRotate : 0; // No rotation for no icon
+
+        itemGroup.add(getDefaultLegendIcon({
+          itemWidth: itemWidth,
+          itemHeight: itemHeight,
+          icon: legendIcon,
+          iconRotate: rotate,
+          itemStyle: style.itemStyle,
+          lineStyle: style.lineStyle,
+          symbolKeepAspect: symbolKeepAspect
+        }));
+      }
+
+      var textX = itemAlign === 'left' ? itemWidth + 5 : -5;
+      var textAlign = itemAlign;
+      var formatter = legendModel.get('formatter');
+      var content = name;
+
+      if (isString(formatter) && formatter) {
+        content = formatter.replace('{name}', name != null ? name : '');
+      } else if (isFunction(formatter)) {
+        content = formatter(name);
+      }
+
+      var inactiveColor = legendItemModel.get('inactiveColor');
+      itemGroup.add(new ZRText({
+        style: createTextStyle(textStyleModel, {
+          text: content,
+          x: textX,
+          y: itemHeight / 2,
+          fill: isSelected ? textStyleModel.getTextColor() : inactiveColor,
+          align: textAlign,
+          verticalAlign: 'middle'
+        })
+      })); // Add a invisible rect to increase the area of mouse hover
+
+      var hitRect = new Rect({
+        shape: itemGroup.getBoundingRect(),
+        invisible: true
+      });
+      var tooltipModel = legendItemModel.getModel('tooltip');
+
+      if (tooltipModel.get('show')) {
+        setTooltipConfig({
+          el: hitRect,
+          componentModel: legendModel,
+          itemName: name,
+          itemTooltipOption: tooltipModel.option
+        });
+      }
+
+      itemGroup.add(hitRect);
+      itemGroup.eachChild(function (child) {
+        child.silent = true;
+      });
+      hitRect.silent = !selectMode;
+      this.getContentGroup().add(itemGroup);
+      enableHoverEmphasis(itemGroup); // @ts-ignore
+
+      itemGroup.__legendDataIndex = dataIndex;
+      return itemGroup;
+    };
+
+    LegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) {
+      var contentGroup = this.getContentGroup();
+      var selectorGroup = this.getSelectorGroup(); // Place items in contentGroup.
+
+      box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), maxSize.width, maxSize.height);
+      var contentRect = contentGroup.getBoundingRect();
+      var contentPos = [-contentRect.x, -contentRect.y];
+      selectorGroup.markRedraw();
+      contentGroup.markRedraw();
+
+      if (selector) {
+        // Place buttons in selectorGroup
+        box( // Buttons in selectorGroup always layout horizontally
+        'horizontal', selectorGroup, legendModel.get('selectorItemGap', true));
+        var selectorRect = selectorGroup.getBoundingRect();
+        var selectorPos = [-selectorRect.x, -selectorRect.y];
+        var selectorButtonGap = legendModel.get('selectorButtonGap', true);
+        var orientIdx = legendModel.getOrient().index;
+        var wh = orientIdx === 0 ? 'width' : 'height';
+        var hw = orientIdx === 0 ? 'height' : 'width';
+        var yx = orientIdx === 0 ? 'y' : 'x';
+
+        if (selectorPosition === 'end') {
+          selectorPos[orientIdx] += contentRect[wh] + selectorButtonGap;
+        } else {
+          contentPos[orientIdx] += selectorRect[wh] + selectorButtonGap;
+        } //Always align selector to content as 'middle'
+
+
+        selectorPos[1 - orientIdx] += contentRect[hw] / 2 - selectorRect[hw] / 2;
+        selectorGroup.x = selectorPos[0];
+        selectorGroup.y = selectorPos[1];
+        contentGroup.x = contentPos[0];
+        contentGroup.y = contentPos[1];
+        var mainRect = {
+          x: 0,
+          y: 0
+        };
+        mainRect[wh] = contentRect[wh] + selectorButtonGap + selectorRect[wh];
+        mainRect[hw] = Math.max(contentRect[hw], selectorRect[hw]);
+        mainRect[yx] = Math.min(0, selectorRect[yx] + selectorPos[1 - orientIdx]);
+        return mainRect;
+      } else {
+        contentGroup.x = contentPos[0];
+        contentGroup.y = contentPos[1];
+        return this.group.getBoundingRect();
+      }
+    };
+    /**
+     * @protected
+     */
+
+
+    LegendView.prototype.remove = function () {
+      this.getContentGroup().removeAll();
+      this._isFirstRender = true;
+    };
+
+    LegendView.type = 'legend.plain';
+    return LegendView;
+  }(ComponentView);
+
+  function getLegendStyle(iconType, legendItemModel, lineVisualStyle, itemVisualStyle, drawType, isSelected, api) {
+    /**
+     * Use series style if is inherit;
+     * elsewise, use legend style
+     */
+    function handleCommonProps(style, visualStyle) {
+      // If lineStyle.width is 'auto', it is set to be 2 if series has border
+      if (style.lineWidth === 'auto') {
+        style.lineWidth = visualStyle.lineWidth > 0 ? 2 : 0;
+      }
+
+      each$3(style, function (propVal, propName) {
+        style[propName] === 'inherit' && (style[propName] = visualStyle[propName]);
+      });
+    } // itemStyle
+
+
+    var itemStyleModel = legendItemModel.getModel('itemStyle');
+    var itemStyle = itemStyleModel.getItemStyle();
+    var iconBrushType = iconType.lastIndexOf('empty', 0) === 0 ? 'fill' : 'stroke';
+    var decalStyle = itemStyleModel.getShallow('decal');
+    itemStyle.decal = !decalStyle || decalStyle === 'inherit' ? itemVisualStyle.decal : createOrUpdatePatternFromDecal(decalStyle, api);
+
+    if (itemStyle.fill === 'inherit') {
+      /**
+       * Series with visualDrawType as 'stroke' should have
+       * series stroke as legend fill
+       */
+      itemStyle.fill = itemVisualStyle[drawType];
+    }
+
+    if (itemStyle.stroke === 'inherit') {
+      /**
+       * icon type with "emptyXXX" should use fill color
+       * in visual style
+       */
+      itemStyle.stroke = itemVisualStyle[iconBrushType];
+    }
+
+    if (itemStyle.opacity === 'inherit') {
+      /**
+       * Use lineStyle.opacity if drawType is stroke
+       */
+      itemStyle.opacity = (drawType === 'fill' ? itemVisualStyle : lineVisualStyle).opacity;
+    }
+
+    handleCommonProps(itemStyle, itemVisualStyle); // lineStyle
+
+    var legendLineModel = legendItemModel.getModel('lineStyle');
+    var lineStyle = legendLineModel.getLineStyle();
+    handleCommonProps(lineStyle, lineVisualStyle); // Fix auto color to real color
+
+    itemStyle.fill === 'auto' && (itemStyle.fill = itemVisualStyle.fill);
+    itemStyle.stroke === 'auto' && (itemStyle.stroke = itemVisualStyle.fill);
+    lineStyle.stroke === 'auto' && (lineStyle.stroke = itemVisualStyle.fill);
+
+    if (!isSelected) {
+      var borderWidth = legendItemModel.get('inactiveBorderWidth');
+      /**
+       * Since stroke is set to be inactiveBorderColor, it may occur that
+       * there is no border in series but border in legend, so we need to
+       * use border only when series has border if is set to be auto
+       */
+
+      var visualHasBorder = itemStyle[iconBrushType];
+      itemStyle.lineWidth = borderWidth === 'auto' ? itemVisualStyle.lineWidth > 0 && visualHasBorder ? 2 : 0 : itemStyle.lineWidth;
+      itemStyle.fill = legendItemModel.get('inactiveColor');
+      itemStyle.stroke = legendItemModel.get('inactiveBorderColor');
+      lineStyle.stroke = legendLineModel.get('inactiveColor');
+      lineStyle.lineWidth = legendLineModel.get('inactiveWidth');
+    }
+
+    return {
+      itemStyle: itemStyle,
+      lineStyle: lineStyle
+    };
+  }
+
+  function getDefaultLegendIcon(opt) {
+    var symboType = opt.icon || 'roundRect';
+    var icon = createSymbol(symboType, 0, 0, opt.itemWidth, opt.itemHeight, opt.itemStyle.fill, opt.symbolKeepAspect);
+    icon.setStyle(opt.itemStyle);
+    icon.rotation = (opt.iconRotate || 0) * Math.PI / 180;
+    icon.setOrigin([opt.itemWidth / 2, opt.itemHeight / 2]);
+
+    if (symboType.indexOf('empty') > -1) {
+      icon.style.stroke = icon.style.fill;
+      icon.style.fill = '#fff';
+      icon.style.lineWidth = 2;
+    }
+
+    return icon;
+  }
+
+  function dispatchSelectAction(seriesName, dataName, api, excludeSeriesId) {
+    // downplay before unselect
+    dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId);
+    api.dispatchAction({
+      type: 'legendToggleSelect',
+      name: seriesName != null ? seriesName : dataName
+    }); // highlight after select
+    // TODO higlight immediately may cause animation loss.
+
+    dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId);
+  }
+
+  function isUseHoverLayer(api) {
+    var list = api.getZr().storage.getDisplayList();
+    var emphasisState;
+    var i = 0;
+    var len = list.length;
+
+    while (i < len && !(emphasisState = list[i].states.emphasis)) {
+      i++;
+    }
+
+    return emphasisState && emphasisState.hoverLayer;
+  }
+
+  function dispatchHighlightAction(seriesName, dataName, api, excludeSeriesId) {
+    // If element hover will move to a hoverLayer.
+    if (!isUseHoverLayer(api)) {
+      api.dispatchAction({
+        type: 'highlight',
+        seriesName: seriesName,
+        name: dataName,
+        excludeSeriesId: excludeSeriesId
+      });
+    }
+  }
+
+  function dispatchDownplayAction(seriesName, dataName, api, excludeSeriesId) {
+    // If element hover will move to a hoverLayer.
+    if (!isUseHoverLayer(api)) {
+      api.dispatchAction({
+        type: 'downplay',
+        seriesName: seriesName,
+        name: dataName,
+        excludeSeriesId: excludeSeriesId
+      });
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 legendFilter(ecModel) {
+    var legendModels = ecModel.findComponents({
+      mainType: 'legend'
+    });
+
+    if (legendModels && legendModels.length) {
+      ecModel.filterSeries(function (series) {
+        // If in any legend component the status is not selected.
+        // Because in legend series is assumed selected when it is not in the legend data.
+        for (var i = 0; i < legendModels.length; i++) {
+          if (!legendModels[i].isSelected(series.name)) {
+            return false;
+          }
+        }
+
+        return true;
+      });
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+  // @ts-nocheck
+
+
+  function legendSelectActionHandler(methodName, payload, ecModel) {
+    var selectedMap = {};
+    var isToggleSelect = methodName === 'toggleSelected';
+    var isSelected; // Update all legend components
+
+    ecModel.eachComponent('legend', function (legendModel) {
+      if (isToggleSelect && isSelected != null) {
+        // Force other legend has same selected status
+        // Or the first is toggled to true and other are toggled to false
+        // In the case one legend has some item unSelected in option. And if other legend
+        // doesn't has the item, they will assume it is selected.
+        legendModel[isSelected ? 'select' : 'unSelect'](payload.name);
+      } else if (methodName === 'allSelect' || methodName === 'inverseSelect') {
+        legendModel[methodName]();
+      } else {
+        legendModel[methodName](payload.name);
+        isSelected = legendModel.isSelected(payload.name);
+      }
+
+      var legendData = legendModel.getData();
+      each(legendData, function (model) {
+        var name = model.get('name'); // Wrap element
+
+        if (name === '\n' || name === '') {
+          return;
+        }
+
+        var isItemSelected = legendModel.isSelected(name);
+
+        if (selectedMap.hasOwnProperty(name)) {
+          // Unselected if any legend is unselected
+          selectedMap[name] = selectedMap[name] && isItemSelected;
+        } else {
+          selectedMap[name] = isItemSelected;
+        }
+      });
+    }); // Return the event explicitly
+
+    return methodName === 'allSelect' || methodName === 'inverseSelect' ? {
+      selected: selectedMap
+    } : {
+      name: payload.name,
+      selected: selectedMap
+    };
+  }
+
+  function installLegendAction(registers) {
+    /**
+     * @event legendToggleSelect
+     * @type {Object}
+     * @property {string} type 'legendToggleSelect'
+     * @property {string} [from]
+     * @property {string} name Series name or data item name
+     */
+    registers.registerAction('legendToggleSelect', 'legendselectchanged', curry(legendSelectActionHandler, 'toggleSelected'));
+    registers.registerAction('legendAllSelect', 'legendselectall', curry(legendSelectActionHandler, 'allSelect'));
+    registers.registerAction('legendInverseSelect', 'legendinverseselect', curry(legendSelectActionHandler, 'inverseSelect'));
+    /**
+     * @event legendSelect
+     * @type {Object}
+     * @property {string} type 'legendSelect'
+     * @property {string} name Series name or data item name
+     */
+
+    registers.registerAction('legendSelect', 'legendselected', curry(legendSelectActionHandler, 'select'));
+    /**
+     * @event legendUnSelect
+     * @type {Object}
+     * @property {string} type 'legendUnSelect'
+     * @property {string} name Series name or data item name
+     */
+
+    registers.registerAction('legendUnSelect', 'legendunselected', curry(legendSelectActionHandler, 'unSelect'));
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install$8(registers) {
+    registers.registerComponentModel(LegendModel);
+    registers.registerComponentView(LegendView);
+    registers.registerProcessor(registers.PRIORITY.PROCESSOR.SERIES_FILTER, legendFilter);
+    registers.registerSubTypeDefaulter('legend', function () {
+      return 'plain';
+    });
+    installLegendAction(registers);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 ScrollableLegendModel =
+  /** @class */
+  function (_super) {
+    __extends(ScrollableLegendModel, _super);
+
+    function ScrollableLegendModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = ScrollableLegendModel.type;
+      return _this;
+    }
+    /**
+     * @param {number} scrollDataIndex
+     */
+
+
+    ScrollableLegendModel.prototype.setScrollDataIndex = function (scrollDataIndex) {
+      this.option.scrollDataIndex = scrollDataIndex;
+    };
+
+    ScrollableLegendModel.prototype.init = function (option, parentModel, ecModel) {
+      var inputPositionParams = getLayoutParams(option);
+
+      _super.prototype.init.call(this, option, parentModel, ecModel);
+
+      mergeAndNormalizeLayoutParams(this, option, inputPositionParams);
+    };
+    /**
+     * @override
+     */
+
+
+    ScrollableLegendModel.prototype.mergeOption = function (option, ecModel) {
+      _super.prototype.mergeOption.call(this, option, ecModel);
+
+      mergeAndNormalizeLayoutParams(this, this.option, option);
+    };
+
+    ScrollableLegendModel.type = 'legend.scroll';
+    ScrollableLegendModel.defaultOption = inheritDefaultOption(LegendModel.defaultOption, {
+      scrollDataIndex: 0,
+      pageButtonItemGap: 5,
+      pageButtonGap: null,
+      pageButtonPosition: 'end',
+      pageFormatter: '{current}/{total}',
+      pageIcons: {
+        horizontal: ['M0,0L12,-10L12,10z', 'M0,0L-12,-10L-12,10z'],
+        vertical: ['M0,0L20,0L10,-20z', 'M0,0L20,0L10,20z']
+      },
+      pageIconColor: '#2f4554',
+      pageIconInactiveColor: '#aaa',
+      pageIconSize: 15,
+      pageTextStyle: {
+        color: '#333'
+      },
+      animationDurationUpdate: 800
+    });
+    return ScrollableLegendModel;
+  }(LegendModel); // Do not `ignoreSize` to enable setting {left: 10, right: 10}.
+
+
+  function mergeAndNormalizeLayoutParams(legendModel, target, raw) {
+    var orient = legendModel.getOrient();
+    var ignoreSize = [1, 1];
+    ignoreSize[orient.index] = 0;
+    mergeLayoutParam(target, raw, {
+      type: 'box',
+      ignoreSize: !!ignoreSize
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Separate legend and scrollable legend to reduce package size.
+   */
+
+
+  var Group$3 = Group;
+  var WH = ['width', 'height'];
+  var XY = ['x', 'y'];
+
+  var ScrollableLegendView =
+  /** @class */
+  function (_super) {
+    __extends(ScrollableLegendView, _super);
+
+    function ScrollableLegendView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = ScrollableLegendView.type;
+      _this.newlineDisabled = true;
+      _this._currentIndex = 0;
+      return _this;
+    }
+
+    ScrollableLegendView.prototype.init = function () {
+      _super.prototype.init.call(this);
+
+      this.group.add(this._containerGroup = new Group$3());
+
+      this._containerGroup.add(this.getContentGroup());
+
+      this.group.add(this._controllerGroup = new Group$3());
+    };
+    /**
+     * @override
+     */
+
+
+    ScrollableLegendView.prototype.resetInner = function () {
+      _super.prototype.resetInner.call(this);
+
+      this._controllerGroup.removeAll();
+
+      this._containerGroup.removeClipPath();
+
+      this._containerGroup.__rectSize = null;
+    };
+    /**
+     * @override
+     */
+
+
+    ScrollableLegendView.prototype.renderInner = function (itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition) {
+      var self = this; // Render content items.
+
+      _super.prototype.renderInner.call(this, itemAlign, legendModel, ecModel, api, selector, orient, selectorPosition);
+
+      var controllerGroup = this._controllerGroup; // FIXME: support be 'auto' adapt to size number text length,
+      // e.g., '3/12345' should not overlap with the control arrow button.
+
+      var pageIconSize = legendModel.get('pageIconSize', true);
+      var pageIconSizeArr = isArray(pageIconSize) ? pageIconSize : [pageIconSize, pageIconSize];
+      createPageButton('pagePrev', 0);
+      var pageTextStyleModel = legendModel.getModel('pageTextStyle');
+      controllerGroup.add(new ZRText({
+        name: 'pageText',
+        style: {
+          // Placeholder to calculate a proper layout.
+          text: 'xx/xx',
+          fill: pageTextStyleModel.getTextColor(),
+          font: pageTextStyleModel.getFont(),
+          verticalAlign: 'middle',
+          align: 'center'
+        },
+        silent: true
+      }));
+      createPageButton('pageNext', 1);
+
+      function createPageButton(name, iconIdx) {
+        var pageDataIndexName = name + 'DataIndex';
+        var icon = createIcon(legendModel.get('pageIcons', true)[legendModel.getOrient().name][iconIdx], {
+          // Buttons will be created in each render, so we do not need
+          // to worry about avoiding using legendModel kept in scope.
+          onclick: bind(self._pageGo, self, pageDataIndexName, legendModel, api)
+        }, {
+          x: -pageIconSizeArr[0] / 2,
+          y: -pageIconSizeArr[1] / 2,
+          width: pageIconSizeArr[0],
+          height: pageIconSizeArr[1]
+        });
+        icon.name = name;
+        controllerGroup.add(icon);
+      }
+    };
+    /**
+     * @override
+     */
+
+
+    ScrollableLegendView.prototype.layoutInner = function (legendModel, itemAlign, maxSize, isFirstRender, selector, selectorPosition) {
+      var selectorGroup = this.getSelectorGroup();
+      var orientIdx = legendModel.getOrient().index;
+      var wh = WH[orientIdx];
+      var xy = XY[orientIdx];
+      var hw = WH[1 - orientIdx];
+      var yx = XY[1 - orientIdx];
+      selector && box( // Buttons in selectorGroup always layout horizontally
+      'horizontal', selectorGroup, legendModel.get('selectorItemGap', true));
+      var selectorButtonGap = legendModel.get('selectorButtonGap', true);
+      var selectorRect = selectorGroup.getBoundingRect();
+      var selectorPos = [-selectorRect.x, -selectorRect.y];
+      var processMaxSize = clone(maxSize);
+      selector && (processMaxSize[wh] = maxSize[wh] - selectorRect[wh] - selectorButtonGap);
+
+      var mainRect = this._layoutContentAndController(legendModel, isFirstRender, processMaxSize, orientIdx, wh, hw, yx, xy);
+
+      if (selector) {
+        if (selectorPosition === 'end') {
+          selectorPos[orientIdx] += mainRect[wh] + selectorButtonGap;
+        } else {
+          var offset = selectorRect[wh] + selectorButtonGap;
+          selectorPos[orientIdx] -= offset;
+          mainRect[xy] -= offset;
+        }
+
+        mainRect[wh] += selectorRect[wh] + selectorButtonGap;
+        selectorPos[1 - orientIdx] += mainRect[yx] + mainRect[hw] / 2 - selectorRect[hw] / 2;
+        mainRect[hw] = Math.max(mainRect[hw], selectorRect[hw]);
+        mainRect[yx] = Math.min(mainRect[yx], selectorRect[yx] + selectorPos[1 - orientIdx]);
+        selectorGroup.x = selectorPos[0];
+        selectorGroup.y = selectorPos[1];
+        selectorGroup.markRedraw();
+      }
+
+      return mainRect;
+    };
+
+    ScrollableLegendView.prototype._layoutContentAndController = function (legendModel, isFirstRender, maxSize, orientIdx, wh, hw, yx, xy) {
+      var contentGroup = this.getContentGroup();
+      var containerGroup = this._containerGroup;
+      var controllerGroup = this._controllerGroup; // Place items in contentGroup.
+
+      box(legendModel.get('orient'), contentGroup, legendModel.get('itemGap'), !orientIdx ? null : maxSize.width, orientIdx ? null : maxSize.height);
+      box( // Buttons in controller are layout always horizontally.
+      'horizontal', controllerGroup, legendModel.get('pageButtonItemGap', true));
+      var contentRect = contentGroup.getBoundingRect();
+      var controllerRect = controllerGroup.getBoundingRect();
+      var showController = this._showController = contentRect[wh] > maxSize[wh]; // In case that the inner elements of contentGroup layout do not based on [0, 0]
+
+      var contentPos = [-contentRect.x, -contentRect.y]; // Remain contentPos when scroll animation perfroming.
+      // If first rendering, `contentGroup.position` is [0, 0], which
+      // does not make sense and may cause unexepcted animation if adopted.
+
+      if (!isFirstRender) {
+        contentPos[orientIdx] = contentGroup[xy];
+      } // Layout container group based on 0.
+
+
+      var containerPos = [0, 0];
+      var controllerPos = [-controllerRect.x, -controllerRect.y];
+      var pageButtonGap = retrieve2(legendModel.get('pageButtonGap', true), legendModel.get('itemGap', true)); // Place containerGroup and controllerGroup and contentGroup.
+
+      if (showController) {
+        var pageButtonPosition = legendModel.get('pageButtonPosition', true); // controller is on the right / bottom.
+
+        if (pageButtonPosition === 'end') {
+          controllerPos[orientIdx] += maxSize[wh] - controllerRect[wh];
+        } // controller is on the left / top.
+        else {
+            containerPos[orientIdx] += controllerRect[wh] + pageButtonGap;
+          }
+      } // Always align controller to content as 'middle'.
+
+
+      controllerPos[1 - orientIdx] += contentRect[hw] / 2 - controllerRect[hw] / 2;
+      contentGroup.setPosition(contentPos);
+      containerGroup.setPosition(containerPos);
+      controllerGroup.setPosition(controllerPos); // Calculate `mainRect` and set `clipPath`.
+      // mainRect should not be calculated by `this.group.getBoundingRect()`
+      // for sake of the overflow.
+
+      var mainRect = {
+        x: 0,
+        y: 0
+      }; // Consider content may be overflow (should be clipped).
+
+      mainRect[wh] = showController ? maxSize[wh] : contentRect[wh];
+      mainRect[hw] = Math.max(contentRect[hw], controllerRect[hw]); // `containerRect[yx] + containerPos[1 - orientIdx]` is 0.
+
+      mainRect[yx] = Math.min(0, controllerRect[yx] + controllerPos[1 - orientIdx]);
+      containerGroup.__rectSize = maxSize[wh];
+
+      if (showController) {
+        var clipShape = {
+          x: 0,
+          y: 0
+        };
+        clipShape[wh] = Math.max(maxSize[wh] - controllerRect[wh] - pageButtonGap, 0);
+        clipShape[hw] = mainRect[hw];
+        containerGroup.setClipPath(new Rect({
+          shape: clipShape
+        })); // Consider content may be larger than container, container rect
+        // can not be obtained from `containerGroup.getBoundingRect()`.
+
+        containerGroup.__rectSize = clipShape[wh];
+      } else {
+        // Do not remove or ignore controller. Keep them set as placeholders.
+        controllerGroup.eachChild(function (child) {
+          child.attr({
+            invisible: true,
+            silent: true
+          });
+        });
+      } // Content translate animation.
+
+
+      var pageInfo = this._getPageInfo(legendModel);
+
+      pageInfo.pageIndex != null && updateProps(contentGroup, {
+        x: pageInfo.contentPosition[0],
+        y: pageInfo.contentPosition[1]
+      }, // When switch from "show controller" to "not show controller", view should be
+      // updated immediately without animation, otherwise causes weird effect.
+      showController ? legendModel : null);
+
+      this._updatePageInfoView(legendModel, pageInfo);
+
+      return mainRect;
+    };
+
+    ScrollableLegendView.prototype._pageGo = function (to, legendModel, api) {
+      var scrollDataIndex = this._getPageInfo(legendModel)[to];
+
+      scrollDataIndex != null && api.dispatchAction({
+        type: 'legendScroll',
+        scrollDataIndex: scrollDataIndex,
+        legendId: legendModel.id
+      });
+    };
+
+    ScrollableLegendView.prototype._updatePageInfoView = function (legendModel, pageInfo) {
+      var controllerGroup = this._controllerGroup;
+      each(['pagePrev', 'pageNext'], function (name) {
+        var key = name + 'DataIndex';
+        var canJump = pageInfo[key] != null;
+        var icon = controllerGroup.childOfName(name);
+
+        if (icon) {
+          icon.setStyle('fill', canJump ? legendModel.get('pageIconColor', true) : legendModel.get('pageIconInactiveColor', true));
+          icon.cursor = canJump ? 'pointer' : 'default';
+        }
+      });
+      var pageText = controllerGroup.childOfName('pageText');
+      var pageFormatter = legendModel.get('pageFormatter');
+      var pageIndex = pageInfo.pageIndex;
+      var current = pageIndex != null ? pageIndex + 1 : 0;
+      var total = pageInfo.pageCount;
+      pageText && pageFormatter && pageText.setStyle('text', isString(pageFormatter) ? pageFormatter.replace('{current}', current == null ? '' : current + '').replace('{total}', total == null ? '' : total + '') : pageFormatter({
+        current: current,
+        total: total
+      }));
+    };
+    /**
+     *  contentPosition: Array.<number>, null when data item not found.
+     *  pageIndex: number, null when data item not found.
+     *  pageCount: number, always be a number, can be 0.
+     *  pagePrevDataIndex: number, null when no previous page.
+     *  pageNextDataIndex: number, null when no next page.
+     * }
+     */
+
+
+    ScrollableLegendView.prototype._getPageInfo = function (legendModel) {
+      var scrollDataIndex = legendModel.get('scrollDataIndex', true);
+      var contentGroup = this.getContentGroup();
+      var containerRectSize = this._containerGroup.__rectSize;
+      var orientIdx = legendModel.getOrient().index;
+      var wh = WH[orientIdx];
+      var xy = XY[orientIdx];
+
+      var targetItemIndex = this._findTargetItemIndex(scrollDataIndex);
+
+      var children = contentGroup.children();
+      var targetItem = children[targetItemIndex];
+      var itemCount = children.length;
+      var pCount = !itemCount ? 0 : 1;
+      var result = {
+        contentPosition: [contentGroup.x, contentGroup.y],
+        pageCount: pCount,
+        pageIndex: pCount - 1,
+        pagePrevDataIndex: null,
+        pageNextDataIndex: null
+      };
+
+      if (!targetItem) {
+        return result;
+      }
+
+      var targetItemInfo = getItemInfo(targetItem);
+      result.contentPosition[orientIdx] = -targetItemInfo.s; // Strategy:
+      // (1) Always align based on the left/top most item.
+      // (2) It is user-friendly that the last item shown in the
+      // current window is shown at the begining of next window.
+      // Otherwise if half of the last item is cut by the window,
+      // it will have no chance to display entirely.
+      // (3) Consider that item size probably be different, we
+      // have calculate pageIndex by size rather than item index,
+      // and we can not get page index directly by division.
+      // (4) The window is to narrow to contain more than
+      // one item, we should make sure that the page can be fliped.
+
+      for (var i = targetItemIndex + 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i <= itemCount; ++i) {
+        currItemInfo = getItemInfo(children[i]);
+
+        if ( // Half of the last item is out of the window.
+        !currItemInfo && winEndItemInfo.e > winStartItemInfo.s + containerRectSize || // If the current item does not intersect with the window, the new page
+        // can be started at the current item or the last item.
+        currItemInfo && !intersect(currItemInfo, winStartItemInfo.s)) {
+          if (winEndItemInfo.i > winStartItemInfo.i) {
+            winStartItemInfo = winEndItemInfo;
+          } else {
+            // e.g., when page size is smaller than item size.
+            winStartItemInfo = currItemInfo;
+          }
+
+          if (winStartItemInfo) {
+            if (result.pageNextDataIndex == null) {
+              result.pageNextDataIndex = winStartItemInfo.i;
+            }
+
+            ++result.pageCount;
+          }
+        }
+
+        winEndItemInfo = currItemInfo;
+      }
+
+      for (var i = targetItemIndex - 1, winStartItemInfo = targetItemInfo, winEndItemInfo = targetItemInfo, currItemInfo = null; i >= -1; --i) {
+        currItemInfo = getItemInfo(children[i]);
+
+        if ( // If the the end item does not intersect with the window started
+        // from the current item, a page can be settled.
+        (!currItemInfo || !intersect(winEndItemInfo, currItemInfo.s)) && // e.g., when page size is smaller than item size.
+        winStartItemInfo.i < winEndItemInfo.i) {
+          winEndItemInfo = winStartItemInfo;
+
+          if (result.pagePrevDataIndex == null) {
+            result.pagePrevDataIndex = winStartItemInfo.i;
+          }
+
+          ++result.pageCount;
+          ++result.pageIndex;
+        }
+
+        winStartItemInfo = currItemInfo;
+      }
+
+      return result;
+
+      function getItemInfo(el) {
+        if (el) {
+          var itemRect = el.getBoundingRect();
+          var start = itemRect[xy] + el[xy];
+          return {
+            s: start,
+            e: start + itemRect[wh],
+            i: el.__legendDataIndex
+          };
+        }
+      }
+
+      function intersect(itemInfo, winStart) {
+        return itemInfo.e >= winStart && itemInfo.s <= winStart + containerRectSize;
+      }
+    };
+
+    ScrollableLegendView.prototype._findTargetItemIndex = function (targetDataIndex) {
+      if (!this._showController) {
+        return 0;
+      }
+
+      var index;
+      var contentGroup = this.getContentGroup();
+      var defaultIndex;
+      contentGroup.eachChild(function (child, idx) {
+        var legendDataIdx = child.__legendDataIndex; // FIXME
+        // If the given targetDataIndex (from model) is illegal,
+        // we use defaultIndex. But the index on the legend model and
+        // action payload is still illegal. That case will not be
+        // changed until some scenario requires.
+
+        if (defaultIndex == null && legendDataIdx != null) {
+          defaultIndex = idx;
+        }
+
+        if (legendDataIdx === targetDataIndex) {
+          index = idx;
+        }
+      });
+      return index != null ? index : defaultIndex;
+    };
+
+    ScrollableLegendView.type = 'legend.scroll';
+    return ScrollableLegendView;
+  }(LegendView);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 installScrollableLegendAction(registers) {
+    /**
+     * @event legendScroll
+     * @type {Object}
+     * @property {string} type 'legendScroll'
+     * @property {string} scrollDataIndex
+     */
+    registers.registerAction('legendScroll', 'legendscroll', function (payload, ecModel) {
+      var scrollDataIndex = payload.scrollDataIndex;
+      scrollDataIndex != null && ecModel.eachComponent({
+        mainType: 'legend',
+        subType: 'scroll',
+        query: payload
+      }, function (legendModel) {
+        legendModel.setScrollDataIndex(scrollDataIndex);
+      });
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install$7(registers) {
+    use(install$8);
+    registers.registerComponentModel(ScrollableLegendModel);
+    registers.registerComponentView(ScrollableLegendView);
+    installScrollableLegendAction(registers);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * Legend component entry file8
+   */
+
+
+  use(install$7);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$7 = makeInner();
+  var clone$3 = clone;
+  var bind$1 = bind;
+  /**
+   * Base axis pointer class in 2D.
+   */
+
+  var BaseAxisPointer =
+  /** @class */
+  function () {
+    function BaseAxisPointer() {
+      this._dragging = false;
+      /**
+       * In px, arbitrary value. Do not set too small,
+       * no animation is ok for most cases.
+       */
+
+      this.animationThreshold = 15;
+    }
+    /**
+     * @implement
+     */
+
+
+    BaseAxisPointer.prototype.render = function (axisModel, axisPointerModel, api, forceRender) {
+      var value = axisPointerModel.get('value');
+      var status = axisPointerModel.get('status'); // Bind them to `this`, not in closure, otherwise they will not
+      // be replaced when user calling setOption in not merge mode.
+
+      this._axisModel = axisModel;
+      this._axisPointerModel = axisPointerModel;
+      this._api = api; // Optimize: `render` will be called repeatly during mouse move.
+      // So it is power consuming if performing `render` each time,
+      // especially on mobile device.
+
+      if (!forceRender && this._lastValue === value && this._lastStatus === status) {
+        return;
+      }
+
+      this._lastValue = value;
+      this._lastStatus = status;
+      var group = this._group;
+      var handle = this._handle;
+
+      if (!status || status === 'hide') {
+        // Do not clear here, for animation better.
+        group && group.hide();
+        handle && handle.hide();
+        return;
+      }
+
+      group && group.show();
+      handle && handle.show(); // Otherwise status is 'show'
+
+      var elOption = {};
+      this.makeElOption(elOption, value, axisModel, axisPointerModel, api); // Enable change axis pointer type.
+
+      var graphicKey = elOption.graphicKey;
+
+      if (graphicKey !== this._lastGraphicKey) {
+        this.clear(api);
+      }
+
+      this._lastGraphicKey = graphicKey;
+      var moveAnimation = this._moveAnimation = this.determineAnimation(axisModel, axisPointerModel);
+
+      if (!group) {
+        group = this._group = new Group();
+        this.createPointerEl(group, elOption, axisModel, axisPointerModel);
+        this.createLabelEl(group, elOption, axisModel, axisPointerModel);
+        api.getZr().add(group);
+      } else {
+        var doUpdateProps = curry(updateProps$1, axisPointerModel, moveAnimation);
+        this.updatePointerEl(group, elOption, doUpdateProps);
+        this.updateLabelEl(group, elOption, doUpdateProps, axisPointerModel);
+      }
+
+      updateMandatoryProps(group, axisPointerModel, true);
+
+      this._renderHandle(value);
+    };
+    /**
+     * @implement
+     */
+
+
+    BaseAxisPointer.prototype.remove = function (api) {
+      this.clear(api);
+    };
+    /**
+     * @implement
+     */
+
+
+    BaseAxisPointer.prototype.dispose = function (api) {
+      this.clear(api);
+    };
+    /**
+     * @protected
+     */
+
+
+    BaseAxisPointer.prototype.determineAnimation = function (axisModel, axisPointerModel) {
+      var animation = axisPointerModel.get('animation');
+      var axis = axisModel.axis;
+      var isCategoryAxis = axis.type === 'category';
+      var useSnap = axisPointerModel.get('snap'); // Value axis without snap always do not snap.
+
+      if (!useSnap && !isCategoryAxis) {
+        return false;
+      }
+
+      if (animation === 'auto' || animation == null) {
+        var animationThreshold = this.animationThreshold;
+
+        if (isCategoryAxis && axis.getBandWidth() > animationThreshold) {
+          return true;
+        } // It is important to auto animation when snap used. Consider if there is
+        // a dataZoom, animation will be disabled when too many points exist, while
+        // it will be enabled for better visual effect when little points exist.
+
+
+        if (useSnap) {
+          var seriesDataCount = getAxisInfo(axisModel).seriesDataCount;
+          var axisExtent = axis.getExtent(); // Approximate band width
+
+          return Math.abs(axisExtent[0] - axisExtent[1]) / seriesDataCount > animationThreshold;
+        }
+
+        return false;
+      }
+
+      return animation === true;
+    };
+    /**
+     * add {pointer, label, graphicKey} to elOption
+     * @protected
+     */
+
+
+    BaseAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) {// Shoule be implemenented by sub-class.
+    };
+    /**
+     * @protected
+     */
+
+
+    BaseAxisPointer.prototype.createPointerEl = function (group, elOption, axisModel, axisPointerModel) {
+      var pointerOption = elOption.pointer;
+
+      if (pointerOption) {
+        var pointerEl = inner$7(group).pointerEl = new graphic[pointerOption.type](clone$3(elOption.pointer));
+        group.add(pointerEl);
+      }
+    };
+    /**
+     * @protected
+     */
+
+
+    BaseAxisPointer.prototype.createLabelEl = function (group, elOption, axisModel, axisPointerModel) {
+      if (elOption.label) {
+        var labelEl = inner$7(group).labelEl = new ZRText(clone$3(elOption.label));
+        group.add(labelEl);
+        updateLabelShowHide(labelEl, axisPointerModel);
+      }
+    };
+    /**
+     * @protected
+     */
+
+
+    BaseAxisPointer.prototype.updatePointerEl = function (group, elOption, updateProps$$1) {
+      var pointerEl = inner$7(group).pointerEl;
+
+      if (pointerEl && elOption.pointer) {
+        pointerEl.setStyle(elOption.pointer.style);
+        updateProps$$1(pointerEl, {
+          shape: elOption.pointer.shape
+        });
+      }
+    };
+    /**
+     * @protected
+     */
+
+
+    BaseAxisPointer.prototype.updateLabelEl = function (group, elOption, updateProps$$1, axisPointerModel) {
+      var labelEl = inner$7(group).labelEl;
+
+      if (labelEl) {
+        labelEl.setStyle(elOption.label.style);
+        updateProps$$1(labelEl, {
+          // Consider text length change in vertical axis, animation should
+          // be used on shape, otherwise the effect will be weird.
+          // TODOTODO
+          // shape: elOption.label.shape,
+          x: elOption.label.x,
+          y: elOption.label.y
+        });
+        updateLabelShowHide(labelEl, axisPointerModel);
+      }
+    };
+    /**
+     * @private
+     */
+
+
+    BaseAxisPointer.prototype._renderHandle = function (value) {
+      if (this._dragging || !this.updateHandleTransform) {
+        return;
+      }
+
+      var axisPointerModel = this._axisPointerModel;
+
+      var zr = this._api.getZr();
+
+      var handle = this._handle;
+      var handleModel = axisPointerModel.getModel('handle');
+      var status = axisPointerModel.get('status');
+
+      if (!handleModel.get('show') || !status || status === 'hide') {
+        handle && zr.remove(handle);
+        this._handle = null;
+        return;
+      }
+
+      var isInit;
+
+      if (!this._handle) {
+        isInit = true;
+        handle = this._handle = createIcon(handleModel.get('icon'), {
+          cursor: 'move',
+          draggable: true,
+          onmousemove: function (e) {
+            // Fot mobile devicem, prevent screen slider on the button.
+            stop(e.event);
+          },
+          onmousedown: bind$1(this._onHandleDragMove, this, 0, 0),
+          drift: bind$1(this._onHandleDragMove, this),
+          ondragend: bind$1(this._onHandleDragEnd, this)
+        });
+        zr.add(handle);
+      }
+
+      updateMandatoryProps(handle, axisPointerModel, false); // update style
+
+      handle.setStyle(handleModel.getItemStyle(null, ['color', 'borderColor', 'borderWidth', 'opacity', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'])); // update position
+
+      var handleSize = handleModel.get('size');
+
+      if (!isArray(handleSize)) {
+        handleSize = [handleSize, handleSize];
+      }
+
+      handle.scaleX = handleSize[0] / 2;
+      handle.scaleY = handleSize[1] / 2;
+      createOrUpdate(this, '_doDispatchAxisPointer', handleModel.get('throttle') || 0, 'fixRate');
+
+      this._moveHandleToValue(value, isInit);
+    };
+
+    BaseAxisPointer.prototype._moveHandleToValue = function (value, isInit) {
+      updateProps$1(this._axisPointerModel, !isInit && this._moveAnimation, this._handle, getHandleTransProps(this.getHandleTransform(value, this._axisModel, this._axisPointerModel)));
+    };
+
+    BaseAxisPointer.prototype._onHandleDragMove = function (dx, dy) {
+      var handle = this._handle;
+
+      if (!handle) {
+        return;
+      }
+
+      this._dragging = true; // Persistent for throttle.
+
+      var trans = this.updateHandleTransform(getHandleTransProps(handle), [dx, dy], this._axisModel, this._axisPointerModel);
+      this._payloadInfo = trans;
+      handle.stopAnimation();
+      handle.attr(getHandleTransProps(trans));
+      inner$7(handle).lastProp = null;
+
+      this._doDispatchAxisPointer();
+    };
+    /**
+     * Throttled method.
+     */
+
+
+    BaseAxisPointer.prototype._doDispatchAxisPointer = function () {
+      var handle = this._handle;
+
+      if (!handle) {
+        return;
+      }
+
+      var payloadInfo = this._payloadInfo;
+      var axisModel = this._axisModel;
+
+      this._api.dispatchAction({
+        type: 'updateAxisPointer',
+        x: payloadInfo.cursorPoint[0],
+        y: payloadInfo.cursorPoint[1],
+        tooltipOption: payloadInfo.tooltipOption,
+        axesInfo: [{
+          axisDim: axisModel.axis.dim,
+          axisIndex: axisModel.componentIndex
+        }]
+      });
+    };
+
+    BaseAxisPointer.prototype._onHandleDragEnd = function () {
+      this._dragging = false;
+      var handle = this._handle;
+
+      if (!handle) {
+        return;
+      }
+
+      var value = this._axisPointerModel.get('value'); // Consider snap or categroy axis, handle may be not consistent with
+      // axisPointer. So move handle to align the exact value position when
+      // drag ended.
+
+
+      this._moveHandleToValue(value); // For the effect: tooltip will be shown when finger holding on handle
+      // button, and will be hidden after finger left handle button.
+
+
+      this._api.dispatchAction({
+        type: 'hideTip'
+      });
+    };
+    /**
+     * @private
+     */
+
+
+    BaseAxisPointer.prototype.clear = function (api) {
+      this._lastValue = null;
+      this._lastStatus = null;
+      var zr = api.getZr();
+      var group = this._group;
+      var handle = this._handle;
+
+      if (zr && group) {
+        this._lastGraphicKey = null;
+        group && zr.remove(group);
+        handle && zr.remove(handle);
+        this._group = null;
+        this._handle = null;
+        this._payloadInfo = null;
+      }
+
+      clear(this, '_doDispatchAxisPointer');
+    };
+    /**
+     * @protected
+     */
+
+
+    BaseAxisPointer.prototype.doClear = function () {// Implemented by sub-class if necessary.
+    };
+
+    BaseAxisPointer.prototype.buildLabel = function (xy, wh, xDimIndex) {
+      xDimIndex = xDimIndex || 0;
+      return {
+        x: xy[xDimIndex],
+        y: xy[1 - xDimIndex],
+        width: wh[xDimIndex],
+        height: wh[1 - xDimIndex]
+      };
+    };
+
+    return BaseAxisPointer;
+  }();
+
+  function updateProps$1(animationModel, moveAnimation, el, props) {
+    // Animation optimize.
+    if (!propsEqual(inner$7(el).lastProp, props)) {
+      inner$7(el).lastProp = props;
+      moveAnimation ? updateProps(el, props, animationModel) : (el.stopAnimation(), el.attr(props));
+    }
+  }
+
+  function propsEqual(lastProps, newProps) {
+    if (isObject(lastProps) && isObject(newProps)) {
+      var equals_1 = true;
+      each(newProps, function (item, key) {
+        equals_1 = equals_1 && propsEqual(lastProps[key], item);
+      });
+      return !!equals_1;
+    } else {
+      return lastProps === newProps;
+    }
+  }
+
+  function updateLabelShowHide(labelEl, axisPointerModel) {
+    labelEl[axisPointerModel.get(['label', 'show']) ? 'show' : 'hide']();
+  }
+
+  function getHandleTransProps(trans) {
+    return {
+      x: trans.x || 0,
+      y: trans.y || 0,
+      rotation: trans.rotation || 0
+    };
+  }
+
+  function updateMandatoryProps(group, axisPointerModel, silent) {
+    var z = axisPointerModel.get('z');
+    var zlevel = axisPointerModel.get('zlevel');
+    group && group.traverse(function (el) {
+      if (el.type !== 'group') {
+        z != null && (el.z = z);
+        zlevel != null && (el.zlevel = zlevel);
+        el.silent = silent;
+      }
+    });
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 buildElStyle(axisPointerModel) {
+    var axisPointerType = axisPointerModel.get('type');
+    var styleModel = axisPointerModel.getModel(axisPointerType + 'Style');
+    var style;
+
+    if (axisPointerType === 'line') {
+      style = styleModel.getLineStyle();
+      style.fill = null;
+    } else if (axisPointerType === 'shadow') {
+      style = styleModel.getAreaStyle();
+      style.stroke = null;
+    }
+
+    return style;
+  }
+  /**
+   * @param {Function} labelPos {align, verticalAlign, position}
+   */
+
+
+  function buildLabelElOption(elOption, axisModel, axisPointerModel, api, labelPos) {
+    var value = axisPointerModel.get('value');
+    var text = getValueLabel(value, axisModel.axis, axisModel.ecModel, axisPointerModel.get('seriesDataIndices'), {
+      precision: axisPointerModel.get(['label', 'precision']),
+      formatter: axisPointerModel.get(['label', 'formatter'])
+    });
+    var labelModel = axisPointerModel.getModel('label');
+    var paddings = normalizeCssArray$1(labelModel.get('padding') || 0);
+    var font = labelModel.getFont();
+    var textRect = getBoundingRect(text, font);
+    var position = labelPos.position;
+    var width = textRect.width + paddings[1] + paddings[3];
+    var height = textRect.height + paddings[0] + paddings[2]; // Adjust by align.
+
+    var align = labelPos.align;
+    align === 'right' && (position[0] -= width);
+    align === 'center' && (position[0] -= width / 2);
+    var verticalAlign = labelPos.verticalAlign;
+    verticalAlign === 'bottom' && (position[1] -= height);
+    verticalAlign === 'middle' && (position[1] -= height / 2); // Not overflow ec container
+
+    confineInContainer(position, width, height, api);
+    var bgColor = labelModel.get('backgroundColor');
+
+    if (!bgColor || bgColor === 'auto') {
+      bgColor = axisModel.get(['axisLine', 'lineStyle', 'color']);
+    }
+
+    elOption.label = {
+      // shape: {x: 0, y: 0, width: width, height: height, r: labelModel.get('borderRadius')},
+      x: position[0],
+      y: position[1],
+      style: createTextStyle(labelModel, {
+        text: text,
+        font: font,
+        fill: labelModel.getTextColor(),
+        padding: paddings,
+        backgroundColor: bgColor
+      }),
+      // Lable should be over axisPointer.
+      z2: 10
+    };
+  } // Do not overflow ec container
+
+
+  function confineInContainer(position, width, height, api) {
+    var viewWidth = api.getWidth();
+    var viewHeight = api.getHeight();
+    position[0] = Math.min(position[0] + width, viewWidth) - width;
+    position[1] = Math.min(position[1] + height, viewHeight) - height;
+    position[0] = Math.max(position[0], 0);
+    position[1] = Math.max(position[1], 0);
+  }
+
+  function getValueLabel(value, axis, ecModel, seriesDataIndices, opt) {
+    value = axis.scale.parse(value);
+    var text = axis.scale.getLabel({
+      value: value
+    }, {
+      // If `precision` is set, width can be fixed (like '12.00500'), which
+      // helps to debounce when when moving label.
+      precision: opt.precision
+    });
+    var formatter = opt.formatter;
+
+    if (formatter) {
+      var params_1 = {
+        value: getAxisRawValue(axis, {
+          value: value
+        }),
+        axisDimension: axis.dim,
+        axisIndex: axis.index,
+        seriesData: []
+      };
+      each(seriesDataIndices, function (idxItem) {
+        var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);
+        var dataIndex = idxItem.dataIndexInside;
+        var dataParams = series && series.getDataParams(dataIndex);
+        dataParams && params_1.seriesData.push(dataParams);
+      });
+
+      if (isString(formatter)) {
+        text = formatter.replace('{value}', text);
+      } else if (isFunction(formatter)) {
+        text = formatter(params_1);
+      }
+    }
+
+    return text;
+  }
+
+  function getTransformedPosition(axis, value, layoutInfo) {
+    var transform = create$1();
+    rotate(transform, transform, layoutInfo.rotation);
+    translate(transform, transform, layoutInfo.position);
+    return applyTransform$1([axis.dataToCoord(value), (layoutInfo.labelOffset || 0) + (layoutInfo.labelDirection || 1) * (layoutInfo.labelMargin || 0)], transform);
+  }
+
+  function buildCartesianSingleLabelElOption(value, elOption, layoutInfo, axisModel, axisPointerModel, api) {
+    // @ts-ignore
+    var textLayout = AxisBuilder.innerTextLayout(layoutInfo.rotation, 0, layoutInfo.labelDirection);
+    layoutInfo.labelMargin = axisPointerModel.get(['label', 'margin']);
+    buildLabelElOption(elOption, axisModel, axisPointerModel, api, {
+      position: getTransformedPosition(axisModel.axis, value, layoutInfo),
+      align: textLayout.textAlign,
+      verticalAlign: textLayout.textVerticalAlign
+    });
+  }
+
+  function makeLineShape(p1, p2, xDimIndex) {
+    xDimIndex = xDimIndex || 0;
+    return {
+      x1: p1[xDimIndex],
+      y1: p1[1 - xDimIndex],
+      x2: p2[xDimIndex],
+      y2: p2[1 - xDimIndex]
+    };
+  }
+
+  function makeRectShape(xy, wh, xDimIndex) {
+    xDimIndex = xDimIndex || 0;
+    return {
+      x: xy[xDimIndex],
+      y: xy[1 - xDimIndex],
+      width: wh[xDimIndex],
+      height: wh[1 - xDimIndex]
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 CartesianAxisPointer =
+  /** @class */
+  function (_super) {
+    __extends(CartesianAxisPointer, _super);
+
+    function CartesianAxisPointer() {
+      return _super !== null && _super.apply(this, arguments) || this;
+    }
+    /**
+     * @override
+     */
+
+
+    CartesianAxisPointer.prototype.makeElOption = function (elOption, value, axisModel, axisPointerModel, api) {
+      var axis = axisModel.axis;
+      var grid = axis.grid;
+      var axisPointerType = axisPointerModel.get('type');
+      var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();
+      var pixelValue = axis.toGlobalCoord(axis.dataToCoord(value, true));
+
+      if (axisPointerType && axisPointerType !== 'none') {
+        var elStyle = buildElStyle(axisPointerModel);
+        var pointerOption = pointerShapeBuilder[axisPointerType](axis, pixelValue, otherExtent);
+        pointerOption.style = elStyle;
+        elOption.graphicKey = pointerOption.type;
+        elOption.pointer = pointerOption;
+      }
+
+      var layoutInfo = layout$1(grid.model, axisModel);
+      buildCartesianSingleLabelElOption( // @ts-ignore
+      value, elOption, layoutInfo, axisModel, axisPointerModel, api);
+    };
+    /**
+     * @override
+     */
+
+
+    CartesianAxisPointer.prototype.getHandleTransform = function (value, axisModel, axisPointerModel) {
+      var layoutInfo = layout$1(axisModel.axis.grid.model, axisModel, {
+        labelInside: false
+      }); // @ts-ignore
+
+      layoutInfo.labelMargin = axisPointerModel.get(['handle', 'margin']);
+      var pos = getTransformedPosition(axisModel.axis, value, layoutInfo);
+      return {
+        x: pos[0],
+        y: pos[1],
+        rotation: layoutInfo.rotation + (layoutInfo.labelDirection < 0 ? Math.PI : 0)
+      };
+    };
+    /**
+     * @override
+     */
+
+
+    CartesianAxisPointer.prototype.updateHandleTransform = function (transform, delta, axisModel, axisPointerModel) {
+      var axis = axisModel.axis;
+      var grid = axis.grid;
+      var axisExtent = axis.getGlobalExtent(true);
+      var otherExtent = getCartesian(grid, axis).getOtherAxis(axis).getGlobalExtent();
+      var dimIndex = axis.dim === 'x' ? 0 : 1;
+      var currPosition = [transform.x, transform.y];
+      currPosition[dimIndex] += delta[dimIndex];
+      currPosition[dimIndex] = Math.min(axisExtent[1], currPosition[dimIndex]);
+      currPosition[dimIndex] = Math.max(axisExtent[0], currPosition[dimIndex]);
+      var cursorOtherValue = (otherExtent[1] + otherExtent[0]) / 2;
+      var cursorPoint = [cursorOtherValue, cursorOtherValue];
+      cursorPoint[dimIndex] = currPosition[dimIndex]; // Make tooltip do not overlap axisPointer and in the middle of the grid.
+
+      var tooltipOptions = [{
+        verticalAlign: 'middle'
+      }, {
+        align: 'center'
+      }];
+      return {
+        x: currPosition[0],
+        y: currPosition[1],
+        rotation: transform.rotation,
+        cursorPoint: cursorPoint,
+        tooltipOption: tooltipOptions[dimIndex]
+      };
+    };
+
+    return CartesianAxisPointer;
+  }(BaseAxisPointer);
+
+  function getCartesian(grid, axis) {
+    var opt = {};
+    opt[axis.dim + 'AxisIndex'] = axis.index;
+    return grid.getCartesian(opt);
+  }
+
+  var pointerShapeBuilder = {
+    line: function (axis, pixelValue, otherExtent) {
+      var targetShape = makeLineShape([pixelValue, otherExtent[0]], [pixelValue, otherExtent[1]], getAxisDimIndex(axis));
+      return {
+        type: 'Line',
+        subPixelOptimize: true,
+        shape: targetShape
+      };
+    },
+    shadow: function (axis, pixelValue, otherExtent) {
+      var bandWidth = Math.max(1, axis.getBandWidth());
+      var span = otherExtent[1] - otherExtent[0];
+      return {
+        type: 'Rect',
+        shape: makeRectShape([pixelValue - bandWidth / 2, otherExtent[0]], [bandWidth, span], getAxisDimIndex(axis))
+      };
+    }
+  };
+
+  function getAxisDimIndex(axis) {
+    return axis.dim === 'x' ? 0 : 1;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 AxisPointerModel =
+  /** @class */
+  function (_super) {
+    __extends(AxisPointerModel, _super);
+
+    function AxisPointerModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = AxisPointerModel.type;
+      return _this;
+    }
+
+    AxisPointerModel.type = 'axisPointer';
+    AxisPointerModel.defaultOption = {
+      // 'auto' means that show when triggered by tooltip or handle.
+      show: 'auto',
+      // zlevel: 0,
+      z: 50,
+      type: 'line',
+      // axispointer triggered by tootip determine snap automatically,
+      // see `modelHelper`.
+      snap: false,
+      triggerTooltip: true,
+      value: null,
+      status: null,
+      link: [],
+      // Do not set 'auto' here, otherwise global animation: false
+      // will not effect at this axispointer.
+      animation: null,
+      animationDurationUpdate: 200,
+      lineStyle: {
+        color: '#B9BEC9',
+        width: 1,
+        type: 'dashed'
+      },
+      shadowStyle: {
+        color: 'rgba(210,219,238,0.2)'
+      },
+      label: {
+        show: true,
+        formatter: null,
+        precision: 'auto',
+        margin: 3,
+        color: '#fff',
+        padding: [5, 7, 5, 7],
+        backgroundColor: 'auto',
+        borderColor: null,
+        borderWidth: 0,
+        borderRadius: 3
+      },
+      handle: {
+        show: false,
+        // eslint-disable-next-line
+        icon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4h1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7v-1.2h6.6z M13.3,22H6.7v-1.2h6.6z M13.3,19.6H6.7v-1.2h6.6z',
+        size: 45,
+        // handle margin is from symbol center to axis, which is stable when circular move.
+        margin: 50,
+        // color: '#1b8bbd'
+        // color: '#2f4554'
+        color: '#333',
+        shadowBlur: 3,
+        shadowColor: '#aaa',
+        shadowOffsetX: 0,
+        shadowOffsetY: 2,
+        // For mobile performance
+        throttle: 40
+      }
+    };
+    return AxisPointerModel;
+  }(ComponentModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$8 = makeInner();
+  var each$4 = each;
+  /**
+   * @param {string} key
+   * @param {module:echarts/ExtensionAPI} api
+   * @param {Function} handler
+   *      param: {string} currTrigger
+   *      param: {Array.<number>} point
+   */
+
+  function register(key, api, handler) {
+    if (env.node) {
+      return;
+    }
+
+    var zr = api.getZr();
+    inner$8(zr).records || (inner$8(zr).records = {});
+    initGlobalListeners(zr, api);
+    var record = inner$8(zr).records[key] || (inner$8(zr).records[key] = {});
+    record.handler = handler;
+  }
+
+  function initGlobalListeners(zr, api) {
+    if (inner$8(zr).initialized) {
+      return;
+    }
+
+    inner$8(zr).initialized = true;
+    useHandler('click', curry(doEnter, 'click'));
+    useHandler('mousemove', curry(doEnter, 'mousemove')); // useHandler('mouseout', onLeave);
+
+    useHandler('globalout', onLeave);
+
+    function useHandler(eventType, cb) {
+      zr.on(eventType, function (e) {
+        var dis = makeDispatchAction(api);
+        each$4(inner$8(zr).records, function (record) {
+          record && cb(record, e, dis.dispatchAction);
+        });
+        dispatchTooltipFinally(dis.pendings, api);
+      });
+    }
+  }
+
+  function dispatchTooltipFinally(pendings, api) {
+    var showLen = pendings.showTip.length;
+    var hideLen = pendings.hideTip.length;
+    var actuallyPayload;
+
+    if (showLen) {
+      actuallyPayload = pendings.showTip[showLen - 1];
+    } else if (hideLen) {
+      actuallyPayload = pendings.hideTip[hideLen - 1];
+    }
+
+    if (actuallyPayload) {
+      actuallyPayload.dispatchAction = null;
+      api.dispatchAction(actuallyPayload);
+    }
+  }
+
+  function onLeave(record, e, dispatchAction) {
+    record.handler('leave', null, dispatchAction);
+  }
+
+  function doEnter(currTrigger, record, e, dispatchAction) {
+    record.handler(currTrigger, e, dispatchAction);
+  }
+
+  function makeDispatchAction(api) {
+    var pendings = {
+      showTip: [],
+      hideTip: []
+    }; // FIXME
+    // better approach?
+    // 'showTip' and 'hideTip' can be triggered by axisPointer and tooltip,
+    // which may be conflict, (axisPointer call showTip but tooltip call hideTip);
+    // So we have to add "final stage" to merge those dispatched actions.
+
+    var dispatchAction = function (payload) {
+      var pendingList = pendings[payload.type];
+
+      if (pendingList) {
+        pendingList.push(payload);
+      } else {
+        payload.dispatchAction = dispatchAction;
+        api.dispatchAction(payload);
+      }
+    };
+
+    return {
+      dispatchAction: dispatchAction,
+      pendings: pendings
+    };
+  }
+
+  function unregister(key, api) {
+    if (env.node) {
+      return;
+    }
+
+    var zr = api.getZr();
+    var record = (inner$8(zr).records || {})[key];
+
+    if (record) {
+      inner$8(zr).records[key] = null;
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 AxisPointerView =
+  /** @class */
+  function (_super) {
+    __extends(AxisPointerView, _super);
+
+    function AxisPointerView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = AxisPointerView.type;
+      return _this;
+    }
+
+    AxisPointerView.prototype.render = function (globalAxisPointerModel, ecModel, api) {
+      var globalTooltipModel = ecModel.getComponent('tooltip');
+      var triggerOn = globalAxisPointerModel.get('triggerOn') || globalTooltipModel && globalTooltipModel.get('triggerOn') || 'mousemove|click'; // Register global listener in AxisPointerView to enable
+      // AxisPointerView to be independent to Tooltip.
+
+      register('axisPointer', api, function (currTrigger, e, dispatchAction) {
+        // If 'none', it is not controlled by mouse totally.
+        if (triggerOn !== 'none' && (currTrigger === 'leave' || triggerOn.indexOf(currTrigger) >= 0)) {
+          dispatchAction({
+            type: 'updateAxisPointer',
+            currTrigger: currTrigger,
+            x: e && e.offsetX,
+            y: e && e.offsetY
+          });
+        }
+      });
+    };
+
+    AxisPointerView.prototype.remove = function (ecModel, api) {
+      unregister('axisPointer', api);
+    };
+
+    AxisPointerView.prototype.dispose = function (ecModel, api) {
+      unregister('axisPointer', api);
+    };
+
+    AxisPointerView.type = 'axisPointer';
+    return AxisPointerView;
+  }(ComponentView);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /**
+   * @param finder contains {seriesIndex, dataIndex, dataIndexInside}
+   * @param ecModel
+   * @return  {point: [x, y], el: ...} point Will not be null.
+   */
+
+
+  function findPointFromSeries(finder, ecModel) {
+    var point = [];
+    var seriesIndex = finder.seriesIndex;
+    var seriesModel;
+
+    if (seriesIndex == null || !(seriesModel = ecModel.getSeriesByIndex(seriesIndex))) {
+      return {
+        point: []
+      };
+    }
+
+    var data = seriesModel.getData();
+    var dataIndex = queryDataIndex(data, finder);
+
+    if (dataIndex == null || dataIndex < 0 || isArray(dataIndex)) {
+      return {
+        point: []
+      };
+    }
+
+    var el = data.getItemGraphicEl(dataIndex);
+    var coordSys = seriesModel.coordinateSystem;
+
+    if (seriesModel.getTooltipPosition) {
+      point = seriesModel.getTooltipPosition(dataIndex) || [];
+    } else if (coordSys && coordSys.dataToPoint) {
+      if (finder.isStacked) {
+        var baseAxis = coordSys.getBaseAxis();
+        var valueAxis = coordSys.getOtherAxis(baseAxis);
+        var valueAxisDim = valueAxis.dim;
+        var baseAxisDim = baseAxis.dim;
+        var baseDataOffset = valueAxisDim === 'x' || valueAxisDim === 'radius' ? 1 : 0;
+        var baseDim = data.mapDimension(baseAxisDim);
+        var stackedData = [];
+        stackedData[baseDataOffset] = data.get(baseDim, dataIndex);
+        stackedData[1 - baseDataOffset] = data.get(data.getCalculationInfo('stackResultDimension'), dataIndex);
+        point = coordSys.dataToPoint(stackedData) || [];
+      } else {
+        point = coordSys.dataToPoint(data.getValues(map(coordSys.dimensions, function (dim) {
+          return data.mapDimension(dim);
+        }), dataIndex)) || [];
+      }
+    } else if (el) {
+      // Use graphic bounding rect
+      var rect = el.getBoundingRect().clone();
+      rect.applyTransform(el.transform);
+      point = [rect.x + rect.width / 2, rect.y + rect.height / 2];
+    }
+
+    return {
+      point: point,
+      el: el
+    };
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 inner$9 = makeInner();
+  /**
+   * Basic logic: check all axis, if they do not demand show/highlight,
+   * then hide/downplay them.
+   *
+   * @return content of event obj for echarts.connect.
+   */
+
+  function axisTrigger(payload, ecModel, api) {
+    var currTrigger = payload.currTrigger;
+    var point = [payload.x, payload.y];
+    var finder = payload;
+    var dispatchAction = payload.dispatchAction || bind(api.dispatchAction, api);
+    var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo; // Pending
+    // See #6121. But we are not able to reproduce it yet.
+
+    if (!coordSysAxesInfo) {
+      return;
+    }
+
+    if (illegalPoint(point)) {
+      // Used in the default behavior of `connection`: use the sample seriesIndex
+      // and dataIndex. And also used in the tooltipView trigger.
+      point = findPointFromSeries({
+        seriesIndex: finder.seriesIndex,
+        // Do not use dataIndexInside from other ec instance.
+        // FIXME: auto detect it?
+        dataIndex: finder.dataIndex
+      }, ecModel).point;
+    }
+
+    var isIllegalPoint = illegalPoint(point); // Axis and value can be specified when calling dispatchAction({type: 'updateAxisPointer'}).
+    // Notice: In this case, it is difficult to get the `point` (which is necessary to show
+    // tooltip, so if point is not given, we just use the point found by sample seriesIndex
+    // and dataIndex.
+
+    var inputAxesInfo = finder.axesInfo;
+    var axesInfo = coordSysAxesInfo.axesInfo;
+    var shouldHide = currTrigger === 'leave' || illegalPoint(point);
+    var outputPayload = {};
+    var showValueMap = {};
+    var dataByCoordSys = {
+      list: [],
+      map: {}
+    };
+    var updaters = {
+      showPointer: curry(showPointer, showValueMap),
+      showTooltip: curry(showTooltip, dataByCoordSys)
+    }; // Process for triggered axes.
+
+    each(coordSysAxesInfo.coordSysMap, function (coordSys, coordSysKey) {
+      // If a point given, it must be contained by the coordinate system.
+      var coordSysContainsPoint = isIllegalPoint || coordSys.containPoint(point);
+      each(coordSysAxesInfo.coordSysAxesInfo[coordSysKey], function (axisInfo, key) {
+        var axis = axisInfo.axis;
+        var inputAxisInfo = findInputAxisInfo(inputAxesInfo, axisInfo); // If no inputAxesInfo, no axis is restricted.
+
+        if (!shouldHide && coordSysContainsPoint && (!inputAxesInfo || inputAxisInfo)) {
+          var val = inputAxisInfo && inputAxisInfo.value;
+
+          if (val == null && !isIllegalPoint) {
+            val = axis.pointToData(point);
+          }
+
+          val != null && processOnAxis(axisInfo, val, updaters, false, outputPayload);
+        }
+      });
+    }); // Process for linked axes.
+
+    var linkTriggers = {};
+    each(axesInfo, function (tarAxisInfo, tarKey) {
+      var linkGroup = tarAxisInfo.linkGroup; // If axis has been triggered in the previous stage, it should not be triggered by link.
+
+      if (linkGroup && !showValueMap[tarKey]) {
+        each(linkGroup.axesInfo, function (srcAxisInfo, srcKey) {
+          var srcValItem = showValueMap[srcKey]; // If srcValItem exist, source axis is triggered, so link to target axis.
+
+          if (srcAxisInfo !== tarAxisInfo && srcValItem) {
+            var val = srcValItem.value;
+            linkGroup.mapper && (val = tarAxisInfo.axis.scale.parse(linkGroup.mapper(val, makeMapperParam(srcAxisInfo), makeMapperParam(tarAxisInfo))));
+            linkTriggers[tarAxisInfo.key] = val;
+          }
+        });
+      }
+    });
+    each(linkTriggers, function (val, tarKey) {
+      processOnAxis(axesInfo[tarKey], val, updaters, true, outputPayload);
+    });
+    updateModelActually(showValueMap, axesInfo, outputPayload);
+    dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction);
+    dispatchHighDownActually(axesInfo, dispatchAction, api);
+    return outputPayload;
+  }
+
+  function processOnAxis(axisInfo, newValue, updaters, noSnap, outputFinder) {
+    var axis = axisInfo.axis;
+
+    if (axis.scale.isBlank() || !axis.containData(newValue)) {
+      return;
+    }
+
+    if (!axisInfo.involveSeries) {
+      updaters.showPointer(axisInfo, newValue);
+      return;
+    } // Heavy calculation. So put it after axis.containData checking.
+
+
+    var payloadInfo = buildPayloadsBySeries(newValue, axisInfo);
+    var payloadBatch = payloadInfo.payloadBatch;
+    var snapToValue = payloadInfo.snapToValue; // Fill content of event obj for echarts.connect.
+    // By default use the first involved series data as a sample to connect.
+
+    if (payloadBatch[0] && outputFinder.seriesIndex == null) {
+      extend(outputFinder, payloadBatch[0]);
+    } // If no linkSource input, this process is for collecting link
+    // target, where snap should not be accepted.
+
+
+    if (!noSnap && axisInfo.snap) {
+      if (axis.containData(snapToValue) && snapToValue != null) {
+        newValue = snapToValue;
+      }
+    }
+
+    updaters.showPointer(axisInfo, newValue, payloadBatch); // Tooltip should always be snapToValue, otherwise there will be
+    // incorrect "axis value ~ series value" mapping displayed in tooltip.
+
+    updaters.showTooltip(axisInfo, payloadInfo, snapToValue);
+  }
+
+  function buildPayloadsBySeries(value, axisInfo) {
+    var axis = axisInfo.axis;
+    var dim = axis.dim;
+    var snapToValue = value;
+    var payloadBatch = [];
+    var minDist = Number.MAX_VALUE;
+    var minDiff = -1;
+    each(axisInfo.seriesModels, function (series, idx) {
+      var dataDim = series.getData().mapDimensionsAll(dim);
+      var seriesNestestValue;
+      var dataIndices;
+
+      if (series.getAxisTooltipData) {
+        var result = series.getAxisTooltipData(dataDim, value, axis);
+        dataIndices = result.dataIndices;
+        seriesNestestValue = result.nestestValue;
+      } else {
+        dataIndices = series.getData().indicesOfNearest(dataDim[0], value, // Add a threshold to avoid find the wrong dataIndex
+        // when data length is not same.
+        // false,
+        axis.type === 'category' ? 0.5 : null);
+
+        if (!dataIndices.length) {
+          return;
+        }
+
+        seriesNestestValue = series.getData().get(dataDim[0], dataIndices[0]);
+      }
+
+      if (seriesNestestValue == null || !isFinite(seriesNestestValue)) {
+        return;
+      }
+
+      var diff = value - seriesNestestValue;
+      var dist = Math.abs(diff); // Consider category case
+
+      if (dist <= minDist) {
+        if (dist < minDist || diff >= 0 && minDiff < 0) {
+          minDist = dist;
+          minDiff = diff;
+          snapToValue = seriesNestestValue;
+          payloadBatch.length = 0;
+        }
+
+        each(dataIndices, function (dataIndex) {
+          payloadBatch.push({
+            seriesIndex: series.seriesIndex,
+            dataIndexInside: dataIndex,
+            dataIndex: series.getData().getRawIndex(dataIndex)
+          });
+        });
+      }
+    });
+    return {
+      payloadBatch: payloadBatch,
+      snapToValue: snapToValue
+    };
+  }
+
+  function showPointer(showValueMap, axisInfo, value, payloadBatch) {
+    showValueMap[axisInfo.key] = {
+      value: value,
+      payloadBatch: payloadBatch
+    };
+  }
+
+  function showTooltip(dataByCoordSys, axisInfo, payloadInfo, value) {
+    var payloadBatch = payloadInfo.payloadBatch;
+    var axis = axisInfo.axis;
+    var axisModel = axis.model;
+    var axisPointerModel = axisInfo.axisPointerModel; // If no data, do not create anything in dataByCoordSys,
+    // whose length will be used to judge whether dispatch action.
+
+    if (!axisInfo.triggerTooltip || !payloadBatch.length) {
+      return;
+    }
+
+    var coordSysModel = axisInfo.coordSys.model;
+    var coordSysKey = makeKey(coordSysModel);
+    var coordSysItem = dataByCoordSys.map[coordSysKey];
+
+    if (!coordSysItem) {
+      coordSysItem = dataByCoordSys.map[coordSysKey] = {
+        coordSysId: coordSysModel.id,
+        coordSysIndex: coordSysModel.componentIndex,
+        coordSysType: coordSysModel.type,
+        coordSysMainType: coordSysModel.mainType,
+        dataByAxis: []
+      };
+      dataByCoordSys.list.push(coordSysItem);
+    }
+
+    coordSysItem.dataByAxis.push({
+      axisDim: axis.dim,
+      axisIndex: axisModel.componentIndex,
+      axisType: axisModel.type,
+      axisId: axisModel.id,
+      value: value,
+      // Caustion: viewHelper.getValueLabel is actually on "view stage", which
+      // depends that all models have been updated. So it should not be performed
+      // here. Considering axisPointerModel used here is volatile, which is hard
+      // to be retrieve in TooltipView, we prepare parameters here.
+      valueLabelOpt: {
+        precision: axisPointerModel.get(['label', 'precision']),
+        formatter: axisPointerModel.get(['label', 'formatter'])
+      },
+      seriesDataIndices: payloadBatch.slice()
+    });
+  }
+
+  function updateModelActually(showValueMap, axesInfo, outputPayload) {
+    var outputAxesInfo = outputPayload.axesInfo = []; // Basic logic: If no 'show' required, 'hide' this axisPointer.
+
+    each(axesInfo, function (axisInfo, key) {
+      var option = axisInfo.axisPointerModel.option;
+      var valItem = showValueMap[key];
+
+      if (valItem) {
+        !axisInfo.useHandle && (option.status = 'show');
+        option.value = valItem.value; // For label formatter param and highlight.
+
+        option.seriesDataIndices = (valItem.payloadBatch || []).slice();
+      } // When always show (e.g., handle used), remain
+      // original value and status.
+      else {
+          // If hide, value still need to be set, consider
+          // click legend to toggle axis blank.
+          !axisInfo.useHandle && (option.status = 'hide');
+        } // If status is 'hide', should be no info in payload.
+
+
+      option.status === 'show' && outputAxesInfo.push({
+        axisDim: axisInfo.axis.dim,
+        axisIndex: axisInfo.axis.model.componentIndex,
+        value: option.value
+      });
+    });
+  }
+
+  function dispatchTooltipActually(dataByCoordSys, point, payload, dispatchAction) {
+    // Basic logic: If no showTip required, hideTip will be dispatched.
+    if (illegalPoint(point) || !dataByCoordSys.list.length) {
+      dispatchAction({
+        type: 'hideTip'
+      });
+      return;
+    } // In most case only one axis (or event one series is used). It is
+    // convinient to fetch payload.seriesIndex and payload.dataIndex
+    // dirtectly. So put the first seriesIndex and dataIndex of the first
+    // axis on the payload.
+
+
+    var sampleItem = ((dataByCoordSys.list[0].dataByAxis[0] || {}).seriesDataIndices || [])[0] || {};
+    dispatchAction({
+      type: 'showTip',
+      escapeConnect: true,
+      x: point[0],
+      y: point[1],
+      tooltipOption: payload.tooltipOption,
+      position: payload.position,
+      dataIndexInside: sampleItem.dataIndexInside,
+      dataIndex: sampleItem.dataIndex,
+      seriesIndex: sampleItem.seriesIndex,
+      dataByCoordSys: dataByCoordSys.list
+    });
+  }
+
+  function dispatchHighDownActually(axesInfo, dispatchAction, api) {
+    // FIXME
+    // highlight status modification shoule be a stage of main process?
+    // (Consider confilct (e.g., legend and axisPointer) and setOption)
+    var zr = api.getZr();
+    var highDownKey = 'axisPointerLastHighlights';
+    var lastHighlights = inner$9(zr)[highDownKey] || {};
+    var newHighlights = inner$9(zr)[highDownKey] = {}; // Update highlight/downplay status according to axisPointer model.
+    // Build hash map and remove duplicate incidentally.
+
+    each(axesInfo, function (axisInfo, key) {
+      var option = axisInfo.axisPointerModel.option;
+      option.status === 'show' && each(option.seriesDataIndices, function (batchItem) {
+        var key = batchItem.seriesIndex + ' | ' + batchItem.dataIndex;
+        newHighlights[key] = batchItem;
+      });
+    }); // Diff.
+
+    var toHighlight = [];
+    var toDownplay = [];
+    each(lastHighlights, function (batchItem, key) {
+      !newHighlights[key] && toDownplay.push(batchItem);
+    });
+    each(newHighlights, function (batchItem, key) {
+      !lastHighlights[key] && toHighlight.push(batchItem);
+    });
+    toDownplay.length && api.dispatchAction({
+      type: 'downplay',
+      escapeConnect: true,
+      // Not blur others when highlight in axisPointer.
+      notBlur: true,
+      batch: toDownplay
+    });
+    toHighlight.length && api.dispatchAction({
+      type: 'highlight',
+      escapeConnect: true,
+      // Not blur others when highlight in axisPointer.
+      notBlur: true,
+      batch: toHighlight
+    });
+  }
+
+  function findInputAxisInfo(inputAxesInfo, axisInfo) {
+    for (var i = 0; i < (inputAxesInfo || []).length; i++) {
+      var inputAxisInfo = inputAxesInfo[i];
+
+      if (axisInfo.axis.dim === inputAxisInfo.axisDim && axisInfo.axis.model.componentIndex === inputAxisInfo.axisIndex) {
+        return inputAxisInfo;
+      }
+    }
+  }
+
+  function makeMapperParam(axisInfo) {
+    var axisModel = axisInfo.axis.model;
+    var item = {};
+    var dim = item.axisDim = axisInfo.axis.dim;
+    item.axisIndex = item[dim + 'AxisIndex'] = axisModel.componentIndex;
+    item.axisName = item[dim + 'AxisName'] = axisModel.name;
+    item.axisId = item[dim + 'AxisId'] = axisModel.id;
+    return item;
+  }
+
+  function illegalPoint(point) {
+    return !point || point[0] == null || isNaN(point[0]) || point[1] == null || isNaN(point[1]);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install$10(registers) {
+    // CartesianAxisPointer is not supposed to be required here. But consider
+    // echarts.simple.js and online build tooltip, which only require gridSimple,
+    // CartesianAxisPointer should be able to required somewhere.
+    AxisView.registerAxisPointerClass('CartesianAxisPointer', CartesianAxisPointer);
+    registers.registerComponentModel(AxisPointerModel);
+    registers.registerComponentView(AxisPointerView);
+    registers.registerPreprocessor(function (option) {
+      // Always has a global axisPointerModel for default setting.
+      if (option) {
+        (!option.axisPointer || option.axisPointer.length === 0) && (option.axisPointer = {});
+        var link = option.axisPointer.link; // Normalize to array to avoid object mergin. But if link
+        // is not set, remain null/undefined, otherwise it will
+        // override existent link setting.
+
+        if (link && !isArray(link)) {
+          option.axisPointer.link = [link];
+        }
+      }
+    }); // This process should proformed after coordinate systems created
+    // and series data processed. So put it on statistic processing stage.
+
+    registers.registerProcessor(registers.PRIORITY.PROCESSOR.STATISTIC, function (ecModel, api) {
+      // Build axisPointerModel, mergin tooltip.axisPointer model for each axis.
+      // allAxesInfo should be updated when setOption performed.
+      ecModel.getComponent('axisPointer').coordSysAxesInfo = collect(ecModel, api);
+    }); // Broadcast to all views.
+
+    registers.registerAction({
+      type: 'updateAxisPointer',
+      event: 'updateAxisPointer',
+      update: ':updateAxisPointer'
+    }, axisTrigger);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 TooltipModel =
+  /** @class */
+  function (_super) {
+    __extends(TooltipModel, _super);
+
+    function TooltipModel() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = TooltipModel.type;
+      return _this;
+    }
+
+    TooltipModel.type = 'tooltip';
+    TooltipModel.dependencies = ['axisPointer'];
+    TooltipModel.defaultOption = {
+      // zlevel: 0,
+      z: 60,
+      show: true,
+      // tooltip main content
+      showContent: true,
+      // 'trigger' only works on coordinate system.
+      // 'item' | 'axis' | 'none'
+      trigger: 'item',
+      // 'click' | 'mousemove' | 'none'
+      triggerOn: 'mousemove|click',
+      alwaysShowContent: false,
+      displayMode: 'single',
+      renderMode: 'auto',
+      // whether restraint content inside viewRect.
+      // If renderMode: 'richText', default true.
+      // If renderMode: 'html', defaut false (for backward compat).
+      confine: null,
+      showDelay: 0,
+      hideDelay: 100,
+      // Animation transition time, unit is second
+      transitionDuration: 0.4,
+      enterable: false,
+      backgroundColor: '#fff',
+      // box shadow
+      shadowBlur: 10,
+      shadowColor: 'rgba(0, 0, 0, .2)',
+      shadowOffsetX: 1,
+      shadowOffsetY: 2,
+      // tooltip border radius, unit is px, default is 4
+      borderRadius: 4,
+      // tooltip border width, unit is px, default is 0 (no border)
+      borderWidth: 1,
+      // Tooltip inside padding, default is 5 for all direction
+      // Array is allowed to set up, right, bottom, left, same with css
+      // The default value: See `tooltip/tooltipMarkup.ts#getPaddingFromTooltipModel`.
+      padding: null,
+      // Extra css text
+      extraCssText: '',
+      // axis indicator, trigger by axis
+      axisPointer: {
+        // default is line
+        // legal values: 'line' | 'shadow' | 'cross'
+        type: 'line',
+        // Valid when type is line, appoint tooltip line locate on which line. Optional
+        // legal values: 'x' | 'y' | 'angle' | 'radius' | 'auto'
+        // default is 'auto', chose the axis which type is category.
+        // for multiply y axis, cartesian coord chose x axis, polar chose angle axis
+        axis: 'auto',
+        animation: 'auto',
+        animationDurationUpdate: 200,
+        animationEasingUpdate: 'exponentialOut',
+        crossStyle: {
+          color: '#999',
+          width: 1,
+          type: 'dashed',
+          // TODO formatter
+          textStyle: {}
+        } // lineStyle and shadowStyle should not be specified here,
+        // otherwise it will always override those styles on option.axisPointer.
+
+      },
+      textStyle: {
+        color: '#666',
+        fontSize: 14
+      }
+    };
+    return TooltipModel;
+  }(ComponentModel);
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /* global document */
+
+
+  function shouldTooltipConfine(tooltipModel) {
+    var confineOption = tooltipModel.get('confine');
+    return confineOption != null ? !!confineOption // In richText mode, the outside part can not be visible.
+    : tooltipModel.get('renderMode') === 'richText';
+  }
+
+  function testStyle(styleProps) {
+    if (!env.domSupported) {
+      return;
+    }
+
+    var style = document.documentElement.style;
+
+    for (var i = 0, len = styleProps.length; i < len; i++) {
+      if (styleProps[i] in style) {
+        return styleProps[i];
+      }
+    }
+  }
+
+  var TRANSFORM_VENDOR = testStyle(['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
+  var TRANSITION_VENDOR = testStyle(['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
+
+  function toCSSVendorPrefix(styleVendor, styleProp) {
+    if (!styleVendor) {
+      return styleProp;
+    }
+
+    styleProp = toCamelCase(styleProp, true);
+    var idx = styleVendor.indexOf(styleProp);
+    styleVendor = idx === -1 ? styleProp : "-" + styleVendor.slice(0, idx) + "-" + styleProp;
+    return styleVendor.toLowerCase();
+  }
+
+  function getComputedStyle(el, style) {
+    var stl = el.currentStyle || document.defaultView && document.defaultView.getComputedStyle(el);
+    return stl ? style ? stl[style] : stl : null;
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+  /* global document, window */
+
+
+  var CSS_TRANSITION_VENDOR = toCSSVendorPrefix(TRANSITION_VENDOR, 'transition');
+  var CSS_TRANSFORM_VENDOR = toCSSVendorPrefix(TRANSFORM_VENDOR, 'transform'); // eslint-disable-next-line
+
+  var gCssText = "position:absolute;display:block;border-style:solid;white-space:nowrap;z-index:9999999;" + (env.transform3dSupported ? 'will-change:transform;' : '');
+
+  function mirrorPos(pos) {
+    pos = pos === 'left' ? 'right' : pos === 'right' ? 'left' : pos === 'top' ? 'bottom' : 'top';
+    return pos;
+  }
+
+  function assembleArrow(tooltipModel, borderColor, arrowPosition) {
+    if (!isString(arrowPosition) || arrowPosition === 'inside') {
+      return '';
+    }
+
+    var backgroundColor = tooltipModel.get('backgroundColor');
+    var borderWidth = tooltipModel.get('borderWidth');
+    borderColor = convertToColorString(borderColor);
+    var arrowPos = mirrorPos(arrowPosition);
+    var arrowSize = Math.max(Math.round(borderWidth) * 1.5, 6);
+    var positionStyle = '';
+    var transformStyle = CSS_TRANSFORM_VENDOR + ':';
+    var rotateDeg;
+
+    if (indexOf(['left', 'right'], arrowPos) > -1) {
+      positionStyle += 'top:50%';
+      transformStyle += "translateY(-50%) rotate(" + (rotateDeg = arrowPos === 'left' ? -225 : -45) + "deg)";
+    } else {
+      positionStyle += 'left:50%';
+      transformStyle += "translateX(-50%) rotate(" + (rotateDeg = arrowPos === 'top' ? 225 : 45) + "deg)";
+    }
+
+    var rotateRadian = rotateDeg * Math.PI / 180;
+    var arrowWH = arrowSize + borderWidth;
+    var rotatedWH = arrowWH * Math.abs(Math.cos(rotateRadian)) + arrowWH * Math.abs(Math.sin(rotateRadian));
+    var arrowOffset = Math.round(((rotatedWH - Math.SQRT2 * borderWidth) / 2 + Math.SQRT2 * borderWidth - (rotatedWH - arrowWH) / 2) * 100) / 100;
+    positionStyle += ";" + arrowPos + ":-" + arrowOffset + "px";
+    var borderStyle = borderColor + " solid " + borderWidth + "px;";
+    var styleCss = ["position:absolute;width:" + arrowSize + "px;height:" + arrowSize + "px;", positionStyle + ";" + transformStyle + ";", "border-bottom:" + borderStyle, "border-right:" + borderStyle, "background-color:" + backgroundColor + ";"];
+    return "<div style=\"" + styleCss.join('') + "\"></div>";
+  }
+
+  function assembleTransition(duration, onlyFade) {
+    var transitionCurve = 'cubic-bezier(0.23,1,0.32,1)';
+    var transitionOption = " " + duration / 2 + "s " + transitionCurve;
+    var transitionText = "opacity" + transitionOption + ",visibility" + transitionOption;
+
+    if (!onlyFade) {
+      transitionOption = " " + duration + "s " + transitionCurve;
+      transitionText += env.transformSupported ? "," + CSS_TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption;
+    }
+
+    return CSS_TRANSITION_VENDOR + ':' + transitionText;
+  }
+
+  function assembleTransform(x, y, toString) {
+    // If using float on style, the final width of the dom might
+    // keep changing slightly while mouse move. So `toFixed(0)` them.
+    var x0 = x.toFixed(0) + 'px';
+    var y0 = y.toFixed(0) + 'px'; // not support transform, use `left` and `top` instead.
+
+    if (!env.transformSupported) {
+      return toString ? "top:" + y0 + ";left:" + x0 + ";" : [['top', y0], ['left', x0]];
+    } // support transform
+
+
+    var is3d = env.transform3dSupported;
+    var translate = "translate" + (is3d ? '3d' : '') + "(" + x0 + "," + y0 + (is3d ? ',0' : '') + ")";
+    return toString ? 'top:0;left:0;' + CSS_TRANSFORM_VENDOR + ':' + translate + ';' : [['top', 0], ['left', 0], [TRANSFORM_VENDOR, translate]];
+  }
+  /**
+   * @param {Object} textStyle
+   * @return {string}
+   * @inner
+   */
+
+
+  function assembleFont(textStyleModel) {
+    var cssText = [];
+    var fontSize = textStyleModel.get('fontSize');
+    var color = textStyleModel.getTextColor();
+    color && cssText.push('color:' + color);
+    cssText.push('font:' + textStyleModel.getFont());
+    fontSize // @ts-ignore, leave it to the tooltip refactor.
+    && cssText.push('line-height:' + Math.round(fontSize * 3 / 2) + 'px');
+    var shadowColor = textStyleModel.get('textShadowColor');
+    var shadowBlur = textStyleModel.get('textShadowBlur') || 0;
+    var shadowOffsetX = textStyleModel.get('textShadowOffsetX') || 0;
+    var shadowOffsetY = textStyleModel.get('textShadowOffsetY') || 0;
+    shadowColor && shadowBlur && cssText.push('text-shadow:' + shadowOffsetX + 'px ' + shadowOffsetY + 'px ' + shadowBlur + 'px ' + shadowColor);
+    each(['decoration', 'align'], function (name) {
+      var val = textStyleModel.get(name);
+      val && cssText.push('text-' + name + ':' + val);
+    });
+    return cssText.join(';');
+  }
+
+  function assembleCssText(tooltipModel, enableTransition, onlyFade) {
+    var cssText = [];
+    var transitionDuration = tooltipModel.get('transitionDuration');
+    var backgroundColor = tooltipModel.get('backgroundColor');
+    var shadowBlur = tooltipModel.get('shadowBlur');
+    var shadowColor = tooltipModel.get('shadowColor');
+    var shadowOffsetX = tooltipModel.get('shadowOffsetX');
+    var shadowOffsetY = tooltipModel.get('shadowOffsetY');
+    var textStyleModel = tooltipModel.getModel('textStyle');
+    var padding = getPaddingFromTooltipModel(tooltipModel, 'html');
+    var boxShadow = shadowOffsetX + "px " + shadowOffsetY + "px " + shadowBlur + "px " + shadowColor;
+    cssText.push('box-shadow:' + boxShadow); // Animation transition. Do not animate when transitionDuration is 0.
+
+    enableTransition && transitionDuration && cssText.push(assembleTransition(transitionDuration, onlyFade));
+
+    if (backgroundColor) {
+      cssText.push('background-color:' + backgroundColor);
+    } // Border style
+
+
+    each(['width', 'color', 'radius'], function (name) {
+      var borderName = 'border-' + name;
+      var camelCase = toCamelCase(borderName);
+      var val = tooltipModel.get(camelCase);
+      val != null && cssText.push(borderName + ':' + val + (name === 'color' ? '' : 'px'));
+    }); // Text style
+
+    cssText.push(assembleFont(textStyleModel)); // Padding
+
+    if (padding != null) {
+      cssText.push('padding:' + normalizeCssArray$1(padding).join('px ') + 'px');
+    }
+
+    return cssText.join(';') + ';';
+  } // If not able to make, do not modify the input `out`.
+
+
+  function makeStyleCoord(out, zr, appendToBody, zrX, zrY) {
+    var zrPainter = zr && zr.painter;
+
+    if (appendToBody) {
+      var zrViewportRoot = zrPainter && zrPainter.getViewportRoot();
+
+      if (zrViewportRoot) {
+        // Some APPs might use scale on body, so we support CSS transform here.
+        transformLocalCoord(out, zrViewportRoot, document.body, zrX, zrY);
+      }
+    } else {
+      out[0] = zrX;
+      out[1] = zrY; // xy should be based on canvas root. But tooltipContent is
+      // the sibling of canvas root. So padding of ec container
+      // should be considered here.
+
+      var viewportRootOffset = zrPainter && zrPainter.getViewportRootOffset();
+
+      if (viewportRootOffset) {
+        out[0] += viewportRootOffset.offsetLeft;
+        out[1] += viewportRootOffset.offsetTop;
+      }
+    }
+
+    out[2] = out[0] / zr.getWidth();
+    out[3] = out[1] / zr.getHeight();
+  }
+
+  var TooltipHTMLContent =
+  /** @class */
+  function () {
+    function TooltipHTMLContent(container, api, opt) {
+      this._show = false;
+      this._styleCoord = [0, 0, 0, 0];
+      this._enterable = true;
+      this._firstShow = true;
+      this._longHide = true;
+
+      if (env.wxa) {
+        return null;
+      }
+
+      var el = document.createElement('div'); // TODO: TYPE
+
+      el.domBelongToZr = true;
+      this.el = el;
+      var zr = this._zr = api.getZr();
+      var appendToBody = this._appendToBody = opt && opt.appendToBody;
+      makeStyleCoord(this._styleCoord, zr, appendToBody, api.getWidth() / 2, api.getHeight() / 2);
+
+      if (appendToBody) {
+        document.body.appendChild(el);
+      } else {
+        container.appendChild(el);
+      }
+
+      this._container = container; // FIXME
+      // Is it needed to trigger zr event manually if
+      // the browser do not support `pointer-events: none`.
+
+      var self = this;
+
+      el.onmouseenter = function () {
+        // clear the timeout in hideLater and keep showing tooltip
+        if (self._enterable) {
+          clearTimeout(self._hideTimeout);
+          self._show = true;
+        }
+
+        self._inContent = true;
+      };
+
+      el.onmousemove = function (e) {
+        e = e || window.event;
+
+        if (!self._enterable) {
+          // `pointer-events: none` is set to tooltip content div
+          // if `enterable` is set as `false`, and `el.onmousemove`
+          // can not be triggered. But in browser that do not
+          // support `pointer-events`, we need to do this:
+          // Try trigger zrender event to avoid mouse
+          // in and out shape too frequently
+          var handler = zr.handler;
+          var zrViewportRoot = zr.painter.getViewportRoot();
+          normalizeEvent(zrViewportRoot, e, true);
+          handler.dispatch('mousemove', e);
+        }
+      };
+
+      el.onmouseleave = function () {
+        // set `_inContent` to `false` before `hideLater`
+        self._inContent = false;
+
+        if (self._enterable) {
+          if (self._show) {
+            self.hideLater(self._hideDelay);
+          }
+        }
+      };
+    }
+    /**
+     * Update when tooltip is rendered
+     */
+
+
+    TooltipHTMLContent.prototype.update = function (tooltipModel) {
+      // FIXME
+      // Move this logic to ec main?
+      var container = this._container;
+      var position = getComputedStyle(container, 'position');
+      var domStyle = container.style;
+
+      if (domStyle.position !== 'absolute' && position !== 'absolute') {
+        domStyle.position = 'relative';
+      } // move tooltip if chart resized
+
+
+      var alwaysShowContent = tooltipModel.get('alwaysShowContent');
+      alwaysShowContent && this._moveIfResized(); // update className
+
+      this.el.className = tooltipModel.get('className') || ''; // Hide the tooltip
+      // PENDING
+      // this.hide();
+    };
+
+    TooltipHTMLContent.prototype.show = function (tooltipModel, nearPointColor) {
+      clearTimeout(this._hideTimeout);
+      clearTimeout(this._longHideTimeout);
+      var el = this.el;
+      var style = el.style;
+      var styleCoord = this._styleCoord;
+
+      if (!el.innerHTML) {
+        style.display = 'none';
+      } else {
+        style.cssText = gCssText + assembleCssText(tooltipModel, !this._firstShow, this._longHide) // initial transform
+        + assembleTransform(styleCoord[0], styleCoord[1], true) + ("border-color:" + convertToColorString(nearPointColor) + ";") + (tooltipModel.get('extraCssText') || '') // If mouse occasionally move over the tooltip, a mouseout event will be
+        // triggered by canvas, and cause some unexpectable result like dragging
+        // stop, "unfocusAdjacency". Here `pointer-events: none` is used to solve
+        // it. Although it is not supported by IE8~IE10, fortunately it is a rare
+        // scenario.
+        + (";pointer-events:" + (this._enterable ? 'auto' : 'none'));
+      }
+
+      this._show = true;
+      this._firstShow = false;
+      this._longHide = false;
+    };
+
+    TooltipHTMLContent.prototype.setContent = function (content, markers, tooltipModel, borderColor, arrowPosition) {
+      var el = this.el;
+
+      if (content == null) {
+        el.innerHTML = '';
+        return;
+      }
+
+      var arrow = '';
+
+      if (isString(arrowPosition) && tooltipModel.get('trigger') === 'item' && !shouldTooltipConfine(tooltipModel)) {
+        arrow = assembleArrow(tooltipModel, borderColor, arrowPosition);
+      }
+
+      if (isString(content)) {
+        el.innerHTML = content + arrow;
+      } else if (content) {
+        // Clear previous
+        el.innerHTML = '';
+
+        if (!isArray(content)) {
+          content = [content];
+        }
+
+        for (var i = 0; i < content.length; i++) {
+          if (isDom(content[i]) && content[i].parentNode !== el) {
+            el.appendChild(content[i]);
+          }
+        } // no arrow if empty
+
+
+        if (arrow && el.childNodes.length) {
+          // no need to create a new parent element, but it's not supported by IE 10 and older.
+          // const arrowEl = document.createRange().createContextualFragment(arrow);
+          var arrowEl = document.createElement('div');
+          arrowEl.innerHTML = arrow;
+          el.appendChild(arrowEl);
+        }
+      }
+    };
+
+    TooltipHTMLContent.prototype.setEnterable = function (enterable) {
+      this._enterable = enterable;
+    };
+
+    TooltipHTMLContent.prototype.getSize = function () {
+      var el = this.el;
+      return [el.offsetWidth, el.offsetHeight];
+    };
+
+    TooltipHTMLContent.prototype.moveTo = function (zrX, zrY) {
+      var styleCoord = this._styleCoord;
+      makeStyleCoord(styleCoord, this._zr, this._appendToBody, zrX, zrY);
+
+      if (styleCoord[0] != null && styleCoord[1] != null) {
+        var style_1 = this.el.style;
+        var transforms = assembleTransform(styleCoord[0], styleCoord[1]);
+        each(transforms, function (transform) {
+          style_1[transform[0]] = transform[1];
+        });
+      }
+    };
+    /**
+     * when `alwaysShowContent` is true,
+     * move the tooltip after chart resized
+     */
+
+
+    TooltipHTMLContent.prototype._moveIfResized = function () {
+      // The ratio of left to width
+      var ratioX = this._styleCoord[2]; // The ratio of top to height
+
+      var ratioY = this._styleCoord[3];
+      this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight());
+    };
+
+    TooltipHTMLContent.prototype.hide = function () {
+      var _this = this;
+
+      var style = this.el.style;
+      style.visibility = 'hidden';
+      style.opacity = '0';
+      env.transform3dSupported && (style.willChange = '');
+      this._show = false;
+      this._longHideTimeout = setTimeout(function () {
+        return _this._longHide = true;
+      }, 500);
+    };
+
+    TooltipHTMLContent.prototype.hideLater = function (time) {
+      if (this._show && !(this._inContent && this._enterable)) {
+        if (time) {
+          this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times
+
+          this._show = false;
+          this._hideTimeout = setTimeout(bind(this.hide, this), time);
+        } else {
+          this.hide();
+        }
+      }
+    };
+
+    TooltipHTMLContent.prototype.isShow = function () {
+      return this._show;
+    };
+
+    TooltipHTMLContent.prototype.dispose = function () {
+      this.el.parentNode.removeChild(this.el);
+    };
+
+    return TooltipHTMLContent;
+  }();
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 TooltipRichContent =
+  /** @class */
+  function () {
+    function TooltipRichContent(api) {
+      this._show = false;
+      this._styleCoord = [0, 0, 0, 0];
+      this._enterable = true;
+      this._zr = api.getZr();
+      makeStyleCoord$1(this._styleCoord, this._zr, api.getWidth() / 2, api.getHeight() / 2);
+    }
+    /**
+     * Update when tooltip is rendered
+     */
+
+
+    TooltipRichContent.prototype.update = function (tooltipModel) {
+      var alwaysShowContent = tooltipModel.get('alwaysShowContent');
+      alwaysShowContent && this._moveIfResized();
+    };
+
+    TooltipRichContent.prototype.show = function () {
+      if (this._hideTimeout) {
+        clearTimeout(this._hideTimeout);
+      }
+
+      this.el.show();
+      this._show = true;
+    };
+    /**
+     * Set tooltip content
+     */
+
+
+    TooltipRichContent.prototype.setContent = function (content, markupStyleCreator, tooltipModel, borderColor, arrowPosition) {
+      var _this = this;
+
+      if (isObject(content)) {
+        throwError('Passing DOM nodes as content is not supported in richText tooltip!');
+      }
+
+      if (this.el) {
+        this._zr.remove(this.el);
+      }
+
+      var textStyleModel = tooltipModel.getModel('textStyle');
+      this.el = new ZRText({
+        style: {
+          rich: markupStyleCreator.richTextStyles,
+          text: content,
+          lineHeight: 22,
+          borderWidth: 1,
+          borderColor: borderColor,
+          textShadowColor: textStyleModel.get('textShadowColor'),
+          fill: tooltipModel.get(['textStyle', 'color']),
+          padding: getPaddingFromTooltipModel(tooltipModel, 'richText'),
+          verticalAlign: 'top',
+          align: 'left'
+        },
+        z: tooltipModel.get('z')
+      });
+      each(['backgroundColor', 'borderRadius', 'shadowColor', 'shadowBlur', 'shadowOffsetX', 'shadowOffsetY'], function (propName) {
+        _this.el.style[propName] = tooltipModel.get(propName);
+      });
+      each(['textShadowBlur', 'textShadowOffsetX', 'textShadowOffsetY'], function (propName) {
+        _this.el.style[propName] = textStyleModel.get(propName) || 0;
+      });
+
+      this._zr.add(this.el);
+
+      var self = this;
+      this.el.on('mouseover', function () {
+        // clear the timeout in hideLater and keep showing tooltip
+        if (self._enterable) {
+          clearTimeout(self._hideTimeout);
+          self._show = true;
+        }
+
+        self._inContent = true;
+      });
+      this.el.on('mouseout', function () {
+        if (self._enterable) {
+          if (self._show) {
+            self.hideLater(self._hideDelay);
+          }
+        }
+
+        self._inContent = false;
+      });
+    };
+
+    TooltipRichContent.prototype.setEnterable = function (enterable) {
+      this._enterable = enterable;
+    };
+
+    TooltipRichContent.prototype.getSize = function () {
+      var el = this.el;
+      var bounding = this.el.getBoundingRect(); // bounding rect does not include shadow. For renderMode richText,
+      // if overflow, it will be cut. So calculate them accurately.
+
+      var shadowOuterSize = calcShadowOuterSize(el.style);
+      return [bounding.width + shadowOuterSize.left + shadowOuterSize.right, bounding.height + shadowOuterSize.top + shadowOuterSize.bottom];
+    };
+
+    TooltipRichContent.prototype.moveTo = function (x, y) {
+      var el = this.el;
+
+      if (el) {
+        var styleCoord = this._styleCoord;
+        makeStyleCoord$1(styleCoord, this._zr, x, y);
+        x = styleCoord[0];
+        y = styleCoord[1];
+        var style = el.style;
+        var borderWidth = mathMaxWith0(style.borderWidth || 0);
+        var shadowOuterSize = calcShadowOuterSize(style); // rich text x, y do not include border.
+
+        el.x = x + borderWidth + shadowOuterSize.left;
+        el.y = y + borderWidth + shadowOuterSize.top;
+        el.markRedraw();
+      }
+    };
+    /**
+     * when `alwaysShowContent` is true,
+     * move the tooltip after chart resized
+     */
+
+
+    TooltipRichContent.prototype._moveIfResized = function () {
+      // The ratio of left to width
+      var ratioX = this._styleCoord[2]; // The ratio of top to height
+
+      var ratioY = this._styleCoord[3];
+      this.moveTo(ratioX * this._zr.getWidth(), ratioY * this._zr.getHeight());
+    };
+
+    TooltipRichContent.prototype.hide = function () {
+      if (this.el) {
+        this.el.hide();
+      }
+
+      this._show = false;
+    };
+
+    TooltipRichContent.prototype.hideLater = function (time) {
+      if (this._show && !(this._inContent && this._enterable)) {
+        if (time) {
+          this._hideDelay = time; // Set show false to avoid invoke hideLater multiple times
+
+          this._show = false;
+          this._hideTimeout = setTimeout(bind(this.hide, this), time);
+        } else {
+          this.hide();
+        }
+      }
+    };
+
+    TooltipRichContent.prototype.isShow = function () {
+      return this._show;
+    };
+
+    TooltipRichContent.prototype.dispose = function () {
+      this._zr.remove(this.el);
+    };
+
+    return TooltipRichContent;
+  }();
+
+  function mathMaxWith0(val) {
+    return Math.max(0, val);
+  }
+
+  function calcShadowOuterSize(style) {
+    var shadowBlur = mathMaxWith0(style.shadowBlur || 0);
+    var shadowOffsetX = mathMaxWith0(style.shadowOffsetX || 0);
+    var shadowOffsetY = mathMaxWith0(style.shadowOffsetY || 0);
+    return {
+      left: mathMaxWith0(shadowBlur - shadowOffsetX),
+      right: mathMaxWith0(shadowBlur + shadowOffsetX),
+      top: mathMaxWith0(shadowBlur - shadowOffsetY),
+      bottom: mathMaxWith0(shadowBlur + shadowOffsetY)
+    };
+  }
+
+  function makeStyleCoord$1(out, zr, zrX, zrY) {
+    out[0] = zrX;
+    out[1] = zrY;
+    out[2] = out[0] / zr.getWidth();
+    out[3] = out[1] / zr.getHeight();
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 proxyRect = new Rect({
+    shape: {
+      x: -1,
+      y: -1,
+      width: 2,
+      height: 2
+    }
+  });
+
+  var TooltipView =
+  /** @class */
+  function (_super) {
+    __extends(TooltipView, _super);
+
+    function TooltipView() {
+      var _this = _super !== null && _super.apply(this, arguments) || this;
+
+      _this.type = TooltipView.type;
+      return _this;
+    }
+
+    TooltipView.prototype.init = function (ecModel, api) {
+      if (env.node || !api.getDom()) {
+        return;
+      }
+
+      var tooltipModel = ecModel.getComponent('tooltip');
+      var renderMode = this._renderMode = getTooltipRenderMode(tooltipModel.get('renderMode'));
+      this._tooltipContent = renderMode === 'richText' ? new TooltipRichContent(api) : new TooltipHTMLContent(api.getDom(), api, {
+        appendToBody: tooltipModel.get('appendToBody', true)
+      });
+    };
+
+    TooltipView.prototype.render = function (tooltipModel, ecModel, api) {
+      if (env.node || !api.getDom()) {
+        return;
+      } // Reset
+
+
+      this.group.removeAll();
+      this._tooltipModel = tooltipModel;
+      this._ecModel = ecModel;
+      this._api = api;
+      /**
+       * @private
+       * @type {boolean}
+       */
+
+      this._alwaysShowContent = tooltipModel.get('alwaysShowContent');
+      var tooltipContent = this._tooltipContent;
+      tooltipContent.update(tooltipModel);
+      tooltipContent.setEnterable(tooltipModel.get('enterable'));
+
+      this._initGlobalListener();
+
+      this._keepShow(); // PENDING
+      // `mousemove` event will be triggered very frequently when the mouse moves fast,
+      // which causes that the `updatePosition` function was also called frequently.
+      // In Chrome with devtools open and Firefox, tooltip looks laggy and shakes. See #14695 #16101
+      // To avoid frequent triggering,
+      // consider throttling it in 50ms when transition is enabled
+
+
+      if (this._renderMode !== 'richText' && tooltipModel.get('transitionDuration')) {
+        createOrUpdate(this, '_updatePosition', 50, 'fixRate');
+      } else {
+        clear(this, '_updatePosition');
+      }
+    };
+
+    TooltipView.prototype._initGlobalListener = function () {
+      var tooltipModel = this._tooltipModel;
+      var triggerOn = tooltipModel.get('triggerOn');
+      register('itemTooltip', this._api, bind(function (currTrigger, e, dispatchAction) {
+        // If 'none', it is not controlled by mouse totally.
+        if (triggerOn !== 'none') {
+          if (triggerOn.indexOf(currTrigger) >= 0) {
+            this._tryShow(e, dispatchAction);
+          } else if (currTrigger === 'leave') {
+            this._hide(dispatchAction);
+          }
+        }
+      }, this));
+    };
+
+    TooltipView.prototype._keepShow = function () {
+      var tooltipModel = this._tooltipModel;
+      var ecModel = this._ecModel;
+      var api = this._api;
+      var triggerOn = tooltipModel.get('triggerOn'); // Try to keep the tooltip show when refreshing
+
+      if (this._lastX != null && this._lastY != null // When user is willing to control tooltip totally using API,
+      // self.manuallyShowTip({x, y}) might cause tooltip hide,
+      // which is not expected.
+      && triggerOn !== 'none' && triggerOn !== 'click') {
+        var self_1 = this;
+        clearTimeout(this._refreshUpdateTimeout);
+        this._refreshUpdateTimeout = setTimeout(function () {
+          // Show tip next tick after other charts are rendered
+          // In case highlight action has wrong result
+          // FIXME
+          !api.isDisposed() && self_1.manuallyShowTip(tooltipModel, ecModel, api, {
+            x: self_1._lastX,
+            y: self_1._lastY,
+            dataByCoordSys: self_1._lastDataByCoordSys
+          });
+        });
+      }
+    };
+    /**
+     * Show tip manually by
+     * dispatchAction({
+     *     type: 'showTip',
+     *     x: 10,
+     *     y: 10
+     * });
+     * Or
+     * dispatchAction({
+     *      type: 'showTip',
+     *      seriesIndex: 0,
+     *      dataIndex or dataIndexInside or name
+     * });
+     *
+     *  TODO Batch
+     */
+
+
+    TooltipView.prototype.manuallyShowTip = function (tooltipModel, ecModel, api, payload) {
+      if (payload.from === this.uid || env.node || !api.getDom()) {
+        return;
+      }
+
+      var dispatchAction = makeDispatchAction$1(payload, api); // Reset ticket
+
+      this._ticket = ''; // When triggered from axisPointer.
+
+      var dataByCoordSys = payload.dataByCoordSys;
+      var cmptRef = findComponentReference(payload, ecModel, api);
+
+      if (cmptRef) {
+        var rect = cmptRef.el.getBoundingRect().clone();
+        rect.applyTransform(cmptRef.el.transform);
+
+        this._tryShow({
+          offsetX: rect.x + rect.width / 2,
+          offsetY: rect.y + rect.height / 2,
+          target: cmptRef.el,
+          position: payload.position,
+          // When manully trigger, the mouse is not on the el, so we'd better to
+          // position tooltip on the bottom of the el and display arrow is possible.
+          positionDefault: 'bottom'
+        }, dispatchAction);
+      } else if (payload.tooltip && payload.x != null && payload.y != null) {
+        var el = proxyRect;
+        el.x = payload.x;
+        el.y = payload.y;
+        el.update();
+        getECData(el).tooltipConfig = {
+          name: null,
+          option: payload.tooltip
+        }; // Manually show tooltip while view is not using zrender elements.
+
+        this._tryShow({
+          offsetX: payload.x,
+          offsetY: payload.y,
+          target: el
+        }, dispatchAction);
+      } else if (dataByCoordSys) {
+        this._tryShow({
+          offsetX: payload.x,
+          offsetY: payload.y,
+          position: payload.position,
+          dataByCoordSys: dataByCoordSys,
+          tooltipOption: payload.tooltipOption
+        }, dispatchAction);
+      } else if (payload.seriesIndex != null) {
+        if (this._manuallyAxisShowTip(tooltipModel, ecModel, api, payload)) {
+          return;
+        }
+
+        var pointInfo = findPointFromSeries(payload, ecModel);
+        var cx = pointInfo.point[0];
+        var cy = pointInfo.point[1];
+
+        if (cx != null && cy != null) {
+          this._tryShow({
+            offsetX: cx,
+            offsetY: cy,
+            target: pointInfo.el,
+            position: payload.position,
+            // When manully trigger, the mouse is not on the el, so we'd better to
+            // position tooltip on the bottom of the el and display arrow is possible.
+            positionDefault: 'bottom'
+          }, dispatchAction);
+        }
+      } else if (payload.x != null && payload.y != null) {
+        // FIXME
+        // should wrap dispatchAction like `axisPointer/globalListener` ?
+        api.dispatchAction({
+          type: 'updateAxisPointer',
+          x: payload.x,
+          y: payload.y
+        });
+
+        this._tryShow({
+          offsetX: payload.x,
+          offsetY: payload.y,
+          position: payload.position,
+          target: api.getZr().findHover(payload.x, payload.y).target
+        }, dispatchAction);
+      }
+    };
+
+    TooltipView.prototype.manuallyHideTip = function (tooltipModel, ecModel, api, payload) {
+      var tooltipContent = this._tooltipContent;
+
+      if (!this._alwaysShowContent && this._tooltipModel) {
+        tooltipContent.hideLater(this._tooltipModel.get('hideDelay'));
+      }
+
+      this._lastX = this._lastY = this._lastDataByCoordSys = null;
+
+      if (payload.from !== this.uid) {
+        this._hide(makeDispatchAction$1(payload, api));
+      }
+    }; // Be compatible with previous design, that is, when tooltip.type is 'axis' and
+    // dispatchAction 'showTip' with seriesIndex and dataIndex will trigger axis pointer
+    // and tooltip.
+
+
+    TooltipView.prototype._manuallyAxisShowTip = function (tooltipModel, ecModel, api, payload) {
+      var seriesIndex = payload.seriesIndex;
+      var dataIndex = payload.dataIndex; // @ts-ignore
+
+      var coordSysAxesInfo = ecModel.getComponent('axisPointer').coordSysAxesInfo;
+
+      if (seriesIndex == null || dataIndex == null || coordSysAxesInfo == null) {
+        return;
+      }
+
+      var seriesModel = ecModel.getSeriesByIndex(seriesIndex);
+
+      if (!seriesModel) {
+        return;
+      }
+
+      var data = seriesModel.getData();
+      var tooltipCascadedModel = buildTooltipModel([data.getItemModel(dataIndex), seriesModel, (seriesModel.coordinateSystem || {}).model], this._tooltipModel);
+
+      if (tooltipCascadedModel.get('trigger') !== 'axis') {
+        return;
+      }
+
+      api.dispatchAction({
+        type: 'updateAxisPointer',
+        seriesIndex: seriesIndex,
+        dataIndex: dataIndex,
+        position: payload.position
+      });
+      return true;
+    };
+
+    TooltipView.prototype._tryShow = function (e, dispatchAction) {
+      var el = e.target;
+      var tooltipModel = this._tooltipModel;
+
+      if (!tooltipModel) {
+        return;
+      } // Save mouse x, mouse y. So we can try to keep showing the tip if chart is refreshed
+
+
+      this._lastX = e.offsetX;
+      this._lastY = e.offsetY;
+      var dataByCoordSys = e.dataByCoordSys;
+
+      if (dataByCoordSys && dataByCoordSys.length) {
+        this._showAxisTooltip(dataByCoordSys, e);
+      } else if (el) {
+        this._lastDataByCoordSys = null;
+        var seriesDispatcher_1;
+        var cmptDispatcher_1;
+        findEventDispatcher(el, function (target) {
+          // Always show item tooltip if mouse is on the element with dataIndex
+          if (getECData(target).dataIndex != null) {
+            seriesDispatcher_1 = target;
+            return true;
+          } // Tooltip provided directly. Like legend.
+
+
+          if (getECData(target).tooltipConfig != null) {
+            cmptDispatcher_1 = target;
+            return true;
+          }
+        }, true);
+
+        if (seriesDispatcher_1) {
+          this._showSeriesItemTooltip(e, seriesDispatcher_1, dispatchAction);
+        } else if (cmptDispatcher_1) {
+          this._showComponentItemTooltip(e, cmptDispatcher_1, dispatchAction);
+        } else {
+          this._hide(dispatchAction);
+        }
+      } else {
+        this._lastDataByCoordSys = null;
+
+        this._hide(dispatchAction);
+      }
+    };
+
+    TooltipView.prototype._showOrMove = function (tooltipModel, cb) {
+      // showDelay is used in this case: tooltip.enterable is set
+      // as true. User intent to move mouse into tooltip and click
+      // something. `showDelay` makes it easier to enter the content
+      // but tooltip do not move immediately.
+      var delay = tooltipModel.get('showDelay');
+      cb = bind(cb, this);
+      clearTimeout(this._showTimout);
+      delay > 0 ? this._showTimout = setTimeout(cb, delay) : cb();
+    };
+
+    TooltipView.prototype._showAxisTooltip = function (dataByCoordSys, e) {
+      var ecModel = this._ecModel;
+      var globalTooltipModel = this._tooltipModel;
+      var point = [e.offsetX, e.offsetY];
+      var singleTooltipModel = buildTooltipModel([e.tooltipOption], globalTooltipModel);
+      var renderMode = this._renderMode;
+      var cbParamsList = [];
+      var articleMarkup = createTooltipMarkup('section', {
+        blocks: [],
+        noHeader: true
+      }); // Only for legacy: `Serise['formatTooltip']` returns a string.
+
+      var markupTextArrLegacy = [];
+      var markupStyleCreator = new TooltipMarkupStyleCreator();
+      each(dataByCoordSys, function (itemCoordSys) {
+        each(itemCoordSys.dataByAxis, function (axisItem) {
+          var axisModel = ecModel.getComponent(axisItem.axisDim + 'Axis', axisItem.axisIndex);
+          var axisValue = axisItem.value;
+
+          if (!axisModel || axisValue == null) {
+            return;
+          }
+
+          var axisValueLabel = getValueLabel(axisValue, axisModel.axis, ecModel, axisItem.seriesDataIndices, axisItem.valueLabelOpt);
+          var axisSectionMarkup = createTooltipMarkup('section', {
+            header: axisValueLabel,
+            noHeader: !trim(axisValueLabel),
+            sortBlocks: true,
+            blocks: []
+          });
+          articleMarkup.blocks.push(axisSectionMarkup);
+          each(axisItem.seriesDataIndices, function (idxItem) {
+            var series = ecModel.getSeriesByIndex(idxItem.seriesIndex);
+            var dataIndex = idxItem.dataIndexInside;
+            var cbParams = series.getDataParams(dataIndex); // Can't find data.
+
+            if (cbParams.dataIndex < 0) {
+              return;
+            }
+
+            cbParams.axisDim = axisItem.axisDim;
+            cbParams.axisIndex = axisItem.axisIndex;
+            cbParams.axisType = axisItem.axisType;
+            cbParams.axisId = axisItem.axisId;
+            cbParams.axisValue = getAxisRawValue(axisModel.axis, {
+              value: axisValue
+            });
+            cbParams.axisValueLabel = axisValueLabel; // Pre-create marker style for makers. Users can assemble richText
+            // text in `formatter` callback and use those markers style.
+
+            cbParams.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(cbParams.color), renderMode);
+            var seriesTooltipResult = normalizeTooltipFormatResult(series.formatTooltip(dataIndex, true, null));
+            var frag = seriesTooltipResult.frag;
+
+            if (frag) {
+              var valueFormatter = buildTooltipModel([series], globalTooltipModel).get('valueFormatter');
+              axisSectionMarkup.blocks.push(valueFormatter ? extend({
+                valueFormatter: valueFormatter
+              }, frag) : frag);
+            }
+
+            if (seriesTooltipResult.text) {
+              markupTextArrLegacy.push(seriesTooltipResult.text);
+            }
+
+            cbParamsList.push(cbParams);
+          });
+        });
+      }); // In most cases, the second axis is displays upper on the first one.
+      // So we reverse it to look better.
+
+      articleMarkup.blocks.reverse();
+      markupTextArrLegacy.reverse();
+      var positionExpr = e.position;
+      var orderMode = singleTooltipModel.get('order');
+      var builtMarkupText = buildTooltipMarkup(articleMarkup, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), singleTooltipModel.get('textStyle'));
+      builtMarkupText && markupTextArrLegacy.unshift(builtMarkupText);
+      var blockBreak = renderMode === 'richText' ? '\n\n' : '<br/>';
+      var allMarkupText = markupTextArrLegacy.join(blockBreak);
+
+      this._showOrMove(singleTooltipModel, function () {
+        if (this._updateContentNotChangedOnAxis(dataByCoordSys, cbParamsList)) {
+          this._updatePosition(singleTooltipModel, positionExpr, point[0], point[1], this._tooltipContent, cbParamsList);
+        } else {
+          this._showTooltipContent(singleTooltipModel, allMarkupText, cbParamsList, Math.random() + '', point[0], point[1], positionExpr, null, markupStyleCreator);
+        }
+      }); // Do not trigger events here, because this branch only be entered
+      // from dispatchAction.
+
+    };
+
+    TooltipView.prototype._showSeriesItemTooltip = function (e, dispatcher, dispatchAction) {
+      var ecModel = this._ecModel;
+      var ecData = getECData(dispatcher); // Use dataModel in element if possible
+      // Used when mouseover on a element like markPoint or edge
+      // In which case, the data is not main data in series.
+
+      var seriesIndex = ecData.seriesIndex;
+      var seriesModel = ecModel.getSeriesByIndex(seriesIndex); // For example, graph link.
+
+      var dataModel = ecData.dataModel || seriesModel;
+      var dataIndex = ecData.dataIndex;
+      var dataType = ecData.dataType;
+      var data = dataModel.getData(dataType);
+      var renderMode = this._renderMode;
+      var positionDefault = e.positionDefault;
+      var tooltipModel = buildTooltipModel([data.getItemModel(dataIndex), dataModel, seriesModel && (seriesModel.coordinateSystem || {}).model], this._tooltipModel, positionDefault ? {
+        position: positionDefault
+      } : null);
+      var tooltipTrigger = tooltipModel.get('trigger');
+
+      if (tooltipTrigger != null && tooltipTrigger !== 'item') {
+        return;
+      }
+
+      var params = dataModel.getDataParams(dataIndex, dataType);
+      var markupStyleCreator = new TooltipMarkupStyleCreator(); // Pre-create marker style for makers. Users can assemble richText
+      // text in `formatter` callback and use those markers style.
+
+      params.marker = markupStyleCreator.makeTooltipMarker('item', convertToColorString(params.color), renderMode);
+      var seriesTooltipResult = normalizeTooltipFormatResult(dataModel.formatTooltip(dataIndex, false, dataType));
+      var orderMode = tooltipModel.get('order');
+      var valueFormatter = tooltipModel.get('valueFormatter');
+      var frag = seriesTooltipResult.frag;
+      var markupText = frag ? buildTooltipMarkup(valueFormatter ? extend({
+        valueFormatter: valueFormatter
+      }, frag) : frag, markupStyleCreator, renderMode, orderMode, ecModel.get('useUTC'), tooltipModel.get('textStyle')) : seriesTooltipResult.text;
+      var asyncTicket = 'item_' + dataModel.name + '_' + dataIndex;
+
+      this._showOrMove(tooltipModel, function () {
+        this._showTooltipContent(tooltipModel, markupText, params, asyncTicket, e.offsetX, e.offsetY, e.position, e.target, markupStyleCreator);
+      }); // FIXME
+      // duplicated showtip if manuallyShowTip is called from dispatchAction.
+
+
+      dispatchAction({
+        type: 'showTip',
+        dataIndexInside: dataIndex,
+        dataIndex: data.getRawIndex(dataIndex),
+        seriesIndex: seriesIndex,
+        from: this.uid
+      });
+    };
+
+    TooltipView.prototype._showComponentItemTooltip = function (e, el, dispatchAction) {
+      var ecData = getECData(el);
+      var tooltipConfig = ecData.tooltipConfig;
+      var tooltipOpt = tooltipConfig.option || {};
+
+      if (isString(tooltipOpt)) {
+        var content = tooltipOpt;
+        tooltipOpt = {
+          content: content,
+          // Fixed formatter
+          formatter: content
+        };
+      }
+
+      var tooltipModelCascade = [tooltipOpt];
+
+      var cmpt = this._ecModel.getComponent(ecData.componentMainType, ecData.componentIndex);
+
+      if (cmpt) {
+        tooltipModelCascade.push(cmpt);
+      } // In most cases, component tooltip formatter has different params with series tooltip formatter,
+      // so that they can not share the same formatter. Since the global tooltip formatter is used for series
+      // by convension, we do not use it as the default formatter for component.
+
+
+      tooltipModelCascade.push({
+        formatter: tooltipOpt.content
+      });
+      var positionDefault = e.positionDefault;
+      var subTooltipModel = buildTooltipModel(tooltipModelCascade, this._tooltipModel, positionDefault ? {
+        position: positionDefault
+      } : null);
+      var defaultHtml = subTooltipModel.get('content');
+      var asyncTicket = Math.random() + ''; // PENDING: this case do not support richText style yet.
+
+      var markupStyleCreator = new TooltipMarkupStyleCreator(); // Do not check whether `trigger` is 'none' here, because `trigger`
+      // only works on coordinate system. In fact, we have not found case
+      // that requires setting `trigger` nothing on component yet.
+
+      this._showOrMove(subTooltipModel, function () {
+        // Use formatterParams from element defined in component
+        // Avoid users modify it.
+        var formatterParams = clone(subTooltipModel.get('formatterParams') || {});
+
+        this._showTooltipContent(subTooltipModel, defaultHtml, formatterParams, asyncTicket, e.offsetX, e.offsetY, e.position, el, markupStyleCreator);
+      }); // If not dispatch showTip, tip may be hide triggered by axis.
+
+
+      dispatchAction({
+        type: 'showTip',
+        from: this.uid
+      });
+    };
+
+    TooltipView.prototype._showTooltipContent = function ( // Use Model<TooltipOption> insteadof TooltipModel because this model may be from series or other options.
+    // Instead of top level tooltip.
+    tooltipModel, defaultHtml, params, asyncTicket, x, y, positionExpr, el, markupStyleCreator) {
+      // Reset ticket
+      this._ticket = '';
+
+      if (!tooltipModel.get('showContent') || !tooltipModel.get('show')) {
+        return;
+      }
+
+      var tooltipContent = this._tooltipContent;
+      tooltipContent.setEnterable(tooltipModel.get('enterable'));
+      var formatter = tooltipModel.get('formatter');
+      positionExpr = positionExpr || tooltipModel.get('position');
+      var html = defaultHtml;
+
+      var nearPoint = this._getNearestPoint([x, y], params, tooltipModel.get('trigger'), tooltipModel.get('borderColor'));
+
+      var nearPointColor = nearPoint.color;
+
+      if (formatter) {
+        if (isString(formatter)) {
+          var useUTC = tooltipModel.ecModel.get('useUTC');
+          var params0 = isArray(params) ? params[0] : params;
+          var isTimeAxis = params0 && params0.axisType && params0.axisType.indexOf('time') >= 0;
+          html = formatter;
+
+          if (isTimeAxis) {
+            html = format(params0.axisValue, html, useUTC);
+          }
+
+          html = formatTpl(html, params, true);
+        } else if (isFunction(formatter)) {
+          var callback = bind(function (cbTicket, html) {
+            if (cbTicket === this._ticket) {
+              tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr);
+
+              this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el);
+            }
+          }, this);
+          this._ticket = asyncTicket;
+          html = formatter(params, asyncTicket, callback);
+        } else {
+          html = formatter;
+        }
+      }
+
+      tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr);
+      tooltipContent.show(tooltipModel, nearPointColor);
+
+      this._updatePosition(tooltipModel, positionExpr, x, y, tooltipContent, params, el);
+    };
+
+    TooltipView.prototype._getNearestPoint = function (point, tooltipDataParams, trigger, borderColor) {
+      if (trigger === 'axis' || isArray(tooltipDataParams)) {
+        return {
+          color: borderColor || (this._renderMode === 'html' ? '#fff' : 'none')
+        };
+      }
+
+      if (!isArray(tooltipDataParams)) {
+        return {
+          color: borderColor || tooltipDataParams.color || tooltipDataParams.borderColor
+        };
+      }
+    };
+
+    TooltipView.prototype._updatePosition = function (tooltipModel, positionExpr, x, // Mouse x
+    y, // Mouse y
+    content, params, el) {
+      var viewWidth = this._api.getWidth();
+
+      var viewHeight = this._api.getHeight();
+
+      positionExpr = positionExpr || tooltipModel.get('position');
+      var contentSize = content.getSize();
+      var align = tooltipModel.get('align');
+      var vAlign = tooltipModel.get('verticalAlign');
+      var rect = el && el.getBoundingRect().clone();
+      el && rect.applyTransform(el.transform);
+
+      if (isFunction(positionExpr)) {
+        // Callback of position can be an array or a string specify the position
+        positionExpr = positionExpr([x, y], params, content.el, rect, {
+          viewSize: [viewWidth, viewHeight],
+          contentSize: contentSize.slice()
+        });
+      }
+
+      if (isArray(positionExpr)) {
+        x = parsePercent$1(positionExpr[0], viewWidth);
+        y = parsePercent$1(positionExpr[1], viewHeight);
+      } else if (isObject(positionExpr)) {
+        var boxLayoutPosition = positionExpr;
+        boxLayoutPosition.width = contentSize[0];
+        boxLayoutPosition.height = contentSize[1];
+        var layoutRect = getLayoutRect(boxLayoutPosition, {
+          width: viewWidth,
+          height: viewHeight
+        });
+        x = layoutRect.x;
+        y = layoutRect.y;
+        align = null; // When positionExpr is left/top/right/bottom,
+        // align and verticalAlign will not work.
+
+        vAlign = null;
+      } // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element
+      else if (isString(positionExpr) && el) {
+          var pos = calcTooltipPosition(positionExpr, rect, contentSize, tooltipModel.get('borderWidth'));
+          x = pos[0];
+          y = pos[1];
+        } else {
+          var pos = refixTooltipPosition(x, y, content, viewWidth, viewHeight, align ? null : 20, vAlign ? null : 20);
+          x = pos[0];
+          y = pos[1];
+        }
+
+      align && (x -= isCenterAlign(align) ? contentSize[0] / 2 : align === 'right' ? contentSize[0] : 0);
+      vAlign && (y -= isCenterAlign(vAlign) ? contentSize[1] / 2 : vAlign === 'bottom' ? contentSize[1] : 0);
+
+      if (shouldTooltipConfine(tooltipModel)) {
+        var pos = confineTooltipPosition(x, y, content, viewWidth, viewHeight);
+        x = pos[0];
+        y = pos[1];
+      }
+
+      content.moveTo(x, y);
+    }; // FIXME
+    // Should we remove this but leave this to user?
+
+
+    TooltipView.prototype._updateContentNotChangedOnAxis = function (dataByCoordSys, cbParamsList) {
+      var lastCoordSys = this._lastDataByCoordSys;
+      var lastCbParamsList = this._cbParamsList;
+      var contentNotChanged = !!lastCoordSys && lastCoordSys.length === dataByCoordSys.length;
+      contentNotChanged && each(lastCoordSys, function (lastItemCoordSys, indexCoordSys) {
+        var lastDataByAxis = lastItemCoordSys.dataByAxis || [];
+        var thisItemCoordSys = dataByCoordSys[indexCoordSys] || {};
+        var thisDataByAxis = thisItemCoordSys.dataByAxis || [];
+        contentNotChanged = contentNotChanged && lastDataByAxis.length === thisDataByAxis.length;
+        contentNotChanged && each(lastDataByAxis, function (lastItem, indexAxis) {
+          var thisItem = thisDataByAxis[indexAxis] || {};
+          var lastIndices = lastItem.seriesDataIndices || [];
+          var newIndices = thisItem.seriesDataIndices || [];
+          contentNotChanged = contentNotChanged && lastItem.value === thisItem.value && lastItem.axisType === thisItem.axisType && lastItem.axisId === thisItem.axisId && lastIndices.length === newIndices.length;
+          contentNotChanged && each(lastIndices, function (lastIdxItem, j) {
+            var newIdxItem = newIndices[j];
+            contentNotChanged = contentNotChanged && lastIdxItem.seriesIndex === newIdxItem.seriesIndex && lastIdxItem.dataIndex === newIdxItem.dataIndex;
+          }); // check is cbParams data value changed
+
+          lastCbParamsList && each(lastItem.seriesDataIndices, function (idxItem) {
+            var seriesIdx = idxItem.seriesIndex;
+            var cbParams = cbParamsList[seriesIdx];
+            var lastCbParams = lastCbParamsList[seriesIdx];
+
+            if (cbParams && lastCbParams && lastCbParams.data !== cbParams.data) {
+              contentNotChanged = false;
+            }
+          });
+        });
+      });
+      this._lastDataByCoordSys = dataByCoordSys;
+      this._cbParamsList = cbParamsList;
+      return !!contentNotChanged;
+    };
+
+    TooltipView.prototype._hide = function (dispatchAction) {
+      // Do not directly hideLater here, because this behavior may be prevented
+      // in dispatchAction when showTip is dispatched.
+      // FIXME
+      // duplicated hideTip if manuallyHideTip is called from dispatchAction.
+      this._lastDataByCoordSys = null;
+      dispatchAction({
+        type: 'hideTip',
+        from: this.uid
+      });
+    };
+
+    TooltipView.prototype.dispose = function (ecModel, api) {
+      if (env.node || !api.getDom()) {
+        return;
+      }
+
+      clear(this, '_updatePosition');
+
+      this._tooltipContent.dispose();
+
+      unregister('itemTooltip', api);
+    };
+
+    TooltipView.type = 'tooltip';
+    return TooltipView;
+  }(ComponentView);
+  /**
+   * From top to bottom. (the last one should be globalTooltipModel);
+   */
+
+
+  function buildTooltipModel(modelCascade, globalTooltipModel, defaultTooltipOption) {
+    // Last is always tooltip model.
+    var ecModel = globalTooltipModel.ecModel;
+    var resultModel;
+
+    if (defaultTooltipOption) {
+      resultModel = new Model(defaultTooltipOption, ecModel, ecModel);
+      resultModel = new Model(globalTooltipModel.option, resultModel, ecModel);
+    } else {
+      resultModel = globalTooltipModel;
+    }
+
+    for (var i = modelCascade.length - 1; i >= 0; i--) {
+      var tooltipOpt = modelCascade[i];
+
+      if (tooltipOpt) {
+        if (tooltipOpt instanceof Model) {
+          tooltipOpt = tooltipOpt.get('tooltip', true);
+        } // In each data item tooltip can be simply write:
+        // {
+        //  value: 10,
+        //  tooltip: 'Something you need to know'
+        // }
+
+
+        if (isString(tooltipOpt)) {
+          tooltipOpt = {
+            formatter: tooltipOpt
+          };
+        }
+
+        if (tooltipOpt) {
+          resultModel = new Model(tooltipOpt, resultModel, ecModel);
+        }
+      }
+    }
+
+    return resultModel;
+  }
+
+  function makeDispatchAction$1(payload, api) {
+    return payload.dispatchAction || bind(api.dispatchAction, api);
+  }
+
+  function refixTooltipPosition(x, y, content, viewWidth, viewHeight, gapH, gapV) {
+    var size = content.getSize();
+    var width = size[0];
+    var height = size[1];
+
+    if (gapH != null) {
+      // Add extra 2 pixels for this case:
+      // At present the "values" in defaut tooltip are using CSS `float: right`.
+      // When the right edge of the tooltip box is on the right side of the
+      // viewport, the `float` layout might push the "values" to the second line.
+      if (x + width + gapH + 2 > viewWidth) {
+        x -= width + gapH;
+      } else {
+        x += gapH;
+      }
+    }
+
+    if (gapV != null) {
+      if (y + height + gapV > viewHeight) {
+        y -= height + gapV;
+      } else {
+        y += gapV;
+      }
+    }
+
+    return [x, y];
+  }
+
+  function confineTooltipPosition(x, y, content, viewWidth, viewHeight) {
+    var size = content.getSize();
+    var width = size[0];
+    var height = size[1];
+    x = Math.min(x + width, viewWidth) - width;
+    y = Math.min(y + height, viewHeight) - height;
+    x = Math.max(x, 0);
+    y = Math.max(y, 0);
+    return [x, y];
+  }
+
+  function calcTooltipPosition(position, rect, contentSize, borderWidth) {
+    var domWidth = contentSize[0];
+    var domHeight = contentSize[1];
+    var offset = Math.ceil(Math.SQRT2 * borderWidth) + 8;
+    var x = 0;
+    var y = 0;
+    var rectWidth = rect.width;
+    var rectHeight = rect.height;
+
+    switch (position) {
+      case 'inside':
+        x = rect.x + rectWidth / 2 - domWidth / 2;
+        y = rect.y + rectHeight / 2 - domHeight / 2;
+        break;
+
+      case 'top':
+        x = rect.x + rectWidth / 2 - domWidth / 2;
+        y = rect.y - domHeight - offset;
+        break;
+
+      case 'bottom':
+        x = rect.x + rectWidth / 2 - domWidth / 2;
+        y = rect.y + rectHeight + offset;
+        break;
+
+      case 'left':
+        x = rect.x - domWidth - offset;
+        y = rect.y + rectHeight / 2 - domHeight / 2;
+        break;
+
+      case 'right':
+        x = rect.x + rectWidth + offset;
+        y = rect.y + rectHeight / 2 - domHeight / 2;
+    }
+
+    return [x, y];
+  }
+
+  function isCenterAlign(align) {
+    return align === 'center' || align === 'middle';
+  }
+  /**
+   * Find target component by payload like:
+   * ```js
+   * { legendId: 'some_id', name: 'xxx' }
+   * { toolboxIndex: 1, name: 'xxx' }
+   * { geoName: 'some_name', name: 'xxx' }
+   * ```
+   * PENDING: at present only
+   *
+   * If not found, return null/undefined.
+   */
+
+
+  function findComponentReference(payload, ecModel, api) {
+    var queryOptionMap = preParseFinder(payload).queryOptionMap;
+    var componentMainType = queryOptionMap.keys()[0];
+
+    if (!componentMainType || componentMainType === 'series') {
+      return;
+    }
+
+    var queryResult = queryReferringComponents(ecModel, componentMainType, queryOptionMap.get(componentMainType), {
+      useDefault: false,
+      enableAll: false,
+      enableNone: false
+    });
+    var model = queryResult.models[0];
+
+    if (!model) {
+      return;
+    }
+
+    var view = api.getViewOfComponentModel(model);
+    var el;
+    view.group.traverse(function (subEl) {
+      var tooltipConfig = getECData(subEl).tooltipConfig;
+
+      if (tooltipConfig && tooltipConfig.name === payload.name) {
+        el = subEl;
+        return true; // stop
+      }
+    });
+
+    if (el) {
+      return {
+        componentMainType: componentMainType,
+        componentIndex: model.componentIndex,
+        el: el
+      };
+    }
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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 install$9(registers) {
+    use(install$10);
+    registers.registerComponentModel(TooltipModel);
+    registers.registerComponentView(TooltipView);
+    /**
+     * @action
+     * @property {string} type
+     * @property {number} seriesIndex
+     * @property {number} dataIndex
+     * @property {number} [x]
+     * @property {number} [y]
+     */
+
+    registers.registerAction({
+      type: 'showTip',
+      event: 'showTip',
+      update: 'tooltip:manuallyShowTip'
+    }, noop);
+    registers.registerAction({
+      type: 'hideTip',
+      event: 'hideTip',
+      update: 'tooltip:manuallyHideTip'
+    }, noop);
+  }
+  /*
+  * 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.
+   */
+
+  /*
+  * 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.
+  */
+
+
+  use(install$9);
+  exports.version = version;
+  exports.dependencies = dependencies;
+  exports.PRIORITY = PRIORITY;
+  exports.init = init;
+  exports.connect = connect;
+  exports.disConnect = disConnect;
+  exports.disconnect = disconnect;
+  exports.dispose = dispose;
+  exports.getInstanceByDom = getInstanceByDom;
+  exports.getInstanceById = getInstanceById;
+  exports.registerTheme = registerTheme;
+  exports.registerPreprocessor = registerPreprocessor;
+  exports.registerProcessor = registerProcessor;
+  exports.registerPostInit = registerPostInit;
+  exports.registerPostUpdate = registerPostUpdate;
+  exports.registerUpdateLifecycle = registerUpdateLifecycle;
+  exports.registerAction = registerAction;
+  exports.registerCoordinateSystem = registerCoordinateSystem;
+  exports.getCoordinateSystemDimensions = getCoordinateSystemDimensions;
+  exports.registerLayout = registerLayout;
+  exports.registerVisual = registerVisual;
+  exports.registerLoading = registerLoading;
+  exports.setCanvasCreator = setCanvasCreator;
+  exports.registerMap = registerMap;
+  exports.getMap = getMap;
+  exports.registerTransform = registerTransform;
+  exports.dataTool = dataTool;
+  exports.registerLocale = registerLocale;
+  exports.zrender = zrender;
+  exports.matrix = matrix;
+  exports.vector = vector;
+  exports.zrUtil = util;
+  exports.color = color;
+  exports.helper = helper;
+  exports.number = number;
+  exports.time = time;
+  exports.graphic = graphic$1;
+  exports.format = format$1;
+  exports.util = util$1;
+  exports.List = SeriesData;
+  exports.ComponentModel = ComponentModel;
+  exports.ComponentView = ComponentView;
+  exports.SeriesModel = SeriesModel;
+  exports.ChartView = ChartView;
+  exports.extendComponentModel = extendComponentModel;
+  exports.extendComponentView = extendComponentView;
+  exports.extendSeriesModel = extendSeriesModel;
+  exports.extendChartView = extendChartView;
+  exports.throttle = throttle;
+  exports.use = use;
+  exports.setPlatformAPI = setPlatformAPI;
+  exports.parseGeoJSON = parseGeoJSON;
+  exports.parseGeoJson = parseGeoJSON;
+  exports.env = env;
+  exports.Model = Model;
+  exports.Axis = Axis;
+  exports.innerDrawElementOnCanvas = brushSingle;
+});
\ No newline at end of file
diff --git a/plugins/echarts/index.js b/plugins/echarts/index.js
new file mode 100644
index 0000000..aaa3f3f
--- /dev/null
+++ b/plugins/echarts/index.js
@@ -0,0 +1,10 @@
+/**
+ * qrcode
+ * @author Tevin
+ */
+
+import CECharts from '@components/plugins/echarts/CECharts';
+
+export {
+    CECharts
+}
\ No newline at end of file
diff --git a/plugins/echarts/wxCanvas.js b/plugins/echarts/wxCanvas.js
new file mode 100644
index 0000000..6c7c90b
--- /dev/null
+++ b/plugins/echarts/wxCanvas.js
@@ -0,0 +1,111 @@
+export default class WxCanvas {
+  constructor(ctx, canvasId, isNew, canvasNode) {
+    this.ctx = ctx;
+    this.canvasId = canvasId;
+    this.chart = null;
+    this.isNew = isNew
+    if (isNew) {
+      this.canvasNode = canvasNode;
+    }
+    else {
+      this._initStyle(ctx);
+    }
+
+    // this._initCanvas(zrender, ctx);
+
+    this._initEvent();
+  }
+
+  getContext(contextType) {
+    if (contextType === '2d') {
+      return this.ctx;
+    }
+  }
+
+  // canvasToTempFilePath(opt) {
+  //   if (!opt.canvasId) {
+  //     opt.canvasId = this.canvasId;
+  //   }
+  //   return wx.canvasToTempFilePath(opt, this);
+  // }
+
+  setChart(chart) {
+    this.chart = chart;
+  }
+
+  addEventListener() {
+    // noop
+  }
+
+  attachEvent() {
+    // noop
+  }
+
+  detachEvent() {
+    // noop
+  }
+
+  _initCanvas(zrender, ctx) {
+    zrender.util.getContext = function () {
+      return ctx;
+    };
+
+    zrender.util.$override('measureText', function (text, font) {
+      ctx.font = font || '12px sans-serif';
+      return ctx.measureText(text);
+    });
+  }
+
+  _initStyle(ctx) {
+    ctx.createRadialGradient = () => {
+      return ctx.createCircularGradient(arguments);
+    };
+  }
+
+  _initEvent() {
+    this.event = {};
+    const eventNames = [{
+      wxName: 'touchStart',
+      ecName: 'mousedown'
+    }, {
+      wxName: 'touchMove',
+      ecName: 'mousemove'
+    }, {
+      wxName: 'touchEnd',
+      ecName: 'mouseup'
+    }, {
+      wxName: 'touchEnd',
+      ecName: 'click'
+    }];
+    eventNames.forEach(name => {
+      this.event[name.wxName] = e => {
+        const touch = e.touches[0];
+        this.chart.getZr().handler.dispatch(name.ecName, {
+          zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
+          zrY: name.wxName === 'tap' ? touch.clientY : touch.y,
+          preventDefault: () => {},
+          stopImmediatePropagation: () => {},
+          stopPropagation: () => {}
+        });
+      };
+    });
+  }
+
+  set width(w) {
+    if (this.canvasNode) this.canvasNode.width = w
+  }
+  set height(h) {
+    if (this.canvasNode) this.canvasNode.height = h
+  }
+
+  get width() {
+    if (this.canvasNode)
+      return this.canvasNode.width
+    return 0
+  }
+  get height() {
+    if (this.canvasNode)
+      return this.canvasNode.height
+    return 0
+  }
+}

--
Gitblit v1.9.1