You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2020/10/26 11:49:48 UTC

[incubator-echarts] branch next updated (d081f84 -> 3e7bdc3)

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

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


    from d081f84  fix(sunburst): fix label show not work bug.
     new 530ae3c  release: 5.0.0-beta.2
     new 3564230  Merge branch 'next' of github.com:apache/incubator-echarts into next
     new 3e7bdc3  rebuild: 5.0.0-beta.2

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


Summary of changes:
 dist/echarts.common.js                   | 14373 +++++++++++++-----------
 dist/echarts.common.js.map               |     2 +-
 dist/echarts.common.min.js               |     2 +-
 dist/echarts.js                          | 17051 +++++++++++++++++------------
 dist/echarts.js.map                      |     2 +-
 dist/echarts.min.js                      |     2 +-
 dist/echarts.simple.js                   | 12479 +++++++++++----------
 dist/echarts.simple.js.map               |     2 +-
 dist/echarts.simple.min.js               |     2 +-
 src/i18n/langJA.ts => i18n/langJA-obj.js |    33 +-
 src/i18n/langJA.ts => i18n/langJA.js     |    29 +-
 package-lock.json                        |  1759 ++-
 package.json                             |     4 +-
 src/echarts.ts                           |     4 +-
 14 files changed, 26386 insertions(+), 19358 deletions(-)
 copy src/i18n/langJA.ts => i18n/langJA-obj.js (88%)
 copy src/i18n/langJA.ts => i18n/langJA.js (88%)


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


[incubator-echarts] 02/03: Merge branch 'next' of github.com:apache/incubator-echarts into next

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

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

commit 3564230656471d37e782582590cfe73c60f38c6b
Merge: 530ae3c d081f84
Author: 100pah <su...@gmail.com>
AuthorDate: Mon Oct 26 19:35:20 2020 +0800

    Merge branch 'next' of github.com:apache/incubator-echarts into next

 src/chart/sunburst/SunburstPiece.ts | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)


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


[incubator-echarts] 01/03: release: 5.0.0-beta.2

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

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

commit 530ae3ccfdb5dcdec2d84d2dfa53d94804fba009
Author: 100pah <su...@gmail.com>
AuthorDate: Mon Oct 26 15:25:33 2020 +0800

    release: 5.0.0-beta.2
---
 dist/echarts.common.js     | 14373 ++++++++++++++++++++----------------
 dist/echarts.common.js.map |     2 +-
 dist/echarts.common.min.js |     2 +-
 dist/echarts.js            | 17040 +++++++++++++++++++++++++------------------
 dist/echarts.js.map        |     2 +-
 dist/echarts.min.js        |     2 +-
 dist/echarts.simple.js     | 12479 +++++++++++++++++--------------
 dist/echarts.simple.js.map |     2 +-
 dist/echarts.simple.min.js |     2 +-
 i18n/langJA-obj.js         |   173 +
 i18n/langJA.js             |   169 +
 package-lock.json          |  1759 ++++-
 package.json               |     4 +-
 src/echarts.ts             |     4 +-
 14 files changed, 26659 insertions(+), 19354 deletions(-)

diff --git a/dist/echarts.common.js b/dist/echarts.common.js
index 90d1eab..a893b34 100644
--- a/dist/echarts.common.js
+++ b/dist/echarts.common.js
@@ -1862,2110 +1862,1646 @@
     return x < 0 || x > painter.getWidth() || y < 0 || y > painter.getHeight();
   }
 
-  var DEFAULT_MIN_MERGE = 32;
-  var DEFAULT_MIN_GALLOPING = 7;
+  function create$1() {
+    return [1, 0, 0, 1, 0, 0];
+  }
 
-  function minRunLength(n) {
-    var r = 0;
+  function identity(out) {
+    out[0] = 1;
+    out[1] = 0;
+    out[2] = 0;
+    out[3] = 1;
+    out[4] = 0;
+    out[5] = 0;
+    return out;
+  }
 
-    while (n >= DEFAULT_MIN_MERGE) {
-      r |= n & 1;
-      n >>= 1;
-    }
+  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;
+  }
 
-    return n + r;
+  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 makeAscendingRun(array, lo, hi, compare) {
-    var runHi = lo + 1;
+  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;
+  }
 
-    if (runHi === hi) {
-      return 1;
-    }
+  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;
+  }
 
-    if (compare(array[runHi++], array[lo]) < 0) {
-      while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
-        runHi++;
-      }
+  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;
+  }
 
-      reverseRun(array, lo, runHi);
-    } else {
-      while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
-        runHi++;
-      }
+  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;
     }
 
-    return runHi - lo;
+    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 reverseRun(array, lo, hi) {
-    hi--;
-
-    while (lo < hi) {
-      var t = array[lo];
-      array[lo++] = array[hi];
-      array[hi--] = t;
-    }
+  function clone$2(a) {
+    var b = create$1();
+    copy$1(b, a);
+    return b;
   }
 
-  function binaryInsertionSort(array, lo, hi, start, compare) {
-    if (start === lo) {
-      start++;
-    }
+  var matrix = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    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 = 5e-5;
 
-    for (; start < hi; start++) {
-      var pivot = array[start];
-      var left = lo;
-      var right = start;
-      var mid;
+  function isNotAroundZero(val) {
+    return val > EPSILON || val < -EPSILON;
+  }
 
-      while (left < right) {
-        mid = left + right >>> 1;
+  var scaleTmp = [];
+  var tmpTransform = [];
+  var originTransform = create$1();
+  var abs = Math.abs;
 
-        if (compare(pivot, array[mid]) < 0) {
-          right = mid;
-        } else {
-          left = mid + 1;
-        }
-      }
+  var Transformable = function () {
+    function Transformable() {}
 
-      var n = start - left;
+    Transformable.prototype.setPosition = function (arr) {
+      this.x = arr[0];
+      this.y = arr[1];
+    };
 
-      switch (n) {
-        case 3:
-          array[left + 3] = array[left + 2];
+    Transformable.prototype.setScale = function (arr) {
+      this.scaleX = arr[0];
+      this.scaleY = arr[1];
+    };
 
-        case 2:
-          array[left + 2] = array[left + 1];
+    Transformable.prototype.setOrigin = function (arr) {
+      this.originX = arr[0];
+      this.originY = arr[1];
+    };
 
-        case 1:
-          array[left + 1] = array[left];
-          break;
+    Transformable.prototype.needLocalTransform = function () {
+      return isNotAroundZero(this.rotation) || isNotAroundZero(this.x) || isNotAroundZero(this.y) || isNotAroundZero(this.scaleX - 1) || isNotAroundZero(this.scaleY - 1);
+    };
 
-        default:
-          while (n > 0) {
-            array[left + n] = array[left + n - 1];
-            n--;
-          }
+    Transformable.prototype.updateTransform = function () {
+      var parent = this.parent;
+      var parentHasTransform = parent && parent.transform;
+      var needLocalTransform = this.needLocalTransform();
+      var m = this.transform;
 
+      if (!(needLocalTransform || parentHasTransform)) {
+        m && mIdentity(m);
+        return;
       }
 
-      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;
+      m = m || create$1();
 
-        if (offset <= 0) {
-          offset = maxOffset;
-        }
+      if (needLocalTransform) {
+        this.getLocalTransform(m);
+      } else {
+        mIdentity(m);
       }
 
-      if (offset > maxOffset) {
-        offset = maxOffset;
+      if (parentHasTransform) {
+        if (needLocalTransform) {
+          mul$1(m, parent.transform, m);
+        } else {
+          copy$1(m, parent.transform);
+        }
       }
 
-      lastOffset += hint;
-      offset += hint;
-    } else {
-      maxOffset = hint + 1;
+      this.transform = m;
 
-      while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
-        lastOffset = offset;
-        offset = (offset << 1) + 1;
+      this._resolveGlobalScaleRatio(m);
+    };
 
-        if (offset <= 0) {
-          offset = maxOffset;
-        }
-      }
+    Transformable.prototype._resolveGlobalScaleRatio = function (m) {
+      var globalScaleRatio = this.globalScaleRatio;
 
-      if (offset > maxOffset) {
-        offset = maxOffset;
+      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;
       }
 
-      var tmp = lastOffset;
-      lastOffset = hint - offset;
-      offset = hint - tmp;
-    }
+      this.invTransform = this.invTransform || create$1();
+      invert(this.invTransform, m);
+    };
 
-    lastOffset++;
+    Transformable.prototype.getLocalTransform = function (m) {
+      return Transformable.getLocalTransform(this, m);
+    };
 
-    while (lastOffset < offset) {
-      var m = lastOffset + (offset - lastOffset >>> 1);
+    Transformable.prototype.getComputedTransform = function () {
+      var transformNode = this;
+      var ancestors = [];
 
-      if (compare(value, array[start + m]) > 0) {
-        lastOffset = m + 1;
-      } else {
-        offset = m;
+      while (transformNode) {
+        ancestors.push(transformNode);
+        transformNode = transformNode.parent;
       }
-    }
 
-    return offset;
-  }
+      while (transformNode = ancestors.pop()) {
+        transformNode.updateTransform();
+      }
 
-  function gallopRight(value, array, start, length, hint, compare) {
-    var lastOffset = 0;
-    var maxOffset = 0;
-    var offset = 1;
+      return this.transform;
+    };
 
-    if (compare(value, array[start + hint]) < 0) {
-      maxOffset = hint + 1;
+    Transformable.prototype.setLocalTransform = function (m) {
+      if (!m) {
+        return;
+      }
 
-      while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
-        lastOffset = offset;
-        offset = (offset << 1) + 1;
+      var sx = m[0] * m[0] + m[1] * m[1];
+      var sy = m[2] * m[2] + m[3] * m[3];
 
-        if (offset <= 0) {
-          offset = maxOffset;
-        }
+      if (isNotAroundZero(sx - 1)) {
+        sx = Math.sqrt(sx);
       }
 
-      if (offset > maxOffset) {
-        offset = maxOffset;
+      if (isNotAroundZero(sy - 1)) {
+        sy = Math.sqrt(sy);
       }
 
-      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;
+      this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);
 
-        if (offset <= 0) {
-          offset = maxOffset;
-        }
+      if (m[0] < 0) {
+        sx = -sx;
       }
 
-      if (offset > maxOffset) {
-        offset = maxOffset;
+      if (m[3] < 0) {
+        sy = -sy;
       }
 
-      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;
+      if (sx < 0 && sy < 0) {
+        this.rotation += Math.PI;
+        sx = -sx;
+        sy = -sy;
       }
-    }
 
-    return offset;
-  }
+      this.x = m[4];
+      this.y = m[5];
+      this.scaleX = sx;
+      this.scaleY = sy;
+    };
 
-  function TimSort(array, compare) {
-    var minGallop = DEFAULT_MIN_GALLOPING;
-    var length = 0;
-    var runStart;
-    var runLength;
-    var stackSize = 0;
-    length = array.length;
-    var tmp = [];
-    runStart = [];
-    runLength = [];
+    Transformable.prototype.decomposeTransform = function () {
+      if (!this.transform) {
+        return;
+      }
 
-    function pushRun(_runStart, _runLength) {
-      runStart[stackSize] = _runStart;
-      runLength[stackSize] = _runLength;
-      stackSize += 1;
-    }
+      var parent = this.parent;
+      var m = this.transform;
 
-    function mergeRuns() {
-      while (stackSize > 1) {
-        var n = stackSize - 2;
+      if (parent && parent.transform) {
+        mul$1(tmpTransform, parent.invTransform, m);
+        m = tmpTransform;
+      }
 
-        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;
-        }
+      var ox = this.originX;
+      var oy = this.originY;
 
-        mergeAt(n);
+      if (ox || oy) {
+        originTransform[4] = ox;
+        originTransform[5] = oy;
+        mul$1(tmpTransform, m, originTransform);
+        tmpTransform[4] -= ox;
+        tmpTransform[5] -= oy;
+        m = tmpTransform;
       }
-    }
 
-    function forceMergeRuns() {
-      while (stackSize > 1) {
-        var n = stackSize - 2;
+      this.setLocalTransform(m);
+    };
 
-        if (n > 0 && runLength[n - 1] < runLength[n + 1]) {
-          n--;
-        }
+    Transformable.prototype.getGlobalScale = function (out) {
+      var m = this.transform;
+      out = out || [];
 
-        mergeAt(n);
+      if (!m) {
+        out[0] = 1;
+        out[1] = 1;
+        return out;
       }
-    }
 
-    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;
+      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 (i === stackSize - 3) {
-        runStart[i + 1] = runStart[i + 2];
-        runLength[i + 1] = runLength[i + 2];
+      if (m[0] < 0) {
+        out[0] = -out[0];
       }
 
-      stackSize--;
-      var k = gallopRight(array[start2], array, start1, length1, 0, compare);
-      start1 += k;
-      length1 -= k;
-
-      if (length1 === 0) {
-        return;
+      if (m[3] < 0) {
+        out[1] = -out[1];
       }
 
-      length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
+      return out;
+    };
 
-      if (length2 === 0) {
-        return;
-      }
+    Transformable.prototype.transformCoordToLocal = function (x, y) {
+      var v2 = [x, y];
+      var invTransform = this.invTransform;
 
-      if (length1 <= length2) {
-        mergeLow(start1, length1, start2, length2);
-      } else {
-        mergeHigh(start1, length1, start2, length2);
+      if (invTransform) {
+        applyTransform(v2, v2, invTransform);
       }
-    }
 
-    function mergeLow(start1, length1, start2, length2) {
-      var i = 0;
+      return v2;
+    };
 
-      for (i = 0; i < length1; i++) {
-        tmp[i] = array[start1 + i];
+    Transformable.prototype.transformCoordToGlobal = function (x, y) {
+      var v2 = [x, y];
+      var transform = this.transform;
+
+      if (transform) {
+        applyTransform(v2, v2, transform);
       }
 
-      var cursor1 = 0;
-      var cursor2 = start2;
-      var dest = start1;
-      array[dest++] = array[cursor2++];
+      return v2;
+    };
 
-      if (--length2 === 0) {
-        for (i = 0; i < length1; i++) {
-          array[dest + i] = tmp[cursor1 + i];
-        }
+    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;
+    };
 
-        return;
+    Transformable.getLocalTransform = function (target, m) {
+      m = m || [];
+      mIdentity(m);
+      var ox = target.originX || 0;
+      var oy = target.originY || 0;
+      var sx = target.scaleX;
+      var sy = target.scaleY;
+      var rotation = target.rotation || 0;
+      var x = target.x;
+      var y = target.y;
+      m[4] -= ox;
+      m[5] -= oy;
+      m[0] *= sx;
+      m[1] *= sy;
+      m[2] *= sx;
+      m[3] *= sy;
+      m[4] *= sx;
+      m[5] *= sy;
+
+      if (rotation) {
+        rotate(m, m, rotation);
       }
 
-      if (length1 === 1) {
-        for (i = 0; i < length2; i++) {
-          array[dest + i] = array[cursor2 + i];
-        }
+      m[4] += ox;
+      m[5] += oy;
+      m[4] += x;
+      m[5] += y;
+      return m;
+    };
 
-        array[dest + length2] = tmp[cursor1];
-        return;
-      }
+    Transformable.initDefaultProps = function () {
+      var proto = Transformable.prototype;
+      proto.x = 0;
+      proto.y = 0;
+      proto.scaleX = 1;
+      proto.scaleY = 1;
+      proto.originX = 0;
+      proto.originY = 0;
+      proto.rotation = 0;
+      proto.globalScaleRatio = 1;
+    }();
 
-      var _minGallop = minGallop;
-      var count1;
-      var count2;
-      var exit;
+    return Transformable;
+  }();
 
-      while (1) {
-        count1 = 0;
-        count2 = 0;
-        exit = false;
+  var easing = {
+    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;
+      }
 
-        do {
-          if (compare(array[cursor2], tmp[cursor1]) < 0) {
-            array[dest++] = array[cursor2++];
-            count2++;
-            count1 = 0;
+      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;
+      }
 
-            if (--length2 === 0) {
-              exit = true;
-              break;
-            }
-          } else {
-            array[dest++] = tmp[cursor1++];
-            count1++;
-            count2 = 0;
+      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;
+      }
 
-            if (--length1 === 1) {
-              exit = true;
-              break;
-            }
-          }
-        } while ((count1 | count2) < _minGallop);
+      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;
+      }
 
-        if (exit) {
-          break;
-        }
+      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;
+      }
 
-        do {
-          count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
+      if (k === 1) {
+        return 1;
+      }
 
-          if (count1 !== 0) {
-            for (i = 0; i < count1; i++) {
-              array[dest + i] = tmp[cursor1 + i];
-            }
+      if ((k *= 2) < 1) {
+        return 0.5 * Math.pow(1024, k - 1);
+      }
 
-            dest += count1;
-            cursor1 += count1;
-            length1 -= count1;
+      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);
+      }
 
-            if (length1 <= 1) {
-              exit = true;
-              break;
-            }
-          }
+      return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
+    },
+    elasticIn: function (k) {
+      var s;
+      var a = 0.1;
+      var p = 0.4;
 
-          array[dest++] = array[cursor2++];
+      if (k === 0) {
+        return 0;
+      }
 
-          if (--length2 === 0) {
-            exit = true;
-            break;
-          }
+      if (k === 1) {
+        return 1;
+      }
 
-          count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
+      if (!a || a < 1) {
+        a = 1;
+        s = p / 4;
+      } else {
+        s = p * Math.asin(1 / a) / (2 * Math.PI);
+      }
 
-          if (count2 !== 0) {
-            for (i = 0; i < count2; i++) {
-              array[dest + i] = array[cursor2 + i];
-            }
+      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;
 
-            dest += count2;
-            cursor2 += count2;
-            length2 -= count2;
+      if (k === 0) {
+        return 0;
+      }
 
-            if (length2 === 0) {
-              exit = true;
-              break;
-            }
-          }
+      if (k === 1) {
+        return 1;
+      }
 
-          array[dest++] = tmp[cursor1++];
+      if (!a || a < 1) {
+        a = 1;
+        s = p / 4;
+      } else {
+        s = p * Math.asin(1 / a) / (2 * Math.PI);
+      }
 
-          if (--length1 === 1) {
-            exit = true;
-            break;
-          }
+      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;
 
-          _minGallop--;
-        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
+      if (k === 0) {
+        return 0;
+      }
 
-        if (exit) {
-          break;
-        }
+      if (k === 1) {
+        return 1;
+      }
 
-        if (_minGallop < 0) {
-          _minGallop = 0;
-        }
+      if (!a || a < 1) {
+        a = 1;
+        s = p / 4;
+      } else {
+        s = p * Math.asin(1 / a) / (2 * Math.PI);
+      }
 
-        _minGallop += 2;
+      if ((k *= 2) < 1) {
+        return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
       }
 
-      minGallop = _minGallop;
-      minGallop < 1 && (minGallop = 1);
+      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 (length1 === 1) {
-        for (i = 0; i < length2; i++) {
-          array[dest + i] = array[cursor2 + i];
-        }
+      if ((k *= 2) < 1) {
+        return 0.5 * (k * k * ((s + 1) * k - s));
+      }
 
-        array[dest + length2] = tmp[cursor1];
-      } else if (length1 === 0) {
-        throw new Error();
+      return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
+    },
+    bounceIn: function (k) {
+      return 1 - easing.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 {
-        for (i = 0; i < length1; i++) {
-          array[dest + i] = tmp[cursor1 + i];
-        }
+        return 7.5625 * (k -= 2.625 / 2.75) * k + 0.984375;
       }
-    }
-
-    function mergeHigh(start1, length1, start2, length2) {
-      var i = 0;
-
-      for (i = 0; i < length2; i++) {
-        tmp[i] = array[start2 + i];
+    },
+    bounceInOut: function (k) {
+      if (k < 0.5) {
+        return easing.bounceIn(k * 2) * 0.5;
       }
 
-      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);
+      return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
+    }
+  };
 
-        for (i = 0; i < length2; i++) {
-          array[customCursor + i] = tmp[i];
-        }
+  var Clip = function () {
+    function Clip(opts) {
+      this._initialized = false;
+      this._startTime = 0;
+      this._pausedTime = 0;
+      this._paused = false;
+      this._life = opts.life || 1000;
+      this._delay = opts.delay || 0;
+      this.loop = opts.loop == null ? false : opts.loop;
+      this.gap = opts.gap || 0;
+      this.easing = opts.easing || 'linear';
+      this.onframe = opts.onframe;
+      this.ondestroy = opts.ondestroy;
+      this.onrestart = opts.onrestart;
+    }
 
-        return;
+    Clip.prototype.step = function (globalTime, deltaTime) {
+      if (!this._initialized) {
+        this._startTime = globalTime + this._delay;
+        this._initialized = true;
       }
 
-      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];
+      if (this._paused) {
+        this._pausedTime += deltaTime;
         return;
       }
 
-      var _minGallop = minGallop;
-
-      while (true) {
-        var count1 = 0;
-        var count2 = 0;
-        var exit = false;
+      var percent = (globalTime - this._startTime - this._pausedTime) / this._life;
 
-        do {
-          if (compare(tmp[cursor2], array[cursor1]) < 0) {
-            array[dest--] = array[cursor1--];
-            count1++;
-            count2 = 0;
+      if (percent < 0) {
+        percent = 0;
+      }
 
-            if (--length1 === 0) {
-              exit = true;
-              break;
-            }
-          } else {
-            array[dest--] = tmp[cursor2--];
-            count2++;
-            count1 = 0;
+      percent = Math.min(percent, 1);
+      var easing$1 = this.easing;
+      var easingFunc = typeof easing$1 === 'string' ? easing[easing$1] : easing$1;
+      var schedule = typeof easingFunc === 'function' ? easingFunc(percent) : percent;
+      this.onframe && this.onframe(schedule);
 
-            if (--length2 === 1) {
-              exit = true;
-              break;
-            }
-          }
-        } while ((count1 | count2) < _minGallop);
+      if (percent === 1) {
+        if (this.loop) {
+          this._restart(globalTime);
 
-        if (exit) {
-          break;
+          this.onrestart && this.onrestart();
+        } else {
+          return true;
         }
+      }
 
-        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;
-            }
-          }
+      return false;
+    };
 
-          array[dest--] = tmp[cursor2--];
+    Clip.prototype._restart = function (globalTime) {
+      var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;
+      this._startTime = globalTime - remainder + this.gap;
+      this._pausedTime = 0;
+    };
 
-          if (--length2 === 1) {
-            exit = true;
-            break;
-          }
+    Clip.prototype.pause = function () {
+      this._paused = true;
+    };
 
-          count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
+    Clip.prototype.resume = function () {
+      this._paused = false;
+    };
 
-          if (count2 !== 0) {
-            dest -= count2;
-            cursor2 -= count2;
-            length2 -= count2;
-            customDest = dest + 1;
-            customCursor = cursor2 + 1;
+    return Clip;
+  }();
 
-            for (i = 0; i < count2; i++) {
-              array[customDest + i] = tmp[customCursor + i];
-            }
+  var Entry = function () {
+    function Entry(val) {
+      this.value = val;
+    }
 
-            if (length2 <= 1) {
-              exit = true;
-              break;
-            }
-          }
+    return Entry;
+  }();
 
-          array[dest--] = array[cursor1--];
+  var LinkedList = function () {
+    function LinkedList() {
+      this._len = 0;
+    }
 
-          if (--length1 === 0) {
-            exit = true;
-            break;
-          }
+    LinkedList.prototype.insert = function (val) {
+      var entry = new Entry(val);
+      this.insertEntry(entry);
+      return entry;
+    };
 
-          _minGallop--;
-        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
+    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;
+      }
 
-        if (exit) {
-          break;
-        }
+      this._len++;
+    };
 
-        if (_minGallop < 0) {
-          _minGallop = 0;
-        }
+    LinkedList.prototype.remove = function (entry) {
+      var prev = entry.prev;
+      var next = entry.next;
 
-        _minGallop += 2;
+      if (prev) {
+        prev.next = next;
+      } else {
+        this.head = next;
       }
 
-      minGallop = _minGallop;
-
-      if (minGallop < 1) {
-        minGallop = 1;
+      if (next) {
+        next.prev = prev;
+      } else {
+        this.tail = prev;
       }
 
-      if (length2 === 1) {
-        dest -= length1;
-        cursor1 -= length1;
-        customDest = dest + 1;
-        customCursor = cursor1 + 1;
+      entry.next = entry.prev = null;
+      this._len--;
+    };
 
-        for (i = length1 - 1; i >= 0; i--) {
-          array[customDest + i] = array[customCursor + i];
-        }
+    LinkedList.prototype.len = function () {
+      return this._len;
+    };
 
-        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
+    LinkedList.prototype.clear = function () {
+      this.head = this.tail = null;
+      this._len = 0;
     };
-  }
 
-  function sort(array, compare, lo, hi) {
-    if (!lo) {
-      lo = 0;
-    }
+    return LinkedList;
+  }();
 
-    if (!hi) {
-      hi = array.length;
+  var LRU = function () {
+    function LRU(maxSize) {
+      this._list = new LinkedList();
+      this._maxSize = 10;
+      this._map = {};
+      this._maxSize = maxSize;
     }
 
-    var remaining = hi - lo;
+    LRU.prototype.put = function (key, value) {
+      var list = this._list;
+      var map = this._map;
+      var removed = null;
 
-    if (remaining < 2) {
-      return;
-    }
+      if (map[key] == null) {
+        var len = list.len();
+        var entry = this._lastRemovedEntry;
 
-    var runLength = 0;
+        if (len >= this._maxSize && len > 0) {
+          var leastUsedEntry = list.head;
+          list.remove(leastUsedEntry);
+          delete map[leastUsedEntry.key];
+          removed = leastUsedEntry.value;
+          this._lastRemovedEntry = leastUsedEntry;
+        }
 
-    if (remaining < DEFAULT_MIN_MERGE) {
-      runLength = makeAscendingRun(array, lo, hi, compare);
-      binaryInsertionSort(array, lo, hi, lo + runLength, compare);
-      return;
-    }
+        if (entry) {
+          entry.value = value;
+        } else {
+          entry = new Entry(value);
+        }
 
-    var ts = TimSort(array, compare);
-    var minRun = minRunLength(remaining);
+        entry.key = key;
+        list.insertEntry(entry);
+        map[key] = entry;
+      }
 
-    do {
-      runLength = makeAscendingRun(array, lo, hi, compare);
+      return removed;
+    };
 
-      if (runLength < minRun) {
-        var force = remaining;
+    LRU.prototype.get = function (key) {
+      var entry = this._map[key];
+      var list = this._list;
 
-        if (force > minRun) {
-          force = minRun;
+      if (entry != null) {
+        if (entry !== list.tail) {
+          list.remove(entry);
+          list.insertEntry(entry);
         }
 
-        binaryInsertionSort(array, lo, lo + force, lo + runLength, compare);
-        runLength = force;
+        return entry.value;
       }
+    };
 
-      ts.pushRun(lo, runLength);
-      ts.mergeRuns();
-      remaining -= runLength;
-      lo += runLength;
-    } while (remaining !== 0);
+    LRU.prototype.clear = function () {
+      this._list.clear();
 
-    ts.forceMergeRuns();
+      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;
   }
 
-  var invalidZErrorLogged = false;
+  function clampCssAngle(i) {
+    i = Math.round(i);
+    return i < 0 ? 0 : i > 360 ? 360 : i;
+  }
 
-  function logInvalidZError() {
-    if (invalidZErrorLogged) {
-      return;
+  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);
     }
 
-    invalidZErrorLogged = true;
-    console.warn('z / z2 / zlevel of displayable is invalid, which may cause unexpected errors');
+    return clampCssByte(parseInt(str, 10));
   }
 
-  function shapeCompareFunc(a, b) {
-    if (a.zlevel === b.zlevel) {
-      if (a.z === b.z) {
-        return a.z2 - b.z2;
-      }
+  function parseCssFloat(val) {
+    var str = val;
 
-      return a.z - b.z;
+    if (str.length && str.charAt(str.length - 1) === '%') {
+      return clampCssFloat(parseFloat(str) / 100);
     }
 
-    return a.zlevel - b.zlevel;
+    return clampCssFloat(parseFloat(str));
   }
 
-  var Storage = function () {
-    function Storage() {
-      this._roots = [];
-      this._displayList = [];
-      this._displayListLen = 0;
-      this.displayableSortFunc = shapeCompareFunc;
+  function cssHueToRgb(m1, m2, h) {
+    if (h < 0) {
+      h += 1;
+    } else if (h > 1) {
+      h -= 1;
     }
 
-    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 (h * 6 < 1) {
+      return m1 + (m2 - m1) * h * 6;
+    }
 
-      if (update || !displayList.length) {
-        this.updateDisplayList(includeIgnore);
-      }
+    if (h * 2 < 1) {
+      return m2;
+    }
 
-      return displayList;
-    };
+    if (h * 3 < 2) {
+      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
+    }
 
-    Storage.prototype.updateDisplayList = function (includeIgnore) {
-      this._displayListLen = 0;
-      var roots = this._roots;
-      var displayList = this._displayList;
+    return m1;
+  }
 
-      for (var i = 0, len = roots.length; i < len; i++) {
-        this._updateAndAddDisplayable(roots[i], null, includeIgnore);
-      }
+  function lerpNumber(a, b, p) {
+    return a + (b - a) * p;
+  }
 
-      displayList.length = this._displayListLen;
-      env.canvasSupported && sort(displayList, shapeCompareFunc);
-    };
+  function setRgba(out, r, g, b, a) {
+    out[0] = r;
+    out[1] = g;
+    out[2] = b;
+    out[3] = a;
+    return out;
+  }
 
-    Storage.prototype._updateAndAddDisplayable = function (el, clipPaths, includeIgnore) {
-      if (el.ignore && !includeIgnore) {
-        return;
-      }
+  function copyRgba(out, a) {
+    out[0] = a[0];
+    out[1] = a[1];
+    out[2] = a[2];
+    out[3] = a[3];
+    return out;
+  }
 
-      el.beforeUpdate();
-      el.update();
-      el.afterUpdate();
-      var userSetClipPath = el.getClipPath();
+  var colorCache = new LRU(20);
+  var lastRemovedArr = null;
 
-      if (el.ignoreClip) {
-        clipPaths = null;
-      } else if (userSetClipPath) {
-        if (clipPaths) {
-          clipPaths = clipPaths.slice();
-        } else {
-          clipPaths = [];
-        }
+  function putToCache(colorStr, rgbaArr) {
+    if (lastRemovedArr) {
+      copyRgba(lastRemovedArr, rgbaArr);
+    }
 
-        var currentClipPath = userSetClipPath;
-        var parentClipPath = el;
+    lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || rgbaArr.slice());
+  }
 
-        while (currentClipPath) {
-          currentClipPath.parent = parentClipPath;
-          currentClipPath.updateTransform();
-          clipPaths.push(currentClipPath);
-          parentClipPath = currentClipPath;
-          currentClipPath = currentClipPath.getClipPath();
-        }
-      }
+  function parse(colorStr, rgbaArr) {
+    if (!colorStr) {
+      return;
+    }
 
-      if (el.childrenRef) {
-        var children = el.childrenRef();
+    rgbaArr = rgbaArr || [];
+    var cached = colorCache.get(colorStr);
 
-        for (var i = 0; i < children.length; i++) {
-          var child = children[i];
+    if (cached) {
+      return copyRgba(rgbaArr, cached);
+    }
 
-          if (el.__dirty) {
-            child.markRedraw();
-          }
+    colorStr = colorStr + '';
+    var str = colorStr.replace(/ /g, '').toLowerCase();
 
-          this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
-        }
+    if (str in kCSSColorTable) {
+      copyRgba(rgbaArr, kCSSColorTable[str]);
+      putToCache(colorStr, rgbaArr);
+      return rgbaArr;
+    }
 
-        el.__dirty = 0;
-      } else {
-        var disp = el;
+    var strLen = str.length;
 
-        if (clipPaths && clipPaths.length) {
-          disp.__clipPaths = clipPaths;
-        } else if (disp.__clipPaths && disp.__clipPaths.length > 0) {
-          disp.__clipPaths = [];
-        }
+    if (str.charAt(0) === '#') {
+      if (strLen === 4 || strLen === 5) {
+        var iv = parseInt(str.slice(1, 4), 16);
 
-        if (isNaN(disp.z)) {
-          logInvalidZError();
-          disp.z = 0;
+        if (!(iv >= 0 && iv <= 0xfff)) {
+          setRgba(rgbaArr, 0, 0, 0, 1);
+          return;
         }
 
-        if (isNaN(disp.z2)) {
-          logInvalidZError();
-          disp.z2 = 0;
-        }
+        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 (isNaN(disp.zlevel)) {
-          logInvalidZError();
-          disp.zlevel = 0;
+        if (!(iv >= 0 && iv <= 0xffffff)) {
+          setRgba(rgbaArr, 0, 0, 0, 1);
+          return;
         }
 
-        this._displayList[this._displayListLen++] = disp;
+        setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, strLen === 9 ? parseInt(str.slice(7), 16) / 0xff : 1);
+        putToCache(colorStr, rgbaArr);
+        return rgbaArr;
       }
 
-      var textGuide = el.getTextGuideLine();
+      return;
+    }
 
-      if (textGuide) {
-        this._updateAndAddDisplayable(textGuide, clipPaths, includeIgnore);
-      }
+    var op = str.indexOf('(');
+    var ep = str.indexOf(')');
 
-      var textEl = el.getTextContent();
+    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;
 
-      if (textEl) {
-        this._updateAndAddDisplayable(textEl, clipPaths, includeIgnore);
-      }
-    };
+      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);
+          }
 
-    Storage.prototype.addRoot = function (el) {
-      if (el.__zr && el.__zr.storage === this) {
-        return;
-      }
+          alpha = parseCssFloat(params.pop());
 
-      this._roots.push(el);
-    };
+        case 'rgb':
+          if (params.length !== 3) {
+            setRgba(rgbaArr, 0, 0, 0, 1);
+            return;
+          }
 
-    Storage.prototype.delRoot = function (el) {
-      if (el instanceof Array) {
-        for (var i = 0, l = el.length; i < l; i++) {
-          this.delRoot(el[i]);
-        }
+          setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), alpha);
+          putToCache(colorStr, rgbaArr);
+          return rgbaArr;
 
-        return;
-      }
+        case 'hsla':
+          if (params.length !== 4) {
+            setRgba(rgbaArr, 0, 0, 0, 1);
+            return;
+          }
 
-      var idx = indexOf(this._roots, el);
+          params[3] = parseCssFloat(params[3]);
+          hsla2rgba(params, rgbaArr);
+          putToCache(colorStr, rgbaArr);
+          return rgbaArr;
 
-      if (idx >= 0) {
-        this._roots.splice(idx, 1);
-      }
-    };
+        case 'hsl':
+          if (params.length !== 3) {
+            setRgba(rgbaArr, 0, 0, 0, 1);
+            return;
+          }
 
-    Storage.prototype.delAllRoots = function () {
-      this._roots = [];
-      this._displayList = [];
-      this._displayListLen = 0;
-      return;
-    };
+          hsla2rgba(params, rgbaArr);
+          putToCache(colorStr, rgbaArr);
+          return rgbaArr;
 
-    Storage.prototype.getRoots = function () {
-      return this._roots;
-    };
+        default:
+          return;
+      }
+    }
 
-    Storage.prototype.dispose = function () {
-      this._displayList = null;
-      this._roots = null;
-    };
+    setRgba(rgbaArr, 0, 0, 0, 1);
+    return;
+  }
 
-    return Storage;
-  }();
+  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);
 
-  var requestAnimationFrame;
+    if (hsla.length === 4) {
+      rgba[3] = hsla[3];
+    }
 
-  requestAnimationFrame = typeof window !== 'undefined' && (window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window) || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame) || function (func) {
-    return setTimeout(func, 16);
-  };
+    return rgba;
+  }
 
-  var requestAnimationFrame$1 = requestAnimationFrame;
-  var easing = {
-    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;
-      }
+  function rgba2hsla(rgba) {
+    if (!rgba) {
+      return;
+    }
 
-      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;
-      }
+    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;
 
-      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;
+    if (delta === 0) {
+      H = 0;
+      S = 0;
+    } else {
+      if (L < 0.5) {
+        S = delta / (vMax + vMin);
+      } else {
+        S = delta / (2 - vMax - vMin);
       }
 
-      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;
-      }
+      var deltaR = ((vMax - R) / 6 + delta / 2) / delta;
+      var deltaG = ((vMax - G) / 6 + delta / 2) / delta;
+      var deltaB = ((vMax - B) / 6 + delta / 2) / delta;
 
-      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 (R === vMax) {
+        H = deltaB - deltaG;
+      } else if (G === vMax) {
+        H = 1 / 3 + deltaR - deltaB;
+      } else if (B === vMax) {
+        H = 2 / 3 + deltaG - deltaR;
       }
 
-      if (k === 1) {
-        return 1;
+      if (H < 0) {
+        H += 1;
       }
 
-      if ((k *= 2) < 1) {
-        return 0.5 * Math.pow(1024, k - 1);
+      if (H > 1) {
+        H -= 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);
-      }
+    var hsla = [H * 360, S, L];
 
-      return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1);
-    },
-    elasticIn: function (k) {
-      var s;
-      var a = 0.1;
-      var p = 0.4;
+    if (rgba[3] != null) {
+      hsla.push(rgba[3]);
+    }
 
-      if (k === 0) {
-        return 0;
-      }
+    return hsla;
+  }
 
-      if (k === 1) {
-        return 1;
-      }
+  function lift(color, level) {
+    var colorArr = parse(color);
 
-      if (!a || a < 1) {
-        a = 1;
-        s = p / 4;
-      } else {
-        s = p * Math.asin(1 / a) / (2 * Math.PI);
+    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 -(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;
+      return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb');
+    }
+  }
 
-      if (k === 0) {
-        return 0;
-      }
+  function toHex(color) {
+    var colorArr = parse(color);
 
-      if (k === 1) {
-        return 1;
-      }
+    if (colorArr) {
+      return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + +colorArr[2]).toString(16).slice(1);
+    }
+  }
 
-      if (!a || a < 1) {
-        a = 1;
-        s = p / 4;
-      } else {
-        s = p * Math.asin(1 / a) / (2 * Math.PI);
-      }
+  function fastLerp(normalizedValue, colors, out) {
+    if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) {
+      return;
+    }
 
-      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;
+    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;
+  }
 
-      if (k === 0) {
-        return 0;
-      }
+  var fastMapToColor = fastLerp;
 
-      if (k === 1) {
-        return 1;
-      }
+  function lerp$1(normalizedValue, colors, fullOutput) {
+    if (!(colors && colors.length) || !(normalizedValue >= 0 && normalizedValue <= 1)) {
+      return;
+    }
 
-      if (!a || a < 1) {
-        a = 1;
-        s = p / 4;
-      } else {
-        s = p * Math.asin(1 / a) / (2 * Math.PI);
-      }
+    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;
+  }
 
-      if ((k *= 2) < 1) {
-        return -0.5 * (a * Math.pow(2, 10 * (k -= 1)) * Math.sin((k - s) * (2 * Math.PI) / p));
-      }
+  var mapToColor = lerp$1;
 
-      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;
+  function modifyHSL(color, h, s, l) {
+    var colorArr = parse(color);
 
-      if ((k *= 2) < 1) {
-        return 0.5 * (k * k * ((s + 1) * k - s));
-      }
+    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');
+    }
+  }
 
-      return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2);
-    },
-    bounceIn: function (k) {
-      return 1 - easing.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 easing.bounceIn(k * 2) * 0.5;
-      }
+  function modifyAlpha(color, alpha) {
+    var colorArr = parse(color);
 
-      return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5;
+    if (colorArr && alpha != null) {
+      colorArr[3] = clampCssFloat(alpha);
+      return stringify(colorArr, 'rgba');
     }
-  };
+  }
 
-  var Clip = function () {
-    function Clip(opts) {
-      this._initialized = false;
-      this._startTime = 0;
-      this._pausedTime = 0;
-      this._paused = false;
-      this._life = opts.life || 1000;
-      this._delay = opts.delay || 0;
-      this.loop = opts.loop == null ? false : opts.loop;
-      this.gap = opts.gap || 0;
-      this.easing = opts.easing || 'linear';
-      this.onframe = opts.onframe;
-      this.ondestroy = opts.ondestroy;
-      this.onrestart = opts.onrestart;
+  function stringify(arrColor, type) {
+    if (!arrColor || !arrColor.length) {
+      return;
     }
 
-    Clip.prototype.step = function (globalTime, deltaTime) {
-      if (!this._initialized) {
-        this._startTime = globalTime + this._delay;
-        this._initialized = true;
-      }
+    var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2];
 
-      if (this._paused) {
-        this._pausedTime += deltaTime;
-        return;
-      }
+    if (type === 'rgba' || type === 'hsva' || type === 'hsla') {
+      colorStr += ',' + arrColor[3];
+    }
 
-      var percent = (globalTime - this._startTime - this._pausedTime) / this._life;
+    return type + '(' + colorStr + ')';
+  }
 
-      if (percent < 0) {
-        percent = 0;
-      }
+  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;
+  }
 
-      percent = Math.min(percent, 1);
-      var easing$1 = this.easing;
-      var easingFunc = typeof easing$1 === 'string' ? easing[easing$1] : easing$1;
-      var schedule = typeof easingFunc === 'function' ? easingFunc(percent) : percent;
-      this.onframe && this.onframe(schedule);
+  function random() {
+    var r = Math.round(Math.random() * 255);
+    var g = Math.round(Math.random() * 255);
+    var b = Math.round(Math.random() * 255);
+    return 'rgb(' + r + ',' + g + ',' + b + ')';
+  }
 
-      if (percent === 1) {
-        if (this.loop) {
-          this._restart(globalTime);
+  var color = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    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
+  });
+  var arraySlice = Array.prototype.slice;
 
-          this.onrestart && this.onrestart();
-        } else {
-          return true;
-        }
-      }
+  function interpolateNumber(p0, p1, percent) {
+    return (p1 - p0) * percent + p0;
+  }
 
-      return false;
-    };
+  function step(p0, p1, percent) {
+    return percent > 0.5 ? p1 : p0;
+  }
 
-    Clip.prototype._restart = function (globalTime) {
-      var remainder = (globalTime - this._startTime - this._pausedTime) % this._life;
-      this._startTime = globalTime - remainder + this.gap;
-      this._pausedTime = 0;
-    };
+  function interpolate1DArray(out, p0, p1, percent) {
+    var len = p0.length;
 
-    Clip.prototype.pause = function () {
-      this._paused = true;
-    };
+    for (var i = 0; i < len; i++) {
+      out[i] = interpolateNumber(p0[i], p1[i], percent);
+    }
+  }
 
-    Clip.prototype.resume = function () {
-      this._paused = false;
-    };
+  function interpolate2DArray(out, p0, p1, percent) {
+    var len = p0.length;
+    var len2 = len && p0[0].length;
 
-    return Clip;
-  }();
+    for (var i = 0; i < len; i++) {
+      if (!out[i]) {
+        out[i] = [];
+      }
 
-  var Entry = function () {
-    function Entry(val) {
-      this.value = val;
+      for (var j = 0; j < len2; j++) {
+        out[i][j] = interpolateNumber(p0[i][j], p1[i][j], percent);
+      }
     }
+  }
 
-    return Entry;
-  }();
+  function add1DArray(out, p0, p1, sign) {
+    var len = p0.length;
 
-  var LinkedList = function () {
-    function LinkedList() {
-      this._len = 0;
+    for (var i = 0; i < len; i++) {
+      out[i] = p0[i] + p1[i] * sign;
     }
 
-    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++;
-    };
+    return out;
+  }
 
-    LinkedList.prototype.remove = function (entry) {
-      var prev = entry.prev;
-      var next = entry.next;
+  function add2DArray(out, p0, p1, sign) {
+    var len = p0.length;
+    var len2 = len && p0[0].length;
 
-      if (prev) {
-        prev.next = next;
-      } else {
-        this.head = next;
+    for (var i = 0; i < len; i++) {
+      if (!out[i]) {
+        out[i] = [];
       }
 
-      if (next) {
-        next.prev = prev;
-      } else {
-        this.tail = prev;
+      for (var j = 0; j < len2; j++) {
+        out[i][j] = p0[i][j] + p1[i][j] * sign;
       }
+    }
 
-      entry.next = entry.prev = null;
-      this._len--;
-    };
-
-    LinkedList.prototype.len = function () {
-      return this._len;
-    };
+    return out;
+  }
 
-    LinkedList.prototype.clear = function () {
-      this.head = this.tail = null;
-      this._len = 0;
-    };
+  function fillArray(val0, val1, arrDim) {
+    var arr0 = val0;
+    var arr1 = val1;
 
-    return LinkedList;
-  }();
-
-  var LRU = function () {
-    function LRU(maxSize) {
-      this._list = new LinkedList();
-      this._maxSize = 10;
-      this._map = {};
-      this._maxSize = maxSize;
+    if (!arr0.push || !arr1.push) {
+      return;
     }
 
-    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;
+    var arr0Len = arr0.length;
+    var arr1Len = arr1.length;
 
-        if (len >= this._maxSize && len > 0) {
-          var leastUsedEntry = list.head;
-          list.remove(leastUsedEntry);
-          delete map[leastUsedEntry.key];
-          removed = leastUsedEntry.value;
-          this._lastRemovedEntry = leastUsedEntry;
-        }
+    if (arr0Len !== arr1Len) {
+      var isPreviousLarger = arr0Len > arr1Len;
 
-        if (entry) {
-          entry.value = value;
-        } else {
-          entry = new Entry(value);
+      if (isPreviousLarger) {
+        arr0.length = arr1Len;
+      } else {
+        for (var i = arr0Len; i < arr1Len; i++) {
+          arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i]));
         }
-
-        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;
+    var len2 = arr0[0] && arr0[0].length;
 
-      if (entry != null) {
-        if (entry !== list.tail) {
-          list.remove(entry);
-          list.insertEntry(entry);
+    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];
+          }
         }
-
-        return entry.value;
       }
-    };
-
-    LRU.prototype.clear = function () {
-      this._list.clear();
-
-      this._map = {};
-    };
-
-    LRU.prototype.len = function () {
-      return this._list.len();
-    };
+    }
+  }
 
-    return LRU;
-  }();
+  function is1DArraySame(arr0, arr1) {
+    var len = arr0.length;
 
-  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]
-  };
+    if (len !== arr1.length) {
+      return false;
+    }
 
-  function clampCssByte(i) {
-    i = Math.round(i);
-    return i < 0 ? 0 : i > 255 ? 255 : i;
-  }
+    for (var i = 0; i < len; i++) {
+      if (arr0[i] !== arr1[i]) {
+        return false;
+      }
+    }
 
-  function clampCssAngle(i) {
-    i = Math.round(i);
-    return i < 0 ? 0 : i > 360 ? 360 : i;
+    return true;
   }
 
-  function clampCssFloat(f) {
-    return f < 0 ? 0 : f > 1 ? 1 : f;
+  function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
+    var v0 = (p2 - p0) * 0.5;
+    var v1 = (p3 - p1) * 0.5;
+    return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1;
   }
 
-  function parseCssInt(val) {
-    var str = val;
+  function catmullRomInterpolate1DArray(out, p0, p1, p2, p3, t, t2, t3) {
+    var len = p0.length;
 
-    if (str.length && str.charAt(str.length - 1) === '%') {
-      return clampCssByte(parseFloat(str) / 100 * 255);
+    for (var i = 0; i < len; i++) {
+      out[i] = catmullRomInterpolate(p0[i], p1[i], p2[i], p3[i], t, t2, t3);
     }
-
-    return clampCssByte(parseInt(str, 10));
   }
 
-  function parseCssFloat(val) {
-    var str = val;
-
-    if (str.length && str.charAt(str.length - 1) === '%') {
-      return clampCssFloat(parseFloat(str) / 100);
-    }
+  function catmullRomInterpolate2DArray(out, p0, p1, p2, p3, t, t2, t3) {
+    var len = p0.length;
+    var len2 = p0[0].length;
 
-    return clampCssFloat(parseFloat(str));
-  }
+    for (var i = 0; i < len; i++) {
+      if (!out[i]) {
+        out[1] = [];
+      }
 
-  function cssHueToRgb(m1, m2, h) {
-    if (h < 0) {
-      h += 1;
-    } else if (h > 1) {
-      h -= 1;
+      for (var j = 0; j < len2; j++) {
+        out[i][j] = catmullRomInterpolate(p0[i][j], p1[i][j], p2[i][j], p3[i][j], t, t2, t3);
+      }
     }
+  }
 
-    if (h * 6 < 1) {
-      return m1 + (m2 - m1) * h * 6;
-    }
+  function cloneValue(value) {
+    if (isArrayLike(value)) {
+      var len = value.length;
 
-    if (h * 2 < 1) {
-      return m2;
-    }
+      if (isArrayLike(value[0])) {
+        var ret = [];
 
-    if (h * 3 < 2) {
-      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
-    }
+        for (var i = 0; i < len; i++) {
+          ret.push(arraySlice.call(value[i]));
+        }
 
-    return m1;
-  }
+        return ret;
+      }
 
-  function lerpNumber(a, b, p) {
-    return a + (b - a) * p;
-  }
+      return arraySlice.call(value);
+    }
 
-  function setRgba(out, r, g, b, a) {
-    out[0] = r;
-    out[1] = g;
-    out[2] = b;
-    out[3] = a;
-    return out;
+    return value;
   }
 
-  function copyRgba(out, a) {
-    out[0] = a[0];
-    out[1] = a[1];
-    out[2] = a[2];
-    out[3] = a[3];
-    return out;
+  function rgba2String(rgba) {
+    rgba[0] = Math.floor(rgba[0]);
+    rgba[1] = Math.floor(rgba[1]);
+    rgba[2] = Math.floor(rgba[2]);
+    return 'rgba(' + rgba.join(',') + ')';
   }
 
-  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 guessArrayDim(value) {
+    return isArrayLike(value && value[0]) ? 2 : 1;
   }
 
-  function parse(colorStr, rgbaArr) {
-    if (!colorStr) {
-      return;
-    }
-
-    rgbaArr = rgbaArr || [];
-    var cached = colorCache.get(colorStr);
+  var tmpRgba = [0, 0, 0, 0];
 
-    if (cached) {
-      return copyRgba(rgbaArr, cached);
+  var Track = function () {
+    function Track(propName) {
+      this.keyframes = [];
+      this.maxTime = 0;
+      this.arrDim = 0;
+      this.interpolable = true;
+      this._needsSort = false;
+      this._isAllValueEqual = true;
+      this._lastFrame = 0;
+      this._lastFramePercent = 0;
+      this.propName = propName;
     }
 
-    colorStr = colorStr + '';
-    var str = colorStr.replace(/ /g, '').toLowerCase();
-
-    if (str in kCSSColorTable) {
-      copyRgba(rgbaArr, kCSSColorTable[str]);
-      putToCache(colorStr, rgbaArr);
-      return rgbaArr;
-    }
+    Track.prototype.isFinished = function () {
+      return this._finished;
+    };
 
-    if (str.charAt(0) === '#') {
-      if (str.length === 4) {
-        var iv = parseInt(str.substr(1), 16);
+    Track.prototype.setFinished = function () {
+      this._finished = true;
 
-        if (!(iv >= 0 && iv <= 0xfff)) {
-          setRgba(rgbaArr, 0, 0, 0, 1);
-          return;
-        }
+      if (this._additiveTrack) {
+        this._additiveTrack.setFinished();
+      }
+    };
 
-        setRgba(rgbaArr, (iv & 0xf00) >> 4 | (iv & 0xf00) >> 8, iv & 0xf0 | (iv & 0xf0) >> 4, iv & 0xf | (iv & 0xf) << 4, 1);
-        putToCache(colorStr, rgbaArr);
-        return rgbaArr;
-      } else if (str.length === 7) {
-        var iv = parseInt(str.substr(1), 16);
+    Track.prototype.needsAnimate = function () {
+      return !this._isAllValueEqual && this.keyframes.length >= 2 && this.interpolable;
+    };
 
-        if (!(iv >= 0 && iv <= 0xffffff)) {
-          setRgba(rgbaArr, 0, 0, 0, 1);
-          return;
-        }
+    Track.prototype.getAdditiveTrack = function () {
+      return this._additiveTrack;
+    };
 
-        setRgba(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, 1);
-        putToCache(colorStr, rgbaArr);
-        return rgbaArr;
+    Track.prototype.addKeyframe = function (time, value) {
+      if (time >= this.maxTime) {
+        this.maxTime = time;
+      } else {
+        this._needsSort = true;
       }
 
-      return;
-    }
-
-    var op = str.indexOf('(');
-    var ep = str.indexOf(')');
+      var keyframes = this.keyframes;
+      var len = keyframes.length;
 
-    if (op !== -1 && ep + 1 === str.length) {
-      var fname = str.substr(0, op);
-      var params = str.substr(op + 1, ep - (op + 1)).split(',');
-      var alpha = 1;
+      if (this.interpolable) {
+        if (isArrayLike(value)) {
+          var arrayDim = guessArrayDim(value);
 
-      switch (fname) {
-        case 'rgba':
-          if (params.length !== 4) {
-            setRgba(rgbaArr, 0, 0, 0, 1);
+          if (len > 0 && this.arrDim !== arrayDim) {
+            this.interpolable = false;
             return;
           }
 
-          alpha = parseCssFloat(params.pop());
-
-        case 'rgb':
-          if (params.length !== 3) {
-            setRgba(rgbaArr, 0, 0, 0, 1);
+          if (arrayDim === 1 && typeof value[0] !== 'number' || arrayDim === 2 && typeof value[0][0] !== 'number') {
+            this.interpolable = false;
             return;
           }
 
-          setRgba(rgbaArr, parseCssInt(params[0]), parseCssInt(params[1]), parseCssInt(params[2]), alpha);
-          putToCache(colorStr, rgbaArr);
-          return rgbaArr;
+          if (len > 0) {
+            var lastFrame = keyframes[len - 1];
 
-        case 'hsla':
-          if (params.length !== 4) {
-            setRgba(rgbaArr, 0, 0, 0, 1);
+            if (this._isAllValueEqual) {
+              if (arrayDim === 1) {
+                if (!is1DArraySame(value, lastFrame.value)) {
+                  this._isAllValueEqual = false;
+                }
+              } else {
+                this._isAllValueEqual = false;
+              }
+            }
+          }
+
+          this.arrDim = arrayDim;
+        } else {
+          if (this.arrDim > 0) {
+            this.interpolable = false;
             return;
           }
 
-          params[3] = parseCssFloat(params[3]);
-          hsla2rgba(params, rgbaArr);
-          putToCache(colorStr, rgbaArr);
-          return rgbaArr;
+          if (typeof value === 'string') {
+            var colorArray = parse(value);
 
-        case 'hsl':
-          if (params.length !== 3) {
-            setRgba(rgbaArr, 0, 0, 0, 1);
+            if (colorArray) {
+              value = colorArray;
+              this.isValueColor = true;
+            } else {
+              this.interpolable = false;
+            }
+          } else if (typeof value !== 'number') {
+            this.interpolable = false;
             return;
           }
 
-          hsla2rgba(params, rgbaArr);
-          putToCache(colorStr, rgbaArr);
-          return rgbaArr;
+          if (this._isAllValueEqual && len > 0) {
+            var lastFrame = keyframes[len - 1];
 
-        default:
-          return;
+            if (this.isValueColor && !is1DArraySame(lastFrame.value, value)) {
+              this._isAllValueEqual = false;
+            } else if (lastFrame.value !== value) {
+              this._isAllValueEqual = false;
+            }
+          }
+        }
       }
-    }
-
-    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);
+      var kf = {
+        time: time,
+        value: value,
+        percent: 0
+      };
+      this.keyframes.push(kf);
+      return kf;
+    };
 
-    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() {
-    var r = Math.round(Math.random() * 255);
-    var g = Math.round(Math.random() * 255);
-    var b = Math.round(Math.random() * 255);
-    return 'rgb(' + r + ',' + g + ',' + b + ')';
-  }
-
-  var color = /*#__PURE__*/Object.freeze({
-    __proto__: null,
-    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
-  });
-  var arraySlice = Array.prototype.slice;
-
-  function interpolateNumber(p0, p1, percent) {
-    return (p1 - p0) * percent + p0;
-  }
-
-  function step(p0, p1, percent) {
-    return percent > 0.5 ? p1 : 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);
-    }
-  }
-
-  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);
-      }
-    }
-  }
-
-  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 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 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 catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
-    var v0 = (p2 - p0) * 0.5;
-    var v1 = (p3 - p1) * 0.5;
-    return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1;
-  }
-
-  function catmullRomInterpolate1DArray(out, p0, p1, p2, p3, t, t2, t3) {
-    var len = p0.length;
-
-    for (var i = 0; i < len; i++) {
-      out[i] = catmullRomInterpolate(p0[i], p1[i], p2[i], p3[i], t, t2, t3);
-    }
-  }
-
-  function catmullRomInterpolate2DArray(out, p0, p1, p2, p3, t, t2, t3) {
-    var len = p0.length;
-    var len2 = p0[0].length;
-
-    for (var i = 0; i < len; i++) {
-      if (!out[i]) {
-        out[1] = [];
-      }
-
-      for (var j = 0; j < len2; j++) {
-        out[i][j] = catmullRomInterpolate(p0[i][j], p1[i][j], p2[i][j], p3[i][j], t, t2, t3);
-      }
-    }
-  }
-
-  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]);
-    rgba[1] = Math.floor(rgba[1]);
-    rgba[2] = Math.floor(rgba[2]);
-    return 'rgba(' + rgba.join(',') + ')';
-  }
-
-  function guessArrayDim(value) {
-    return isArrayLike(value && value[0]) ? 2 : 1;
-  }
-
-  var tmpRgba = [0, 0, 0, 0];
-
-  var Track = function () {
-    function Track(propName) {
-      this.keyframes = [];
-      this.maxTime = 0;
-      this.arrDim = 0;
-      this.interpolable = true;
-      this._needsSort = false;
-      this._isAllValueEqual = true;
-      this._lastFrame = 0;
-      this._lastFramePercent = 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._isAllValueEqual && this.keyframes.length >= 2 && this.interpolable;
-    };
-
-    Track.prototype.getAdditiveTrack = function () {
-      return this._additiveTrack;
-    };
-
-    Track.prototype.addKeyframe = function (time, value) {
-      if (time >= this.maxTime) {
-        this.maxTime = time;
-      } else {
-        this._needsSort = true;
-      }
-
-      var keyframes = this.keyframes;
-      var len = keyframes.length;
-
-      if (this.interpolable) {
-        if (isArrayLike(value)) {
-          var arrayDim = guessArrayDim(value);
-
-          if (len > 0 && this.arrDim !== arrayDim) {
-            this.interpolable = false;
-            return;
-          }
-
-          if (arrayDim === 1 && typeof value[0] !== 'number' || arrayDim === 2 && typeof value[0][0] !== 'number') {
-            this.interpolable = false;
-            return;
-          }
-
-          if (len > 0) {
-            var lastFrame = keyframes[len - 1];
-
-            if (this._isAllValueEqual) {
-              if (arrayDim === 1) {
-                if (!is1DArraySame(value, lastFrame.value)) {
-                  this._isAllValueEqual = false;
-                }
-              } else {
-                this._isAllValueEqual = false;
-              }
-            }
-          }
-
-          this.arrDim = arrayDim;
-        } else {
-          if (this.arrDim > 0) {
-            this.interpolable = false;
-            return;
-          }
-
-          if (typeof value === 'string') {
-            var colorArray = parse(value);
-
-            if (colorArray) {
-              value = colorArray;
-              this.isValueColor = true;
-            } else {
-              this.interpolable = false;
-            }
-          } else if (typeof value !== 'number') {
-            this.interpolable = false;
-            return;
-          }
-
-          if (this._isAllValueEqual && len > 0) {
-            var lastFrame = keyframes[len - 1];
-
-            if (this.isValueColor && !is1DArraySame(lastFrame.value, value)) {
-              this._isAllValueEqual = false;
-            } else if (lastFrame.value !== value) {
-              this._isAllValueEqual = false;
-            }
-          }
-        }
-      }
-
-      var kf = {
-        time: time,
-        value: value,
-        percent: 0
-      };
-      this.keyframes.push(kf);
-      return kf;
-    };
-
-    Track.prototype.prepare = function (additiveTrack) {
-      var kfs = this.keyframes;
+    Track.prototype.prepare = function (additiveTrack) {
+      var kfs = this.keyframes;
 
       if (this._needsSort) {
         kfs.sort(function (a, b) {
@@ -4540,2689 +4076,3193 @@
     return Animator;
   }();
 
-  var Animation = function (_super) {
-    __extends(Animation, _super);
+  var Point = function () {
+    function Point(x, y) {
+      this.x = x || 0;
+      this.y = y || 0;
+    }
 
-    function Animation(opts) {
-      var _this = _super.call(this) || this;
+    Point.prototype.copy = function (other) {
+      this.x = other.x;
+      this.y = other.y;
+      return this;
+    };
 
-      _this._running = false;
-      _this._time = 0;
-      _this._pausedTime = 0;
-      _this._pauseStart = 0;
-      _this._paused = false;
-      opts = opts || {};
-      _this.stage = opts.stage || {};
+    Point.prototype.clone = function () {
+      return new Point(this.x, this.y);
+    };
 
-      _this.onframe = opts.onframe || function () {};
+    Point.prototype.set = function (x, y) {
+      this.x = x;
+      this.y = y;
+      return this;
+    };
 
-      return _this;
-    }
+    Point.prototype.equal = function (other) {
+      return other.x === this.x && other.y === this.y;
+    };
 
-    Animation.prototype.addClip = function (clip) {
-      if (clip.animation) {
-        this.removeClip(clip);
-      }
+    Point.prototype.add = function (other) {
+      this.x += other.x;
+      this.y += other.y;
+      return this;
+    };
 
-      if (!this._clipsHead) {
-        this._clipsHead = this._clipsTail = clip;
-      } else {
-        this._clipsTail.next = clip;
-        clip.prev = this._clipsTail;
-        clip.next = null;
-        this._clipsTail = clip;
-      }
+    Point.prototype.scale = function (scalar) {
+      this.x *= scalar;
+      this.y *= scalar;
+    };
 
-      clip.animation = this;
+    Point.prototype.scaleAndAdd = function (other, scalar) {
+      this.x += other.x * scalar;
+      this.y += other.y * scalar;
     };
 
-    Animation.prototype.addAnimator = function (animator) {
-      animator.animation = this;
-      var clip = animator.getClip();
+    Point.prototype.sub = function (other) {
+      this.x -= other.x;
+      this.y -= other.y;
+      return this;
+    };
 
-      if (clip) {
-        this.addClip(clip);
-      }
+    Point.prototype.dot = function (other) {
+      return this.x * other.x + this.y * other.y;
     };
 
-    Animation.prototype.removeClip = function (clip) {
-      if (!clip.animation) {
+    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 prev = clip.prev;
-      var next = clip.next;
+      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;
+    };
 
-      if (prev) {
-        prev.next = next;
+    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 && isFinite(width)) {
+        x = x + width;
+        width = -width;
+      }
+
+      if (height < 0 && isFinite(height)) {
+        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._clipsHead = next;
+        this.width = other.width;
       }
 
-      if (next) {
-        next.prev = prev;
+      if (isFinite(this.y) && isFinite(this.height)) {
+        this.height = mathMax(other.y + other.height, this.y + this.height) - y;
       } else {
-        this._clipsTail = prev;
+        this.height = other.height;
       }
 
-      clip.next = clip.prev = clip.animation = null;
+      this.x = x;
+      this.y = y;
     };
 
-    Animation.prototype.removeAnimator = function (animator) {
-      var clip = animator.getClip();
+    BoundingRect.prototype.applyTransform = function (m) {
+      BoundingRect.applyTransform(this, this, m);
+    };
 
-      if (clip) {
-        this.removeClip(clip);
+    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;
       }
 
-      animator.animation = null;
-    };
+      if (!(b instanceof BoundingRect)) {
+        b = BoundingRect.create(b);
+      }
 
-    Animation.prototype.update = function (notTriggerStageUpdate) {
-      var time = new Date().getTime() - this._pausedTime;
+      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);
 
-      var delta = time - this._time;
-      var clip = this._clipsHead;
+      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);
 
-      while (clip) {
-        var nextClip = clip.next;
-        var finished = clip.step(time, delta);
+        if (ax1 < bx0 || bx1 < ax0) {
+          if (dx > dMax) {
+            dMax = dx;
 
-        if (finished) {
-          clip.ondestroy && clip.ondestroy();
-          this.removeClip(clip);
-          clip = nextClip;
+            if (d0 < d1) {
+              Point.set(maxTv, -d0, 0);
+            } else {
+              Point.set(maxTv, d1, 0);
+            }
+          }
         } else {
-          clip = nextClip;
-        }
-      }
+          if (dx < dMin) {
+            dMin = dx;
 
-      this._time = time;
-      this.onframe(delta);
-      this.trigger('frame', delta);
+            if (d0 < d1) {
+              Point.set(minTv, d0, 0);
+            } else {
+              Point.set(minTv, -d1, 0);
+            }
+          }
+        }
 
-      if (this.stage.update && !notTriggerStageUpdate) {
-        this.stage.update();
-      }
-    };
+        if (ay1 < by0 || by1 < ay0) {
+          if (dy > dMax) {
+            dMax = dy;
 
-    Animation.prototype._startLoop = function () {
-      var self = this;
-      this._running = true;
+            if (d2 < d3) {
+              Point.set(maxTv, 0, -d2);
+            } else {
+              Point.set(maxTv, 0, d3);
+            }
+          }
+        } else {
+          if (dx < dMin) {
+            dMin = dx;
 
-      function step() {
-        if (self._running) {
-          requestAnimationFrame$1(step);
-          !self._paused && self.update();
+            if (d2 < d3) {
+              Point.set(minTv, 0, d2);
+            } else {
+              Point.set(minTv, 0, -d3);
+            }
+          }
         }
       }
 
-      requestAnimationFrame$1(step);
-    };
-
-    Animation.prototype.start = function () {
-      if (this._running) {
-        return;
+      if (mtv) {
+        Point.copy(mtv, overlap ? minTv : maxTv);
       }
 
-      this._time = new Date().getTime();
-      this._pausedTime = 0;
-
-      this._startLoop();
+      return overlap;
     };
 
-    Animation.prototype.stop = function () {
-      this._running = false;
+    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;
     };
 
-    Animation.prototype.pause = function () {
-      if (!this._paused) {
-        this._pauseStart = new Date().getTime();
-        this._paused = true;
-      }
+    BoundingRect.prototype.clone = function () {
+      return new BoundingRect(this.x, this.y, this.width, this.height);
     };
 
-    Animation.prototype.resume = function () {
-      if (this._paused) {
-        this._pausedTime += new Date().getTime() - this._pauseStart;
-        this._paused = false;
-      }
+    BoundingRect.prototype.copy = function (other) {
+      BoundingRect.copy(this, other);
     };
 
-    Animation.prototype.clear = function () {
-      var clip = this._clipsHead;
+    BoundingRect.prototype.plain = function () {
+      return {
+        x: this.x,
+        y: this.y,
+        width: this.width,
+        height: this.height
+      };
+    };
 
-      while (clip) {
-        var nextClip = clip.next;
-        clip.prev = clip.next = clip.animation = null;
-        clip = nextClip;
-      }
+    BoundingRect.prototype.isFinite = function () {
+      return isFinite(this.x) && isFinite(this.y) && isFinite(this.width) && isFinite(this.height);
+    };
 
-      this._clipsHead = this._clipsTail = null;
+    BoundingRect.prototype.isZero = function () {
+      return this.width === 0 || this.height === 0;
     };
 
-    Animation.prototype.isFinished = function () {
-      return this._clipsHead == null;
+    BoundingRect.create = function (rect) {
+      return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
     };
 
-    Animation.prototype.animate = function (target, options) {
-      options = options || {};
-      this.start();
-      var animator = new Animator(target, options.loop);
-      this.addAnimator(animator);
-      return animator;
+    BoundingRect.copy = function (target, source) {
+      target.x = source.x;
+      target.y = source.y;
+      target.width = source.width;
+      target.height = source.height;
     };
 
-    return Animation;
-  }(Eventful);
+    BoundingRect.applyTransform = function (target, source, m) {
+      if (!m) {
+        if (target !== source) {
+          BoundingRect.copy(target, source);
+        }
 
-  var TOUCH_CLICK_DELAY = 300;
-  var globalEventSupported = env.domSupported;
+        return;
+      }
 
-  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
+      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 globalNativeListenerNames = {
-    mouse: ['mousemove', 'mouseup'],
-    pointer: ['pointermove', 'pointerup']
-  };
-  var wheelEventSupported = false;
+  var textWidthCache = {};
+  var DEFAULT_FONT = '12px sans-serif';
 
-  function isPointerFromTouch(event) {
-    var pointerType = event.pointerType;
-    return pointerType === 'pen' || pointerType === 'touch';
-  }
+  var _ctx;
 
-  function setTouchTimer(scope) {
-    scope.touching = true;
+  var _cachedFont;
 
-    if (scope.touchTimer != null) {
-      clearTimeout(scope.touchTimer);
-      scope.touchTimer = null;
+  function defaultMeasureText(text, font) {
+    if (!_ctx) {
+      _ctx = createCanvas().getContext('2d');
     }
 
-    scope.touchTimer = setTimeout(function () {
-      scope.touching = false;
-      scope.touchTimer = null;
-    }, 700);
+    if (_cachedFont !== font) {
+      _cachedFont = _ctx.font = font || DEFAULT_FONT;
+    }
+
+    return _ctx.measureText(text);
   }
 
-  function markTouch(event) {
-    event && (event.zrByTouch = true);
+  var methods$1 = {
+    measureText: defaultMeasureText
+  };
+
+  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 = methods$1.measureText(text, font).width;
+      cacheOfFont.put(text, width);
+    }
+
+    return width;
   }
 
-  function normalizeGlobalEvent(instance, event) {
-    return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true);
+  function innerGetBoundingRect(text, font, textAlign, textBaseline) {
+    var width = getWidth(text, font);
+    var height = getLineHeight(font);
+    var x = adjustTextX(0, width, textAlign);
+    var y = adjustTextY(0, height, textBaseline);
+    var rect = new BoundingRect(x, y, width, height);
+    return rect;
   }
 
-  function isLocalEl(instance, el) {
-    var elTmp = el;
-    var isLocal = false;
+  function getBoundingRect(text, font, textAlign, textBaseline) {
+    var textLines = ((text || '') + '').split('\n');
+    var len = textLines.length;
 
-    while (elTmp && elTmp.nodeType !== 9 && !(isLocal = elTmp.domBelongToZr || elTmp !== el && elTmp === instance.painterRoot)) {
-      elTmp = elTmp.parentNode;
+    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;
     }
+  }
 
-    return isLocal;
+  function adjustTextX(x, width, textAlign) {
+    if (textAlign === 'right') {
+      x -= width;
+    } else if (textAlign === 'center') {
+      x -= width / 2;
+    }
+
+    return x;
   }
 
-  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;
+  function adjustTextY(y, height, verticalAlign) {
+    if (verticalAlign === 'middle') {
+      y -= height / 2;
+    } else if (verticalAlign === 'bottom') {
+      y -= height;
     }
 
-    return FakeGlobalEvent;
-  }();
+    return y;
+  }
 
-  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;
+  function getLineHeight(font) {
+    return getWidth('国', font);
+  }
 
-      if (downPoint && (event.zrX !== downPoint[0] || event.zrY !== downPoint[1])) {
-        this.__togglePointerCapture(true);
+  function parsePercent(value, maxValue) {
+    if (typeof value === 'string') {
+      if (value.lastIndexOf('%') >= 0) {
+        return parseFloat(value) / 100 * maxValue;
       }
 
-      this.trigger('mousemove', event);
-    },
-    mouseup: function (event) {
-      event = normalizeEvent(this.dom, event);
+      return parseFloat(value);
+    }
 
-      this.__togglePointerCapture(false);
+    return value;
+  }
 
-      this.trigger('mouseup', event);
-    },
-    mouseout: function (event) {
-      event = normalizeEvent(this.dom, event);
+  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 (this.__pointerCapturing) {
-        event.zrEventControl = 'no_globalout';
-      }
+    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;
 
-      var element = event.toElement || event.relatedTarget;
-      event.zrIsToLocalDOM = isLocalEl(this, element);
-      this.trigger('mouseout', event);
-    },
-    wheel: function (event) {
-      wheelEventSupported = true;
-      event = normalizeEvent(this.dom, event);
-      this.trigger('mousewheel', event);
-    },
-    mousewheel: function (event) {
-      if (wheelEventSupported) {
-        return;
-      }
+        case 'right':
+          x += distance + width;
+          y += halfHeight;
+          textVerticalAlign = 'middle';
+          break;
 
-      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);
+        case 'top':
+          x += width / 2;
+          y -= distance;
+          textAlign = 'center';
+          textVerticalAlign = 'bottom';
+          break;
 
-      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);
+        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 dpr = 1;
+
+  if (typeof window !== 'undefined') {
+    dpr = Math.max(window.devicePixelRatio || 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';
+  var PRESERVED_NORMAL_STATE = '__zr_normal__';
+  var PRIMARY_STATES_KEYS = ['x', 'y', 'scaleX', 'scaleY', 'originX', 'originY', 'rotation', 'ignore'];
+  var DEFAULT_ANIMATABLE_MAP = {
+    x: true,
+    y: true,
+    scaleX: true,
+    scaleY: true,
+    originX: true,
+    originY: true,
+    rotation: true,
+    ignore: false
   };
-  each(['click', 'dblclick', 'contextmenu'], function (name) {
-    localDOMHandlers[name] = function (event) {
-      event = normalizeEvent(this.dom, event);
-      this.trigger(name, event);
+  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);
     };
-  });
-  var globalDOMHandlers = {
-    pointermove: function (event) {
-      if (!isPointerFromTouch(event)) {
-        globalDOMHandlers.mousemove.call(this, event);
+
+    Element.prototype.drift = function (dx, dy, e) {
+      switch (this.draggable) {
+        case 'horizontal':
+          dy = 0;
+          break;
+
+        case 'vertical':
+          dx = 0;
+          break;
       }
-    },
-    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);
+      var m = this.transform;
 
-      this.trigger('mouseup', event);
+      if (!m) {
+        m = this.transform = [1, 0, 0, 1, 0, 0];
+      }
 
-      if (pointerCaptureReleasing) {
-        event.zrEventControl = 'only_globalout';
-        this.trigger('mouseout', event);
+      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 attachedTransform = textEl.attachedTransform;
+        var textAlign = void 0;
+        var textVerticalAlign = void 0;
+        var textStyleChanged = false;
+
+        if (isLocal) {
+          attachedTransform.parent = this;
+        } else {
+          attachedTransform.parent = null;
+        }
+
+        var innerOrigin = false;
+        attachedTransform.x = textEl.x;
+        attachedTransform.y = textEl.y;
+        attachedTransform.originX = textEl.originX;
+        attachedTransform.originY = textEl.originY;
+        attachedTransform.rotation = textEl.rotation;
+        attachedTransform.scaleX = textEl.scaleX;
+        attachedTransform.scaleY = textEl.scaleY;
+
+        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);
+          }
+
+          attachedTransform.x = tmpTextPosCalcRes.x;
+          attachedTransform.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;
+            attachedTransform.originX = -attachedTransform.x + relOriginX + (isLocal ? 0 : layoutRect.x);
+            attachedTransform.originY = -attachedTransform.y + relOriginY + (isLocal ? 0 : layoutRect.y);
+          }
+        }
+
+        if (textConfig.rotation != null) {
+          attachedTransform.rotation = textConfig.rotation;
+        }
+
+        var textOffset = textConfig.offset;
+
+        if (textOffset) {
+          attachedTransform.x += textOffset[0];
+          attachedTransform.y += textOffset[1];
 
-  function mountLocalDOMEventListeners(instance, scope) {
-    var domHandlers = scope.domHandlers;
+          if (!innerOrigin) {
+            attachedTransform.originX = -textOffset[0];
+            attachedTransform.originY = -textOffset[1];
+          }
+        }
 
-    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);
-          });
-        });
-      }
+        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;
 
-      each(localNativeListenerNames.mouse, function (nativeEventName) {
-        mountSingleDOMEventListener(scope, nativeEventName, function (event) {
-          event = getNativeEvent(event);
+        if (isInside && this.canBeInsideText()) {
+          textFill = textConfig.insideFill;
+          textStroke = textConfig.insideStroke;
 
-          if (!scope.touching) {
-            domHandlers[nativeEventName].call(instance, event);
+          if (textFill == null || textFill === 'auto') {
+            textFill = this.getInsideTextFill();
           }
-        });
-      });
-    }
-  }
 
-  function mountGlobalDOMEventListeners(instance, scope) {
-    if (env.pointerEventsSupported) {
-      each(globalNativeListenerNames.pointer, mount);
-    } else if (!env.touchEventsSupported) {
-      each(globalNativeListenerNames.mouse, mount);
-    }
+          if (textStroke == null || textStroke === 'auto') {
+            textStroke = this.getInsideTextStroke(textFill);
+            autoStroke = true;
+          }
+        } else {
+          textFill = textConfig.outsideFill;
+          textStroke = textConfig.outsideStroke;
 
-    function mount(nativeEventName) {
-      function nativeEventListener(event) {
-        event = getNativeEvent(event);
+          if (textFill == null || textFill === 'auto') {
+            textFill = this.getOutsideFill();
+          }
 
-        if (!isLocalEl(instance, event.target)) {
-          event = normalizeGlobalEvent(instance, event);
-          scope.domHandlers[nativeEventName].call(instance, event);
+          if (textStroke == null || textStroke === 'auto') {
+            textStroke = this.getOutsideStroke(textFill);
+            autoStroke = true;
+          }
         }
-      }
 
-      mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, {
-        capture: true
-      });
-    }
-  }
+        textFill = textFill || '#000';
 
-  function mountSingleDOMEventListener(scope, nativeEventName, listener, opt) {
-    scope.mounted[nativeEventName] = listener;
-    scope.listenerOpts[nativeEventName] = opt;
-    addEventListener(scope.domTarget, nativeEventName, listener, opt);
-  }
+        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);
+        }
 
-  function unmountDOMEventListeners(scope) {
-    var mounted = scope.mounted;
+        if (textStyleChanged) {
+          textEl.dirtyStyle();
+        }
 
-    for (var nativeEventName in mounted) {
-      if (mounted.hasOwnProperty(nativeEventName)) {
-        removeEventListener(scope.domTarget, nativeEventName, mounted[nativeEventName], scope.listenerOpts[nativeEventName]);
+        textEl.markRedraw();
       }
-    }
+    };
 
-    scope.mounted = {};
-  }
+    Element.prototype.canBeInsideText = function () {
+      return true;
+    };
 
-  var DOMHandlerScope = function () {
-    function DOMHandlerScope(domTarget, domHandlers) {
-      this.mounted = {};
-      this.listenerOpts = {};
-      this.touching = false;
-      this.domTarget = domTarget;
-      this.domHandlers = domHandlers;
-    }
+    Element.prototype.getInsideTextFill = function () {
+      return '#fff';
+    };
 
-    return DOMHandlerScope;
-  }();
+    Element.prototype.getInsideTextStroke = function (textFill) {
+      return '#000';
+    };
 
-  var HandlerDomProxy = function (_super) {
-    __extends(HandlerDomProxy, _super);
+    Element.prototype.getOutsideFill = function () {
+      return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR;
+    };
 
-    function HandlerDomProxy(dom, painterRoot) {
-      var _this = _super.call(this) || this;
+    Element.prototype.getOutsideStroke = function (textFill) {
+      var backgroundColor = this.__zr && this.__zr.getBackgroundColor();
 
-      _this.__pointerCapturing = false;
-      _this.dom = dom;
-      _this.painterRoot = painterRoot;
-      _this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers);
+      var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor);
 
-      if (globalEventSupported) {
-        _this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers);
+      if (!colorArr) {
+        colorArr = [255, 255, 255, 1];
       }
 
-      mountLocalDOMEventListeners(_this, _this._localHandlerScope);
-      return _this;
-    }
+      var alpha = colorArr[3];
 
-    HandlerDomProxy.prototype.dispose = function () {
-      unmountDOMEventListeners(this._localHandlerScope);
+      var isDark = this.__zr.isDarkMode();
 
-      if (globalEventSupported) {
-        unmountDOMEventListeners(this._globalHandlerScope);
+      for (var i = 0; i < 3; i++) {
+        colorArr[i] = colorArr[i] * alpha + (isDark ? 0 : 255) * (1 - alpha);
       }
-    };
 
-    HandlerDomProxy.prototype.setCursor = function (cursorStyle) {
-      this.dom.style && (this.dom.style.cursor = cursorStyle || 'default');
+      colorArr[3] = 1;
+      return stringify(colorArr, 'rgba');
     };
 
-    HandlerDomProxy.prototype.__togglePointerCapture = function (isPointerCapturing) {
-      this.__mayPointerCapture = null;
+    Element.prototype.traverse = function (cb, context) {};
 
-      if (globalEventSupported && +this.__pointerCapturing ^ +isPointerCapturing) {
-        this.__pointerCapturing = isPointerCapturing;
-        var globalHandlerScope = this._globalHandlerScope;
-        isPointerCapturing ? mountGlobalDOMEventListeners(this, globalHandlerScope) : unmountDOMEventListeners(globalHandlerScope);
+    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;
       }
     };
 
-    return HandlerDomProxy;
-  }(Eventful);
+    Element.prototype.hide = function () {
+      this.ignore = true;
+      this.markRedraw();
+    };
 
-  function create$1() {
-    return [1, 0, 0, 1, 0, 0];
-  }
+    Element.prototype.show = function () {
+      this.ignore = false;
+      this.markRedraw();
+    };
 
-  function identity(out) {
-    out[0] = 1;
-    out[1] = 0;
-    out[2] = 0;
-    out[3] = 1;
-    out[4] = 0;
-    out[5] = 0;
-    return out;
-  }
+    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);
 
-  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;
-  }
+        for (var i = 0; i < keysArr.length; i++) {
+          var key = keysArr[i];
+          this.attrKV(key, keyOrObj[key]);
+        }
+      }
 
-  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;
-  }
+      this.markRedraw();
+      return this;
+    };
 
-  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;
-  }
+    Element.prototype.saveCurrentToNormalState = function (toState) {
+      this._innerSaveToNormal(toState);
 
-  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;
-  }
+      var normalState = this._normalState;
 
-  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;
-  }
+      for (var i = 0; i < this.animators.length; i++) {
+        var animator = this.animators[i];
+        var fromStateTransition = animator.__fromStateTransition;
 
-  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 (fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) {
+          continue;
+        }
 
-    if (!det) {
-      return null;
-    }
+        var targetName = animator.targetName;
+        var target = targetName ? normalState[targetName] : normalState;
+        animator.saveFinalToTarget(target);
+      }
+    };
 
-    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;
-  }
+    Element.prototype._innerSaveToNormal = function (toState) {
+      var normalState = this._normalState;
 
-  function clone$2(a) {
-    var b = create$1();
-    copy$1(b, a);
-    return b;
-  }
+      if (!normalState) {
+        normalState = this._normalState = {};
+      }
 
-  var matrix = /*#__PURE__*/Object.freeze({
-    __proto__: null,
-    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 = 5e-5;
+      if (toState.textConfig && !normalState.textConfig) {
+        normalState.textConfig = this.textConfig;
+      }
 
-  function isNotAroundZero(val) {
-    return val > EPSILON || val < -EPSILON;
-  }
+      this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS);
+    };
 
-  var scaleTmp = [];
-  var tmpTransform = [];
-  var originTransform = create$1();
-  var abs = Math.abs;
+    Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) {
+      for (var i = 0; i < primaryKeys.length; i++) {
+        var key = primaryKeys[i];
 
-  var Transformable = function () {
-    function Transformable() {}
+        if (toState[key] != null && !(key in normalState)) {
+          normalState[key] = this[key];
+        }
+      }
+    };
 
-    Transformable.prototype.setPosition = function (arr) {
-      this.x = arr[0];
-      this.y = arr[1];
+    Element.prototype.hasState = function () {
+      return this.currentStates.length > 0;
     };
 
-    Transformable.prototype.setScale = function (arr) {
-      this.scaleX = arr[0];
-      this.scaleY = arr[1];
+    Element.prototype.getState = function (name) {
+      return this.states[name];
     };
 
-    Transformable.prototype.setOrigin = function (arr) {
-      this.originX = arr[0];
-      this.originY = arr[1];
+    Element.prototype.ensureState = function (name) {
+      var states = this.states;
+
+      if (!states[name]) {
+        states[name] = {};
+      }
+
+      return states[name];
     };
 
-    Transformable.prototype.needLocalTransform = function () {
-      return isNotAroundZero(this.rotation) || isNotAroundZero(this.x) || isNotAroundZero(this.y) || isNotAroundZero(this.scaleX - 1) || isNotAroundZero(this.scaleY - 1);
+    Element.prototype.clearStates = function (noAnimation) {
+      this.useState(PRESERVED_NORMAL_STATE, false, noAnimation);
     };
 
-    Transformable.prototype.updateTransform = function () {
-      var parent = this.parent;
-      var parentHasTransform = parent && parent.transform;
-      var needLocalTransform = this.needLocalTransform();
-      var m = this.transform;
+    Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation) {
+      var toNormalState = stateName === PRESERVED_NORMAL_STATE;
+      var hasStates = this.hasState();
 
-      if (!(needLocalTransform || parentHasTransform)) {
-        m && mIdentity(m);
+      if (!hasStates && toNormalState) {
         return;
       }
 
-      m = m || create$1();
+      var currentStates = this.currentStates;
+      var animationCfg = this.stateTransition;
 
-      if (needLocalTransform) {
-        this.getLocalTransform(m);
-      } else {
-        mIdentity(m);
+      if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) {
+        return;
       }
 
-      if (parentHasTransform) {
-        if (needLocalTransform) {
-          mul$1(m, parent.transform, m);
+      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);
+
+      if (useHoverLayer) {
+        this._toggleHoverLayerFlag(true);
+      }
+
+      this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
+
+      if (this._textContent) {
+        this._textContent.useState(stateName, keepCurrentStates);
+      }
+
+      if (this._textGuide) {
+        this._textGuide.useState(stateName, keepCurrentStates);
+      }
+
+      if (toNormalState) {
+        this.currentStates = [];
+        this._normalState = {};
+      } else {
+        if (!keepCurrentStates) {
+          this.currentStates = [stateName];
         } else {
-          copy$1(m, parent.transform);
+          this.currentStates.push(stateName);
         }
       }
 
-      this.transform = m;
+      this._updateAnimationTargets();
+
+      this.markRedraw();
+
+      if (!useHoverLayer && this.__inHover) {
+        this._toggleHoverLayerFlag(false);
+
+        this.__dirty &= ~Element.REDARAW_BIT;
+      }
+
+      return state;
+    };
+
+    Element.prototype.useStates = function (states, noAnimation) {
+      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 useHoverLayer = !!(stateObjects[len - 1] && stateObjects[len - 1].hoverLayer);
+
+        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);
+
+        if (this._textContent) {
+          this._textContent.useStates(states);
+        }
+
+        if (this._textGuide) {
+          this._textGuide.useStates(states);
+        }
+
+        this._updateAnimationTargets();
 
-      this._resolveGlobalScaleRatio(m);
-    };
+        this.currentStates = states.slice();
+        this.markRedraw();
 
-    Transformable.prototype._resolveGlobalScaleRatio = function (m) {
-      var globalScaleRatio = this.globalScaleRatio;
+        if (!useHoverLayer && this.__inHover) {
+          this._toggleHoverLayerFlag(false);
 
-      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.__dirty &= ~Element.REDARAW_BIT;
+        }
       }
-
-      this.invTransform = this.invTransform || create$1();
-      invert(this.invTransform, m);
     };
 
-    Transformable.prototype.getLocalTransform = function (m) {
-      return Transformable.getLocalTransform(this, m);
+    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]);
+        }
+      }
     };
 
-    Transformable.prototype.getComputedTransform = function () {
-      var transformNode = this;
-      var ancestors = [];
+    Element.prototype.removeState = function (state) {
+      var idx = indexOf(this.currentStates, state);
 
-      while (transformNode) {
-        ancestors.push(transformNode);
-        transformNode = transformNode.parent;
+      if (idx >= 0) {
+        var currentStates = this.currentStates.slice();
+        currentStates.splice(idx, 1);
+        this.useStates(currentStates);
       }
+    };
 
-      while (transformNode = ancestors.pop()) {
-        transformNode.updateTransform();
+    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);
       }
 
-      return this.transform;
+      this.useStates(currentStates);
     };
 
-    Transformable.prototype.setLocalTransform = function (m) {
-      if (!m) {
-        return;
+    Element.prototype.toggleState = function (state, enable) {
+      if (enable) {
+        this.useState(state, true);
+      } else {
+        this.removeState(state);
       }
+    };
 
-      var sx = m[0] * m[0] + m[1] * m[1];
-      var sy = m[2] * m[2] + m[3] * m[3];
+    Element.prototype._mergeStates = function (states) {
+      var mergedState = {};
+      var mergedTextConfig;
 
-      if (isNotAroundZero(sx - 1)) {
-        sx = Math.sqrt(sx);
+      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 (isNotAroundZero(sy - 1)) {
-        sy = Math.sqrt(sy);
+      if (mergedTextConfig) {
+        mergedState.textConfig = mergedTextConfig;
       }
 
-      this.rotation = Math.atan2(-m[1] / sy, m[0] / sx);
+      return mergedState;
+    };
 
-      if (m[0] < 0) {
-        sx = -sx;
-      }
+    Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
+      var needsRestoreToNormal = !(state && keepCurrentStates);
 
-      if (m[3] < 0) {
-        sy = -sy;
+      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;
+        }
       }
 
-      if (sx < 0 && sy < 0) {
-        this.rotation += Math.PI;
-        sx = -sx;
-        sy = -sy;
-      }
+      var transitionTarget = {};
+      var hasTransition = false;
 
-      this.x = m[4];
-      this.y = m[5];
-      this.scaleX = sx;
-      this.scaleY = sy;
-    };
+      for (var i = 0; i < PRIMARY_STATES_KEYS.length; i++) {
+        var key = PRIMARY_STATES_KEYS[i];
+        var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key];
 
-    Transformable.prototype.decomposeTransform = function () {
-      if (!this.transform) {
-        return;
+        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];
+            }
+          }
+        }
       }
 
-      var parent = this.parent;
-      var m = this.transform;
+      if (!transition) {
+        for (var i = 0; i < this.animators.length; i++) {
+          var animator = this.animators[i];
+          var targetName = animator.targetName;
 
-      if (parent && parent.transform) {
-        mul$1(tmpTransform, parent.invTransform, m);
-        m = tmpTransform;
+          animator.__changeFinalValue(targetName ? (state || normalState)[targetName] : state || normalState);
+        }
       }
 
-      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;
+      if (hasTransition) {
+        this._transitionState(stateName, transitionTarget, animationCfg);
       }
-
-      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];
+    Element.prototype._attachComponent = function (componentEl) {
+      if (componentEl.__zr && !componentEl.__hostTarget) {
+        throw new Error('Text element has been added to zrender.');
       }
 
-      if (m[3] < 0) {
-        out[1] = -out[1];
+      if (componentEl === this) {
+        throw new Error('Recursive component attachment.');
       }
 
-      return out;
-    };
-
-    Transformable.prototype.transformCoordToLocal = function (x, y) {
-      var v2 = [x, y];
-      var invTransform = this.invTransform;
+      var zr = this.__zr;
 
-      if (invTransform) {
-        applyTransform(v2, v2, invTransform);
+      if (zr) {
+        componentEl.addSelfToZr(zr);
       }
 
-      return v2;
+      componentEl.__zr = zr;
+      componentEl.__hostTarget = this;
     };
 
-    Transformable.prototype.transformCoordToGlobal = function (x, y) {
-      var v2 = [x, y];
-      var transform = this.transform;
-
-      if (transform) {
-        applyTransform(v2, v2, transform);
+    Element.prototype._detachComponent = function (componentEl) {
+      if (componentEl.__zr) {
+        componentEl.removeSelfFromZr(componentEl.__zr);
       }
 
-      return v2;
+      componentEl.__zr = null;
+      componentEl.__hostTarget = null;
     };
 
-    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;
+    Element.prototype.getClipPath = function () {
+      return this._clipPath;
     };
 
-    Transformable.getLocalTransform = function (target, m) {
-      m = m || [];
-      mIdentity(m);
-      var ox = target.originX || 0;
-      var oy = target.originY || 0;
-      var sx = target.scaleX;
-      var sy = target.scaleY;
-      var rotation = target.rotation || 0;
-      var x = target.x;
-      var y = target.y;
-      m[4] -= ox;
-      m[5] -= oy;
-      m[0] *= sx;
-      m[1] *= sy;
-      m[2] *= sx;
-      m[3] *= sy;
-      m[4] *= sx;
-      m[5] *= sy;
-
-      if (rotation) {
-        rotate(m, m, rotation);
+    Element.prototype.setClipPath = function (clipPath) {
+      if (this._clipPath && this._clipPath !== clipPath) {
+        this.removeClipPath();
       }
 
-      m[4] += ox;
-      m[5] += oy;
-      m[4] += x;
-      m[5] += y;
-      return m;
-    };
+      this._attachComponent(clipPath);
 
-    Transformable.initDefaultProps = function () {
-      var proto = Transformable.prototype;
-      proto.x = 0;
-      proto.y = 0;
-      proto.scaleX = 1;
-      proto.scaleY = 1;
-      proto.originX = 0;
-      proto.originY = 0;
-      proto.rotation = 0;
-      proto.globalScaleRatio = 1;
-    }();
+      this._clipPath = clipPath;
+      this.markRedraw();
+    };
 
-    return Transformable;
-  }();
+    Element.prototype.removeClipPath = function () {
+      var clipPath = this._clipPath;
 
-  var Point = function () {
-    function Point(x, y) {
-      this.x = x || 0;
-      this.y = y || 0;
-    }
+      if (clipPath) {
+        this._detachComponent(clipPath);
 
-    Point.prototype.copy = function (other) {
-      this.x = other.x;
-      this.y = other.y;
-      return this;
+        this._clipPath = null;
+        this.markRedraw();
+      }
     };
 
-    Point.prototype.clone = function () {
-      return new Point(this.x, this.y);
+    Element.prototype.getTextContent = function () {
+      return this._textContent;
     };
 
-    Point.prototype.set = function (x, y) {
-      this.x = x;
-      this.y = y;
-      return this;
-    };
+    Element.prototype.setTextContent = function (textEl) {
+      var previousTextContent = this._textContent;
 
-    Point.prototype.equal = function (other) {
-      return other.x === this.x && other.y === this.y;
-    };
+      if (previousTextContent === textEl) {
+        return;
+      }
 
-    Point.prototype.add = function (other) {
-      this.x += other.x;
-      this.y += other.y;
-      return this;
-    };
+      if (previousTextContent && previousTextContent !== textEl) {
+        this.removeTextContent();
+      }
 
-    Point.prototype.scale = function (scalar) {
-      this.x *= scalar;
-      this.y *= scalar;
-    };
+      if (textEl.__zr && !textEl.__hostTarget) {
+        throw new Error('Text element has been added to zrender.');
+      }
 
-    Point.prototype.scaleAndAdd = function (other, scalar) {
-      this.x += other.x * scalar;
-      this.y += other.y * scalar;
-    };
+      textEl.attachedTransform = new Transformable();
 
-    Point.prototype.sub = function (other) {
-      this.x -= other.x;
-      this.y -= other.y;
-      return this;
-    };
+      this._attachComponent(textEl);
 
-    Point.prototype.dot = function (other) {
-      return this.x * other.x + this.y * other.y;
+      this._textContent = textEl;
+      this.markRedraw();
     };
 
-    Point.prototype.len = function () {
-      return Math.sqrt(this.x * this.x + this.y * this.y);
-    };
+    Element.prototype.setTextConfig = function (cfg) {
+      if (!this.textConfig) {
+        this.textConfig = {};
+      }
 
-    Point.prototype.lenSquare = function () {
-      return this.x * this.x + this.y * this.y;
+      extend(this.textConfig, cfg);
+      this.markRedraw();
     };
 
-    Point.prototype.normalize = function () {
-      var len = this.len();
-      this.x /= len;
-      this.y /= len;
-      return this;
-    };
+    Element.prototype.removeTextContent = function () {
+      var textEl = this._textContent;
 
-    Point.prototype.distance = function (other) {
-      var dx = this.x - other.x;
-      var dy = this.y - other.y;
-      return Math.sqrt(dx * dx + dy * dy);
-    };
+      if (textEl) {
+        textEl.attachedTransform = null;
 
-    Point.prototype.distanceSquare = function (other) {
-      var dx = this.x - other.x;
-      var dy = this.y - other.y;
-      return dx * dx + dy * dy;
+        this._detachComponent(textEl);
+
+        this._textContent = null;
+        this._innerTextDefaultStyle = null;
+        this.markRedraw();
+      }
     };
 
-    Point.prototype.negate = function () {
-      this.x = -this.x;
-      this.y = -this.y;
-      return this;
+    Element.prototype.getTextGuideLine = function () {
+      return this._textGuide;
     };
 
-    Point.prototype.transform = function (m) {
-      if (!m) {
-        return;
+    Element.prototype.setTextGuideLine = function (guideLine) {
+      if (this._textGuide && this._textGuide !== guideLine) {
+        this.removeTextGuideLine();
       }
 
-      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;
-    };
+      this._attachComponent(guideLine);
 
-    Point.prototype.toArray = function (out) {
-      out[0] = this.x;
-      out[1] = this.y;
-      return out;
+      this._textGuide = guideLine;
+      this.markRedraw();
     };
 
-    Point.prototype.fromArray = function (input) {
-      this.x = input[0];
-      this.y = input[1];
-    };
+    Element.prototype.removeTextGuideLine = function () {
+      var textGuide = this._textGuide;
 
-    Point.set = function (p, x, y) {
-      p.x = x;
-      p.y = y;
-    };
+      if (textGuide) {
+        this._detachComponent(textGuide);
 
-    Point.copy = function (p, p2) {
-      p.x = p2.x;
-      p.y = p2.y;
+        this._textGuide = null;
+        this.markRedraw();
+      }
     };
 
-    Point.len = function (p) {
-      return Math.sqrt(p.x * p.x + p.y * p.y);
-    };
+    Element.prototype.markRedraw = function () {
+      this.__dirty |= Element.REDARAW_BIT;
+      var zr = this.__zr;
 
-    Point.lenSquare = function (p) {
-      return p.x * p.x + p.y * p.y;
-    };
+      if (zr) {
+        if (this.__inHover) {
+          zr.refreshHover();
+        } else {
+          zr.refresh();
+        }
+      }
 
-    Point.dot = function (p0, p1) {
-      return p0.x * p1.x + p0.y * p1.y;
+      if (this.__hostTarget) {
+        this.__hostTarget.markRedraw();
+      }
     };
 
-    Point.add = function (out, p0, p1) {
-      out.x = p0.x + p1.x;
-      out.y = p0.y + p1.y;
+    Element.prototype.dirty = function () {
+      this.markRedraw();
     };
 
-    Point.sub = function (out, p0, p1) {
-      out.x = p0.x - p1.x;
-      out.y = p0.y - p1.y;
-    };
+    Element.prototype._toggleHoverLayerFlag = function (inHover) {
+      this.__inHover = inHover;
+      var textContent = this._textContent;
+      var textGuide = this._textGuide;
 
-    Point.scale = function (out, p0, scalar) {
-      out.x = p0.x * scalar;
-      out.y = p0.y * scalar;
-    };
+      if (textContent) {
+        textContent.__inHover = inHover;
+      }
 
-    Point.scaleAndAdd = function (out, p0, p1, scalar) {
-      out.x = p0.x + p1.x * scalar;
-      out.y = p0.y + p1.y * scalar;
+      if (textGuide) {
+        textGuide.__inHover = inHover;
+      }
     };
 
-    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;
-    };
+    Element.prototype.addSelfToZr = function (zr) {
+      this.__zr = zr;
+      var animators = this.animators;
 
-    return Point;
-  }();
+      if (animators) {
+        for (var i = 0; i < animators.length; i++) {
+          zr.animation.addAnimator(animators[i]);
+        }
+      }
 
-  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();
+      if (this._clipPath) {
+        this._clipPath.addSelfToZr(zr);
+      }
 
-  var BoundingRect = function () {
-    function BoundingRect(x, y, width, height) {
-      if (width < 0) {
-        x = x + width;
-        width = -width;
+      if (this._textContent) {
+        this._textContent.addSelfToZr(zr);
       }
 
-      if (height < 0) {
-        y = y + height;
-        height = -height;
+      if (this._textGuide) {
+        this._textGuide.addSelfToZr(zr);
+      }
+    };
+
+    Element.prototype.removeSelfFromZr = function (zr) {
+      this.__zr = null;
+      var animators = this.animators;
+
+      if (animators) {
+        for (var i = 0; i < animators.length; i++) {
+          zr.animation.removeAnimator(animators[i]);
+        }
       }
 
-      this.x = x;
-      this.y = y;
-      this.width = width;
-      this.height = height;
-    }
+      if (this._clipPath) {
+        this._clipPath.removeSelfFromZr(zr);
+      }
 
-    BoundingRect.prototype.union = function (other) {
-      var x = mathMin(other.x, this.x);
-      var y = mathMin(other.y, this.y);
-      this.width = mathMax(other.x + other.width, this.x + this.width) - x;
-      this.height = mathMax(other.y + other.height, this.y + this.height) - y;
-      this.x = x;
-      this.y = y;
-    };
+      if (this._textContent) {
+        this._textContent.removeSelfFromZr(zr);
+      }
 
-    BoundingRect.prototype.applyTransform = function (m) {
-      BoundingRect.applyTransform(this, this, m);
+      if (this._textGuide) {
+        this._textGuide.removeSelfFromZr(zr);
+      }
     };
 
-    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;
-    };
+    Element.prototype.animate = function (key, loop) {
+      var target = key ? this[key] : this;
 
-    BoundingRect.prototype.intersect = function (b, mtv) {
-      if (!b) {
-        return false;
+      if (!target) {
+        logError('Property "' + key + '" is not existed in element ' + this.id);
+        return;
       }
 
-      if (!(b instanceof BoundingRect)) {
-        b = BoundingRect.create(b);
-      }
+      var animator = new Animator(target, loop);
+      this.addAnimator(animator, key);
+      return animator;
+    };
 
-      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);
+    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 (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 (idx >= 0) {
+          animators.splice(idx, 1);
+        }
+      });
+      this.animators.push(animator);
 
-        if (ax1 < bx0 || bx1 < ax0) {
-          if (dx > dMax) {
-            dMax = dx;
+      if (zr) {
+        zr.animation.addAnimator(animator);
+      }
 
-            if (d0 < d1) {
-              Point.set(maxTv, -d0, 0);
-            } else {
-              Point.set(maxTv, d1, 0);
-            }
-          }
-        } else {
-          if (dx < dMin) {
-            dMin = dx;
+      zr && zr.wakeUp();
+    };
 
-            if (d0 < d1) {
-              Point.set(minTv, d0, 0);
-            } else {
-              Point.set(minTv, -d1, 0);
-            }
-          }
-        }
+    Element.prototype.updateDuringAnimation = function (key) {
+      this.markRedraw();
+    };
 
-        if (ay1 < by0 || by1 < ay0) {
-          if (dy > dMax) {
-            dMax = dy;
+    Element.prototype.stopAnimation = function (scope, forwardToLast) {
+      var animators = this.animators;
+      var len = animators.length;
+      var leftAnimators = [];
 
-            if (d2 < d3) {
-              Point.set(maxTv, 0, -d2);
-            } else {
-              Point.set(maxTv, 0, d3);
-            }
-          }
-        } else {
-          if (dx < dMin) {
-            dMin = dx;
+      for (var i = 0; i < len; i++) {
+        var animator = animators[i];
 
-            if (d2 < d3) {
-              Point.set(minTv, 0, d2);
-            } else {
-              Point.set(minTv, 0, -d3);
-            }
-          }
+        if (!scope || scope === animator.scope) {
+          animator.stop(forwardToLast);
+        } else {
+          leftAnimators.push(animator);
         }
       }
 
-      if (mtv) {
-        Point.copy(mtv, overlap ? minTv : maxTv);
-      }
-
-      return overlap;
+      this.animators = leftAnimators;
+      return this;
     };
 
-    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;
+    Element.prototype.animateTo = function (target, cfg, animationProps) {
+      animateTo(this, target, cfg, animationProps);
     };
 
-    BoundingRect.prototype.clone = function () {
-      return new BoundingRect(this.x, this.y, this.width, this.height);
+    Element.prototype.animateFrom = function (target, cfg, animationProps) {
+      animateTo(this, target, cfg, animationProps, true);
     };
 
-    BoundingRect.prototype.copy = function (other) {
-      BoundingRect.copy(this, other);
-    };
+    Element.prototype._transitionState = function (stateName, target, cfg, animationProps) {
+      var animators = animateTo(this, target, cfg, animationProps);
 
-    BoundingRect.prototype.plain = function () {
-      return {
-        x: this.x,
-        y: this.y,
-        width: this.width,
-        height: this.height
-      };
+      for (var i = 0; i < animators.length; i++) {
+        animators[i].__fromStateTransition = stateName;
+      }
     };
 
-    BoundingRect.create = function (rect) {
-      return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
+    Element.prototype.getBoundingRect = function () {
+      return null;
     };
 
-    BoundingRect.copy = function (target, source) {
-      target.x = source.x;
-      target.y = source.y;
-      target.width = source.width;
-      target.height = source.height;
+    Element.prototype.getPaintRect = function () {
+      return null;
     };
 
-    BoundingRect.applyTransform = function (target, source, m) {
-      if (!m) {
-        if (target !== source) {
-          BoundingRect.copy(target, source);
-        }
+    Element.REDARAW_BIT = 1;
 
-        return;
+    Element.initDefaultProps = function () {
+      var elProto = Element.prototype;
+      elProto.type = 'element';
+      elProto.name = '';
+      elProto.ignore = false;
+      elProto.silent = false;
+      elProto.isGroup = false;
+      elProto.draggable = false;
+      elProto.dragging = false;
+      elProto.ignoreClip = false;
+      elProto.__inHover = false;
+      elProto.__dirty = Element.REDARAW_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;
+        }
       }
 
-      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;
+      function createLegacyProperty(key, privateKey, xKey, yKey) {
+        Object.defineProperty(elProto, key, {
+          get: function () {
+            logDeprecatedError(key, xKey, yKey);
 
-        if (target.width < 0) {
-          target.x += target.width;
-          target.width = -target.width;
-        }
+            if (!this[privateKey]) {
+              var pos = this[privateKey] = [];
+              enhanceArray(this, pos);
+            }
 
-        if (target.height < 0) {
-          target.y += target.height;
-          target.height = -target.height;
-        }
+            return this[privateKey];
+          },
+          set: function (pos) {
+            logDeprecatedError(key, xKey, yKey);
+            this[xKey] = pos[0];
+            this[yKey] = pos[1];
+            this[privateKey] = pos;
+            enhanceArray(this, pos);
+          }
+        });
 
-        return;
+        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;
+            }
+          });
+        }
       }
 
-      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;
-    };
+      if (Object.defineProperty && (!env.browser.ie || env.browser.version > 8)) {
+        createLegacyProperty('position', '_legacyPos', 'x', 'y');
+        createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY');
+        createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY');
+      }
+    }();
 
-    return BoundingRect;
+    return Element;
   }();
 
-  var textWidthCache = {};
-  var DEFAULT_FONT = '12px sans-serif';
+  mixin(Element, Eventful);
+  mixin(Element, Transformable);
 
-  var _ctx;
+  function animateTo(animatable, target, cfg, animationProps, reverse) {
+    cfg = cfg || {};
+    var animators = [];
+    animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse);
+    var doneCount = animators.length;
+    var abortedCount = doneCount;
+    var cfgDone = cfg.done;
+    var cfgAborted = cfg.aborted;
+    var doneCb = cfgDone ? function () {
+      doneCount--;
 
-  var _cachedFont;
+      if (!doneCount) {
+        cfgDone();
+      }
+    } : null;
+    var abortedCb = cfgAborted ? function () {
+      abortedCount--;
 
-  function defaultMeasureText(text, font) {
-    if (!_ctx) {
-      _ctx = createCanvas().getContext('2d');
+      if (!abortedCount) {
+        cfgAborted();
+      }
+    } : null;
+
+    if (!doneCount) {
+      cfgDone && cfgDone();
     }
 
-    if (_cachedFont !== font) {
-      _cachedFont = _ctx.font = font || DEFAULT_FONT;
+    if (animators.length > 0 && cfg.during) {
+      animators[0].during(function (target, percent) {
+        cfg.during(percent);
+      });
     }
 
-    return _ctx.measureText(text);
-  }
+    for (var i = 0; i < animators.length; i++) {
+      var animator = animators[i];
 
-  var methods$1 = {
-    measureText: defaultMeasureText
-  };
+      if (doneCb) {
+        animator.done(doneCb);
+      }
 
-  function getWidth(text, font) {
-    font = font || DEFAULT_FONT;
-    var cacheOfFont = textWidthCache[font];
+      if (abortedCb) {
+        animator.aborted(abortedCb);
+      }
 
-    if (!cacheOfFont) {
-      cacheOfFont = textWidthCache[font] = new LRU(500);
+      animator.start(cfg.easing, cfg.force);
     }
 
-    var width = cacheOfFont.get(text);
+    return animators;
+  }
 
-    if (width == null) {
-      width = methods$1.measureText(text, font).width;
-      cacheOfFont.put(text, width);
+  function copyArrShallow(source, target, len) {
+    for (var i = 0; i < len; i++) {
+      source[i] = target[i];
     }
-
-    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(0, height, textBaseline);
-    var rect = new BoundingRect(x, y, width, height);
-    return rect;
+  function is2DArray(value) {
+    return isArrayLike(value[0]);
   }
 
-  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);
+  function copyValue(target, source, key) {
+    if (isArrayLike(source[key])) {
+      if (!isArrayLike(target[key])) {
+        target[key] = [];
       }
 
-      return uniondRect;
-    }
-  }
+      if (isTypedArray(source[key])) {
+        var len = source[key].length;
 
-  function adjustTextX(x, width, textAlign) {
-    if (textAlign === 'right') {
-      x -= width;
-    } else if (textAlign === 'center') {
-      x -= width / 2;
-    }
+        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;
 
-    return x;
-  }
+        if (is2DArray(sourceArr)) {
+          var len1 = sourceArr[0].length;
 
-  function adjustTextY(y, height, verticalAlign) {
-    if (verticalAlign === 'middle') {
-      y -= height / 2;
-    } else if (verticalAlign === 'bottom') {
-      y -= height;
-    }
+          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);
+        }
 
-    return y;
+        targetArr.length = sourceArr.length;
+      }
+    } else {
+      target[key] = source[key];
+    }
   }
 
-  function getLineHeight(font) {
-    return getWidth('国', font);
-  }
+  function animateToShallow(animatable, topKey, source, target, cfg, animationProps, animators, reverse) {
+    var animatableKeys = [];
+    var changedKeys = [];
+    var targetKeys = keys(target);
+    var duration = cfg.duration;
+    var delay = cfg.delay;
+    var additive = cfg.additive;
+    var setToFinal = cfg.setToFinal;
+    var animateAll = !isObject(animationProps);
 
-  function parsePercent(value, maxValue) {
-    if (typeof value === 'string') {
-      if (value.lastIndexOf('%') >= 0) {
-        return parseFloat(value) / 100 * maxValue;
-      }
+    for (var k = 0; k < targetKeys.length; k++) {
+      var innerKey = targetKeys[k];
 
-      return parseFloat(value);
-    }
+      if (source[innerKey] != null && target[innerKey] != null && (animateAll || animationProps[innerKey])) {
+        if (isObject(target[innerKey]) && !isArrayLike(target[innerKey])) {
+          if (topKey) {
+            if (!reverse) {
+              source[innerKey] = target[innerKey];
+              animatable.updateDuringAnimation(topKey);
+            }
 
-    return value;
-  }
+            continue;
+          }
 
-  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';
+          animateToShallow(animatable, innerKey, source[innerKey], target[innerKey], cfg, animationProps && animationProps[innerKey], animators, reverse);
+        } else {
+          animatableKeys.push(innerKey);
+          changedKeys.push(innerKey);
+        }
+      } else if (!reverse) {
+        source[innerKey] = target[innerKey];
+        animatable.updateDuringAnimation(topKey);
+        changedKeys.push(innerKey);
+      }
+    }
 
-    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;
+    var keyLen = animatableKeys.length;
 
-        case 'right':
-          x += distance + width;
-          y += halfHeight;
-          textVerticalAlign = 'middle';
-          break;
+    if (keyLen > 0 || cfg.force) {
+      var existsAnimators = animatable.animators;
+      var existsAnimatorsOnSameTarget = [];
 
-        case 'top':
-          x += width / 2;
-          y -= distance;
-          textAlign = 'center';
-          textVerticalAlign = 'bottom';
-          break;
+      for (var i = 0; i < existsAnimators.length; i++) {
+        if (existsAnimators[i].targetName === topKey) {
+          existsAnimatorsOnSameTarget.push(existsAnimators[i]);
+        }
+      }
 
-        case 'bottom':
-          x += width / 2;
-          y += height + distance;
-          textAlign = 'center';
-          break;
+      if (!additive && existsAnimatorsOnSameTarget.length) {
+        for (var i = 0; i < existsAnimatorsOnSameTarget.length; i++) {
+          var allAborted = existsAnimatorsOnSameTarget[i].stopTracks(changedKeys);
 
-        case 'inside':
-          x += width / 2;
-          y += halfHeight;
-          textAlign = 'center';
-          textVerticalAlign = 'middle';
-          break;
+          if (allAborted) {
+            var idx = indexOf(existsAnimators, existsAnimatorsOnSameTarget[i]);
+            existsAnimators.splice(idx, 1);
+          }
+        }
+      }
 
-        case 'insideLeft':
-          x += distance;
-          y += halfHeight;
-          textVerticalAlign = 'middle';
-          break;
+      var revertedSource = void 0;
+      var reversedTarget = void 0;
+      var sourceClone = void 0;
 
-        case 'insideRight':
-          x += width - distance;
-          y += halfHeight;
-          textAlign = 'right';
-          textVerticalAlign = 'middle';
-          break;
+      if (reverse) {
+        reversedTarget = {};
 
-        case 'insideTop':
-          x += width / 2;
-          y += distance;
-          textAlign = 'center';
-          break;
+        if (setToFinal) {
+          revertedSource = {};
+        }
 
-        case 'insideBottom':
-          x += width / 2;
-          y += height - distance;
-          textAlign = 'center';
-          textVerticalAlign = 'bottom';
-          break;
+        for (var i = 0; i < keyLen; i++) {
+          var innerKey = animatableKeys[i];
+          reversedTarget[innerKey] = source[innerKey];
 
-        case 'insideTopLeft':
-          x += distance;
-          y += distance;
-          break;
+          if (setToFinal) {
+            revertedSource[innerKey] = target[innerKey];
+          } else {
+            source[innerKey] = target[innerKey];
+          }
+        }
+      } else if (setToFinal) {
+        sourceClone = {};
 
-        case 'insideTopRight':
-          x += width - distance;
-          y += distance;
-          textAlign = 'right';
-          break;
+        for (var i = 0; i < keyLen; i++) {
+          var innerKey = animatableKeys[i];
+          sourceClone[innerKey] = cloneValue(source[innerKey]);
+          copyValue(source, target, innerKey);
+        }
+      }
 
-        case 'insideBottomLeft':
-          x += distance;
-          y += height - distance;
-          textVerticalAlign = 'bottom';
-          break;
+      var animator = new Animator(source, false, additive ? existsAnimatorsOnSameTarget : null);
+      animator.targetName = topKey;
 
-        case 'insideBottomRight':
-          x += width - distance;
-          y += height - distance;
-          textAlign = 'right';
-          textVerticalAlign = 'bottom';
-          break;
+      if (cfg.scope) {
+        animator.scope = cfg.scope;
       }
-    }
 
-    out = out || {};
-    out.x = x;
-    out.y = y;
-    out.align = textAlign;
-    out.verticalAlign = textVerticalAlign;
-    return out;
-  }
+      if (setToFinal && revertedSource) {
+        animator.whenWithKeys(0, revertedSource, animatableKeys);
+      }
 
-  var dpr = 1;
+      if (sourceClone) {
+        animator.whenWithKeys(0, sourceClone, animatableKeys);
+      }
 
-  if (typeof window !== 'undefined') {
-    dpr = Math.max(window.devicePixelRatio || window.screen.deviceXDPI / window.screen.logicalXDPI || 1, 1);
+      animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animatableKeys).delay(delay || 0);
+      animatable.addAnimator(animator, topKey);
+      animators.push(animator);
+    }
   }
 
-  var devicePixelRatio = dpr;
-  var DARK_MODE_THRESHOLD = 0.4;
-  var DARK_LABEL_COLOR = '#333';
-  var LIGHT_LABEL_COLOR = '#ccc';
-  var LIGHTER_LABEL_COLOR = '#eee';
-  var PRESERVED_NORMAL_STATE = '__zr_normal__';
-  var PRIMARY_STATES_KEYS = ['x', 'y', 'scaleX', 'scaleY', 'originX', 'originY', 'rotation', 'ignore'];
-  var DEFAULT_ANIMATABLE_MAP = {
-    x: true,
-    y: true,
-    scaleX: true,
-    scaleY: true,
-    originX: true,
-    originY: true,
-    rotation: true,
-    ignore: false
-  };
-  var tmpTextPosCalcRes = {};
-  var tmpBoundingRect = new BoundingRect(0, 0, 0, 0);
+  var DEFAULT_MIN_MERGE = 32;
+  var DEFAULT_MIN_GALLOPING = 7;
 
-  var Element = function () {
-    function Element(props) {
-      this.id = guid();
-      this.animators = [];
-      this.currentStates = [];
-      this.states = {};
+  function minRunLength(n) {
+    var r = 0;
 
-      this._init(props);
+    while (n >= DEFAULT_MIN_MERGE) {
+      r |= n & 1;
+      n >>= 1;
     }
 
-    Element.prototype._init = function (props) {
-      this.attr(props);
-    };
-
-    Element.prototype.drift = function (dx, dy, e) {
-      switch (this.draggable) {
-        case 'horizontal':
-          dy = 0;
-          break;
+    return n + r;
+  }
 
-        case 'vertical':
-          dx = 0;
-          break;
-      }
+  function makeAscendingRun(array, lo, hi, compare) {
+    var runHi = lo + 1;
 
-      var m = this.transform;
+    if (runHi === hi) {
+      return 1;
+    }
 
-      if (!m) {
-        m = this.transform = [1, 0, 0, 1, 0, 0];
+    if (compare(array[runHi++], array[lo]) < 0) {
+      while (runHi < hi && compare(array[runHi], array[runHi - 1]) < 0) {
+        runHi++;
       }
 
-      m[4] += dx;
-      m[5] += dy;
-      this.decomposeTransform();
-      this.markRedraw();
-    };
+      reverseRun(array, lo, runHi);
+    } else {
+      while (runHi < hi && compare(array[runHi], array[runHi - 1]) >= 0) {
+        runHi++;
+      }
+    }
 
-    Element.prototype.beforeUpdate = function () {};
+    return runHi - lo;
+  }
 
-    Element.prototype.afterUpdate = function () {};
+  function reverseRun(array, lo, hi) {
+    hi--;
 
-    Element.prototype.update = function () {
-      this.updateTransform();
-      this.updateInnerText();
-    };
+    while (lo < hi) {
+      var t = array[lo];
+      array[lo++] = array[hi];
+      array[hi--] = t;
+    }
+  }
 
-    Element.prototype.updateInnerText = function (forceUpdate) {
-      var textEl = this._textContent;
+  function binaryInsertionSort(array, lo, hi, start, compare) {
+    if (start === lo) {
+      start++;
+    }
 
-      if (textEl && (!textEl.ignore || forceUpdate)) {
-        if (!this.textConfig) {
-          this.textConfig = {};
-        }
+    for (; start < hi; start++) {
+      var pivot = array[start];
+      var left = lo;
+      var right = start;
+      var mid;
 
-        var textConfig = this.textConfig;
-        var isLocal = textConfig.local;
-        var attachedTransform = textEl.attachedTransform;
-        var textAlign = void 0;
-        var textVerticalAlign = void 0;
-        var textStyleChanged = false;
+      while (left < right) {
+        mid = left + right >>> 1;
 
-        if (isLocal) {
-          attachedTransform.parent = this;
+        if (compare(pivot, array[mid]) < 0) {
+          right = mid;
         } else {
-          attachedTransform.parent = null;
+          left = mid + 1;
         }
+      }
 
-        var innerOrigin = false;
-        attachedTransform.x = textEl.x;
-        attachedTransform.y = textEl.y;
-        attachedTransform.originX = textEl.originX;
-        attachedTransform.originY = textEl.originY;
-        attachedTransform.rotation = textEl.rotation;
-        attachedTransform.scaleX = textEl.scaleX;
-        attachedTransform.scaleY = textEl.scaleY;
+      var n = start - left;
 
-        if (textConfig.position != null) {
-          var layoutRect = tmpBoundingRect;
+      switch (n) {
+        case 3:
+          array[left + 3] = array[left + 2];
 
-          if (textConfig.layoutRect) {
-            layoutRect.copy(textConfig.layoutRect);
-          } else {
-            layoutRect.copy(this.getBoundingRect());
-          }
+        case 2:
+          array[left + 2] = array[left + 1];
 
-          if (!isLocal) {
-            layoutRect.applyTransform(this.transform);
-          }
+        case 1:
+          array[left + 1] = array[left];
+          break;
 
-          if (this.calculateTextPosition) {
-            this.calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
-          } else {
-            calculateTextPosition(tmpTextPosCalcRes, textConfig, layoutRect);
+        default:
+          while (n > 0) {
+            array[left + n] = array[left + n - 1];
+            n--;
           }
 
-          attachedTransform.x = tmpTextPosCalcRes.x;
-          attachedTransform.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;
+      array[left] = pivot;
+    }
+  }
 
-            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);
-            }
+  function gallopLeft(value, array, start, length, hint, compare) {
+    var lastOffset = 0;
+    var maxOffset = 0;
+    var offset = 1;
 
-            innerOrigin = true;
-            attachedTransform.originX = -attachedTransform.x + relOriginX + (isLocal ? 0 : layoutRect.x);
-            attachedTransform.originY = -attachedTransform.y + relOriginY + (isLocal ? 0 : layoutRect.y);
-          }
-        }
+    if (compare(value, array[start + hint]) > 0) {
+      maxOffset = length - hint;
 
-        if (textConfig.rotation != null) {
-          attachedTransform.rotation = textConfig.rotation;
+      while (offset < maxOffset && compare(value, array[start + hint + offset]) > 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
+
+        if (offset <= 0) {
+          offset = maxOffset;
         }
+      }
 
-        var textOffset = textConfig.offset;
+      if (offset > maxOffset) {
+        offset = maxOffset;
+      }
 
-        if (textOffset) {
-          attachedTransform.x += textOffset[0];
-          attachedTransform.y += textOffset[1];
+      lastOffset += hint;
+      offset += hint;
+    } else {
+      maxOffset = hint + 1;
 
-          if (!innerOrigin) {
-            attachedTransform.originX = -textOffset[0];
-            attachedTransform.originY = -textOffset[1];
-          }
+      while (offset < maxOffset && compare(value, array[start + hint - offset]) <= 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
+
+        if (offset <= 0) {
+          offset = maxOffset;
         }
+      }
 
-        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 (offset > maxOffset) {
+        offset = maxOffset;
+      }
 
-        if (isInside && this.canBeInsideText()) {
-          textFill = textConfig.insideFill;
-          textStroke = textConfig.insideStroke;
+      var tmp = lastOffset;
+      lastOffset = hint - offset;
+      offset = hint - tmp;
+    }
 
-          if (textFill == null || textFill === 'auto') {
-            textFill = this.getInsideTextFill();
-          }
+    lastOffset++;
 
-          if (textStroke == null || textStroke === 'auto') {
-            textStroke = this.getInsideTextStroke(textFill);
-            autoStroke = true;
-          }
-        } else {
-          textFill = textConfig.outsideFill;
-          textStroke = textConfig.outsideStroke;
+    while (lastOffset < offset) {
+      var m = lastOffset + (offset - lastOffset >>> 1);
 
-          if (textFill == null || textFill === 'auto') {
-            textFill = this.getOutsideFill();
-          }
+      if (compare(value, array[start + m]) > 0) {
+        lastOffset = m + 1;
+      } else {
+        offset = m;
+      }
+    }
 
-          if (textStroke == null || textStroke === 'auto') {
-            textStroke = this.getOutsideStroke(textFill);
-            autoStroke = true;
-          }
-        }
+    return offset;
+  }
 
-        textFill = textFill || '#000';
+  function gallopRight(value, array, start, length, hint, compare) {
+    var lastOffset = 0;
+    var maxOffset = 0;
+    var offset = 1;
 
-        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);
-        }
+    if (compare(value, array[start + hint]) < 0) {
+      maxOffset = hint + 1;
 
-        if (textStyleChanged) {
-          textEl.dirtyStyle();
+      while (offset < maxOffset && compare(value, array[start + hint - offset]) < 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
+
+        if (offset <= 0) {
+          offset = maxOffset;
         }
+      }
 
-        textEl.markRedraw();
+      if (offset > maxOffset) {
+        offset = maxOffset;
       }
-    };
 
-    Element.prototype.canBeInsideText = function () {
-      return true;
-    };
+      var tmp = lastOffset;
+      lastOffset = hint - offset;
+      offset = hint - tmp;
+    } else {
+      maxOffset = length - hint;
 
-    Element.prototype.getInsideTextFill = function () {
-      return '#fff';
-    };
+      while (offset < maxOffset && compare(value, array[start + hint + offset]) >= 0) {
+        lastOffset = offset;
+        offset = (offset << 1) + 1;
 
-    Element.prototype.getInsideTextStroke = function (textFill) {
-      return '#000';
-    };
+        if (offset <= 0) {
+          offset = maxOffset;
+        }
+      }
 
-    Element.prototype.getOutsideFill = function () {
-      return this.__zr && this.__zr.isDarkMode() ? LIGHT_LABEL_COLOR : DARK_LABEL_COLOR;
-    };
+      if (offset > maxOffset) {
+        offset = maxOffset;
+      }
 
-    Element.prototype.getOutsideStroke = function (textFill) {
-      var backgroundColor = this.__zr && this.__zr.getBackgroundColor();
+      lastOffset += hint;
+      offset += hint;
+    }
 
-      var colorArr = typeof backgroundColor === 'string' && parse(backgroundColor);
+    lastOffset++;
 
-      if (!colorArr) {
-        colorArr = [255, 255, 255, 1];
+    while (lastOffset < offset) {
+      var m = lastOffset + (offset - lastOffset >>> 1);
+
+      if (compare(value, array[start + m]) < 0) {
+        offset = m;
+      } else {
+        lastOffset = m + 1;
       }
+    }
 
-      var alpha = colorArr[3];
+    return offset;
+  }
 
-      for (var i = 0; i < 3; i++) {
-        colorArr[i] = colorArr[i] * alpha + 255 * (1 - alpha);
+  function TimSort(array, compare) {
+    var minGallop = DEFAULT_MIN_GALLOPING;
+    var length = 0;
+    var runStart;
+    var runLength;
+    var stackSize = 0;
+    length = array.length;
+    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);
       }
+    }
 
-      colorArr[3] = 1;
-      return stringify(colorArr, 'rgba');
-    };
+    function forceMergeRuns() {
+      while (stackSize > 1) {
+        var n = stackSize - 2;
 
-    Element.prototype.traverse = function (cb, context) {};
+        if (n > 0 && runLength[n - 1] < runLength[n + 1]) {
+          n--;
+        }
 
-    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;
+        mergeAt(n);
       }
-    };
+    }
 
-    Element.prototype.hide = function () {
-      this.ignore = true;
-      this.markRedraw();
-    };
+    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;
 
-    Element.prototype.show = function () {
-      this.ignore = false;
-      this.markRedraw();
-    };
+      if (i === stackSize - 3) {
+        runStart[i + 1] = runStart[i + 2];
+        runLength[i + 1] = runLength[i + 2];
+      }
 
-    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);
+      stackSize--;
+      var k = gallopRight(array[start2], array, start1, length1, 0, compare);
+      start1 += k;
+      length1 -= k;
 
-        for (var i = 0; i < keysArr.length; i++) {
-          var key = keysArr[i];
-          this.attrKV(key, keyOrObj[key]);
-        }
+      if (length1 === 0) {
+        return;
+      }
+
+      length2 = gallopLeft(array[start1 + length1 - 1], array, start2, length2, length2 - 1, compare);
+
+      if (length2 === 0) {
+        return;
       }
 
-      this.markRedraw();
-      return this;
-    };
+      if (length1 <= length2) {
+        mergeLow(start1, length1, start2, length2);
+      } else {
+        mergeHigh(start1, length1, start2, length2);
+      }
+    }
 
-    Element.prototype.saveCurrentToNormalState = function (toState) {
-      this._innerSaveToNormal(toState);
+    function mergeLow(start1, length1, start2, length2) {
+      var i = 0;
 
-      var normalState = this._normalState;
+      for (i = 0; i < length1; i++) {
+        tmp[i] = array[start1 + i];
+      }
 
-      for (var i = 0; i < this.animators.length; i++) {
-        var animator = this.animators[i];
-        var fromStateTransition = animator.__fromStateTransition;
+      var cursor1 = 0;
+      var cursor2 = start2;
+      var dest = start1;
+      array[dest++] = array[cursor2++];
 
-        if (fromStateTransition && fromStateTransition !== PRESERVED_NORMAL_STATE) {
-          continue;
+      if (--length2 === 0) {
+        for (i = 0; i < length1; i++) {
+          array[dest + i] = tmp[cursor1 + i];
         }
 
-        var targetName = animator.targetName;
-        var target = targetName ? normalState[targetName] : normalState;
-        animator.saveFinalToTarget(target);
+        return;
       }
-    };
 
-    Element.prototype._innerSaveToNormal = function (toState) {
-      var normalState = this._normalState;
+      if (length1 === 1) {
+        for (i = 0; i < length2; i++) {
+          array[dest + i] = array[cursor2 + i];
+        }
 
-      if (!normalState) {
-        normalState = this._normalState = {};
+        array[dest + length2] = tmp[cursor1];
+        return;
       }
 
-      if (toState.textConfig && !normalState.textConfig) {
-        normalState.textConfig = this.textConfig;
-      }
+      var _minGallop = minGallop;
+      var count1;
+      var count2;
+      var exit;
 
-      this._savePrimaryToNormal(toState, normalState, PRIMARY_STATES_KEYS);
-    };
+      while (1) {
+        count1 = 0;
+        count2 = 0;
+        exit = false;
 
-    Element.prototype._savePrimaryToNormal = function (toState, normalState, primaryKeys) {
-      for (var i = 0; i < primaryKeys.length; i++) {
-        var key = primaryKeys[i];
+        do {
+          if (compare(array[cursor2], tmp[cursor1]) < 0) {
+            array[dest++] = array[cursor2++];
+            count2++;
+            count1 = 0;
 
-        if (toState[key] != null && !(key in normalState)) {
-          normalState[key] = this[key];
+            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;
         }
-      }
-    };
 
-    Element.prototype.hasState = function () {
-      return this.currentStates.length > 0;
-    };
+        do {
+          count1 = gallopRight(array[cursor2], tmp, cursor1, length1, 0, compare);
 
-    Element.prototype.getState = function (name) {
-      return this.states[name];
-    };
+          if (count1 !== 0) {
+            for (i = 0; i < count1; i++) {
+              array[dest + i] = tmp[cursor1 + i];
+            }
 
-    Element.prototype.ensureState = function (name) {
-      var states = this.states;
+            dest += count1;
+            cursor1 += count1;
+            length1 -= count1;
 
-      if (!states[name]) {
-        states[name] = {};
-      }
+            if (length1 <= 1) {
+              exit = true;
+              break;
+            }
+          }
 
-      return states[name];
-    };
+          array[dest++] = array[cursor2++];
 
-    Element.prototype.clearStates = function (noAnimation) {
-      this.useState(PRESERVED_NORMAL_STATE, false, noAnimation);
-    };
+          if (--length2 === 0) {
+            exit = true;
+            break;
+          }
 
-    Element.prototype.useState = function (stateName, keepCurrentStates, noAnimation) {
-      var toNormalState = stateName === PRESERVED_NORMAL_STATE;
-      var hasStates = this.hasState();
+          count2 = gallopLeft(tmp[cursor1], array, cursor2, length2, 0, compare);
 
-      if (!hasStates && toNormalState) {
-        return;
-      }
+          if (count2 !== 0) {
+            for (i = 0; i < count2; i++) {
+              array[dest + i] = array[cursor2 + i];
+            }
 
-      var currentStates = this.currentStates;
-      var animationCfg = this.stateTransition;
+            dest += count2;
+            cursor2 += count2;
+            length2 -= count2;
 
-      if (indexOf(currentStates, stateName) >= 0 && (keepCurrentStates || currentStates.length === 1)) {
-        return;
-      }
+            if (length2 === 0) {
+              exit = true;
+              break;
+            }
+          }
 
-      var state;
+          array[dest++] = tmp[cursor1++];
 
-      if (this.stateProxy && !toNormalState) {
-        state = this.stateProxy(stateName);
-      }
+          if (--length1 === 1) {
+            exit = true;
+            break;
+          }
 
-      if (!state) {
-        state = this.states && this.states[stateName];
-      }
+          _minGallop--;
+        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
 
-      if (!state && !toNormalState) {
-        logError("State " + stateName + " not exists.");
-        return;
-      }
+        if (exit) {
+          break;
+        }
 
-      if (!toNormalState) {
-        this.saveCurrentToNormalState(state);
+        if (_minGallop < 0) {
+          _minGallop = 0;
+        }
+
+        _minGallop += 2;
       }
 
-      var useHoverLayer = !!(state && state.hoverLayer);
+      minGallop = _minGallop;
+      minGallop < 1 && (minGallop = 1);
 
-      if (useHoverLayer) {
-        this._toggleHoverLayerFlag(true);
+      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];
+        }
       }
+    }
 
-      this._applyStateObj(stateName, state, this._normalState, keepCurrentStates, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
+    function mergeHigh(start1, length1, start2, length2) {
+      var i = 0;
 
-      if (this._textContent) {
-        this._textContent.useState(stateName, keepCurrentStates);
+      for (i = 0; i < length2; i++) {
+        tmp[i] = array[start2 + i];
       }
 
-      if (this._textGuide) {
-        this._textGuide.useState(stateName, keepCurrentStates);
-      }
+      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 (toNormalState) {
-        this.currentStates = [];
-        this._normalState = {};
-      } else {
-        if (!keepCurrentStates) {
-          this.currentStates = [stateName];
-        } else {
-          this.currentStates.push(stateName);
+      if (--length1 === 0) {
+        customCursor = dest - (length2 - 1);
+
+        for (i = 0; i < length2; i++) {
+          array[customCursor + i] = tmp[i];
         }
-      }
 
-      this._updateAnimationTargets();
+        return;
+      }
 
-      this.markRedraw();
+      if (length2 === 1) {
+        dest -= length1;
+        cursor1 -= length1;
+        customDest = dest + 1;
+        customCursor = cursor1 + 1;
 
-      if (!useHoverLayer && this.__inHover) {
-        this._toggleHoverLayerFlag(false);
+        for (i = length1 - 1; i >= 0; i--) {
+          array[customDest + i] = array[customCursor + i];
+        }
 
-        this.__dirty &= ~Element.REDARAW_BIT;
+        array[dest] = tmp[cursor2];
+        return;
       }
 
-      return state;
-    };
+      var _minGallop = minGallop;
 
-    Element.prototype.useStates = function (states, noAnimation) {
-      if (!states.length) {
-        this.clearStates();
-      } else {
-        var stateObjects = [];
-        var currentStates = this.currentStates;
-        var len = states.length;
-        var notChange = len === currentStates.length;
+      while (true) {
+        var count1 = 0;
+        var count2 = 0;
+        var exit = false;
 
-        if (notChange) {
-          for (var i = 0; i < len; i++) {
-            if (states[i] !== currentStates[i]) {
-              notChange = 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 (notChange) {
-          return;
+        if (exit) {
+          break;
         }
 
-        for (var i = 0; i < len; i++) {
-          var stateName = states[i];
-          var stateObj = void 0;
+        do {
+          count1 = length1 - gallopRight(tmp[cursor2], array, start1, length1, length1 - 1, compare);
 
-          if (this.stateProxy) {
-            stateObj = this.stateProxy(stateName, states);
-          }
+          if (count1 !== 0) {
+            dest -= count1;
+            cursor1 -= count1;
+            length1 -= count1;
+            customDest = dest + 1;
+            customCursor = cursor1 + 1;
 
-          if (!stateObj) {
-            stateObj = this.states[stateName];
-          }
+            for (i = count1 - 1; i >= 0; i--) {
+              array[customDest + i] = array[customCursor + i];
+            }
 
-          if (stateObj) {
-            stateObjects.push(stateObj);
+            if (length1 === 0) {
+              exit = true;
+              break;
+            }
           }
-        }
 
-        var useHoverLayer = !!(stateObjects[len - 1] && stateObjects[len - 1].hoverLayer);
+          array[dest--] = tmp[cursor2--];
 
-        if (useHoverLayer) {
-          this._toggleHoverLayerFlag(true);
-        }
+          if (--length2 === 1) {
+            exit = true;
+            break;
+          }
 
-        var mergedState = this._mergeStates(stateObjects);
+          count2 = length2 - gallopLeft(array[cursor1], tmp, 0, length2, length2 - 1, compare);
 
-        var animationCfg = this.stateTransition;
-        this.saveCurrentToNormalState(mergedState);
+          if (count2 !== 0) {
+            dest -= count2;
+            cursor2 -= count2;
+            length2 -= count2;
+            customDest = dest + 1;
+            customCursor = cursor2 + 1;
 
-        this._applyStateObj(states.join(','), mergedState, this._normalState, false, !noAnimation && !this.__inHover && animationCfg && animationCfg.duration > 0, animationCfg);
+            for (i = 0; i < count2; i++) {
+              array[customDest + i] = tmp[customCursor + i];
+            }
 
-        if (this._textContent) {
-          this._textContent.useStates(states);
-        }
+            if (length2 <= 1) {
+              exit = true;
+              break;
+            }
+          }
 
-        if (this._textGuide) {
-          this._textGuide.useStates(states);
-        }
+          array[dest--] = array[cursor1--];
 
-        this._updateAnimationTargets();
+          if (--length1 === 0) {
+            exit = true;
+            break;
+          }
 
-        this.currentStates = states.slice();
-        this.markRedraw();
+          _minGallop--;
+        } while (count1 >= DEFAULT_MIN_GALLOPING || count2 >= DEFAULT_MIN_GALLOPING);
 
-        if (!useHoverLayer && this.__inHover) {
-          this._toggleHoverLayerFlag(false);
+        if (exit) {
+          break;
+        }
 
-          this.__dirty &= ~Element.REDARAW_BIT;
+        if (_minGallop < 0) {
+          _minGallop = 0;
         }
+
+        _minGallop += 2;
       }
-    };
 
-    Element.prototype._updateAnimationTargets = function () {
-      for (var i = 0; i < this.animators.length; i++) {
-        var animator = this.animators[i];
+      minGallop = _minGallop;
 
-        if (animator.targetName) {
-          animator.changeTarget(this[animator.targetName]);
-        }
+      if (minGallop < 1) {
+        minGallop = 1;
       }
-    };
 
-    Element.prototype.removeState = function (state) {
-      var idx = indexOf(this.currentStates, state);
+      if (length2 === 1) {
+        dest -= length1;
+        cursor1 -= length1;
+        customDest = dest + 1;
+        customCursor = cursor1 + 1;
 
-      if (idx >= 0) {
-        var currentStates = this.currentStates.slice();
-        currentStates.splice(idx, 1);
-        this.useStates(currentStates);
-      }
-    };
+        for (i = length1 - 1; i >= 0; i--) {
+          array[customDest + i] = array[customCursor + i];
+        }
 
-    Element.prototype.replaceState = function (oldState, newState, forceAdd) {
-      var currentStates = this.currentStates.slice();
-      var idx = indexOf(currentStates, oldState);
-      var newStateExists = indexOf(currentStates, newState) >= 0;
+        array[dest] = tmp[cursor2];
+      } else if (length2 === 0) {
+        throw new Error();
+      } else {
+        customCursor = dest - (length2 - 1);
 
-      if (idx >= 0) {
-        if (!newStateExists) {
-          currentStates[idx] = newState;
-        } else {
-          currentStates.splice(idx, 1);
+        for (i = 0; i < length2; i++) {
+          array[customCursor + i] = tmp[i];
         }
-      } else if (forceAdd && !newStateExists) {
-        currentStates.push(newState);
       }
+    }
 
-      this.useStates(currentStates);
+    return {
+      mergeRuns: mergeRuns,
+      forceMergeRuns: forceMergeRuns,
+      pushRun: pushRun
     };
+  }
 
-    Element.prototype.toggleState = function (state, enable) {
-      if (enable) {
-        this.useState(state, true);
-      } else {
-        this.removeState(state);
-      }
-    };
+  function sort(array, compare, lo, hi) {
+    if (!lo) {
+      lo = 0;
+    }
 
-    Element.prototype._mergeStates = function (states) {
-      var mergedState = {};
-      var mergedTextConfig;
+    if (!hi) {
+      hi = array.length;
+    }
 
-      for (var i = 0; i < states.length; i++) {
-        var state = states[i];
-        extend(mergedState, state);
+    var remaining = hi - lo;
 
-        if (state.textConfig) {
-          mergedTextConfig = mergedTextConfig || {};
-          extend(mergedTextConfig, state.textConfig);
-        }
-      }
+    if (remaining < 2) {
+      return;
+    }
 
-      if (mergedTextConfig) {
-        mergedState.textConfig = mergedTextConfig;
-      }
+    var runLength = 0;
 
-      return mergedState;
-    };
+    if (remaining < DEFAULT_MIN_MERGE) {
+      runLength = makeAscendingRun(array, lo, hi, compare);
+      binaryInsertionSort(array, lo, hi, lo + runLength, compare);
+      return;
+    }
 
-    Element.prototype._applyStateObj = function (stateName, state, normalState, keepCurrentStates, transition, animationCfg) {
-      var needsRestoreToNormal = !(state && keepCurrentStates);
+    var ts = TimSort(array, compare);
+    var minRun = minRunLength(remaining);
 
-      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;
+    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;
       }
 
-      var transitionTarget = {};
-      var hasTransition = false;
+      ts.pushRun(lo, runLength);
+      ts.mergeRuns();
+      remaining -= runLength;
+      lo += runLength;
+    } while (remaining !== 0);
 
-      for (var i = 0; i < PRIMARY_STATES_KEYS.length; i++) {
-        var key = PRIMARY_STATES_KEYS[i];
-        var propNeedsTransition = transition && DEFAULT_ANIMATABLE_MAP[key];
+    ts.forceMergeRuns();
+  }
 
-        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];
-            }
-          }
-        }
-      }
+  var invalidZErrorLogged = false;
+
+  function logInvalidZError() {
+    if (invalidZErrorLogged) {
+      return;
+    }
 
-      if (!transition) {
-        for (var i = 0; i < this.animators.length; i++) {
-          var animator = this.animators[i];
-          var targetName = animator.targetName;
+    invalidZErrorLogged = true;
+    console.warn('z / z2 / zlevel of displayable is invalid, which may cause unexpected errors');
+  }
 
-          animator.__changeFinalValue(targetName ? (state || normalState)[targetName] : state || normalState);
-        }
+  function shapeCompareFunc(a, b) {
+    if (a.zlevel === b.zlevel) {
+      if (a.z === b.z) {
+        return a.z2 - b.z2;
       }
 
-      if (hasTransition) {
-        this._transitionState(stateName, transitionTarget, animationCfg);
+      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);
       }
     };
 
-    Element.prototype._attachComponent = function (componentEl) {
-      if (componentEl.__zr && !componentEl.__hostTarget) {
-        throw new Error('Text element has been added to zrender.');
-      }
+    Storage.prototype.getDisplayList = function (update, includeIgnore) {
+      includeIgnore = includeIgnore || false;
+      var displayList = this._displayList;
 
-      if (componentEl === this) {
-        throw new Error('Recursive component attachment.');
+      if (update || !displayList.length) {
+        this.updateDisplayList(includeIgnore);
       }
 
-      var zr = this.__zr;
+      return displayList;
+    };
 
-      if (zr) {
-        componentEl.addSelfToZr(zr);
+    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);
       }
 
-      componentEl.__zr = zr;
-      componentEl.__hostTarget = this;
+      displayList.length = this._displayListLen;
+      env.canvasSupported && sort(displayList, shapeCompareFunc);
     };
 
-    Element.prototype._detachComponent = function (componentEl) {
-      if (componentEl.__zr) {
-        componentEl.removeSelfFromZr(componentEl.__zr);
+    Storage.prototype._updateAndAddDisplayable = function (el, clipPaths, includeIgnore) {
+      if (el.ignore && !includeIgnore) {
+        return;
       }
 
-      componentEl.__zr = null;
-      componentEl.__hostTarget = null;
-    };
+      el.beforeUpdate();
+      el.update();
+      el.afterUpdate();
+      var userSetClipPath = el.getClipPath();
 
-    Element.prototype.getClipPath = function () {
-      return this._clipPath;
-    };
+      if (el.ignoreClip) {
+        clipPaths = null;
+      } else if (userSetClipPath) {
+        if (clipPaths) {
+          clipPaths = clipPaths.slice();
+        } else {
+          clipPaths = [];
+        }
 
-    Element.prototype.setClipPath = function (clipPath) {
-      if (this._clipPath && this._clipPath !== clipPath) {
-        this.removeClipPath();
+        var currentClipPath = userSetClipPath;
+        var parentClipPath = el;
+
+        while (currentClipPath) {
+          currentClipPath.parent = parentClipPath;
+          currentClipPath.updateTransform();
+          clipPaths.push(currentClipPath);
+          parentClipPath = currentClipPath;
+          currentClipPath = currentClipPath.getClipPath();
+        }
       }
 
-      this._attachComponent(clipPath);
+      if (el.childrenRef) {
+        var children = el.childrenRef();
 
-      this._clipPath = clipPath;
-      this.markRedraw();
-    };
+        for (var i = 0; i < children.length; i++) {
+          var child = children[i];
 
-    Element.prototype.removeClipPath = function () {
-      var clipPath = this._clipPath;
+          if (el.__dirty) {
+            child.__dirty |= Element.REDARAW_BIT;
+          }
 
-      if (clipPath) {
-        this._detachComponent(clipPath);
+          this._updateAndAddDisplayable(child, clipPaths, includeIgnore);
+        }
 
-        this._clipPath = null;
-        this.markRedraw();
-      }
-    };
+        el.__dirty = 0;
+      } else {
+        var disp = el;
 
-    Element.prototype.getTextContent = function () {
-      return this._textContent;
-    };
+        if (clipPaths && clipPaths.length) {
+          disp.__clipPaths = clipPaths;
+        } else if (disp.__clipPaths && disp.__clipPaths.length > 0) {
+          disp.__clipPaths = [];
+        }
 
-    Element.prototype.setTextContent = function (textEl) {
-      var previousTextContent = this._textContent;
+        if (isNaN(disp.z)) {
+          logInvalidZError();
+          disp.z = 0;
+        }
 
-      if (previousTextContent === textEl) {
-        return;
-      }
+        if (isNaN(disp.z2)) {
+          logInvalidZError();
+          disp.z2 = 0;
+        }
 
-      if (previousTextContent && previousTextContent !== textEl) {
-        this.removeTextContent();
-      }
+        if (isNaN(disp.zlevel)) {
+          logInvalidZError();
+          disp.zlevel = 0;
+        }
 
-      if (textEl.__zr && !textEl.__hostTarget) {
-        throw new Error('Text element has been added to zrender.');
+        this._displayList[this._displayListLen++] = disp;
       }
 
-      textEl.attachedTransform = new Transformable();
+      var decalEl = el.getDecalElement && el.getDecalElement();
 
-      this._attachComponent(textEl);
+      if (decalEl) {
+        this._updateAndAddDisplayable(decalEl, clipPaths, includeIgnore);
+      }
 
-      this._textContent = textEl;
-      this.markRedraw();
-    };
+      var textGuide = el.getTextGuideLine();
 
-    Element.prototype.setTextConfig = function (cfg) {
-      if (!this.textConfig) {
-        this.textConfig = {};
+      if (textGuide) {
+        this._updateAndAddDisplayable(textGuide, clipPaths, includeIgnore);
       }
 
-      extend(this.textConfig, cfg);
-      this.markRedraw();
-    };
-
-    Element.prototype.removeTextContent = function () {
-      var textEl = this._textContent;
+      var textEl = el.getTextContent();
 
       if (textEl) {
-        textEl.attachedTransform = null;
-
-        this._detachComponent(textEl);
-
-        this._textContent = null;
-        this._innerTextDefaultStyle = null;
-        this.markRedraw();
+        this._updateAndAddDisplayable(textEl, clipPaths, includeIgnore);
       }
     };
 
-    Element.prototype.getTextGuideLine = function () {
-      return this._textGuide;
+    Storage.prototype.addRoot = function (el) {
+      if (el.__zr && el.__zr.storage === this) {
+        return;
+      }
+
+      this._roots.push(el);
     };
 
-    Element.prototype.setTextGuideLine = function (guideLine) {
-      if (this._textGuide && this._textGuide !== guideLine) {
-        this.removeTextGuideLine();
+    Storage.prototype.delRoot = function (el) {
+      if (el instanceof Array) {
+        for (var i = 0, l = el.length; i < l; i++) {
+          this.delRoot(el[i]);
+        }
+
+        return;
       }
 
-      this._attachComponent(guideLine);
+      var idx = indexOf(this._roots, el);
 
-      this._textGuide = guideLine;
-      this.markRedraw();
+      if (idx >= 0) {
+        this._roots.splice(idx, 1);
+      }
     };
 
-    Element.prototype.removeTextGuideLine = function () {
-      var textGuide = this._textGuide;
+    Storage.prototype.delAllRoots = function () {
+      this._roots = [];
+      this._displayList = [];
+      this._displayListLen = 0;
+      return;
+    };
 
-      if (textGuide) {
-        this._detachComponent(textGuide);
+    Storage.prototype.getRoots = function () {
+      return this._roots;
+    };
 
-        this._textGuide = null;
-        this.markRedraw();
-      }
+    Storage.prototype.dispose = function () {
+      this._displayList = null;
+      this._roots = null;
     };
 
-    Element.prototype.markRedraw = function () {
-      this.__dirty |= Element.REDARAW_BIT;
-      var zr = this.__zr;
+    return Storage;
+  }();
 
-      if (zr) {
-        if (this.__inHover) {
-          zr.refreshHover();
-        } else {
-          zr.refresh();
-        }
-      }
+  var requestAnimationFrame;
 
-      if (this.__hostTarget) {
-        this.__hostTarget.markRedraw();
-      }
-    };
+  requestAnimationFrame = typeof window !== 'undefined' && (window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.msRequestAnimationFrame && window.msRequestAnimationFrame.bind(window) || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame) || function (func) {
+    return setTimeout(func, 16);
+  };
 
-    Element.prototype.dirty = function () {
-      this.markRedraw();
-    };
+  var requestAnimationFrame$1 = requestAnimationFrame;
 
-    Element.prototype._toggleHoverLayerFlag = function (inHover) {
-      this.__inHover = inHover;
-      var textContent = this._textContent;
-      var textGuide = this._textGuide;
+  var Animation = function (_super) {
+    __extends(Animation, _super);
 
-      if (textContent) {
-        textContent.__inHover = inHover;
-      }
+    function Animation(opts) {
+      var _this = _super.call(this) || this;
 
-      if (textGuide) {
-        textGuide.__inHover = inHover;
-      }
-    };
+      _this._running = false;
+      _this._time = 0;
+      _this._pausedTime = 0;
+      _this._pauseStart = 0;
+      _this._paused = false;
+      opts = opts || {};
+      _this.stage = opts.stage || {};
 
-    Element.prototype.addSelfToZr = function (zr) {
-      this.__zr = zr;
-      var animators = this.animators;
+      _this.onframe = opts.onframe || function () {};
 
-      if (animators) {
-        for (var i = 0; i < animators.length; i++) {
-          zr.animation.addAnimator(animators[i]);
-        }
-      }
+      return _this;
+    }
 
-      if (this._clipPath) {
-        this._clipPath.addSelfToZr(zr);
+    Animation.prototype.addClip = function (clip) {
+      if (clip.animation) {
+        this.removeClip(clip);
       }
 
-      if (this._textContent) {
-        this._textContent.addSelfToZr(zr);
+      if (!this._clipsHead) {
+        this._clipsHead = this._clipsTail = clip;
+      } else {
+        this._clipsTail.next = clip;
+        clip.prev = this._clipsTail;
+        clip.next = null;
+        this._clipsTail = clip;
       }
 
-      if (this._textGuide) {
-        this._textGuide.addSelfToZr(zr);
-      }
+      clip.animation = this;
     };
 
-    Element.prototype.removeSelfFromZr = function (zr) {
-      this.__zr = null;
-      var animators = this.animators;
+    Animation.prototype.addAnimator = function (animator) {
+      animator.animation = this;
+      var clip = animator.getClip();
 
-      if (animators) {
-        for (var i = 0; i < animators.length; i++) {
-          zr.animation.removeAnimator(animators[i]);
-        }
+      if (clip) {
+        this.addClip(clip);
       }
+    };
 
-      if (this._clipPath) {
-        this._clipPath.removeSelfFromZr(zr);
+    Animation.prototype.removeClip = function (clip) {
+      if (!clip.animation) {
+        return;
       }
 
-      if (this._textContent) {
-        this._textContent.removeSelfFromZr(zr);
+      var prev = clip.prev;
+      var next = clip.next;
+
+      if (prev) {
+        prev.next = next;
+      } else {
+        this._clipsHead = next;
       }
 
-      if (this._textGuide) {
-        this._textGuide.removeSelfFromZr(zr);
+      if (next) {
+        next.prev = prev;
+      } else {
+        this._clipsTail = prev;
       }
+
+      clip.next = clip.prev = clip.animation = null;
     };
 
-    Element.prototype.animate = function (key, loop) {
-      var target = key ? this[key] : this;
+    Animation.prototype.removeAnimator = function (animator) {
+      var clip = animator.getClip();
 
-      if (!target) {
-        logError('Property "' + key + '" is not existed in element ' + this.id);
-        return;
+      if (clip) {
+        this.removeClip(clip);
       }
 
-      var animator = new Animator(target, loop);
-      this.addAnimator(animator, key);
-      return animator;
+      animator.animation = null;
     };
 
-    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);
+    Animation.prototype.update = function (notTriggerStageUpdate) {
+      var time = new Date().getTime() - this._pausedTime;
 
-        if (idx >= 0) {
-          animators.splice(idx, 1);
-        }
-      });
-      this.animators.push(animator);
+      var delta = time - this._time;
+      var clip = this._clipsHead;
 
-      if (zr) {
-        zr.animation.addAnimator(animator);
+      while (clip) {
+        var nextClip = clip.next;
+        var finished = clip.step(time, delta);
+
+        if (finished) {
+          clip.ondestroy && clip.ondestroy();
+          this.removeClip(clip);
+          clip = nextClip;
+        } else {
+          clip = nextClip;
+        }
       }
 
-      zr && zr.wakeUp();
-    };
+      this._time = time;
+      this.onframe(delta);
+      this.trigger('frame', delta);
 
-    Element.prototype.updateDuringAnimation = function (key) {
-      this.markRedraw();
+      if (this.stage.update && !notTriggerStageUpdate) {
+        this.stage.update();
+      }
     };
 
-    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];
+    Animation.prototype._startLoop = function () {
+      var self = this;
+      this._running = true;
 
-        if (!scope || scope === animator.scope) {
-          animator.stop(forwardToLast);
-        } else {
-          leftAnimators.push(animator);
+      function step() {
+        if (self._running) {
+          requestAnimationFrame$1(step);
+          !self._paused && self.update();
         }
       }
 
-      this.animators = leftAnimators;
-      return this;
+      requestAnimationFrame$1(step);
     };
 
-    Element.prototype.animateTo = function (target, cfg, animationProps) {
-      animateTo(this, target, cfg, animationProps);
-    };
+    Animation.prototype.start = function () {
+      if (this._running) {
+        return;
+      }
 
-    Element.prototype.animateFrom = function (target, cfg, animationProps) {
-      animateTo(this, target, cfg, animationProps, true);
+      this._time = new Date().getTime();
+      this._pausedTime = 0;
+
+      this._startLoop();
     };
 
-    Element.prototype._transitionState = function (stateName, target, cfg, animationProps) {
-      var animators = animateTo(this, target, cfg, animationProps);
+    Animation.prototype.stop = function () {
+      this._running = false;
+    };
 
-      for (var i = 0; i < animators.length; i++) {
-        animators[i].__fromStateTransition = stateName;
+    Animation.prototype.pause = function () {
+      if (!this._paused) {
+        this._pauseStart = new Date().getTime();
+        this._paused = true;
       }
     };
 
-    Element.prototype.getBoundingRect = function () {
-      return null;
+    Animation.prototype.resume = function () {
+      if (this._paused) {
+        this._pausedTime += new Date().getTime() - this._pauseStart;
+        this._paused = false;
+      }
     };
 
-    Element.REDARAW_BIT = 1;
-
-    Element.initDefaultProps = function () {
-      var elProto = Element.prototype;
-      elProto.type = 'element';
-      elProto.name = '';
-      elProto.ignore = false;
-      elProto.silent = false;
-      elProto.isGroup = false;
-      elProto.draggable = false;
-      elProto.dragging = false;
-      elProto.ignoreClip = false;
-      elProto.__inHover = false;
-      elProto.__dirty = Element.REDARAW_BIT;
-      var logs = {};
+    Animation.prototype.clear = function () {
+      var clip = this._clipsHead;
 
-      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;
-        }
+      while (clip) {
+        var nextClip = clip.next;
+        clip.prev = clip.next = clip.animation = null;
+        clip = nextClip;
       }
 
-      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);
-            }
+      this._clipsHead = this._clipsTail = null;
+    };
 
-            return this[privateKey];
-          },
-          set: function (pos) {
-            logDeprecatedError(key, xKey, yKey);
-            this[xKey] = pos[0];
-            this[yKey] = pos[1];
-            this[privateKey] = pos;
-            enhanceArray(this, pos);
-          }
-        });
+    Animation.prototype.isFinished = function () {
+      return this._clipsHead == null;
+    };
 
-        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;
-            }
-          });
-        }
-      }
+    Animation.prototype.animate = function (target, options) {
+      options = options || {};
+      this.start();
+      var animator = new Animator(target, options.loop);
+      this.addAnimator(animator);
+      return animator;
+    };
 
-      if (Object.defineProperty && (!env.browser.ie || env.browser.version > 8)) {
-        createLegacyProperty('position', '_legacyPos', 'x', 'y');
-        createLegacyProperty('scale', '_legacyScale', 'scaleX', 'scaleY');
-        createLegacyProperty('origin', '_legacyOrigin', 'originX', 'originY');
-      }
-    }();
+    return Animation;
+  }(Eventful);
 
-    return Element;
-  }();
+  var TOUCH_CLICK_DELAY = 300;
+  var globalEventSupported = env.domSupported;
 
-  mixin(Element, Eventful);
-  mixin(Element, Transformable);
+  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
+    };
+  }();
 
-  function animateTo(animatable, target, cfg, animationProps, reverse) {
-    cfg = cfg || {};
-    var animators = [];
-    animateToShallow(animatable, '', animatable, target, cfg, animationProps, animators, reverse);
-    var doneCount = animators.length;
-    var abortedCount = doneCount;
-    var cfgDone = cfg.done;
-    var cfgAborted = cfg.aborted;
-    var doneCb = cfgDone ? function () {
-      doneCount--;
+  var globalNativeListenerNames = {
+    mouse: ['mousemove', 'mouseup'],
+    pointer: ['pointermove', 'pointerup']
+  };
+  var wheelEventSupported = false;
 
-      if (!doneCount) {
-        cfgDone();
-      }
-    } : null;
-    var abortedCb = cfgAborted ? function () {
-      abortedCount--;
+  function isPointerFromTouch(event) {
+    var pointerType = event.pointerType;
+    return pointerType === 'pen' || pointerType === 'touch';
+  }
 
-      if (!abortedCount) {
-        cfgAborted();
-      }
-    } : null;
+  function setTouchTimer(scope) {
+    scope.touching = true;
 
-    if (!doneCount) {
-      cfgDone && cfgDone();
+    if (scope.touchTimer != null) {
+      clearTimeout(scope.touchTimer);
+      scope.touchTimer = null;
     }
 
-    if (animators.length > 0 && cfg.during) {
-      animators[0].during(function (target, percent) {
-        cfg.during(percent);
-      });
-    }
+    scope.touchTimer = setTimeout(function () {
+      scope.touching = false;
+      scope.touchTimer = null;
+    }, 700);
+  }
 
-    for (var i = 0; i < animators.length; i++) {
-      var animator = animators[i];
+  function markTouch(event) {
+    event && (event.zrByTouch = true);
+  }
 
-      if (doneCb) {
-        animator.done(doneCb);
-      }
+  function normalizeGlobalEvent(instance, event) {
+    return normalizeEvent(instance.dom, new FakeGlobalEvent(instance, event), true);
+  }
 
-      if (abortedCb) {
-        animator.aborted(abortedCb);
-      }
+  function isLocalEl(instance, el) {
+    var elTmp = el;
+    var isLocal = false;
 
-      animator.start(cfg.easing, cfg.force);
+    while (elTmp && elTmp.nodeType !== 9 && !(isLocal = elTmp.domBelongToZr || elTmp !== el && elTmp === instance.painterRoot)) {
+      elTmp = elTmp.parentNode;
     }
 
-    return animators;
+    return isLocal;
   }
 
-  function copyArrShallow(source, target, len) {
-    for (var i = 0; i < len; i++) {
-      source[i] = target[i];
+  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;
     }
-  }
 
-  function is2DArray(value) {
-    return isArrayLike(value[0]);
-  }
+    return FakeGlobalEvent;
+  }();
 
-  function copyValue(target, source, key) {
-    if (isArrayLike(source[key])) {
-      if (!isArrayLike(target[key])) {
-        target[key] = [];
+  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);
       }
 
-      if (isTypedArray(source[key])) {
-        var len = source[key].length;
+      this.trigger('mousemove', event);
+    },
+    mouseup: function (event) {
+      event = normalizeEvent(this.dom, event);
 
-        if (target[key].length !== len) {
-          target[key] = new source[key].constructor(len);
-          copyArrShallow(target[key], source[key], len);
-        }
+      this.__togglePointerCapture(false);
+
+      this.trigger('mouseup', event);
+    },
+    mouseout: function (event) {
+      if (event.target !== this.dom) {
+        return;
       }
 
-      var sourceArr = source[key];
-      var targetArr = target[key];
-      var len0 = sourceArr.length;
+      event = normalizeEvent(this.dom, event);
 
-      if (is2DArray(sourceArr)) {
-        var len1 = sourceArr[0].length;
+      if (this.__pointerCapturing) {
+        event.zrEventControl = 'no_globalout';
+      }
 
-        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);
+      var element = event.toElement || event.relatedTarget;
+      event.zrIsToLocalDOM = isLocalEl(this, element);
+      this.trigger('mouseout', event);
+    },
+    wheel: function (event) {
+      wheelEventSupported = true;
+      event = normalizeEvent(this.dom, event);
+      this.trigger('mousewheel', event);
+    },
+    mousewheel: function (event) {
+      if (wheelEventSupported) {
+        return;
       }
 
-      targetArr.length = sourceArr.length;
-    } else {
-      target[key] = source[key];
+      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;
 
-  function animateToShallow(animatable, topKey, source, target, cfg, animationProps, animators, reverse) {
-    var animatableKeys = [];
-    var changedKeys = [];
-    var targetKeys = keys(target);
-    var duration = cfg.duration;
-    var delay = cfg.delay;
-    var additive = cfg.additive;
-    var setToFinal = cfg.setToFinal;
-    var animateAll = !isObject(animationProps);
+      this.__togglePointerCapture(false);
 
-    for (var k = 0; k < targetKeys.length; k++) {
-      var innerKey = targetKeys[k];
+      this.trigger('mouseup', event);
 
-      if (source[innerKey] != null && target[innerKey] != null && (animateAll || animationProps[innerKey])) {
-        if (isObject(target[innerKey]) && !isArrayLike(target[innerKey])) {
-          if (topKey) {
-            if (!reverse) {
-              source[innerKey] = target[innerKey];
-              animatable.updateDuringAnimation(topKey);
-            }
+      if (pointerCaptureReleasing) {
+        event.zrEventControl = 'only_globalout';
+        this.trigger('mouseout', event);
+      }
+    }
+  };
 
-            continue;
-          }
+  function mountLocalDOMEventListeners(instance, scope) {
+    var domHandlers = scope.domHandlers;
 
-          animateToShallow(animatable, innerKey, source[innerKey], target[innerKey], cfg, animationProps && animationProps[innerKey], animators, reverse);
-        } else {
-          animatableKeys.push(innerKey);
-          changedKeys.push(innerKey);
-        }
-      } else if (!reverse) {
-        source[innerKey] = target[innerKey];
-        animatable.updateDuringAnimation(topKey);
-        changedKeys.push(innerKey);
+    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);
+          }
+        });
+      });
     }
+  }
 
-    var keyLen = animatableKeys.length;
+  function mountGlobalDOMEventListeners(instance, scope) {
+    if (env.pointerEventsSupported) {
+      each(globalNativeListenerNames.pointer, mount);
+    } else if (!env.touchEventsSupported) {
+      each(globalNativeListenerNames.mouse, mount);
+    }
 
-    if (keyLen > 0 || cfg.force) {
-      var existsAnimators = animatable.animators;
-      var existsAnimatorsOnSameTarget = [];
+    function mount(nativeEventName) {
+      function nativeEventListener(event) {
+        event = getNativeEvent(event);
 
-      for (var i = 0; i < existsAnimators.length; i++) {
-        if (existsAnimators[i].targetName === topKey) {
-          existsAnimatorsOnSameTarget.push(existsAnimators[i]);
+        if (!isLocalEl(instance, event.target)) {
+          event = normalizeGlobalEvent(instance, event);
+          scope.domHandlers[nativeEventName].call(instance, event);
         }
       }
 
-      if (!additive && existsAnimatorsOnSameTarget.length) {
-        for (var i = 0; i < existsAnimatorsOnSameTarget.length; i++) {
-          var allAborted = existsAnimatorsOnSameTarget[i].stopTracks(changedKeys);
+      mountSingleDOMEventListener(scope, nativeEventName, nativeEventListener, {
+        capture: true
+      });
+    }
+  }
 
-          if (allAborted) {
-            var idx = indexOf(existsAnimators, existsAnimatorsOnSameTarget[i]);
-            existsAnimators.splice(idx, 1);
-          }
-        }
+  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]);
       }
+    }
 
-      var revertedSource = void 0;
-      var reversedTarget = void 0;
-      var sourceClone = void 0;
+    scope.mounted = {};
+  }
 
-      if (reverse) {
-        reversedTarget = {};
+  var DOMHandlerScope = function () {
+    function DOMHandlerScope(domTarget, domHandlers) {
+      this.mounted = {};
+      this.listenerOpts = {};
+      this.touching = false;
+      this.domTarget = domTarget;
+      this.domHandlers = domHandlers;
+    }
 
-        if (setToFinal) {
-          revertedSource = {};
-        }
+    return DOMHandlerScope;
+  }();
 
-        for (var i = 0; i < keyLen; i++) {
-          var innerKey = animatableKeys[i];
-          reversedTarget[innerKey] = source[innerKey];
+  var HandlerDomProxy = function (_super) {
+    __extends(HandlerDomProxy, _super);
 
-          if (setToFinal) {
-            revertedSource[innerKey] = target[innerKey];
-          } else {
-            source[innerKey] = target[innerKey];
-          }
-        }
-      } else if (setToFinal) {
-        sourceClone = {};
+    function HandlerDomProxy(dom, painterRoot) {
+      var _this = _super.call(this) || this;
 
-        for (var i = 0; i < keyLen; i++) {
-          var innerKey = animatableKeys[i];
-          sourceClone[innerKey] = cloneValue(source[innerKey]);
-          copyValue(source, target, innerKey);
-        }
+      _this.__pointerCapturing = false;
+      _this.dom = dom;
+      _this.painterRoot = painterRoot;
+      _this._localHandlerScope = new DOMHandlerScope(dom, localDOMHandlers);
+
+      if (globalEventSupported) {
+        _this._globalHandlerScope = new DOMHandlerScope(document, globalDOMHandlers);
       }
 
-      var animator = new Animator(source, false, additive ? existsAnimatorsOnSameTarget : null);
-      animator.targetName = topKey;
+      mountLocalDOMEventListeners(_this, _this._localHandlerScope);
+      return _this;
+    }
 
-      if (cfg.scope) {
-        animator.scope = cfg.scope;
-      }
+    HandlerDomProxy.prototype.dispose = function () {
+      unmountDOMEventListeners(this._localHandlerScope);
 
-      if (setToFinal && revertedSource) {
-        animator.whenWithKeys(0, revertedSource, animatableKeys);
+      if (globalEventSupported) {
+        unmountDOMEventListeners(this._globalHandlerScope);
       }
+    };
 
-      if (sourceClone) {
-        animator.whenWithKeys(0, sourceClone, animatableKeys);
+    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);
       }
+    };
 
-      animator.whenWithKeys(duration == null ? 500 : duration, reverse ? reversedTarget : target, animatableKeys).delay(delay || 0);
-      animatable.addAnimator(animator, topKey);
-      animators.push(animator);
-    }
-  }
+    return HandlerDomProxy;
+  }(Eventful);
 
   var STYLE_MAGIC_KEY = '__zr_style_' + Math.round(Math.random() * 10);
   var DEFAULT_COMMON_STYLE = {
@@ -7278,6 +7318,36 @@
 
     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);
     };
@@ -7292,6 +7362,58 @@
       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);
     };
@@ -7433,7 +7555,7 @@
 
           this._transitionState(stateName, {
             style: targetStyle
-          }, animationCfg, this._getAnimationStyleProps());
+          }, animationCfg, this.getAnimationStyleProps());
         } else {
           this.useStyle(targetStyle);
         }
@@ -7479,7 +7601,7 @@
       return targetStyle;
     };
 
-    Displayable.prototype._getAnimationStyleProps = function () {
+    Displayable.prototype.getAnimationStyleProps = function () {
       return DEFAULT_COMMON_ANIMATION_PROPS;
     };
 
@@ -7497,12 +7619,28 @@
       dispProto.rectHover = false;
       dispProto.incremental = false;
       dispProto._rect = null;
+      dispProto.dirtyRectTolerance = 0;
       dispProto.__dirty = Element.REDARAW_BIT | Displayable.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 mathPow = Math.pow;
   var mathSqrt = Math.sqrt;
   var EPSILON$1 = 1e-8;
@@ -8510,7 +8648,7 @@
       var y0 = 0;
       var i;
 
-      for (i = 0; i < data.length;) {
+      for (i = 0; i < this._len;) {
         var cmd = data[i++];
         var isFirst = i === 1;
 
@@ -9296,7 +9434,9 @@
     return w;
   }
 
-  function containPath(data, lineWidth, isStroke, x, y) {
+  function containPath(path, lineWidth, isStroke, x, y) {
+    var data = path.data;
+    var len = path.len();
     var w = 0;
     var xi = 0;
     var yi = 0;
@@ -9305,7 +9445,7 @@
     var x1;
     var y1;
 
-    for (var i = 0; i < data.length;) {
+    for (var i = 0; i < len;) {
       var cmd = data[i++];
       var isFirst = i === 1;
 
@@ -9443,12 +9583,12 @@
     return w !== 0;
   }
 
-  function contain(pathData, x, y) {
-    return containPath(pathData, 0, false, x, y);
+  function contain(pathProxy, x, y) {
+    return containPath(pathProxy, 0, false, x, y);
   }
 
-  function containStroke$4(pathData, lineWidth, x, y) {
-    return containPath(pathData, lineWidth, true, x, y);
+  function containStroke$4(pathProxy, lineWidth, x, y) {
+    return containPath(pathProxy, lineWidth, true, x, y);
   }
 
   var DEFAULT_PATH_STYLE = defaults({
@@ -9476,6 +9616,7 @@
       miterLimit: true
     }, DEFAULT_COMMON_ANIMATION_PROPS.style)
   };
+  var pathCopyParams = ['x', 'y', 'rotation', 'scaleX', 'scaleY', 'originX', 'originY', 'invisible', 'culling', 'z', 'z2', 'zlevel', 'parent'];
 
   var Path = function (_super) {
     __extends(Path, _super);
@@ -9484,6 +9625,50 @@
       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 |= Element.REDARAW_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();
@@ -9611,7 +9796,7 @@
 
       this._rect = rect;
 
-      if (this.hasStroke()) {
+      if (this.hasStroke() && this.path && this.path.len() > 0) {
         var rectWithStroke = this._rectWithStroke || (this._rectWithStroke = rect.clone());
 
         if (this.__dirty || needsUpdateRect) {
@@ -9646,7 +9831,7 @@
       y = localPos[1];
 
       if (rect.contain(x, y)) {
-        var pathData = this.path.data;
+        var pathProxy = this.path;
 
         if (this.hasStroke()) {
           var lineWidth = style.lineWidth;
@@ -9657,14 +9842,14 @@
               lineWidth = Math.max(lineWidth, this.strokeContainThreshold);
             }
 
-            if (containStroke$4(pathData, lineWidth / lineScale, x, y)) {
+            if (containStroke$4(pathProxy, lineWidth / lineScale, x, y)) {
               return true;
             }
           }
         }
 
         if (this.hasFill()) {
-          return contain(pathData, x, y);
+          return contain(pathProxy, x, y);
         }
       }
 
@@ -9678,6 +9863,10 @@
         this._rect = null;
       }
 
+      if (this._decalEl) {
+        this._decalEl.dirtyShape();
+      }
+
       this.markRedraw();
     };
 
@@ -9813,7 +10002,7 @@
       return mergedState;
     };
 
-    Path.prototype._getAnimationStyleProps = function () {
+    Path.prototype.getAnimationStyleProps = function () {
       return DEFAULT_PATH_ANIMATION_PROPS;
     };
 
@@ -9874,6 +10063,7 @@
 
   function transformPath(path, m) {
     var data = path.data;
+    var len = path.len();
     var cmd;
     var nPoint;
     var i;
@@ -9887,7 +10077,7 @@
     var A = CMD$2.A;
     var Q = CMD$2.Q;
 
-    for (i = 0, j = 0; i < data.length;) {
+    for (i = 0, j = 0; i < len;) {
       cmd = data[i++];
       j = i;
       nPoint = 0;
@@ -10591,6 +10781,10 @@
     }, DEFAULT_COMMON_ANIMATION_PROPS.style)
   };
 
+  function isImageLike(source) {
+    return source && typeof source !== 'string' && source.width && source.height;
+  }
+
   var ZRImage = function (_super) {
     __extends(ZRImage, _super);
 
@@ -10602,7 +10796,61 @@
       return createObject(DEFAULT_IMAGE_STYLE, obj);
     };
 
-    ZRImage.prototype._getAnimationStyleProps = function () {
+    ZRImage.prototype.getWidth = function () {
+      var style = this.style;
+      var imageSource = style.image;
+
+      if (isImageLike(imageSource)) {
+        return imageSource.width;
+      }
+
+      if (!this.__image) {
+        return 0;
+      }
+
+      var width = style.width;
+      var height = style.height;
+
+      if (width == null) {
+        if (height == null) {
+          return this.__image.width;
+        } else {
+          var aspect = this.__image.width / this.__image.height;
+          return aspect * height;
+        }
+      } else {
+        return width;
+      }
+    };
+
+    ZRImage.prototype.getHeight = function () {
+      var style = this.style;
+      var imageSource = style.image;
+
+      if (isImageLike(imageSource)) {
+        return imageSource.height;
+      }
+
+      if (!this.__image) {
+        return 0;
+      }
+
+      var width = style.width;
+      var height = style.height;
+
+      if (height == null) {
+        if (width == null) {
+          return this.__image.height;
+        } else {
+          var aspect = this.__image.height / this.__image.width;
+          return aspect * width;
+        }
+      } else {
+        return height;
+      }
+    };
+
+    ZRImage.prototype.getAnimationStyleProps = function () {
       return DEFAULT_IMAGE_ANIMATION_PROPS;
     };
 
@@ -10610,7 +10858,7 @@
       var style = this.style;
 
       if (!this._rect) {
-        this._rect = new BoundingRect(style.x || 0, style.y || 0, style.width || 0, style.height || 0);
+        this._rect = new BoundingRect(style.x || 0, style.y || 0, this.getWidth(), this.getHeight());
       }
 
       return this._rect;
@@ -11239,7 +11487,8 @@
     x: 0,
     y: 0,
     textAlign: 'left',
-    textBaseline: 'top'
+    textBaseline: 'top',
+    miterLimit: 2
   }, DEFAULT_PATH_STYLE);
 
   var TSpan = function (_super) {
@@ -11293,6 +11542,11 @@
       return this._rect;
     };
 
+    TSpan.initDefaultProps = function () {
+      var tspanProto = TSpan.prototype;
+      tspanProto.dirtyRectTolerance = 10;
+    }();
+
     return TSpan;
   }(Displayable);
 
@@ -11317,6 +11571,236 @@
     return svgNode;
   }
 
+  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$4 = Math.sqrt;
+  var mathMax$3 = Math.max;
+  var mathMin$3 = Math.min;
+  var e = 1e-4;
+
+  function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
+    var x10 = x1 - x0;
+    var y10 = y1 - y0;
+    var x32 = x3 - x2;
+    var y32 = y3 - y2;
+    var t = y32 * x10 - x32 * y10;
+
+    if (t * t < e) {
+      return;
+    }
+
+    t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
+    return [x0 + t * x10, y0 + t * y10];
+  }
+
+  function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) {
+    var x01 = x0 - x1;
+    var y01 = y0 - y1;
+    var lo = (clockwise ? cr : -cr) / mathSqrt$4(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$4(mathMax$3(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,
+      x01: -ox,
+      y01: -oy,
+      x11: cx0 * (radius / r - 1),
+      y11: cy0 * (radius / r - 1)
+    };
+  }
+
+  function buildPath$2(ctx, shape) {
+    var radius = mathMax$3(shape.r, 0);
+    var innerRadius = mathMax$3(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 x = shape.cx;
+    var y = shape.cy;
+    var clockwise = !!shape.clockwise;
+    var startAngle = shape.startAngle;
+    var endAngle = shape.endAngle;
+    var cornerRadius = shape.cornerRadius || 0;
+    var innerCornerRadius = shape.innerCornerRadius || 0;
+    var tmpAngles = [startAngle, endAngle];
+    normalizeArcAngles(tmpAngles, !clockwise);
+    var arc = mathAbs$1(tmpAngles[0] - tmpAngles[1]);
+
+    if (!(radius > e)) {
+      ctx.moveTo(x, y);
+    } else if (arc > PI2$5 - e) {
+      ctx.moveTo(x + radius * mathCos$3(startAngle), y + radius * mathSin$3(startAngle));
+      ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
+
+      if (innerRadius > e) {
+        ctx.moveTo(x + innerRadius * mathCos$3(endAngle), y + innerRadius * mathSin$3(endAngle));
+        ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
+      }
+    } else {
+      var halfRd = mathAbs$1(radius - innerRadius) / 2;
+      var cr = mathMin$3(halfRd, cornerRadius);
+      var icr = mathMin$3(halfRd, innerCornerRadius);
+      var cr0 = icr;
+      var cr1 = cr;
+      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 xre = void 0;
+      var yre = void 0;
+      var xirs = void 0;
+      var yirs = void 0;
+
+      if (cr > e || icr > 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$4(x0 * x0 + y0 * y0) * mathSqrt$4(x1 * x1 + y1 * y1))) / 2);
+            var b = mathSqrt$4(it_1[0] * it_1[0] + it_1[1] * it_1[1]);
+            cr0 = mathMin$3(icr, (innerRadius - b) / (a - 1));
+            cr1 = mathMin$3(cr, (radius - b) / (a + 1));
+          }
+        }
+      }
+
+      if (!(arc > e)) {
+        ctx.moveTo(x + xrs, y + yrs);
+      } else if (cr1 > e) {
+        var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, cr1, clockwise);
+        var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, cr1, clockwise);
+        ctx.moveTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
+
+        if (cr1 < cr) {
+          ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
+        } else {
+          ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
+          ctx.arc(x, y, radius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), !clockwise);
+          ctx.arc(x + ct1.cx, y + ct1.cy, cr1, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
+        }
+      } else {
+        ctx.moveTo(x + xrs, y + yrs);
+        ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
+      }
+
+      if (!(innerRadius > e)) {
+        ctx.lineTo(x + xire, y + yire);
+      } else if (cr0 > e) {
+        var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -cr0, clockwise);
+        var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -cr0, clockwise);
+        ctx.lineTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
+
+        if (cr0 < icr) {
+          ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
+        } else {
+          ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
+          ctx.arc(x, y, innerRadius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), clockwise);
+          ctx.arc(x + ct1.cx, y + ct1.cy, cr0, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
+        }
+      } else {
+        ctx.lineTo(x + xire, y + yire);
+        ctx.arc(x, y, 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;
+      this.innerCornerRadius = 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$2(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 CompoundPath = function (_super) {
     __extends(CompoundPath, _super);
 
@@ -11530,7 +12014,7 @@
     }
   }
 
-  function createOrUpdateImage(newImageOrSrc, image, hostEl, cb, cbPayload) {
+  function createOrUpdateImage(newImageOrSrc, image, hostEl, onload, cbPayload) {
     if (!newImageOrSrc) {
       return image;
     } else if (typeof newImageOrSrc === 'string') {
@@ -11541,7 +12025,7 @@
       var cachedImgObj = globalImageCache.get(newImageOrSrc);
       var pendingWrap = {
         hostEl: hostEl,
-        cb: cb,
+        cb: onload,
         cbPayload: cbPayload
       };
 
@@ -11817,6 +12301,13 @@
     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;
@@ -11840,6 +12331,7 @@
         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);
@@ -11891,10 +12383,7 @@
         tokenStyle && (lineHeight = Math.max(lineHeight, token.lineHeight));
       }
 
-      line.width = lineWidth;
-      line.lineHeight = lineHeight;
-      calculatedHeight += lineHeight;
-      calculatedWidth = Math.max(calculatedWidth, lineWidth);
+      finishLine(line, lineWidth, lineHeight);
     }
 
     contentBlock.outerWidth = contentBlock.width = retrieve2(topWidth, calculatedWidth);
@@ -12305,7 +12794,7 @@
       }
     };
 
-    ZRText.prototype._getAnimationStyleProps = function () {
+    ZRText.prototype.getAnimationStyleProps = function () {
       return DEFAULT_TEXT_ANIMATION_PROPS;
     };
 
@@ -12920,7 +13409,7 @@
   }(Path);
 
   Heart.prototype.type = 'heart';
-  var PI$2 = Math.PI;
+  var PI$3 = Math.PI;
   var sin = Math.sin;
   var cos = Math.cos;
 
@@ -12956,8 +13445,8 @@
       var x = shape.x;
       var y = shape.y;
       var r = shape.r;
-      var dStep = 2 * PI$2 / n;
-      var deg = -PI$2 / 2;
+      var dStep = 2 * PI$3 / n;
+      var deg = -PI$3 / 2;
       ctx.moveTo(x + r * cos(deg), y + r * sin(deg));
 
       for (var i = 0, end = n - 1; i < end; i++) {
@@ -13070,235 +13559,6 @@
   }(Path);
 
   Rose.prototype.type = 'rose';
-  var PI$3 = Math.PI;
-  var PI2$5 = PI$3 * 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$4 = Math.sqrt;
-  var mathMax$3 = Math.max;
-  var mathMin$3 = Math.min;
-  var e = 1e-4;
-
-  function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
-    var x10 = x1 - x0;
-    var y10 = y1 - y0;
-    var x32 = x3 - x2;
-    var y32 = y3 - y2;
-    var t = y32 * x10 - x32 * y10;
-
-    if (t * t < e) {
-      return;
-    }
-
-    t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / t;
-    return [x0 + t * x10, y0 + t * y10];
-  }
-
-  function computeCornerTangents(x0, y0, x1, y1, radius, cr, clockwise) {
-    var x01 = x0 - x1;
-    var y01 = y0 - y1;
-    var lo = (clockwise ? cr : -cr) / mathSqrt$4(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$4(mathMax$3(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,
-      x01: -ox,
-      y01: -oy,
-      x11: cx0 * (radius / r - 1),
-      y11: cy0 * (radius / r - 1)
-    };
-  }
-
-  function buildPath$2(ctx, shape) {
-    var radius = mathMax$3(shape.r, 0);
-    var innerRadius = mathMax$3(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 x = shape.cx;
-    var y = shape.cy;
-    var clockwise = !!shape.clockwise;
-    var startAngle = shape.startAngle;
-    var endAngle = shape.endAngle;
-    var cornerRadius = shape.cornerRadius || 0;
-    var innerCornerRadius = shape.innerCornerRadius || 0;
-    var tmpAngles = [startAngle, endAngle];
-    normalizeArcAngles(tmpAngles, !clockwise);
-    var arc = mathAbs$1(tmpAngles[0] - tmpAngles[1]);
-
-    if (!(radius > e)) {
-      ctx.moveTo(x, y);
-    } else if (arc > PI2$5 - e) {
-      ctx.moveTo(x + radius * mathCos$3(startAngle), y + radius * mathSin$3(startAngle));
-      ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
-
-      if (innerRadius > e) {
-        ctx.moveTo(x + innerRadius * mathCos$3(endAngle), y + innerRadius * mathSin$3(endAngle));
-        ctx.arc(x, y, innerRadius, endAngle, startAngle, clockwise);
-      }
-    } else {
-      var halfRd = mathAbs$1(radius - innerRadius) / 2;
-      var cr = mathMin$3(halfRd, cornerRadius);
-      var icr = mathMin$3(halfRd, innerCornerRadius);
-      var cr0 = icr;
-      var cr1 = cr;
-      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 xre = void 0;
-      var yre = void 0;
-      var xirs = void 0;
-      var yirs = void 0;
-
-      if (cr > e || icr > e) {
-        xre = radius * mathCos$3(endAngle);
-        yre = radius * mathSin$3(endAngle);
-        xirs = innerRadius * mathCos$3(startAngle);
-        yirs = innerRadius * mathSin$3(startAngle);
-
-        if (arc < PI$3) {
-          var it = intersect(xrs, yrs, xirs, yirs, xre, yre, xire, yire);
-
-          if (it) {
-            var x0 = xrs - it[0];
-            var y0 = yrs - it[1];
-            var x1 = xre - it[0];
-            var y1 = yre - it[1];
-            var a = 1 / mathSin$3(mathACos((x0 * x1 + y0 * y1) / (mathSqrt$4(x0 * x0 + y0 * y0) * mathSqrt$4(x1 * x1 + y1 * y1))) / 2);
-            var b = mathSqrt$4(it[0] * it[0] + it[1] * it[1]);
-            cr0 = mathMin$3(icr, (innerRadius - b) / (a - 1));
-            cr1 = mathMin$3(cr, (radius - b) / (a + 1));
-          }
-        }
-      }
-
-      if (!(arc > e)) {
-        ctx.moveTo(x + xrs, y + yrs);
-      } else if (cr1 > e) {
-        var ct0 = computeCornerTangents(xirs, yirs, xrs, yrs, radius, cr1, clockwise);
-        var ct1 = computeCornerTangents(xre, yre, xire, yire, radius, cr1, clockwise);
-        ctx.moveTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
-
-        if (cr1 < cr) {
-          ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
-        } else {
-          ctx.arc(x + ct0.cx, y + ct0.cy, cr1, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
-          ctx.arc(x, y, radius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), !clockwise);
-          ctx.arc(x + ct1.cx, y + ct1.cy, cr1, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
-        }
-      } else {
-        ctx.moveTo(x + xrs, y + yrs);
-        ctx.arc(x, y, radius, startAngle, endAngle, !clockwise);
-      }
-
-      if (!(innerRadius > e)) {
-        ctx.lineTo(x + xire, y + yire);
-      } else if (cr0 > e) {
-        var ct0 = computeCornerTangents(xire, yire, xre, yre, innerRadius, -cr0, clockwise);
-        var ct1 = computeCornerTangents(xrs, yrs, xirs, yirs, innerRadius, -cr0, clockwise);
-        ctx.lineTo(x + ct0.cx + ct0.x01, y + ct0.cy + ct0.y01);
-
-        if (cr0 < icr) {
-          ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct1.y01, ct1.x01), !clockwise);
-        } else {
-          ctx.arc(x + ct0.cx, y + ct0.cy, cr0, mathATan2(ct0.y01, ct0.x01), mathATan2(ct0.y11, ct0.x11), !clockwise);
-          ctx.arc(x, y, innerRadius, mathATan2(ct0.cy + ct0.y11, ct0.cx + ct0.x11), mathATan2(ct1.cy + ct1.y11, ct1.cx + ct1.x11), clockwise);
-          ctx.arc(x + ct1.cx, y + ct1.cy, cr0, mathATan2(ct1.y11, ct1.x11), mathATan2(ct1.y01, ct1.x01), !clockwise);
-        }
-      } else {
-        ctx.lineTo(x + xire, y + yire);
-        ctx.arc(x, y, 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;
-      this.innerCornerRadius = 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$2(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 PI$4 = Math.PI;
   var cos$2 = Math.cos;
   var sin$2 = Math.sin;
@@ -13668,6 +13928,7 @@
         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);
       this.storage = storage;
       this.painter = painter;
@@ -13754,10 +14015,11 @@
 
     ZRender.prototype._flush = function (fromInside) {
       var triggerRendered;
+      var start = new Date().getTime();
 
       if (this._needsRefresh) {
         triggerRendered = true;
-        this.refreshImmediately(true);
+        this.refreshImmediately(fromInside);
       }
 
       if (this._needsRefreshHover) {
@@ -13765,9 +14027,13 @@
         this.refreshHoverImmediately();
       }
 
+      var end = new Date().getTime();
+
       if (triggerRendered) {
         this._stillFrameAccum = 0;
-        this.trigger('rendered');
+        this.trigger('rendered', {
+          elapsedTime: end - start
+        });
       } else if (this._sleepAfterStill > 0) {
         this._stillFrameAccum++;
 
@@ -13903,7 +14169,7 @@
     painterCtors[name] = Ctor;
   }
 
-  var version = '5.0.0-beta.1';
+  var version = '5.0.0-beta.2';
   var zrender = /*#__PURE__*/Object.freeze({
     __proto__: null,
     init: init,
@@ -14238,6 +14504,26 @@
     return Math.round(Math.random() * 9);
   }
 
+  function getGreatestCommonDividor(a, b) {
+    if (b === 0) {
+      return a;
+    }
+
+    return getGreatestCommonDividor(b, a % b);
+  }
+
+  function getLeastCommonMultiple(a, b) {
+    if (a == null) {
+      return b;
+    }
+
+    if (b == null) {
+      return a;
+    }
+
+    return a * b / getGreatestCommonDividor(a, b);
+  }
+
   var numberUtil = /*#__PURE__*/Object.freeze({
     __proto__: null,
     linearMap: linearMap,
@@ -14259,8 +14545,104 @@
     reformIntervals: reformIntervals,
     numericToNumber: numericToNumber,
     isNumeric: isNumeric,
-    getRandomIdBase: getRandomIdBase
+    getRandomIdBase: getRandomIdBase,
+    getGreatestCommonDividor: getGreatestCommonDividor,
+    getLeastCommonMultiple: getLeastCommonMultiple
   });
+  var ECHARTS_PREFIX = '[ECharts] ';
+  var storedLogs = {};
+  var hasConsole = typeof console !== 'undefined' && console.warn && console.log;
+
+  function warn(str) {
+    if (hasConsole) {
+      console.warn(ECHARTS_PREFIX + str);
+    }
+  }
+
+  function error(str) {
+    if (hasConsole) {
+      console.error(ECHARTS_PREFIX + str);
+    }
+  }
+
+  function deprecateLog(str) {
+    if (true) {
+      if (storedLogs[str]) {
+        return;
+      }
+
+      if (hasConsole) {
+        storedLogs[str] = true;
+        console.warn(ECHARTS_PREFIX + 'DEPRECATED: ' + str);
+      }
+    }
+  }
+
+  function deprecateReplaceLog(oldOpt, newOpt, scope) {
+    if (true) {
+      deprecateLog((scope ? "[" + scope + "]" : '') + (oldOpt + " is deprecated, use " + newOpt + " instead."));
+    }
+  }
+
+  function consoleLog() {
+    var args = [];
+
+    for (var _i = 0; _i < arguments.length; _i++) {
+      args[_i] = arguments[_i];
+    }
+
+    if (true) {
+      if (typeof console !== 'undefined' && console.log) {
+        console.log.apply(console, args);
+      }
+    }
+  }
+
+  function makePrintable() {
+    var hintInfo = [];
+
+    for (var _i = 0; _i < arguments.length; _i++) {
+      hintInfo[_i] = arguments[_i];
+    }
+
+    var msg = '';
+
+    if (true) {
+      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)) {
+          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;
+              });
+            } catch (err) {
+              return '?';
+            }
+          } else {
+            return '?';
+          }
+        }
+      }).join(' ');
+    }
+
+    return msg;
+  }
+
+  function throwError(msg) {
+    throw new Error(msg);
+  }
+
   var DUMMY_COMPONENT_NAME_PREFIX = 'series\0';
   var INTERNAL_COMPONENT_ID_PREFIX = '\0_ec_\0';
 
@@ -14307,8 +14689,15 @@
         return;
       }
 
-      cmptOption.id == null || validateIdOrName(cmptOption.id);
-      cmptOption.name == null || validateIdOrName(cmptOption.name);
+      if (true) {
+        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);
 
@@ -14393,13 +14782,13 @@
   }
 
   function mappingByIndex(result, newCmptOptions, brandNew) {
-    var nextIdx = 0;
     each(newCmptOptions, function (cmptOption) {
       if (!cmptOption) {
         return;
       }
 
       var resultItem;
+      var nextIdx = 0;
 
       while ((resultItem = result[nextIdx]) && (resultItem.newOption || isComponentIdInternal(resultItem.existing) || resultItem.existing && cmptOption.id != null && !keyExistAndEqual('id', cmptOption, resultItem.existing))) {
         nextIdx++;
@@ -14472,9 +14861,9 @@
   }
 
   function keyExistAndEqual(attr, obj1, obj2) {
-    var key1 = obj1[attr];
-    var key2 = obj2[attr];
-    return key1 != null && key2 != null && key1 + '' === key2 + '';
+    var key1 = convertOptionIdName(obj1[attr], null);
+    var key2 = convertOptionIdName(obj2[attr], null);
+    return key1 != null && key2 != null && key1 === key2;
   }
 
   function makeComparableKey(val) {
@@ -14488,13 +14877,17 @@
   }
 
   function convertOptionIdName(idOrName, defaultValue) {
+    if (idOrName == null) {
+      return defaultValue;
+    }
+
     var type = typeof idOrName;
     return type === 'string' ? idOrName : type === 'number' || isStringSafe(idOrName) ? idOrName + '' : defaultValue;
   }
 
-  function validateIdOrName(idOrName) {
+  function warnInvalidateIdOrName(idOrName) {
     if (true) {
-      assert(isValidIdOrName(idOrName), '`' + idOrName + '` is invalid id or name. Must be a string.');
+      warn('`' + idOrName + '` is invalid id or name. Must be a string or number.');
     }
   }
 
@@ -14565,9 +14958,9 @@
       finder = finderInput;
     }
 
-    var defaultMainType = opt ? opt.defaultMainType : null;
     var queryOptionMap = createHashMap();
     var result = {};
+    var mainTypeSpecified = false;
     each(finder, function (value, key) {
       if (key === 'dataIndex' || key === 'dataIndexInside') {
         result[key] = value;
@@ -14578,18 +14971,25 @@
       var mainType = parsedKey[1];
       var queryType = (parsedKey[2] || '').toLowerCase();
 
-      if (!mainType || !queryType || mainType !== defaultMainType && value == null || opt && opt.includeMainTypes && indexOf(opt.includeMainTypes, mainType) < 0) {
+      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;
     });
+    var defaultMainType = opt ? opt.defaultMainType : null;
+
+    if (!mainTypeSpecified && defaultMainType) {
+      queryOptionMap.set(defaultMainType, {});
+    }
+
     queryOptionMap.each(function (queryOption, mainType) {
       var queryResult = queryReferringComponents(ecModel, mainType, queryOption, {
-        useDefault: mainType === defaultMainType,
-        enableAll: true,
-        enableNone: true
+        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];
@@ -14663,6 +15063,10 @@
   function interpolateRawValues(data, precision, sourceValue, targetValue, percent) {
     var isAutoPrecision = precision == null || precision === 'auto';
 
+    if (targetValue == null) {
+      return targetValue;
+    }
+
     if (typeof targetValue === 'number') {
       var value = interpolateNumber(sourceValue || 0, targetValue, percent);
       return round$1(value, isAutoPrecision ? Math.max(getPrecisionSafe(sourceValue || 0), getPrecisionSafe(targetValue)) : precision);
@@ -14929,7 +15333,7 @@
     };
   }
 
-  var AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor']];
+  var AREA_STYLE_KEY_MAP = [['fill', 'color'], ['shadowBlur'], ['shadowOffsetX'], ['shadowOffsetY'], ['opacity'], ['shadowColor'], ['decal']];
   var getAreaStyle = makeStyleMapper(AREA_STYLE_KEY_MAP);
 
   var AreaStyleMixin = function () {
@@ -14993,7 +15397,9 @@
   }
 
   function singleLeaveEmphasis(el) {
-    doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
+    if (el.hoverState === HOVER_STATE_EMPHASIS) {
+      doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
+    }
   }
 
   function singleEnterBlur(el) {
@@ -15001,7 +15407,9 @@
   }
 
   function singleLeaveBlur(el) {
-    doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
+    if (el.hoverState === HOVER_STATE_BLUR) {
+      doChangeHoverState(el, 'normal', HOVER_STATE_NORMAL);
+    }
   }
 
   function singleEnterSelect(el) {
@@ -15457,94 +15865,484 @@
     store.selectStroke = selectState.style && selectState.style.stroke || null;
   }
 
-  var ECHARTS_PREFIX = '[ECharts] ';
-  var storedLogs = {};
-  var hasConsole = typeof console !== 'undefined' && console.warn && console.log;
+  var mathMax$4 = Math.max;
+  var mathMin$4 = Math.min;
+  var _customShapeMap = {};
 
-  function warn(str) {
-    if (hasConsole) {
-      console.warn(ECHARTS_PREFIX + str);
+  function extendShape(opts) {
+    return Path.extend(opts);
+  }
+
+  var extendPathFromString = extendFromString;
+
+  function extendPath(pathData, opts) {
+    return extendPathFromString(pathData, opts);
+  }
+
+  function registerShape(name, ShapeClass) {
+    _customShapeMap[name] = ShapeClass;
+  }
+
+  function getShapeClass(name) {
+    if (_customShapeMap.hasOwnProperty(name)) {
+      return _customShapeMap[name];
     }
   }
 
-  function deprecateLog(str) {
-    if (true) {
-      if (storedLogs[str]) {
-        return;
+  function makePath(pathData, opts, rect, layout) {
+    var path = createFromString(pathData, opts);
+
+    if (rect) {
+      if (layout === 'center') {
+        rect = centerGraphic(rect, path.getBoundingRect());
       }
 
-      if (hasConsole) {
-        storedLogs[str] = true;
-        console.warn(ECHARTS_PREFIX + 'DEPRECATED: ' + str);
+      resizePath(path, rect);
+    }
+
+    return path;
+  }
+
+  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));
+        }
       }
... 47788 lines suppressed ...


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


[incubator-echarts] 03/03: rebuild: 5.0.0-beta.2

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

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

commit 3e7bdc37ffadcc10fbeda1bfb7d711c7906c83d1
Author: 100pah <su...@gmail.com>
AuthorDate: Mon Oct 26 19:44:06 2020 +0800

    rebuild: 5.0.0-beta.2
---
 dist/echarts.js     | 11 +++++++++--
 dist/echarts.js.map |  2 +-
 dist/echarts.min.js |  2 +-
 3 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/dist/echarts.js b/dist/echarts.js
index 36d741e..0b9ef45 100644
--- a/dist/echarts.js
+++ b/dist/echarts.js
@@ -62164,9 +62164,11 @@
       var sector = this;
       var label = sector.getTextContent();
       var dataIndex = this.node.dataIndex;
+      var labelMinAngle = normalLabelModel.get('minAngle') / 180 * Math.PI;
+      var isNormalShown = normalLabelModel.get('show') && !(labelMinAngle != null && Math.abs(angle) < labelMinAngle);
+      label.ignore = !isNormalShown;
       each(DISPLAY_STATES, function (stateName) {
         var labelStateModel = stateName === 'normal' ? itemModel.getModel('label') : itemModel.getModel([stateName, 'label']);
-        var labelMinAngle = labelStateModel.get('minAngle') / 180 * Math.PI;
         var isNormal = stateName === 'normal';
         var state = isNormal ? label : label.ensureState(stateName);
         var text = seriesModel.getFormattedLabel(dataIndex, stateName);
@@ -62181,7 +62183,12 @@
           state.style.text = text;
         }
 
-        state.ignore = labelMinAngle != null && Math.abs(angle) < labelMinAngle;
+        var isShown = labelStateModel.get('show');
+
+        if (isShown != null && !isNormal) {
+          state.ignore = !isShown;
+        }
+
         var labelPosition = getLabelAttr(labelStateModel, 'position');
         var sectorState = isNormal ? sector : sector.states[stateName];
         var labelColor = sectorState.style.fill;
diff --git a/dist/echarts.js.map b/dist/echarts.js.map
index 1eabfce..48febd7 100644
--- a/dist/echarts.js.map
+++ b/dist/echarts.js.map
@@ -1 +1 @@
-{"version":3,"sources":["unknown"],"names":["global","factory","exports","module","define","amd","self","echarts","extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","hasOwnProperty","__extends","__","constructor","prototype","create","__assign","assign","t","s","i","n","arguments","length","call","apply","__spreadArrays","il","r","k","a","j","jl","Browser","firefox","ie","edge","weChat","Env","browser","node","wxa","worker","canvasSupported","svgSupported","touchEv [...]
\ No newline at end of file
+{"version":3,"sources":["unknown"],"names":["global","factory","exports","module","define","amd","self","echarts","extendStatics","d","b","Object","setPrototypeOf","__proto__","Array","p","hasOwnProperty","__extends","__","constructor","prototype","create","__assign","assign","t","s","i","n","arguments","length","call","apply","__spreadArrays","il","r","k","a","j","jl","Browser","firefox","ie","edge","weChat","Env","browser","node","wxa","worker","canvasSupported","svgSupported","touchEv [...]
\ No newline at end of file
diff --git a/dist/echarts.min.js b/dist/echarts.min.js
index 6def60e..f96d08c 100644
--- a/dist/echarts.min.js
+++ b/dist/echarts.min.js
@@ -19,4 +19,4 @@
 */
 
 
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).echarts={})}(this,function(t){"use strict";var i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)};function l(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prot [...]
\ No newline at end of file
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).echarts={})}(this,function(t){"use strict";var i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)};function l(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prot [...]
\ No newline at end of file


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