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

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

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