]> source.dussan.org Git - svg.js.git/commitdiff
introduce register and registerMethod method to get rid of dependency problems
authorUlrich-Matthias Schäfer <ulima.ums@googlemail.com>
Thu, 1 Nov 2018 14:04:55 +0000 (15:04 +0100)
committerUlrich-Matthias Schäfer <ulima.ums@googlemail.com>
Thu, 1 Nov 2018 14:04:55 +0000 (15:04 +0100)
48 files changed:
dirty.html
dist/svg.js
dist/svg.min.js
src/A.js
src/Bare.js
src/Box.js
src/Circle.js
src/ClipPath.js
src/Defs.js
src/Doc.js
src/Element.js
src/Ellipse.js
src/EventTarget.js
src/G.js
src/Gradient.js
src/HtmlNode.js
src/Image.js
src/Line.js
src/Marker.js
src/Mask.js
src/Matrix.js
src/Parent.js
src/Path.js
src/Pattern.js
src/Point.js
src/Polygon.js
src/Polyline.js
src/Rect.js
src/Runner.js
src/Stop.js
src/Symbol.js
src/Text.js
src/TextPath.js
src/Timeline.js
src/Tspan.js
src/Use.js
src/adopter.js
src/arrange.js
src/attr.js
src/css.js
src/data.js
src/event.js
src/memory.js
src/methods.js [new file with mode: 0644]
src/selector.js
src/specialNeeds.js [deleted file]
src/svg.js
src/transform.js

index 82f289e7307ec0c0ab12df4947c4f51e86858cdf..9792d5edca105e946a0f68e739f0a399d154a521 100644 (file)
@@ -4,7 +4,7 @@
 <head>
   <meta charset="utf-8">
   <title></title>
-  <script type="text/javascript" src="dist/svg.js"></script>-->
+  <script type="text/javascript" src="dist/svg.js"></script>
 
 
 
@@ -25,9 +25,9 @@
 <!-- Modifying the svg -->
 <script type="module">
 
-//import SVG from './src/svg.js'
-
-//window.SVG = SVG
+// import SVG from './src/svg.js'
+//
+// window.SVG = SVG
 
 let rect = SVG('rect').hide()
 let {sin, PI: pi, round, sqrt} = Math
index a15bea1715c9e38c09237724bb2c438260c63831..7c9bc18eb8b70501dbc5ae0a041e66d12bbb45b4 100644 (file)
@@ -186,6 +186,10 @@ var SVG = (function () {
     return _assertThisInitialized(self);
   }
 
+  function _slicedToArray(arr, i) {
+    return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest();
+  }
+
   function _toConsumableArray(arr) {
     return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread();
   }
@@ -198,14 +202,48 @@ var SVG = (function () {
     }
   }
 
+  function _arrayWithHoles(arr) {
+    if (Array.isArray(arr)) return arr;
+  }
+
   function _iterableToArray(iter) {
     if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
   }
 
+  function _iterableToArrayLimit(arr, i) {
+    var _arr = [];
+    var _n = true;
+    var _d = false;
+    var _e = undefined;
+
+    try {
+      for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
+        _arr.push(_s.value);
+
+        if (i && _arr.length === i) break;
+      }
+    } catch (err) {
+      _d = true;
+      _e = err;
+    } finally {
+      try {
+        if (!_n && _i["return"] != null) _i["return"]();
+      } finally {
+        if (_d) throw _e;
+      }
+    }
+
+    return _arr;
+  }
+
   function _nonIterableSpread() {
     throw new TypeError("Invalid attempt to spread non-iterable instance");
   }
 
+  function _nonIterableRest() {
+    throw new TypeError("Invalid attempt to destructure non-iterable instance");
+  }
+
   var Base$1 =
   /*#__PURE__*/
   function () {
@@ -252,12 +290,6 @@ var SVG = (function () {
     return Base;
   }();
 
-  // Default namespaces
-  var ns$1 = 'http://www.w3.org/2000/svg';
-  var xmlns = 'http://www.w3.org/2000/xmlns/';
-  var xlink = 'http://www.w3.org/1999/xlink';
-  var svgjs = 'http://svgjs.com/svgjs';
-
   // Parse unit value
   var numberAndUnit = /^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i; // Parse hex value
 
@@ -447,11 +479,17 @@ var SVG = (function () {
     return [ox, oy];
   }
 
+  // Default namespaces
+  var ns$1 = 'http://www.w3.org/2000/svg';
+  var xmlns = 'http://www.w3.org/2000/xmlns/';
+  var xlink = 'http://www.w3.org/1999/xlink';
+  var svgjs = 'http://svgjs.com/svgjs';
+
   function nodeOrNew$1(name, node) {
-    return node || makeNode$1(name);
+    return node || makeNode(name);
   } // Method for element creation
 
-  function makeNode$1(name) {
+  function makeNode(name) {
     // create element
     return document.createElementNS(ns$1, name);
   } // Method for extending objects
@@ -487,7 +525,7 @@ var SVG = (function () {
   function invent(config) {
     // Create element initializer
     var initializer = typeof config.create === 'function' ? config.create : function (node) {
-      config.inherit.call(this, node || makeNode$1(config.create));
+      config.inherit.call(this, node || makeNode(config.create));
     }; // Inherit prototype
 
     if (config.inherit) {
@@ -510,354 +548,216 @@ var SVG = (function () {
 
   var tools = /*#__PURE__*/Object.freeze({
     nodeOrNew: nodeOrNew$1,
-    makeNode: makeNode$1,
+    makeNode: makeNode,
     extend: extend$1,
     addFactory: addFactory,
     invent: invent
   });
 
-  function Bare(element) {
-    var inherit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+  var elements = {};
+  var root = Symbol('root');
+  function makeInstance(element) {
+    if (element instanceof Base$1) return element;
+
+    if (_typeof(element) === 'object') {
+      return adopt$1(element);
+    }
+
+    if (element == null) {
+      return new elements[root]();
+    }
 
-    var custom =
-    /*#__PURE__*/
-    function (_inherit) {
-      _inherits(Custom, _inherit);
+    if (typeof element === 'string' && element.charAt(0) !== '<') {
+      return adopt$1(document.querySelector(element));
+    }
 
-      function Custom(node) {
-        _classCallCheck(this, Custom);
+    var node = makeNode('svg');
+    node.innerHTML = element;
+    element = adopt$1(node.firstElementChild);
+    return element;
+  } // Adopt existing svg elements
 
-        return _possibleConstructorReturn(this, _getPrototypeOf(Custom).call(this, nodeOrNew$1(element, node), Custom));
-      }
+  function adopt$1(node) {
+    // check for presence of node
+    if (!node) return null; // make sure a node isn't already adopted
 
-      _createClass(Custom, [{
-        key: "words",
-        value: function words(text) {
-          // remove contents
-          while (this.node.hasChildNodes()) {
-            this.node.removeChild(this.node.lastChild);
-          } // create text node
+    if (node.instance instanceof Base$1) return node.instance;
 
+    if (!(node instanceof window.SVGElement)) {
+      return new elements.HtmlNode(node);
+    } // initialize variables
 
-          this.node.appendChild(document.createTextNode(text));
-          return this;
-        }
-      }]);
-
-      return Custom;
-    }(inherit);
-
-    extend(custom, inherit);
-  } // export let constructors = {
-  //   // Create an element that is not described by SVG.js
-  //   element: function (element, inherit) {
-  //     let custom = createCustom(element, inherit)
-  //     return this.put(new custom())
-  //   }
-  // }
-  // extend(Parent, {
-  //   // Create an element that is not described by SVG.js
-  //   element: function (element, inherit) {
-  //     let custom = createCustom(element, inherit)
-  //     return this.put(new custom())
-  //   }
-  // })
 
-  var SVGNumber =
-  /*#__PURE__*/
-  function () {
-    // Initialize
-    function SVGNumber() {
-      _classCallCheck(this, SVGNumber);
+    var element; // adopt with element-specific settings
 
-      this.init.apply(this, arguments);
+    if (node.nodeName === 'svg') {
+      element = new elements[root](node);
+    } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {
+      element = new elements.Gradient(node);
+    } else if (elements[capitalize(node.nodeName)]) {
+      element = new elements[capitalize(node.nodeName)](node);
+    } else {
+      element = new elements.Bare(node);
     }
 
-    _createClass(SVGNumber, [{
-      key: "init",
-      value: function init(value, unit) {
-        unit = Array.isArray(value) ? value[1] : unit;
-        value = Array.isArray(value) ? value[0] : value; // initialize defaults
+    return element;
+  }
+  function register(element) {
+    var name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : element.name;
+    var asRoot = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
+    elements[name] = element;
+    if (asRoot) elements[root] = element;
+    return element;
+  }
+  function getClass(name) {
+    return elements[name];
+  } // Element id sequence
 
-        this.value = 0;
-        this.unit = unit || ''; // parse value
+  var did = 1000; // Get next named element id
 
-        if (typeof value === 'number') {
-          // ensure a valid numeric value
-          this.value = isNaN(value) ? 0 : !isFinite(value) ? value < 0 ? -3.4e+38 : +3.4e+38 : value;
-        } else if (typeof value === 'string') {
-          unit = value.match(numberAndUnit);
+  function eid(name) {
+    return 'Svgjs' + capitalize(name) + did++;
+  } // Deep new id assignment
 
-          if (unit) {
-            // make value numeric
-            this.value = parseFloat(unit[1]); // normalize
+  function assignNewId(node) {
+    // do the same for SVG child nodes as well
+    for (var i = node.children.length - 1; i >= 0; i--) {
+      assignNewId(node.children[i]);
+    }
 
-            if (unit[5] === '%') {
-              this.value /= 100;
-            } else if (unit[5] === 's') {
-              this.value *= 1000;
-            } // store unit
+    if (node.id) {
+      return adopt$1(node).id(eid(node.nodeName));
+    }
 
+    return adopt$1(node);
+  }
 
-            this.unit = unit[5];
-          }
-        } else {
-          if (value instanceof SVGNumber) {
-            this.value = value.valueOf();
-            this.unit = value.unit;
-          }
+  var adopter = /*#__PURE__*/Object.freeze({
+    root: root,
+    makeInstance: makeInstance,
+    adopt: adopt$1,
+    register: register,
+    getClass: getClass,
+    eid: eid,
+    assignNewId: assignNewId
+  });
+
+  var HtmlNode =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(HtmlNode, _Base);
+
+    function HtmlNode(element) {
+      var _this;
+
+      _classCallCheck(this, HtmlNode);
+
+      _this = _possibleConstructorReturn(this, _getPrototypeOf(HtmlNode).call(this, element, HtmlNode));
+      _this.node = element;
+      return _this;
+    }
+
+    _createClass(HtmlNode, [{
+      key: "add",
+      value: function add(element, i) {
+        element = makeInstance(element);
+
+        if (element.node !== this.node.children[i]) {
+          this.node.insertBefore(element.node, this.node.children[i] || null);
         }
+
+        return this;
       }
     }, {
-      key: "toString",
-      value: function toString() {
-        return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6 : this.unit === 's' ? this.value / 1e3 : this.value) + this.unit;
-      }
-    }, {
-      key: "toJSON",
-      value: function toJSON() {
-        return this.toString();
+      key: "put",
+      value: function put(element, i) {
+        this.add(element, i);
+        return element;
       }
     }, {
-      key: "toArray",
-      value: function toArray() {
-        return [this.value, this.unit];
+      key: "getEventTarget",
+      value: function getEventTarget() {
+        return this.node;
       }
-    }, {
-      key: "valueOf",
-      value: function valueOf() {
-        return this.value;
-      } // Add number
+    }]);
 
-    }, {
-      key: "plus",
-      value: function plus(number) {
-        number = new SVGNumber(number);
-        return new SVGNumber(this + number, this.unit || number.unit);
-      } // Subtract number
+    return HtmlNode;
+  }(Base$1);
+  register(HtmlNode);
 
-    }, {
-      key: "minus",
-      value: function minus(number) {
-        number = new SVGNumber(number);
-        return new SVGNumber(this - number, this.unit || number.unit);
-      } // Multiply number
+  var Defs =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Defs, _Base);
 
-    }, {
-      key: "times",
-      value: function times(number) {
-        number = new SVGNumber(number);
-        return new SVGNumber(this * number, this.unit || number.unit);
-      } // Divide number
+    function Defs(node) {
+      _classCallCheck(this, Defs);
+
+      return _possibleConstructorReturn(this, _getPrototypeOf(Defs).call(this, nodeOrNew$1('defs', node), Defs));
+    }
 
+    _createClass(Defs, [{
+      key: "flatten",
+      value: function flatten() {
+        return this;
+      }
     }, {
-      key: "divide",
-      value: function divide(number) {
-        number = new SVGNumber(number);
-        return new SVGNumber(this / number, this.unit || number.unit);
+      key: "ungroup",
+      value: function ungroup() {
+        return this;
       }
     }]);
 
-    return SVGNumber;
-  }();
+    return Defs;
+  }(Base$1);
+  register(Defs);
 
-  // FIXME: import this to runner
+  var methods = {};
+  var constructors = {};
+  function registerMethods(name, m) {
+    if (_typeof(name) == 'object') {
+      var _arr = Object.entries(name);
 
-  function rx(rx) {
-    return this.attr('rx', rx);
-  } // Radius y value
+      for (var _i = 0; _i < _arr.length; _i++) {
+        var _arr$_i = _slicedToArray(_arr[_i], 2),
+            _name = _arr$_i[0],
+            _m = _arr$_i[1];
 
-  function ry(ry) {
-    return this.attr('ry', ry);
-  } // Move over x-axis
+        registerMethods(_name, _m);
+      }
+    }
 
-  function x(x) {
-    return x == null ? this.cx() - this.rx() : this.cx(x + this.rx());
-  } // Move over y-axis
+    methods[name] = Object.assign(methods[name] || {}, m);
+  }
+  function getMethodsFor(name) {
+    return methods[name];
+  } // FIXME: save memory?
+  function registerConstructor(name, setup) {
+    constructors[name] = setup;
+  }
+  function getConstructor(name) {
+    return {
+      setup: constructors[name],
+      name: name
+    };
+  }
 
-  function y(y) {
-    return y == null ? this.cy() - this.ry() : this.cy(y + this.ry());
-  } // Move by center over x-axis
+  var Doc$1 =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Doc, _Base);
 
-  function cx(x) {
-    return x == null ? this.attr('cx') : this.attr('cx', x);
-  } // Move by center over y-axis
+    function Doc(node) {
+      var _this;
 
-  function cy(y) {
-    return y == null ? this.attr('cy') : this.attr('cy', y);
-  } // Set width of element
+      _classCallCheck(this, Doc);
 
-  function width(width) {
-    return width == null ? this.rx() * 2 : this.rx(new SVGNumber(width).divide(2));
-  } // Set height of element
+      _this = _possibleConstructorReturn(this, _getPrototypeOf(Doc).call(this, nodeOrNew$1('svg', node), Doc));
 
-  function height(height) {
-    return height == null ? this.ry() * 2 : this.ry(new SVGNumber(height).divide(2));
-  } // Custom size function
+      _this.namespace();
 
-  function size(width, height) {
-    var p = proportionalSize$1(this, width, height);
-    return this.rx(new SVGNumber(p.width).divide(2)).ry(new SVGNumber(p.height).divide(2));
-  }
-
-  var circled = /*#__PURE__*/Object.freeze({
-    rx: rx,
-    ry: ry,
-    x: x,
-    y: y,
-    cx: cx,
-    cy: cy,
-    width: width,
-    height: height,
-    size: size
-  });
-
-  var Circle =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Circle, _Base);
-
-    function Circle(node) {
-      _classCallCheck(this, Circle);
-
-      return _possibleConstructorReturn(this, _getPrototypeOf(Circle).call(this, nodeOrNew$1('circle', node), Circle));
-    }
-
-    _createClass(Circle, [{
-      key: "radius",
-      value: function radius(r) {
-        return this.attr('r', r);
-      } // Radius x value
-
-    }, {
-      key: "rx",
-      value: function rx$$1(_rx) {
-        return this.attr('r', _rx);
-      } // Alias radius x value
-
-    }, {
-      key: "ry",
-      value: function ry$$1(_ry) {
-        return this.rx(_ry);
-      }
-    }]);
-
-    return Circle;
-  }(Base$1);
-  extend$1(Circle, {
-    x: x,
-    y: y,
-    cx: cx,
-    cy: cy,
-    width: width,
-    height: height,
-    size: size
-  });
-  Circle.constructors = {
-    Element: {
-      // Create circle element
-      circle: function circle(size$$1) {
-        return this.put(new Circle()).radius(new SVGNumber(size$$1).divide(2)).move(0, 0);
-      }
-    }
-  };
-
-  //import {remove} from './Element.js'
-
-  var ClipPath =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(ClipPath, _Base);
-
-    function ClipPath(node) {
-      _classCallCheck(this, ClipPath);
-
-      return _possibleConstructorReturn(this, _getPrototypeOf(ClipPath).call(this, nodeOrNew$1('clipPath', node), ClipPath));
-    } // // Unclip all clipped elements and remove itself
-    // remove () {
-    //   // unclip all targets
-    //   this.targets().forEach(function (el) {
-    //     el.unclip()
-    //   })
-    //
-    //   // remove clipPath from parent
-    //   return remove.call(this)
-    // }
-    //
-    // targets () {
-    //   return find('svg [clip-path*="' + this.id() + '"]')
-    // }
-
-
-    return ClipPath;
-  }(Base$1);
-  ClipPath.constructors = {
-    Container: {
-      // Create clipping element
-      clip: function clip() {
-        return this.defs().put(new ClipPath());
-      }
-    },
-    Element: {
-      // Distribute clipPath to svg element
-      clipWith: function clipWith(element) {
-        // use given clip or create a new one
-        var clipper = element instanceof ClipPath ? element : this.parent().clip().add(element); // apply mask
-
-        return this.attr('clip-path', 'url("#' + clipper.id() + '")');
-      },
-      // Unclip element
-      unclip: function unclip() {
-        return this.attr('clip-path', null);
-      },
-      clipper: function clipper() {
-        return this.reference('clip-path');
-      }
-    }
-  };
-
-  var Defs =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Defs, _Base);
-
-    function Defs(node) {
-      _classCallCheck(this, Defs);
-
-      return _possibleConstructorReturn(this, _getPrototypeOf(Defs).call(this, nodeOrNew$1('defs', node), Defs));
-    }
-
-    _createClass(Defs, [{
-      key: "flatten",
-      value: function flatten() {
-        return this;
-      }
-    }, {
-      key: "ungroup",
-      value: function ungroup() {
-        return this;
-      }
-    }]);
-
-    return Defs;
-  }(Base$1);
-
-  var Doc$1 =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Doc, _Base);
-
-    function Doc(node) {
-      var _this;
-
-      _classCallCheck(this, Doc);
-
-      _this = _possibleConstructorReturn(this, _getPrototypeOf(Doc).call(this, nodeOrNew$1('svg', node), Doc));
-
-      _this.namespace();
-
-      return _this;
-    }
+      return _this;
+    }
 
     _createClass(Doc, [{
       key: "isRoot",
@@ -887,10 +787,7 @@ var SVG = (function () {
       key: "defs",
       value: function defs() {
         if (!this.isRoot()) return this.doc().defs();
-        var node = this.node.getElementsByTagName('defs')[0];
-        return node ? node.instance || new Defs(node) : this.put(new Defs()); // 
-        // return adopt(this.node.getElementsByTagName('defs')[0]) ||
-        //   this.put(new Defs())
+        return adopt$1(this.node.getElementsByTagName('defs')[0]) || this.put(new Defs());
       } // custom parent method
 
     }, {
@@ -930,5492 +827,5600 @@ var SVG = (function () {
 
     return Doc;
   }(Base$1);
-  Doc$1.constructors = {
+  registerMethods({
     Container: {
       // Create nested svg document
       nested: function nested() {
         return this.put(new Doc$1());
       }
     }
-  };
+  });
+  register(Doc$1, 'Doc', true);
 
-  var Ellipse =
+  var G =
   /*#__PURE__*/
   function (_Base) {
-    _inherits(Ellipse, _Base);
+    _inherits(G, _Base);
 
-    function Ellipse(node) {
-      _classCallCheck(this, Ellipse);
+    function G(node) {
+      _classCallCheck(this, G);
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Ellipse).call(this, nodeOrNew('ellipse', node), Ellipse));
+      return _possibleConstructorReturn(this, _getPrototypeOf(G).call(this, nodeorNew('g', node), G));
     }
 
-    return Ellipse;
+    return G;
   }(Base$1);
-  extend$1(Ellipse, circled); // addFactory(Container, {
-  //   // Create an ellipse
-  //   ellipse: function (width, height) {
-  //     return this.put(new Ellipse()).size(width, height).move(0, 0)
-  //   }
-  // })
+  registerMethods({
+    Element: {
+      // Create a group element
+      group: function group() {
+        return this.put(new G());
+      }
+    }
+  });
+  register(G);
 
-  var Stop =
+  var Queue =
   /*#__PURE__*/
-  function (_Base) {
-    _inherits(Stop, _Base);
+  function () {
+    function Queue() {
+      _classCallCheck(this, Queue);
 
-    function Stop(node) {
-      _classCallCheck(this, Stop);
+      this._first = null;
+      this._last = null;
+    }
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Stop).call(this, nodeOrNew$1('stop', node), Stop));
-    } // add color stops
+    _createClass(Queue, [{
+      key: "push",
+      value: function push(value) {
+        // An item stores an id and the provided value
+        var item = value.next ? value : {
+          value: value,
+          next: null,
+          prev: null // Deal with the queue being empty or populated
 
+        };
 
-    _createClass(Stop, [{
-      key: "update",
-      value: function update(o) {
-        if (typeof o === 'number' || o instanceof SVGNumber) {
-          o = {
-            offset: arguments[0],
-            color: arguments[1],
-            opacity: arguments[2]
-          };
-        } // set attributes
+        if (this._last) {
+          item.prev = this._last;
+          this._last.next = item;
+          this._last = item;
+        } else {
+          this._last = item;
+          this._first = item;
+        } // Update the length and return the current item
 
 
-        if (o.opacity != null) this.attr('stop-opacity', o.opacity);
-        if (o.color != null) this.attr('stop-color', o.color);
-        if (o.offset != null) this.attr('offset', new SVGNumber(o.offset));
-        return this;
+        return item;
       }
-    }]);
-
-    return Stop;
-  }(Base$1);
+    }, {
+      key: "shift",
+      value: function shift() {
+        // Check if we have a value
+        var remove = this._first;
+        if (!remove) return null; // If we do, remove it and relink things
 
-  // FIXME: add to runner
-  function from(x, y) {
-    return (this._element || this).type === 'radialGradient' ? this.attr({
-      fx: new SVGNumber(x),
-      fy: new SVGNumber(y)
-    }) : this.attr({
-      x1: new SVGNumber(x),
-      y1: new SVGNumber(y)
-    });
-  }
-  function to(x, y) {
-    return (this._element || this).type === 'radialGradient' ? this.attr({
-      cx: new SVGNumber(x),
-      cy: new SVGNumber(y)
-    }) : this.attr({
-      x2: new SVGNumber(x),
-      y2: new SVGNumber(y)
-    });
-  }
+        this._first = remove.next;
+        if (this._first) this._first.prev = null;
+        this._last = this._first ? this._last : null;
+        return remove.value;
+      } // Shows us the first item in the list
 
-  var gradiented = /*#__PURE__*/Object.freeze({
-    from: from,
-    to: to
-  });
+    }, {
+      key: "first",
+      value: function first() {
+        return this._first && this._first.value;
+      } // Shows us the last item in the list
 
-  var Gradient =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Gradient, _Base);
-
-    function Gradient(type) {
-      _classCallCheck(this, Gradient);
+    }, {
+      key: "last",
+      value: function last() {
+        return this._last && this._last.value;
+      } // Removes the item that was returned from the push
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Gradient).call(this, nodeOrNew$1(type + 'Gradient', typeof type === 'string' ? null : type), Gradient));
-    } // Add a color stop
+    }, {
+      key: "remove",
+      value: function remove(item) {
+        // Relink the previous item
+        if (item.prev) item.prev.next = item.next;
+        if (item.next) item.next.prev = item.prev;
+        if (item === this._last) this._last = item.prev;
+        if (item === this._first) this._first = item.next; // Invalidate item
 
+        item.prev = null;
+        item.next = null;
+      }
+    }]);
 
-    _createClass(Gradient, [{
-      key: "stop",
-      value: function stop(offset, color, opacity) {
-        return this.put(new Stop()).update(offset, color, opacity);
-      } // Update gradient
+    return Queue;
+  }();
 
-    }, {
-      key: "update",
-      value: function update(block) {
-        // remove all stops
-        this.clear(); // invoke passed block
+  var Animator = {
+    nextDraw: null,
+    frames: new Queue(),
+    timeouts: new Queue(),
+    timer: window.performance || window.Date,
+    transforms: [],
+    frame: function frame(fn) {
+      // Store the node
+      var node = Animator.frames.push({
+        run: fn
+      }); // Request an animation frame if we don't have one
 
-        if (typeof block === 'function') {
-          block.call(this, this);
-        }
+      if (Animator.nextDraw === null) {
+        Animator.nextDraw = window.requestAnimationFrame(Animator._draw);
+      } // Return the node so we can remove it easily
 
-        return this;
-      } // Return the fill id
 
-    }, {
-      key: "url",
-      value: function url() {
-        return 'url(#' + this.id() + ')';
-      } // Alias string convertion to fill
+      return node;
+    },
+    transform_frame: function transform_frame(fn, id) {
+      Animator.transforms[id] = fn;
+    },
+    timeout: function timeout(fn, delay) {
+      delay = delay || 0; // Work out when the event should fire
 
-    }, {
-      key: "toString",
-      value: function toString() {
-        return this.url();
-      } // // custom attr to handle transform
-      // attr (a, b, c) {
-      //   if (a === 'transform') a = 'gradientTransform'
-      //   return attr.call(this, a, b, c)
-      // }
+      var time = Animator.timer.now() + delay; // Add the timeout to the end of the queue
 
-    }]);
+      var node = Animator.timeouts.push({
+        run: fn,
+        time: time
+      }); // Request another animation frame if we need one
 
-    return Gradient;
-  }(Base$1);
-  extend$1(Gradient, gradiented);
-  Gradient.constructors = {
-    Container: {
-      // Create gradient element in defs
-      gradient: function gradient(type, block) {
-        return this.defs().gradient(type, block);
+      if (Animator.nextDraw === null) {
+        Animator.nextDraw = window.requestAnimationFrame(Animator._draw);
       }
+
+      return node;
     },
-    // define gradient
-    Defs: {
-      gradient: function gradient(type, block) {
-        return this.put(new Gradient(type)).update(block);
-      }
-    }
-  };
+    cancelFrame: function cancelFrame(node) {
+      Animator.frames.remove(node);
+    },
+    clearTimeout: function clearTimeout(node) {
+      Animator.timeouts.remove(node);
+    },
+    _draw: function _draw(now) {
+      // Run all the timeouts we can run, if they are not ready yet, add them
+      // to the end of the queue immediately! (bad timeouts!!! [sarcasm])
+      var nextTimeout = null;
+      var lastTimeout = Animator.timeouts.last();
 
-  var G =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(G, _Base);
+      while (nextTimeout = Animator.timeouts.shift()) {
+        // Run the timeout if its time, or push it to the end
+        if (now >= nextTimeout.time) {
+          nextTimeout.run();
+        } else {
+          Animator.timeouts.push(nextTimeout);
+        } // If we hit the last item, we should stop shifting out more items
 
-    function G(node) {
-      _classCallCheck(this, G);
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(G).call(this, nodeorNew('g', node), G));
-    }
+        if (nextTimeout === lastTimeout) break;
+      } // Run all of the animation frames
 
-    return G;
-  }(Base$1);
-  G.constructors = {
-    Element: {
-      // Create a group element
-      group: function group() {
-        return this.put(new G());
+
+      var nextFrame = null;
+      var lastFrame = Animator.frames.last();
+
+      while (nextFrame !== lastFrame && (nextFrame = Animator.frames.shift())) {
+        nextFrame.run();
       }
+
+      Animator.transforms.forEach(function (el) {
+        el();
+      }); // If we have remaining timeouts or frames, draw until we don't anymore
+
+      Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first() ? window.requestAnimationFrame(Animator._draw) : null;
     }
   };
 
-  var HtmlNode =
+  var Bare =
   /*#__PURE__*/
   function (_Base) {
-    _inherits(HtmlNode, _Base);
+    _inherits(Bare, _Base);
 
-    function HtmlNode(element) {
+    function Bare(node, inherit) {
       var _this;
 
-      _classCallCheck(this, HtmlNode);
+      _classCallCheck(this, Bare);
 
-      _this = _possibleConstructorReturn(this, _getPrototypeOf(HtmlNode).call(this, element, HtmlNode));
-      _this.node = element;
+      _this = _possibleConstructorReturn(this, _getPrototypeOf(Bare).call(this, nodeOrNew$1(null, node), Bare));
+      extend(_assertThisInitialized(_assertThisInitialized(_this)), inherit);
       return _this;
-    } // add (element, i) {
-    //   element = makeInstance(element)
-    //
-    //   if (element.node !== this.node.children[i]) {
-    //     this.node.insertBefore(element.node, this.node.children[i] || null)
-    //   }
-    //
-    //   return this
-    // }
+    }
 
+    _createClass(Bare, [{
+      key: "words",
+      value: function words(text) {
+        // remove contents
+        while (this.node.hasChildNodes()) {
+          this.node.removeChild(this.node.lastChild);
+        } // create text node
 
-    _createClass(HtmlNode, [{
-      key: "put",
-      value: function put(element, i) {
-        this.add(element, i);
-        return element;
-      }
-    }, {
-      key: "getEventTarget",
-      value: function getEventTarget() {
-        return this.node;
+
+        this.node.appendChild(document.createTextNode(text));
+        return this;
       }
     }]);
 
-    return HtmlNode;
+    return Bare;
   }(Base$1);
+  register(Bare);
+  registerMethods('Bare', {
+    // Create an element that is not described by SVG.js
+    element: function element(_element, inherit) {
+      var custom = createCustom(_element, inherit);
+      return this.put(new custom());
+    }
+  });
 
-  var A =
+  var SVGNumber =
   /*#__PURE__*/
-  function (_Base) {
-    _inherits(A, _Base);
+  function () {
+    // Initialize
+    function SVGNumber() {
+      _classCallCheck(this, SVGNumber);
 
-    function A(node) {
-      _classCallCheck(this, A);
+      this.init.apply(this, arguments);
+    }
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(A).call(this, nodeOrNew$1('a', node), A));
-    } // Link url
+    _createClass(SVGNumber, [{
+      key: "init",
+      value: function init(value, unit) {
+        unit = Array.isArray(value) ? value[1] : unit;
+        value = Array.isArray(value) ? value[0] : value; // initialize defaults
 
+        this.value = 0;
+        this.unit = unit || ''; // parse value
 
-    _createClass(A, [{
-      key: "to",
-      value: function to(url) {
-        return this.attr('href', url, xlink);
-      } // Link target attribute
+        if (typeof value === 'number') {
+          // ensure a valid numeric value
+          this.value = isNaN(value) ? 0 : !isFinite(value) ? value < 0 ? -3.4e+38 : +3.4e+38 : value;
+        } else if (typeof value === 'string') {
+          unit = value.match(numberAndUnit);
 
-    }, {
-      key: "target",
-      value: function target(_target) {
-        return this.attr('target', _target);
-      }
-    }]);
+          if (unit) {
+            // make value numeric
+            this.value = parseFloat(unit[1]); // normalize
 
-    return A;
-  }(Base$1);
-  A.constructors = {
-    Container: {
-      // Create a hyperlink element
-      link: function link(url) {
-        return this.put(new A()).to(url);
-      }
-    },
-    Element: {
-      // Create a hyperlink element
-      linkTo: function linkTo(url) {
-        var link = new A();
+            if (unit[5] === '%') {
+              this.value /= 100;
+            } else if (unit[5] === 's') {
+              this.value *= 1000;
+            } // store unit
 
-        if (typeof url === 'function') {
-          url.call(link, link);
+
+            this.unit = unit[5];
+          }
         } else {
-          link.to(url);
+          if (value instanceof SVGNumber) {
+            this.value = value.valueOf();
+            this.unit = value.unit;
+          }
         }
-
-        return this.parent().put(link).put(this);
       }
-    }
-  };
-
-  var Pattern =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Pattern, _Base);
-
-    // Initialize node
-    function Pattern(node) {
-      _classCallCheck(this, Pattern);
-
-      return _possibleConstructorReturn(this, _getPrototypeOf(Pattern).call(this, nodeOrNew$1('pattern', node)));
-    } // Return the fill id
-
-
-    _createClass(Pattern, [{
-      key: "url",
-      value: function url() {
-        return 'url(#' + this.id() + ')';
-      } // Update pattern by rebuilding
-
-    }, {
-      key: "update",
-      value: function update(block) {
-        // remove content
-        this.clear(); // invoke passed block
-
-        if (typeof block === 'function') {
-          block.call(this, this);
-        }
-
-        return this;
-      } // Alias string convertion to fill
-
     }, {
       key: "toString",
       value: function toString() {
-        return this.url();
-      } // // custom attr to handle transform
-      // attr (a, b, c) {
-      //   if (a === 'transform') a = 'patternTransform'
-      //   return attr.call(this, a, b, c)
-      // }
-
-    }]);
-
-    return Pattern;
-  }(Base$1);
-  Pattern.constructors = {
-    Container: {
-      // Create pattern element in defs
-      pattern: function pattern(width, height, block) {
-        return this.defs().pattern(width, height, block);
+        return (this.unit === '%' ? ~~(this.value * 1e8) / 1e6 : this.unit === 's' ? this.value / 1e3 : this.value) + this.unit;
       }
-    },
-    Defs: {
-      pattern: function pattern(width, height, block) {
-        return this.put(new Pattern()).update(block).attr({
-          x: 0,
-          y: 0,
-          width: width,
-          height: height,
-          patternUnits: 'userSpaceOnUse'
-        });
+    }, {
+      key: "toJSON",
+      value: function toJSON() {
+        return this.toString();
       }
-    }
-  };
-
-  // ;[ 'click',
-  //   'dblclick',
-  //   'mousedown',
-  //   'mouseup',
-  //   'mouseover',
-  //   'mouseout',
-  //   'mousemove',
-  //   'mouseenter',
-  //   'mouseleave',
-  //   'touchstart',
-  //   'touchmove',
-  //   'touchleave',
-  //   'touchend',
-  //   'touchcancel' ].forEach(function (event) {
-  //     // add event to Element
-  //     Element.prototype[event] = function (f) {
-  //       if (f === null) {
-  //         off(this, event)
-  //       } else {
-  //         on(this, event, f)
-  //       }
-  //       return this
-  //     }
-  //   })
-
-  var listenerId = 0;
-
-  function getEventTarget(node) {
-    return node instanceof Base && node.is('EventTarget') ? node.getEventTarget() : node;
-  } // Add event binder in the SVG namespace
-
-
-  function on(node, events, listener, binding, options) {
-    var l = listener.bind(binding || node);
-    var n = getEventTarget(node); // events can be an array of events or a string of events
-
-    events = Array.isArray(events) ? events : events.split(delimiter); // ensure instance object for nodes which are not adopted
-
-    n.instance = n.instance || {
-      events: {} // pull event handlers from the element
-
-    };
-    var bag = n.instance.events; // add id to listener
+    }, {
+      key: "toArray",
+      value: function toArray() {
+        return [this.value, this.unit];
+      }
+    }, {
+      key: "valueOf",
+      value: function valueOf() {
+        return this.value;
+      } // Add number
 
-    if (!listener._svgjsListenerId) {
-      listener._svgjsListenerId = ++listenerId;
-    }
+    }, {
+      key: "plus",
+      value: function plus(number) {
+        number = new SVGNumber(number);
+        return new SVGNumber(this + number, this.unit || number.unit);
+      } // Subtract number
 
-    events.forEach(function (event) {
-      var ev = event.split('.')[0];
-      var ns = event.split('.')[1] || '*'; // ensure valid object
+    }, {
+      key: "minus",
+      value: function minus(number) {
+        number = new SVGNumber(number);
+        return new SVGNumber(this - number, this.unit || number.unit);
+      } // Multiply number
 
-      bag[ev] = bag[ev] || {};
-      bag[ev][ns] = bag[ev][ns] || {}; // reference listener
+    }, {
+      key: "times",
+      value: function times(number) {
+        number = new SVGNumber(number);
+        return new SVGNumber(this * number, this.unit || number.unit);
+      } // Divide number
 
-      bag[ev][ns][listener._svgjsListenerId] = l; // add listener
+    }, {
+      key: "divide",
+      value: function divide(number) {
+        number = new SVGNumber(number);
+        return new SVGNumber(this / number, this.unit || number.unit);
+      }
+    }]);
 
-      n.addEventListener(ev, l, options || false);
-    });
-  } // Add event unbinder in the SVG namespace
+    return SVGNumber;
+  }();
 
-  function off(node, events, listener, options) {
-    var n = getEventTarget(node); // we cannot remove an event if its not an svg.js instance
+  // FIXME: import this to runner
 
-    if (!n.instance) return; // listener can be a function or a number
+  function rx(rx) {
+    return this.attr('rx', rx);
+  } // Radius y value
 
-    if (typeof listener === 'function') {
-      listener = listener._svgjsListenerId;
-      if (!listener) return;
-    } // pull event handlers from the element
+  function ry(ry) {
+    return this.attr('ry', ry);
+  } // Move over x-axis
 
+  function x(x) {
+    return x == null ? this.cx() - this.rx() : this.cx(x + this.rx());
+  } // Move over y-axis
 
-    var bag = n.instance.events; // events can be an array of events or a string or undefined
+  function y(y) {
+    return y == null ? this.cy() - this.ry() : this.cy(y + this.ry());
+  } // Move by center over x-axis
 
-    events = Array.isArray(events) ? events : (events || '').split(delimiter);
-    events.forEach(function (event) {
-      var ev = event && event.split('.')[0];
-      var ns = event && event.split('.')[1];
-      var namespace, l;
+  function cx(x) {
+    return x == null ? this.attr('cx') : this.attr('cx', x);
+  } // Move by center over y-axis
 
-      if (listener) {
-        // remove listener reference
-        if (bag[ev] && bag[ev][ns || '*']) {
-          // removeListener
-          n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false);
-          delete bag[ev][ns || '*'][listener];
-        }
-      } else if (ev && ns) {
-        // remove all listeners for a namespaced event
-        if (bag[ev] && bag[ev][ns]) {
-          for (l in bag[ev][ns]) {
-            off(n, [ev, ns].join('.'), l);
-          }
+  function cy(y) {
+    return y == null ? this.attr('cy') : this.attr('cy', y);
+  } // Set width of element
 
-          delete bag[ev][ns];
-        }
-      } else if (ns) {
-        // remove all listeners for a specific namespace
-        for (event in bag) {
-          for (namespace in bag[event]) {
-            if (ns === namespace) {
-              off(n, [event, ns].join('.'));
-            }
-          }
-        }
-      } else if (ev) {
-        // remove all listeners for the event
-        if (bag[ev]) {
-          for (namespace in bag[ev]) {
-            off(n, [ev, namespace].join('.'));
-          }
+  function width(width) {
+    return width == null ? this.rx() * 2 : this.rx(new SVGNumber(width).divide(2));
+  } // Set height of element
 
-          delete bag[ev];
-        }
-      } else {
-        // remove all listeners on a given node
-        for (event in bag) {
-          off(n, event);
-        }
+  function height(height) {
+    return height == null ? this.ry() * 2 : this.ry(new SVGNumber(height).divide(2));
+  } // Custom size function
 
-        n.instance.events = {};
-      }
-    });
+  function size(width, height) {
+    var p = proportionalSize$1(this, width, height);
+    return this.rx(new SVGNumber(p.width).divide(2)).ry(new SVGNumber(p.height).divide(2));
   }
-  function dispatch(node, event, data) {
-    var n = getEventTarget(node); // Dispatch event
-
-    if (event instanceof window.Event) {
-      n.dispatchEvent(event);
-    } else {
-      event = new window.CustomEvent(event, {
-        detail: data,
-        cancelable: true
-      });
-      n.dispatchEvent(event);
-    }
 
-    return event;
-  }
+  var circled = /*#__PURE__*/Object.freeze({
+    rx: rx,
+    ry: ry,
+    x: x,
+    y: y,
+    cx: cx,
+    cy: cy,
+    width: width,
+    height: height,
+    size: size
+  });
 
-  var Image =
+  var Circle =
   /*#__PURE__*/
   function (_Base) {
-    _inherits(Image, _Base);
+    _inherits(Circle, _Base);
 
-    function Image(node) {
-      _classCallCheck(this, Image);
+    function Circle(node) {
+      _classCallCheck(this, Circle);
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Image).call(this, nodeOrNew$1('image', node), Image));
-    } // (re)load image
+      return _possibleConstructorReturn(this, _getPrototypeOf(Circle).call(this, nodeOrNew$1('circle', node), Circle));
+    }
 
+    _createClass(Circle, [{
+      key: "radius",
+      value: function radius(r) {
+        return this.attr('r', r);
+      } // Radius x value
 
-    _createClass(Image, [{
-      key: "load",
-      value: function load(url, callback) {
-        if (!url) return this;
-        var img = new window.Image();
-        on(img, 'load', function (e) {
-          var p = this.parent(Pattern); // ensure image size
-
-          if (this.width() === 0 && this.height() === 0) {
-            this.size(img.width, img.height);
-          }
-
-          if (p instanceof Pattern) {
-            // ensure pattern size if not set
-            if (p.width() === 0 && p.height() === 0) {
-              p.size(this.width(), this.height());
-            }
-          }
+    }, {
+      key: "rx",
+      value: function rx$$1(_rx) {
+        return this.attr('r', _rx);
+      } // Alias radius x value
 
-          if (typeof callback === 'function') {
-            callback.call(this, {
-              width: img.width,
-              height: img.height,
-              ratio: img.width / img.height,
-              url: url
-            });
-          }
-        }, this);
-        on(img, 'load error', function () {
-          // dont forget to unbind memory leaking events
-          off(img);
-        });
-        return this.attr('href', img.src = url, xlink);
+    }, {
+      key: "ry",
+      value: function ry$$1(_ry) {
+        return this.rx(_ry);
       }
     }]);
 
-    return Image;
+    return Circle;
   }(Base$1);
-  Image.constructors = {
-    Container: {
-      // create image element, load image and set its size
-      image: function image(source, callback) {
-        return this.put(new Image()).size(0, 0).load(source, callback);
+  extend$1(Circle, {
+    x: x,
+    y: y,
+    cx: cx,
+    cy: cy,
+    width: width,
+    height: height,
+    size: size
+  });
+  registerMethods({
+    Element: {
+      // Create circle element
+      circle: function circle(size$$1) {
+        return this.put(new Circle()).radius(new SVGNumber(size$$1).divide(2)).move(0, 0);
       }
     }
-  };
-
-  var BaseArray = function () {
-    try {
-      var b =
-      /*#__PURE__*/
-      function (_Array) {
-        _inherits(b, _Array);
-
-        function b() {
-          _classCallCheck(this, b);
-
-          return _possibleConstructorReturn(this, _getPrototypeOf(b).apply(this, arguments));
-        }
+  });
+  register(Circle);
 
-        return b;
-      }(_wrapNativeSuper(Array));
+  // Map function
+  function map(array, block) {
+    var i;
+    var il = array.length;
+    var result = [];
 
-      return Array;
-    } catch (e) {
-      return Array;
+    for (i = 0; i < il; i++) {
+      result.push(block(array[i]));
     }
-  }();
 
-  var SVGArray =
-  /*#__PURE__*/
-  function (_BaseArray) {
-    _inherits(SVGArray, _BaseArray);
+    return result;
+  } // Filter function
 
-    function SVGArray() {
-      var _this2;
+  function radians(d) {
+    return d % 360 * Math.PI / 180;
+  } // Radians to degrees
 
-      var _this;
+  // SVG.get = function (id) {
+  //   var node = document.getElementById(idFromReference(id) || id)
+  //   return SVG.adopt(node)
+  // }
+  //
+  // // Select elements by query string
+  // SVG.select = function (query, parent) {
+  //   return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
+  //     return SVG.adopt(node)
+  //   })
+  // }
+  //
+  // SVG.$$ = function (query, parent) {
+  //   return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
+  //     return SVG.adopt(node)
+  //   })
+  // }
+  //
+  // SVG.$ = function (query, parent) {
+  //   return SVG.adopt((parent || document).querySelector(query))
+  // }
 
-      _classCallCheck(this, SVGArray);
+  function baseFind(query, parent) {
+    return utils.map((parent || document).querySelectorAll(query), function (node) {
+      return adopt$1(node);
+    });
+  } // Scoped find method
 
-      _this = _possibleConstructorReturn(this, _getPrototypeOf(SVGArray).call(this));
+  function find$1(query) {
+    return baseFind(query, this.node);
+  }
+  registerMethods('Container', {
+    find: find$1
+  });
 
-      (_this2 = _this).init.apply(_this2, arguments);
+  var Doc$2 = getClass(root);
+  function setup(node) {
+    // initialize data object
+    this.dom = {}; // create circular reference
 
-      return _this;
+    this.node = node;
+    this.type = node.nodeName;
+    this.node.instance = this;
+
+    if (node.hasAttribute('svgjs:data')) {
+      // pull svgjs data from the dom (getAttributeNS doesn't work in html5)
+      this.setData(JSON.parse(node.getAttribute('svgjs:data')) || {});
     }
+  } // Move over x-axis
 
-    _createClass(SVGArray, [{
-      key: "init",
-      value: function init(array, fallback) {
-        //this.splice(0, this.length)
-        this.length = 0;
-        this.push.apply(this, _toConsumableArray(this.parse(array || fallback)));
-      }
-    }, {
-      key: "toArray",
-      value: function toArray() {
-        return Array.prototype.slice(this);
-      }
-    }, {
-      key: "toString",
-      value: function toString() {
-        this.join(' ');
-      }
-    }, {
-      key: "valueOf",
-      value: function valueOf() {
-        return this.toArray();
-      } // Parse whitespace separated string
+  function x$1(x) {
+    return this.attr('x', x);
+  } // Move over y-axis
 
-    }, {
-      key: "parse",
-      value: function parse(array) {
-        array = array.valueOf(); // if already is an array, no need to parse it
+  function y$1(y) {
+    return this.attr('y', y);
+  } // Move by center over x-axis
 
-        if (Array.isArray(array)) return array;
-        return array.trim().split(delimiter).map(parseFloat);
-      }
-    }, {
-      key: "clone",
-      value: function clone() {
-        return new this.constructor(this);
-      }
-    }, {
-      key: "toSet",
-      value: function toSet() {
-        return new Set(this);
-      }
-    }]);
+  function cx$1(x) {
+    return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2);
+  } // Move by center over y-axis
 
-    return SVGArray;
-  }(BaseArray);
+  function cy$1(y) {
+    return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2);
+  } // Move element to given x and y values
 
-  var PointArray$1 =
-  /*#__PURE__*/
-  function (_SVGArray) {
-    _inherits(PointArray, _SVGArray);
+  function move(x, y) {
+    return this.x(x).y(y);
+  } // Move element by its center
 
-    function PointArray(array) {
-      var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [[0, 0]];
+  function center(x, y) {
+    return this.cx(x).cy(y);
+  } // Set width of element
 
-      _classCallCheck(this, PointArray);
+  function width$1(width) {
+    return this.attr('width', width);
+  } // Set height of element
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(PointArray).call(this, array, fallback));
-    } // Convert array to string
+  function height$1(height) {
+    return this.attr('height', height);
+  } // Set element size to given width and height
 
+  function size$1(width, height) {
+    var p = proportionalSize$1(this, width, height);
+    return this.width(new SVGNumber(p.width)).height(new SVGNumber(p.height));
+  } // Clone element
 
-    _createClass(PointArray, [{
-      key: "toString",
-      value: function toString() {
-        // convert to a poly point string
-        for (var i = 0, il = this.value.length, array = []; i < il; i++) {
-          array.push(this.value[i].join(','));
-        }
+  function clone(parent) {
+    // write dom data to the dom so the clone can pickup the data
+    this.writeDataToDom(); // clone element and assign new id
 
-        return array.join(' ');
-      }
-    }, {
-      key: "toArray",
-      value: function toArray() {
-        return this.value.reduce(function (prev, curr) {
-          return [].concat.call(prev, curr);
-        }, []);
-      } // Convert array to line object
+    var clone = assignNewId(this.node.cloneNode(true)); // insert the clone in the given parent or after myself
 
-    }, {
-      key: "toLine",
-      value: function toLine() {
-        return {
-          x1: this.value[0][0],
-          y1: this.value[0][1],
-          x2: this.value[1][0],
-          y2: this.value[1][1]
-        };
-      } // Get morphed array at given position
+    if (parent) parent.add(clone);else this.after(clone);
+    return clone;
+  } // Remove element
 
-    }, {
-      key: "at",
-      value: function at(pos) {
-        // make sure a destination is defined
-        if (!this.destination) return this; // generate morphed point string
-
-        for (var i = 0, il = this.value.length, array = []; i < il; i++) {
-          array.push([this.value[i][0] + (this.destination[i][0] - this.value[i][0]) * pos, this.value[i][1] + (this.destination[i][1] - this.value[i][1]) * pos]);
-        }
-
-        return new PointArray(array);
-      } // Parse point string and flat array
+  function remove() {
+    if (this.parent()) {
+      this.parent().removeElement(this);
+    }
 
-    }, {
-      key: "parse",
-      value: function parse(array) {
-        var points = [];
-        array = array.valueOf(); // if it is an array
+    return this;
+  } // Replace element
 
-        if (Array.isArray(array)) {
-          // and it is not flat, there is no need to parse it
-          if (Array.isArray(array[0])) {
-            return array;
-          }
-        } else {
-          // Else, it is considered as a string
-          // parse points
-          array = array.trim().split(delimiter).map(parseFloat);
-        } // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
-        // Odd number of coordinates is an error. In such cases, drop the last odd coordinate.
+  function replace(element) {
+    this.after(element).remove();
+    return element;
+  } // Add element to given container and return self
 
+  function putIn(parent) {
+    return makeInstance(parent).add(this);
+  } // Get / set id
 
-        if (array.length % 2 !== 0) array.pop(); // wrap points in two-tuples and parse points as floats
+  function id$1(id) {
+    // generate new id if no id set
+    if (typeof id === 'undefined' && !this.node.id) {
+      this.node.id = eid(this.type);
+    } // dont't set directly width this.node.id to make `null` work correctly
 
-        for (var i = 0, len = array.length; i < len; i = i + 2) {
-          points.push([array[i], array[i + 1]]);
-        }
 
-        return points;
-      } // Move point string
+    return this.attr('id', id);
+  } // Checks whether the given point inside the bounding box of the element
 
-    }, {
-      key: "move",
-      value: function move(x, y) {
-        var box = this.bbox(); // get relative offset
+  function inside(x, y) {
+    var box = this.bbox();
+    return x > box.x && y > box.y && x < box.x + box.width && y < box.y + box.height;
+  } // Return id on string conversion
 
-        x -= box.x;
-        y -= box.y; // move every point
+  function toString() {
+    return this.id();
+  } // Return array of classes on the node
 
-        if (!isNaN(x) && !isNaN(y)) {
-          for (var i = this.value.length - 1; i >= 0; i--) {
-            this.value[i] = [this.value[i][0] + x, this.value[i][1] + y];
-          }
-        }
+  function classes() {
+    var attr = this.attr('class');
+    return attr == null ? [] : attr.trim().split(delimiter);
+  } // Return true if class exists on the node, false otherwise
 
-        return this;
-      } // Resize poly string
+  function hasClass(name) {
+    return this.classes().indexOf(name) !== -1;
+  } // Add class to the node
 
-    }, {
-      key: "size",
-      value: function size(width, height) {
-        var i;
-        var box = this.bbox(); // recalculate position of all points according to new size
+  function addClass(name) {
+    if (!this.hasClass(name)) {
+      var array = this.classes();
+      array.push(name);
+      this.attr('class', array.join(' '));
+    }
 
-        for (i = this.value.length - 1; i >= 0; i--) {
-          if (box.width) this.value[i][0] = (this.value[i][0] - box.x) * width / box.width + box.x;
-          if (box.height) this.value[i][1] = (this.value[i][1] - box.y) * height / box.height + box.y;
-        }
+    return this;
+  } // Remove class from the node
 
-        return this;
-      } // Get bounding box of points
+  function removeClass(name) {
+    if (this.hasClass(name)) {
+      this.attr('class', this.classes().filter(function (c) {
+        return c !== name;
+      }).join(' '));
+    }
 
-    }, {
-      key: "bbox",
-      value: function bbox() {
-        var maxX = -Infinity;
-        var maxY = -Infinity;
-        var minX = Infinity;
-        var minY = Infinity;
-        this.value.forEach(function (el) {
-          maxX = Math.max(el[0], maxX);
-          maxY = Math.max(el[1], maxY);
-          minX = Math.min(el[0], minX);
-          minY = Math.min(el[1], minY);
-        });
-        return {
-          x: minX,
-          y: minY,
-          width: maxX - minX,
-          height: maxY - minY
-        };
-      }
-    }]);
+    return this;
+  } // Toggle the presence of a class on the node
 
-    return PointArray;
-  }(SVGArray);
+  function toggleClass(name) {
+    return this.hasClass(name) ? this.removeClass(name) : this.addClass(name);
+  } // FIXME: getIdFromReference
+  // Get referenced element form attribute value
 
-  var Line =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Line, _Base);
+  function reference$1(attr) {
+    return get(this.attr(attr));
+  } // Returns the parent element instance
 
-    // Initialize node
-    function Line(node) {
-      _classCallCheck(this, Line);
+  function doc() {
+    var p = this.parent(Doc$2);
+    return p && p.doc();
+  } // Get defs
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Line).call(this, nodeOrNew$1('line', node), Line));
-    } // Get array
+  function defs() {
+    return this.doc().defs();
+  } // return array of all ancestors of given type up to the root svg
 
+  function parents(type) {
+    var parents = [];
+    var parent = this;
 
-    _createClass(Line, [{
-      key: "array",
-      value: function array() {
-        return new PointArray$1([[this.attr('x1'), this.attr('y1')], [this.attr('x2'), this.attr('y2')]]);
-      } // Overwrite native plot() method
+    do {
+      parent = parent.parent(type);
+      if (!parent || !parent.node) break;
+      parents.push(parent);
+    } while (parent.parent);
 
-    }, {
-      key: "plot",
-      value: function plot(x1, y1, x2, y2) {
-        if (x1 == null) {
-          return this.array();
-        } else if (typeof y1 !== 'undefined') {
-          x1 = {
-            x1: x1,
-            y1: y1,
-            x2: x2,
-            y2: y2
-          };
-        } else {
-          x1 = new PointArray$1(x1).toLine();
-        }
+    return parents;
+  } // matches the element vs a css selector
 
-        return this.attr(x1);
-      } // Move by left top corner
+  function matches(selector) {
+    return matches(this.node, selector);
+  } // Returns the svg node to call native svg methods on it
 
-    }, {
-      key: "move",
-      value: function move(x, y) {
-        return this.attr(this.array().move(x, y).toLine());
-      } // Set element size to given width and height
+  function native() {
+    return this.node;
+  } // Import raw svg
 
-    }, {
-      key: "size",
-      value: function size(width, height) {
-        var p = proportionalSize$1(this, width, height);
-        return this.attr(this.array().size(p.width, p.height).toLine());
-      }
-    }]);
+  function svg() {
+    // write svgjs data to the dom
+    this.writeDataToDom();
+    return this.node.outerHTML;
+  } // write svgjs data to the dom
 
-    return Line;
-  }(Base$1);
-  Line.constructors = {
-    Container: {
-      // Create a line element
-      line: function line() {
-        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
-          args[_key] = arguments[_key];
-        }
+  function writeDataToDom() {
+    // remove previously set data
+    this.node.removeAttribute('svgjs:data');
 
-        // make sure plot is called as a setter
-        // x1 is not necessarily a number, it can also be an array, a string and a PointArray
-        return Line.prototype.plot.apply(this.put(new Line()), args[0] != null ? args : [0, 0, 0, 0]);
-      }
+    if (Object.keys(this.dom).length) {
+      this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)); // see #428
     }
-  };
-
-  // import Line from './Line.js'
-  // import Polyline from './Polyline.js'
-  // import Polygon from './Polygon.js'
-  // import Path from './Path.js'
-
-  var Marker =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Marker, _Base);
-
-    // Initialize node
-    function Marker(node) {
-      _classCallCheck(this, Marker);
-
-      return _possibleConstructorReturn(this, _getPrototypeOf(Marker).call(this, nodeOrNew('marker', node), Marker));
-    } // Set width of element
-
-
-    _createClass(Marker, [{
-      key: "width",
-      value: function width(_width) {
-        return this.attr('markerWidth', _width);
-      } // Set height of element
 
-    }, {
-      key: "height",
-      value: function height(_height) {
-        return this.attr('markerHeight', _height);
-      } // Set marker refX and refY
-
-    }, {
-      key: "ref",
-      value: function ref(x, y) {
-        return this.attr('refX', x).attr('refY', y);
-      } // Update marker
+    return this;
+  } // set given data to the elements data property
 
-    }, {
-      key: "update",
-      value: function update(block) {
-        // remove all content
-        this.clear(); // invoke passed block
+  function setData(o) {
+    this.dom = o;
+    return this;
+  }
+  function getEventTarget() {
+    return this.node;
+  }
+  registerMethods('Element', {
+    x: x$1,
+    y: y$1,
+    cx: cx$1,
+    cy: cy$1,
+    move: move,
+    center: center,
+    width: width$1,
+    height: height$1,
+    size: size$1,
+    clone: clone,
+    remove: remove,
+    replace: replace,
+    putIn: putIn,
+    id: id$1,
+    inside: inside,
+    toString: toString,
+    classes: classes,
+    hasClass: hasClass,
+    addClass: addClass,
+    removeClass: removeClass,
+    toggleClass: toggleClass,
+    reference: reference$1,
+    doc: doc,
+    defs: defs,
+    parents: parents,
+    matches: matches,
+    native: native,
+    svg: svg,
+    writeDataToDom: writeDataToDom,
+    setData: setData,
+    getEventTarget: getEventTarget
+  });
+  registerConstructor('Element', setup);
 
-        if (typeof block === 'function') {
-          block.call(this, this);
-        }
+  var ClipPath =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(ClipPath, _Base);
 
-        return this;
-      } // Return the fill id
+    function ClipPath(node) {
+      _classCallCheck(this, ClipPath);
 
+      return _possibleConstructorReturn(this, _getPrototypeOf(ClipPath).call(this, nodeOrNew$1('clipPath', node), ClipPath));
+    } // Unclip all clipped elements and remove itself
+
+
+    _createClass(ClipPath, [{
+      key: "remove",
+      value: function remove$$1() {
+        // unclip all targets
+        this.targets().forEach(function (el) {
+          el.unclip();
+        }); // remove clipPath from parent
+
+        return remove.call(this);
+      }
     }, {
-      key: "toString",
-      value: function toString() {
-        return 'url(#' + this.id() + ')';
+      key: "targets",
+      value: function targets() {
+        return baseFind('svg [clip-path*="' + this.id() + '"]');
       }
     }]);
 
-    return Marker;
+    return ClipPath;
   }(Base$1);
-  Marker.constructors = {
+  registerMethods({
     Container: {
-      marker: function marker(width, height, block) {
-        // Create marker element in defs
-        return this.defs().marker(width, height, block);
-      }
-    },
-    Defs: {
-      // Create marker
-      marker: function marker(width, height, block) {
-        // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto
-        return this.put(new Marker()).size(width, height).ref(width / 2, height / 2).viewbox(0, 0, width, height).attr('orient', 'auto').update(block);
+      // Create clipping element
+      clip: function clip() {
+        return this.defs().put(new ClipPath());
       }
     },
-    marker: {
-      // Create and attach markers
-      marker: function marker(_marker, width, height, block) {
-        var attr = ['marker']; // Build attribute name
-
-        if (_marker !== 'all') attr.push(_marker);
-        attr = attr.join('-'); // Set marker attribute
+    Element: {
+      // Distribute clipPath to svg element
+      clipWith: function clipWith(element) {
+        // use given clip or create a new one
+        var clipper = element instanceof ClipPath ? element : this.parent().clip().add(element); // apply mask
 
-        _marker = arguments[1] instanceof Marker ? arguments[1] : this.defs().marker(width, height, block);
-        return this.attr(attr, _marker);
+        return this.attr('clip-path', 'url("#' + clipper.id() + '")');
+      },
+      // Unclip element
+      unclip: function unclip() {
+        return this.attr('clip-path', null);
+      },
+      clipper: function clipper() {
+        return this.reference('clip-path');
       }
     }
-  };
-
-  // import {remove} from  './Element.js'
+  });
+  register(ClipPath);
 
-  var Mask =
+  var A =
   /*#__PURE__*/
   function (_Base) {
-    _inherits(Mask, _Base);
+    _inherits(A, _Base);
 
-    // Initialize node
-    function Mask(node) {
-      _classCallCheck(this, Mask);
+    function A(node) {
+      _classCallCheck(this, A);
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Mask).call(this, nodeOrNew$1('mask', node)));
-    } // // Unmask all masked elements and remove itself
-    // remove () {
-    //   // unmask all targets
-    //   this.targets().forEach(function (el) {
-    //     el.unmask()
-    //   })
-    //
-    //   // remove mask from parent
-    //   return remove.call(this)
-    // }
-    //
-    // targets () {
-    //   return find('svg [mask*="' + this.id() + '"]')
-    // }
+      return _possibleConstructorReturn(this, _getPrototypeOf(A).call(this, nodeOrNew$1('a', node), A));
+    } // Link url
 
 
-    return Mask;
+    _createClass(A, [{
+      key: "to",
+      value: function to(url) {
+        return this.attr('href', url, xlink);
+      } // Link target attribute
+
+    }, {
+      key: "target",
+      value: function target(_target) {
+        return this.attr('target', _target);
+      }
+    }]);
+
+    return A;
   }(Base$1);
-  Mask.constructors = {
+  registerMethods({
     Container: {
-      mask: function mask() {
-        return this.defs().put(new Mask());
+      // Create a hyperlink element
+      link: function link(url) {
+        return this.put(new A()).to(url);
       }
     },
     Element: {
-      // Distribute mask to svg element
-      maskWith: function maskWith(element) {
-        // use given mask or create a new one
-        var masker = element instanceof Mask ? element : this.parent().mask().add(element); // apply mask
+      // Create a hyperlink element
+      linkTo: function linkTo(url) {
+        var link = new A();
 
-        return this.attr('mask', 'url("#' + masker.id() + '")');
-      },
-      // Unmask element
-      unmask: function unmask() {
-        return this.attr('mask', null);
-      },
-      masker: function masker() {
-        return this.reference('mask');
+        if (typeof url === 'function') {
+          url.call(link, link);
+        } else {
+          link.to(url);
+        }
+
+        return this.parent().put(link).put(this);
       }
     }
-  };
+  });
+  register(A);
 
-  function parser() {
-    // Reuse cached element if possible
-    if (!parser.nodes) {
-      var svg = new Doc$1().size(2, 0).css({
-        opacity: 0,
-        position: 'absolute',
-        left: '-100%',
-        top: '-100%',
-        overflow: 'hidden'
-      });
-      var path = svg.path().node;
-      parser.nodes = {
-        svg: svg,
-        path: path
-      };
-    }
+  var Ellipse =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Ellipse, _Base);
 
-    if (!parser.nodes.svg.node.parentNode) {
-      var b = document.body || document.documentElement;
-      parser.nodes.svg.addTo(b);
+    function Ellipse(node) {
+      _classCallCheck(this, Ellipse);
+
+      return _possibleConstructorReturn(this, _getPrototypeOf(Ellipse).call(this, nodeOrNew('ellipse', node), Ellipse));
     }
 
-    return parser.nodes;
-  }
+    return Ellipse;
+  }(Base$1);
+  extend$1(Ellipse, circled);
+  registerMethods('Container', {
+    // Create an ellipse
+    ellipse: function ellipse(width$$1, height$$1) {
+      return this.put(new Ellipse()).size(width$$1, height$$1).move(0, 0);
+    }
+  });
+  register(Ellipse);
 
-  var Point =
+  var Stop =
   /*#__PURE__*/
-  function () {
-    // Initialize
-    function Point(x, y, base) {
-      _classCallCheck(this, Point);
-
-      var source;
-      base = base || {
-        x: 0,
-        y: 0 // ensure source as object
-
-      };
-      source = Array.isArray(x) ? {
-        x: x[0],
-        y: x[1]
-      } : _typeof(x) === 'object' ? {
-        x: x.x,
-        y: x.y
-      } : {
-        x: x,
-        y: y // merge source
-
-      };
-      this.x = source.x == null ? base.x : source.x;
-      this.y = source.y == null ? base.y : source.y;
-    } // Clone point
+  function (_Base) {
+    _inherits(Stop, _Base);
 
+    function Stop(node) {
+      _classCallCheck(this, Stop);
 
-    _createClass(Point, [{
-      key: "clone",
-      value: function clone() {
-        return new Point(this);
-      } // Convert to native SVGPoint
+      return _possibleConstructorReturn(this, _getPrototypeOf(Stop).call(this, nodeOrNew$1('stop', node), Stop));
+    } // add color stops
 
-    }, {
-      key: "native",
-      value: function native() {
-        // create new point
-        var point = parser().svg.createSVGPoint(); // update with current values
 
-        point.x = this.x;
-        point.y = this.y;
-        return point;
-      } // transform point with matrix
+    _createClass(Stop, [{
+      key: "update",
+      value: function update(o) {
+        if (typeof o === 'number' || o instanceof SVGNumber) {
+          o = {
+            offset: arguments[0],
+            color: arguments[1],
+            opacity: arguments[2]
+          };
+        } // set attributes
 
-    }, {
-      key: "transform",
-      value: function transform(m) {
-        // Perform the matrix multiplication
-        var x = m.a * this.x + m.c * this.y + m.e;
-        var y = m.b * this.x + m.d * this.y + m.f; // Return the required point
 
-        return new Point(x, y);
+        if (o.opacity != null) this.attr('stop-opacity', o.opacity);
+        if (o.color != null) this.attr('stop-color', o.color);
+        if (o.offset != null) this.attr('offset', new SVGNumber(o.offset));
+        return this;
       }
     }]);
 
-    return Point;
-  }();
-  Point.constructors = {
-    Element: {
-      // Get point
-      point: function point(x, y) {
-        return new Point(x, y).transform(this.screenCTM().inverse());
-      }
-    }
-  };
-
-  var pathHandlers = {
-    M: function M(c, p, p0) {
-      p.x = p0.x = c[0];
-      p.y = p0.y = c[1];
-      return ['M', p.x, p.y];
-    },
-    L: function L(c, p) {
-      p.x = c[0];
-      p.y = c[1];
-      return ['L', c[0], c[1]];
-    },
-    H: function H(c, p) {
-      p.x = c[0];
-      return ['H', c[0]];
-    },
-    V: function V(c, p) {
-      p.y = c[0];
-      return ['V', c[0]];
-    },
-    C: function C(c, p) {
-      p.x = c[4];
-      p.y = c[5];
-      return ['C', c[0], c[1], c[2], c[3], c[4], c[5]];
-    },
-    S: function S(c, p) {
-      p.x = c[2];
-      p.y = c[3];
-      return ['S', c[0], c[1], c[2], c[3]];
-    },
-    Q: function Q(c, p) {
-      p.x = c[2];
-      p.y = c[3];
-      return ['Q', c[0], c[1], c[2], c[3]];
-    },
-    T: function T(c, p) {
-      p.x = c[0];
-      p.y = c[1];
-      return ['T', c[0], c[1]];
-    },
-    Z: function Z(c, p, p0) {
-      p.x = p0.x;
-      p.y = p0.y;
-      return ['Z'];
-    },
-    A: function A(c, p) {
-      p.x = c[5];
-      p.y = c[6];
-      return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]];
-    }
-  };
-  var mlhvqtcsaz = 'mlhvqtcsaz'.split('');
+    return Stop;
+  }(Base$1);
+  register(Stop);
 
-  for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
-    pathHandlers[mlhvqtcsaz[i]] = function (i) {
-      return function (c, p, p0) {
-        if (i === 'H') c[0] = c[0] + p.x;else if (i === 'V') c[0] = c[0] + p.y;else if (i === 'A') {
-          c[5] = c[5] + p.x;
-          c[6] = c[6] + p.y;
-        } else {
-          for (var j = 0, jl = c.length; j < jl; ++j) {
-            c[j] = c[j] + (j % 2 ? p.y : p.x);
-          }
-        }
-        return pathHandlers[i](c, p, p0);
-      };
-    }(mlhvqtcsaz[i].toUpperCase());
+  // FIXME: add to runner
+  function from(x, y) {
+    return (this._element || this).type === 'radialGradient' ? this.attr({
+      fx: new SVGNumber(x),
+      fy: new SVGNumber(y)
+    }) : this.attr({
+      x1: new SVGNumber(x),
+      y1: new SVGNumber(y)
+    });
+  }
+  function to(x, y) {
+    return (this._element || this).type === 'radialGradient' ? this.attr({
+      cx: new SVGNumber(x),
+      cy: new SVGNumber(y)
+    }) : this.attr({
+      x2: new SVGNumber(x),
+      y2: new SVGNumber(y)
+    });
   }
 
-  var PathArray =
+  var gradiented = /*#__PURE__*/Object.freeze({
+    from: from,
+    to: to
+  });
+
+  function noop() {} // Default animation values
+
+  var timeline = {
+    duration: 400,
+    ease: '>',
+    delay: 0 // Default attribute values
+
+  };
+  var attrs = {
+    // fill and stroke
+    'fill-opacity': 1,
+    'stroke-opacity': 1,
+    'stroke-width': 0,
+    'stroke-linejoin': 'miter',
+    'stroke-linecap': 'butt',
+    fill: '#000000',
+    stroke: '#000000',
+    opacity: 1,
+    // position
+    x: 0,
+    y: 0,
+    cx: 0,
+    cy: 0,
+    // size
+    width: 0,
+    height: 0,
+    // radius
+    r: 0,
+    rx: 0,
+    ry: 0,
+    // gradient
+    offset: 0,
+    'stop-opacity': 1,
+    'stop-color': '#000000',
+    // text
+    'font-size': 16,
+    'font-family': 'Helvetica, Arial, sans-serif',
+    'text-anchor': 'start'
+  };
+
+  var Color =
   /*#__PURE__*/
-  function (_SVGArray) {
-    _inherits(PathArray, _SVGArray);
+  function () {
+    function Color() {
+      _classCallCheck(this, Color);
 
-    function PathArray(array) {
-      var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [['M', 0, 0]];
+      this.init.apply(this, arguments);
+    }
 
-      _classCallCheck(this, PathArray);
+    _createClass(Color, [{
+      key: "init",
+      value: function init(color, g, b) {
+        var match; // initialize defaults
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(PathArray).call(this, array, fallback));
-    } // Convert array to string
+        this.r = 0;
+        this.g = 0;
+        this.b = 0;
+        if (!color) return; // parse color
 
+        if (typeof color === 'string') {
+          if (isRgb.test(color)) {
+            // get rgb values
+            match = rgb.exec(color.replace(whitespace, '')); // parse numeric values
 
-    _createClass(PathArray, [{
+            this.r = parseInt(match[1]);
+            this.g = parseInt(match[2]);
+            this.b = parseInt(match[3]);
+          } else if (isHex.test(color)) {
+            // get hex values
+            match = hex.exec(fullHex(color)); // parse numeric values
+
+            this.r = parseInt(match[1], 16);
+            this.g = parseInt(match[2], 16);
+            this.b = parseInt(match[3], 16);
+          }
+        } else if (Array.isArray(color)) {
+          this.r = color[0];
+          this.g = color[1];
+          this.b = color[2];
+        } else if (_typeof(color) === 'object') {
+          this.r = color.r;
+          this.g = color.g;
+          this.b = color.b;
+        } else if (arguments.length === 3) {
+          this.r = color;
+          this.g = g;
+          this.b = b;
+        }
+      } // Default to hex conversion
+
+    }, {
       key: "toString",
       value: function toString() {
-        return arrayToString(this);
+        return this.toHex();
       }
     }, {
       key: "toArray",
       value: function toArray() {
-        return this.reduce(function (prev, curr) {
-          return [].concat.call(prev, curr);
-        }, []);
-      } // Move path string
+        return [this.r, this.g, this.b];
+      } // Build hex value
 
     }, {
-      key: "move",
-      value: function move(x, y) {
-        // get bounding box of current situation
-        var box = this.bbox(); // get relative offset
-
-        x -= box.x;
-        y -= box.y;
+      key: "toHex",
+      value: function toHex() {
+        return '#' + compToHex(Math.round(this.r)) + compToHex(Math.round(this.g)) + compToHex(Math.round(this.b));
+      } // Build rgb value
 
-        if (!isNaN(x) && !isNaN(y)) {
-          // move every point
-          for (var l, i = this.length - 1; i >= 0; i--) {
-            l = this[i][0];
+    }, {
+      key: "toRgb",
+      value: function toRgb() {
+        return 'rgb(' + [this.r, this.g, this.b].join() + ')';
+      } // Calculate true brightness
 
-            if (l === 'M' || l === 'L' || l === 'T') {
-              this[i][1] += x;
-              this[i][2] += y;
-            } else if (l === 'H') {
-              this[i][1] += x;
-            } else if (l === 'V') {
-              this[i][1] += y;
-            } else if (l === 'C' || l === 'S' || l === 'Q') {
-              this[i][1] += x;
-              this[i][2] += y;
-              this[i][3] += x;
-              this[i][4] += y;
+    }, {
+      key: "brightness",
+      value: function brightness() {
+        return this.r / 255 * 0.30 + this.g / 255 * 0.59 + this.b / 255 * 0.11;
+      } // Testers
+      // Test if given value is a color string
 
-              if (l === 'C') {
-                this[i][5] += x;
-                this[i][6] += y;
-              }
-            } else if (l === 'A') {
-              this[i][6] += x;
-              this[i][7] += y;
-            }
-          }
-        }
-
-        return this;
-      } // Resize path string
+    }], [{
+      key: "test",
+      value: function test(color) {
+        color += '';
+        return isHex.test(color) || isRgb.test(color);
+      } // Test if given value is a rgb object
 
     }, {
-      key: "size",
-      value: function size(width, height) {
-        // get bounding box of current situation
-        var box = this.bbox();
-        var i, l; // recalculate position of all points according to new size
-
-        for (i = this.length - 1; i >= 0; i--) {
-          l = this[i][0];
-
-          if (l === 'M' || l === 'L' || l === 'T') {
-            this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
-            this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;
-          } else if (l === 'H') {
-            this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
-          } else if (l === 'V') {
-            this[i][1] = (this[i][1] - box.y) * height / box.height + box.y;
-          } else if (l === 'C' || l === 'S' || l === 'Q') {
-            this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
-            this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;
-            this[i][3] = (this[i][3] - box.x) * width / box.width + box.x;
-            this[i][4] = (this[i][4] - box.y) * height / box.height + box.y;
+      key: "isRgb",
+      value: function isRgb$$1(color) {
+        return color && typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number';
+      } // Test if given value is a color
 
-            if (l === 'C') {
-              this[i][5] = (this[i][5] - box.x) * width / box.width + box.x;
-              this[i][6] = (this[i][6] - box.y) * height / box.height + box.y;
-            }
-          } else if (l === 'A') {
-            // resize radii
-            this[i][1] = this[i][1] * width / box.width;
-            this[i][2] = this[i][2] * height / box.height; // move position values
+    }, {
+      key: "isColor",
+      value: function isColor(color) {
+        return this.isRgb(color) || this.test(color);
+      }
+    }]);
 
-            this[i][6] = (this[i][6] - box.x) * width / box.width + box.x;
-            this[i][7] = (this[i][7] - box.y) * height / box.height + box.y;
-          }
-        }
+    return Color;
+  }();
 
-        return this;
-      } // Test if the passed path array use the same path data commands as this path array
+  var BaseArray = function () {
+    try {
+      var b =
+      /*#__PURE__*/
+      function (_Array) {
+        _inherits(b, _Array);
 
-    }, {
-      key: "equalCommands",
-      value: function equalCommands(pathArray) {
-        var i, il, equalCommands;
-        pathArray = new PathArray(pathArray);
-        equalCommands = this.length === pathArray.value.length;
+        function b() {
+          _classCallCheck(this, b);
 
-        for (i = 0, il = this.length; equalCommands && i < il; i++) {
-          equalCommands = this[i][0] === pathArray.value[i][0];
+          return _possibleConstructorReturn(this, _getPrototypeOf(b).apply(this, arguments));
         }
 
-        return equalCommands;
-      } // Make path array morphable
-
-    }, {
-      key: "morph",
-      value: function morph(pathArray) {
-        pathArray = new PathArray(pathArray);
+        return b;
+      }(_wrapNativeSuper(Array));
 
-        if (this.equalCommands(pathArray)) {
-          this.destination = pathArray;
-        } else {
-          this.destination = null;
-        }
+      return Array;
+    } catch (e) {
+      return Array;
+    }
+  }();
 
-        return this;
-      } // Get morphed path array at given position
+  var SVGArray =
+  /*#__PURE__*/
+  function (_BaseArray) {
+    _inherits(SVGArray, _BaseArray);
 
-    }, {
-      key: "at",
-      value: function at(pos) {
-        // make sure a destination is defined
-        if (!this.destination) return this;
-        var sourceArray = this;
-        var destinationArray = this.destination.value;
-        var array = [];
-        var pathArray = new PathArray();
-        var i, il, j, jl; // Animate has specified in the SVG spec
-        // See: https://www.w3.org/TR/SVG11/paths.html#PathElement
+    function SVGArray() {
+      var _this2;
 
-        for (i = 0, il = sourceArray.length; i < il; i++) {
-          array[i] = [sourceArray[i][0]];
+      var _this;
 
-          for (j = 1, jl = sourceArray[i].length; j < jl; j++) {
-            array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos;
-          } // For the two flags of the elliptical arc command, the SVG spec say:
-          // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
-          // Elliptical arc command as an array followed by corresponding indexes:
-          // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
-          //   0    1   2        3                 4             5      6  7
+      _classCallCheck(this, SVGArray);
 
+      _this = _possibleConstructorReturn(this, _getPrototypeOf(SVGArray).call(this));
 
-          if (array[i][0] === 'A') {
-            array[i][4] = +(array[i][4] !== 0);
-            array[i][5] = +(array[i][5] !== 0);
-          }
-        } // Directly modify the value of a path array, this is done this way for performance
+      (_this2 = _this).init.apply(_this2, arguments);
 
+      return _this;
+    }
 
-        pathArray.value = array;
-        return pathArray;
-      } // Absolutize and parse path to array
+    _createClass(SVGArray, [{
+      key: "init",
+      value: function init(array, fallback) {
+        //this.splice(0, this.length)
+        this.length = 0;
+        this.push.apply(this, _toConsumableArray(this.parse(array || fallback)));
+      }
+    }, {
+      key: "toArray",
+      value: function toArray() {
+        return Array.prototype.slice(this);
+      }
+    }, {
+      key: "toString",
+      value: function toString() {
+        this.join(' ');
+      }
+    }, {
+      key: "valueOf",
+      value: function valueOf() {
+        return this.toArray();
+      } // Parse whitespace separated string
 
     }, {
       key: "parse",
       value: function parse(array) {
-        // if it's already a patharray, no need to parse it
-        if (array instanceof PathArray) return array.valueOf(); // prepare for parsing
-
-        var s;
-        var paramCnt = {
-          'M': 2,
-          'L': 2,
-          'H': 1,
-          'V': 1,
-          'C': 6,
-          'S': 4,
-          'Q': 4,
-          'T': 2,
-          'A': 7,
-          'Z': 0
-        };
-
-        if (typeof array === 'string') {
-          array = array.replace(numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
-          .replace(pathLetters, ' $& ') // put some room between letters and numbers
-          .replace(hyphen, '$1 -') // add space before hyphen
-          .trim() // trim
-          .split(delimiter); // split into array
-        } else {
-          array = array.reduce(function (prev, curr) {
-            return [].concat.call(prev, curr);
-          }, []);
-        } // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
-
-
-        var result = [];
-        var p = new Point();
-        var p0 = new Point();
-        var index = 0;
-        var len = array.length;
-
-        do {
-          // Test if we have a path letter
-          if (isPathLetter.test(array[index])) {
-            s = array[index];
-            ++index; // If last letter was a move command and we got no new, it defaults to [L]ine
-          } else if (s === 'M') {
-            s = 'L';
-          } else if (s === 'm') {
-            s = 'l';
-          }
-
-          result.push(pathHandlers[s].call(null, array.slice(index, index = index + paramCnt[s.toUpperCase()]).map(parseFloat), p, p0));
-        } while (len > index);
-
-        return result;
-      } // Get bounding box of path
+        array = array.valueOf(); // if already is an array, no need to parse it
 
+        if (Array.isArray(array)) return array;
+        return array.trim().split(delimiter).map(parseFloat);
+      }
     }, {
-      key: "bbox",
-      value: function bbox() {
-        parser().path.setAttribute('d', this.toString());
-        return parser.nodes.path.getBBox();
+      key: "clone",
+      value: function clone() {
+        return new this.constructor(this);
+      }
+    }, {
+      key: "toSet",
+      value: function toSet() {
+        return new Set(this);
       }
     }]);
 
-    return PathArray;
-  }(SVGArray);
-
-  var Path =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Path, _Base);
-
-    // Initialize node
-    function Path(node) {
-      _classCallCheck(this, Path);
-
-      return _possibleConstructorReturn(this, _getPrototypeOf(Path).call(this, nodeOrNew$1('path', node), Path));
-    } // Get array
-
-
-    _createClass(Path, [{
-      key: "array",
-      value: function array() {
-        return this._array || (this._array = new PathArray(this.attr('d')));
-      } // Plot new path
+    return SVGArray;
+  }(BaseArray);
 
-    }, {
-      key: "plot",
-      value: function plot(d) {
-        return d == null ? this.array() : this.clear().attr('d', typeof d === 'string' ? d : this._array = new PathArray(d));
-      } // Clear array cache
+  function attr(attr, val, ns) {
+    // act as full getter
+    if (attr == null) {
+      // get an object of attributes
+      attr = {};
+      val = this.node.attributes;
+      var _iteratorNormalCompletion = true;
+      var _didIteratorError = false;
+      var _iteratorError = undefined;
 
-    }, {
-      key: "clear",
-      value: function clear() {
-        delete this._array;
-        return this;
-      } // Move by left top corner
+      try {
+        for (var _iterator = val[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+          var node = _step.value;
+          attr[node.nodeName] = isNumer.test(node.nodeValue) ? parseFloat(node.nodeValue) : node.nodeValue;
+        }
+      } catch (err) {
+        _didIteratorError = true;
+        _iteratorError = err;
+      } finally {
+        try {
+          if (!_iteratorNormalCompletion && _iterator.return != null) {
+            _iterator.return();
+          }
+        } finally {
+          if (_didIteratorError) {
+            throw _iteratorError;
+          }
+        }
+      }
 
-    }, {
-      key: "move",
-      value: function move(x, y) {
-        return this.attr('d', this.array().move(x, y));
-      } // Move by left top corner over x-axis
+      return attr;
+    } else if (Array.isArray(attr)) ; else if (_typeof(attr) === 'object') {
+      // apply every attribute individually if an object is passed
+      for (val in attr) {
+        this.attr(val, attr[val]);
+      }
+    } else if (val === null) {
+      // remove value
+      this.node.removeAttribute(attr);
+    } else if (val == null) {
+      // act as a getter if the first and only argument is not an object
+      val = this.node.getAttribute(attr);
+      return val == null ? attrs[attr] // FIXME: do we need to return defaults?
+      : isNumber.test(val) ? parseFloat(val) : val;
+    } else {
+      // convert image fill and stroke to patterns
+      if (attr === 'fill' || attr === 'stroke') {
+        if (isImage.test(val)) {
+          val = this.doc().defs().image(val);
+        }
+      } // FIXME: This is fine, but what about the lines above?
+      // How does attr know about image()?
 
-    }, {
-      key: "x",
-      value: function x(_x) {
-        return _x == null ? this.bbox().x : this.move(_x, this.bbox().y);
-      } // Move by left top corner over y-axis
 
-    }, {
-      key: "y",
-      value: function y(_y) {
-        return _y == null ? this.bbox().y : this.move(this.bbox().x, _y);
-      } // Set element size to given width and height
+      while (typeof val.attrHook == 'function') {
+        val = val.attrHook(this, attr);
+      } // ensure correct numeric values (also accepts NaN and Infinity)
 
-    }, {
-      key: "size",
-      value: function size(width, height) {
-        var p = proportionalSize$1(this, width, height);
-        return this.attr('d', this.array().size(p.width, p.height));
-      } // Set width of element
 
-    }, {
-      key: "width",
-      value: function width(_width) {
-        return _width == null ? this.bbox().width : this.size(_width, this.bbox().height);
-      } // Set height of element
+      if (typeof val === 'number') {
+        val = new SVGNumber(val);
+      } else if (Color.isColor(val)) {
+        // ensure full hex color
+        val = new Color(val);
+      } else if (Array.isArray(val)) {
+        // parse array values
+        val = new SVGArray(val);
+      } // if the passed attribute is leading...
 
-    }, {
-      key: "height",
-      value: function height(_height) {
-        return _height == null ? this.bbox().height : this.size(this.bbox().width, _height);
-      }
-    }]);
 
-    return Path;
-  }(Base$1); // Define morphable array
-  Path.prototype.MorphArray = PathArray; // Add parent method
+      if (attr === 'leading') {
+        // ... call the leading method instead
+        if (this.leading) {
+          this.leading(val);
+        }
+      } else {
+        // set given attribute on node
+        typeof ns === 'string' ? this.node.setAttributeNS(ns, attr, val.toString()) : this.node.setAttribute(attr, val.toString());
+      } // rebuild if required
 
-  Path.constructors = {
-    Container: {
-      // Create a wrapped path element
-      path: function path(d) {
-        // make sure plot is called as a setter
-        return this.put(new Path()).plot(d || new PathArray());
+
+      if (this.rebuild && (attr === 'font-size' || attr === 'x')) {
+        this.rebuild();
       }
     }
-  };
-
-  var MorphArray = PointArray$1; // Move by left top corner over x-axis
-
-  function x$1(x) {
-    return x == null ? this.bbox().x : this.move(x, this.bbox().y);
-  } // Move by left top corner over y-axis
-
-  function y$1(y) {
-    return y == null ? this.bbox().y : this.move(this.bbox().x, y);
-  } // Set width of element
-
-  function width$1(width) {
-    var b = this.bbox();
-    return width == null ? b.width : this.size(width, b.height);
-  } // Set height of element
 
-  function height$1(height) {
-    var b = this.bbox();
-    return height == null ? b.height : this.size(b.width, height);
+    return this;
   }
-
-  var pointed = /*#__PURE__*/Object.freeze({
-    MorphArray: MorphArray,
-    x: x$1,
-    y: y$1,
-    width: width$1,
-    height: height$1
+  registerMethods('Element', {
+    attr: attr
   });
 
-  // Add polygon-specific functions
-  // Get array
-  function array() {
-    return this._array || (this._array = new PointArray(this.attr('points')));
-  } // Plot new path
+  var Gradient =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Gradient, _Base);
 
-  function plot(p) {
-    return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new PointArray(p));
-  } // Clear array cache
+    function Gradient(type) {
+      _classCallCheck(this, Gradient);
 
-  function clear() {
-    delete this._array;
-    return this;
-  } // Move by left top corner
+      return _possibleConstructorReturn(this, _getPrototypeOf(Gradient).call(this, nodeOrNew$1(type + 'Gradient', typeof type === 'string' ? null : type), Gradient));
+    } // Add a color stop
 
-  function move(x, y) {
-    return this.attr('points', this.array().move(x, y));
-  } // Set element size to given width and height
 
-  function size$1(width, height) {
-    var p = proportionalSize(this, width, height);
-    return this.attr('points', this.array().size(p.width, p.height));
-  }
+    _createClass(Gradient, [{
+      key: "stop",
+      value: function stop(offset, color, opacity) {
+        return this.put(new Stop()).update(offset, color, opacity);
+      } // Update gradient
 
-  var poly = /*#__PURE__*/Object.freeze({
-    array: array,
-    plot: plot,
-    clear: clear,
-    move: move,
-    size: size$1
-  });
+    }, {
+      key: "update",
+      value: function update(block) {
+        // remove all stops
+        this.clear(); // invoke passed block
 
-  var Polygon =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Polygon, _Base);
+        if (typeof block === 'function') {
+          block.call(this, this);
+        }
 
-    // Initialize node
-    function Polygon(node) {
-      _classCallCheck(this, Polygon);
+        return this;
+      } // Return the fill id
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Polygon).call(this, nodeOrNew$1('polygon', node), Polygon));
-    }
+    }, {
+      key: "url",
+      value: function url() {
+        return 'url(#' + this.id() + ')';
+      } // Alias string convertion to fill
 
-    return Polygon;
+    }, {
+      key: "toString",
+      value: function toString() {
+        return this.url();
+      } // custom attr to handle transform
+
+    }, {
+      key: "attr",
+      value: function attr$$1(a, b, c) {
+        if (a === 'transform') a = 'gradientTransform';
+        return attr.call(this, a, b, c);
+      }
+    }, {
+      key: "targets",
+      value: function targets() {
+        return find('svg [fill*="' + this.id() + '"]');
+      }
+    }]);
+
+    return Gradient;
   }(Base$1);
-  Polygon.constructors = {
-    Parent: {
-      // Create a wrapped polygon element
-      polygon: function polygon(p) {
-        // make sure plot is called as a setter
-        return this.put(new Polygon()).plot(p || new PointArray$1());
+  extend$1(Gradient, gradiented);
+  registerMethods({
+    Container: {
+      // Create gradient element in defs
+      gradient: function gradient(type, block) {
+        return this.defs().gradient(type, block);
+      }
+    },
+    // define gradient
+    Defs: {
+      gradient: function gradient(type, block) {
+        return this.put(new Gradient(type)).update(block);
       }
     }
-  };
-  extend$1(Polygon, pointed);
-  extend$1(Polygon, poly);
+  });
+  register(Gradient);
 
-  var Polyline =
+  var Pattern =
   /*#__PURE__*/
   function (_Base) {
-    _inherits(Polyline, _Base);
+    _inherits(Pattern, _Base);
 
     // Initialize node
-    function Polyline(node) {
-      _classCallCheck(this, Polyline);
+    function Pattern(node) {
+      _classCallCheck(this, Pattern);
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Polyline).call(this, nodeOrNew$1('polyline', node), Polyline));
-    }
+      return _possibleConstructorReturn(this, _getPrototypeOf(Pattern).call(this, nodeOrNew$1('pattern', node)));
+    } // Return the fill id
 
-    return Polyline;
-  }(Base$1);
-  Polyline.constructors = {
-    Parent: {
-      // Create a wrapped polygon element
-      polyline: function polyline(p) {
-        // make sure plot is called as a setter
-        return this.put(new Polyline()).plot(p || new PointArray$1());
-      }
-    }
-  };
-  extend$1(Polyline, pointed);
-  extend$1(Polyline, poly);
 
-  var Rect =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Rect, _Base);
-
-    // Initialize node
-    function Rect(node) {
-      _classCallCheck(this, Rect);
+    _createClass(Pattern, [{
+      key: "url",
+      value: function url() {
+        return 'url(#' + this.id() + ')';
+      } // Update pattern by rebuilding
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Rect).call(this, nodeOrNew$1('rect', node), Rect));
-    }
+    }, {
+      key: "update",
+      value: function update(block) {
+        // remove content
+        this.clear(); // invoke passed block
 
-    return Rect;
-  }(Base$1);
-  Rect.constructors = {
-    Container: {
-      // Create a rect element
-      rect: function rect(width, height) {
-        return this.put(new Rect()).size(width, height);
-      }
-    }
-  };
+        if (typeof block === 'function') {
+          block.call(this, this);
+        }
 
-  var _Symbol =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(_Symbol, _Base);
+        return this;
+      } // Alias string convertion to fill
 
-    // Initialize node
-    function _Symbol(node) {
-      _classCallCheck(this, _Symbol);
+    }, {
+      key: "toString",
+      value: function toString() {
+        return this.url();
+      } // custom attr to handle transform
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(_Symbol).call(this, nodeOrNew$1('symbol', node), _Symbol));
-    }
+    }, {
+      key: "attr",
+      value: function attr$$1(a, b, c) {
+        if (a === 'transform') a = 'patternTransform';
+        return attr.call(this, a, b, c);
+      }
+    }, {
+      key: "targets",
+      value: function targets() {
+        return find('svg [fill*="' + this.id() + '"]');
+      }
+    }]);
 
-    return _Symbol;
+    return Pattern;
   }(Base$1);
-  _Symbol.constructors = {
+  registerMethods({
     Container: {
-      symbol: function symbol() {
-        return this.put(new _Symbol());
+      // Create pattern element in defs
+      pattern: function pattern(width, height, block) {
+        return this.defs().pattern(width, height, block);
+      }
+    },
+    Defs: {
+      pattern: function pattern(width, height, block) {
+        return this.put(new Pattern()).update(block).attr({
+          x: 0,
+          y: 0,
+          width: width,
+          height: height,
+          patternUnits: 'userSpaceOnUse'
+        });
       }
     }
-  };
-
-  function noop() {} // Default animation values
+  });
+  register(Pattern);
 
-  var timeline = {
-    duration: 400,
-    ease: '>',
-    delay: 0 // Default attribute values
+  // ;[ 'click',
+  //   'dblclick',
+  //   'mousedown',
+  //   'mouseup',
+  //   'mouseover',
+  //   'mouseout',
+  //   'mousemove',
+  //   'mouseenter',
+  //   'mouseleave',
+  //   'touchstart',
+  //   'touchmove',
+  //   'touchleave',
+  //   'touchend',
+  //   'touchcancel' ].forEach(function (event) {
+  //     // add event to Element
+  //     Element.prototype[event] = function (f) {
+  //       if (f === null) {
+  //         off(this, event)
+  //       } else {
+  //         on(this, event, f)
+  //       }
+  //       return this
+  //     }
+  //   })
 
-  };
-  var attrs = {
-    // fill and stroke
-    'fill-opacity': 1,
-    'stroke-opacity': 1,
-    'stroke-width': 0,
-    'stroke-linejoin': 'miter',
-    'stroke-linecap': 'butt',
-    fill: '#000000',
-    stroke: '#000000',
-    opacity: 1,
-    // position
-    x: 0,
-    y: 0,
-    cx: 0,
-    cy: 0,
-    // size
-    width: 0,
-    height: 0,
-    // radius
-    r: 0,
-    rx: 0,
-    ry: 0,
-    // gradient
-    offset: 0,
-    'stop-opacity': 1,
-    'stop-color': '#000000',
-    // text
-    'font-size': 16,
-    'font-family': 'Helvetica, Arial, sans-serif',
-    'text-anchor': 'start'
-  };
+  var listenerId = 0;
 
-  // Create plain text node
-  function plain(text) {
-    // clear if build mode is disabled
-    if (this._build === false) {
-      this.clear();
-    } // create text node
+  function getEventTarget$1(node) {
+    return node instanceof Base && node.is('EventTarget') ? node.getEventTarget() : node;
+  } // Add event binder in the SVG namespace
 
 
-    this.node.appendChild(document.createTextNode(text));
-    return this;
-  } // FIXME: Does this also work for textpath?
-  // Get length of text element
+  function on(node, events, listener, binding, options) {
+    var l = listener.bind(binding || node);
+    var n = getEventTarget$1(node); // events can be an array of events or a string of events
 
-  function length() {
-    return this.node.getComputedTextLength();
-  }
+    events = Array.isArray(events) ? events : events.split(delimiter); // ensure instance object for nodes which are not adopted
 
-  var textable = /*#__PURE__*/Object.freeze({
-    plain: plain,
-    length: length
-  });
+    n.instance = n.instance || {
+      events: {} // pull event handlers from the element
 
-  var Text$1 =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Text, _Base);
+    };
+    var bag = n.instance.events; // add id to listener
 
-    // Initialize node
-    function Text(node) {
-      var _this;
+    if (!listener._svgjsListenerId) {
+      listener._svgjsListenerId = ++listenerId;
+    }
 
-      _classCallCheck(this, Text);
+    events.forEach(function (event) {
+      var ev = event.split('.')[0];
+      var ns = event.split('.')[1] || '*'; // ensure valid object
 
-      _this = _possibleConstructorReturn(this, _getPrototypeOf(Text).call(this, nodeOrNew$1('text', node), Text));
-      _this.dom.leading = new SVGNumber(1.3); // store leading value for rebuilding
+      bag[ev] = bag[ev] || {};
+      bag[ev][ns] = bag[ev][ns] || {}; // reference listener
 
-      _this._rebuild = true; // enable automatic updating of dy values
+      bag[ev][ns][listener._svgjsListenerId] = l; // add listener
 
-      _this._build = false; // disable build mode for adding multiple lines
-      // set default font
+      n.addEventListener(ev, l, options || false);
+    });
+  } // Add event unbinder in the SVG namespace
 
-      _this.attr('font-family', attrs['font-family']);
+  function off(node, events, listener, options) {
+    var n = getEventTarget$1(node); // we cannot remove an event if its not an svg.js instance
 
-      return _this;
-    } // Move over x-axis
+    if (!n.instance) return; // listener can be a function or a number
 
+    if (typeof listener === 'function') {
+      listener = listener._svgjsListenerId;
+      if (!listener) return;
+    } // pull event handlers from the element
 
-    _createClass(Text, [{
-      key: "x",
-      value: function x(_x) {
-        // act as getter
-        if (_x == null) {
-          return this.attr('x');
-        }
 
-        return this.attr('x', _x);
-      } // Move over y-axis
+    var bag = n.instance.events; // events can be an array of events or a string or undefined
 
-    }, {
-      key: "y",
-      value: function y(_y) {
-        var oy = this.attr('y');
-        var o = typeof oy === 'number' ? oy - this.bbox().y : 0; // act as getter
+    events = Array.isArray(events) ? events : (events || '').split(delimiter);
+    events.forEach(function (event) {
+      var ev = event && event.split('.')[0];
+      var ns = event && event.split('.')[1];
+      var namespace, l;
 
-        if (_y == null) {
-          return typeof oy === 'number' ? oy - o : oy;
+      if (listener) {
+        // remove listener reference
+        if (bag[ev] && bag[ev][ns || '*']) {
+          // removeListener
+          n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false);
+          delete bag[ev][ns || '*'][listener];
         }
+      } else if (ev && ns) {
+        // remove all listeners for a namespaced event
+        if (bag[ev] && bag[ev][ns]) {
+          for (l in bag[ev][ns]) {
+            off(n, [ev, ns].join('.'), l);
+          }
 
-        return this.attr('y', typeof _y === 'number' ? _y + o : _y);
-      } // Move center over x-axis
+          delete bag[ev][ns];
+        }
+      } else if (ns) {
+        // remove all listeners for a specific namespace
+        for (event in bag) {
+          for (namespace in bag[event]) {
+            if (ns === namespace) {
+              off(n, [event, ns].join('.'));
+            }
+          }
+        }
+      } else if (ev) {
+        // remove all listeners for the event
+        if (bag[ev]) {
+          for (namespace in bag[ev]) {
+            off(n, [ev, namespace].join('.'));
+          }
 
-    }, {
-      key: "cx",
-      value: function cx(x) {
-        return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2);
-      } // Move center over y-axis
-
-    }, {
-      key: "cy",
-      value: function cy(y) {
-        return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2);
-      } // Set the text content
-
-    }, {
-      key: "text",
-      value: function text(_text) {
-        // act as getter
-        if (_text === undefined) {
-          var children = this.node.childNodes;
-          var firstLine = 0;
-          _text = '';
-
-          for (var i = 0, len = children.length; i < len; ++i) {
-            // skip textPaths - they are no lines
-            if (children[i].nodeName === 'textPath') {
-              if (i === 0) firstLine = 1;
-              continue;
-            } // add newline if its not the first child and newLined is set to true
+          delete bag[ev];
+        }
+      } else {
+        // remove all listeners on a given node
+        for (event in bag) {
+          off(n, event);
+        }
 
+        n.instance.events = {};
+      }
+    });
+  }
+  function dispatch(node, event, data) {
+    var n = getEventTarget$1(node); // Dispatch event
 
-            if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) {
-              _text += '\n';
-            } // add content of this node
+    if (event instanceof window.Event) {
+      n.dispatchEvent(event);
+    } else {
+      event = new window.CustomEvent(event, {
+        detail: data,
+        cancelable: true
+      });
+      n.dispatchEvent(event);
+    }
 
+    return event;
+  }
 
-            _text += children[i].textContent;
-          }
+  var Image =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Image, _Base);
 
-          return _text;
-        } // remove existing content
+    function Image(node) {
+      _classCallCheck(this, Image);
 
+      return _possibleConstructorReturn(this, _getPrototypeOf(Image).call(this, nodeOrNew$1('image', node), Image));
+    } // (re)load image
 
-        this.clear().build(true);
 
-        if (typeof _text === 'function') {
-          // call block
-          _text.call(this, this);
-        } else {
-          // store text and make sure text is not blank
-          _text = _text.split('\n'); // build new lines
+    _createClass(Image, [{
+      key: "load",
+      value: function load(url, callback) {
+        if (!url) return this;
+        var img = new window.Image();
+        on(img, 'load', function (e) {
+          var p = this.parent(Pattern); // ensure image size
 
-          for (var j = 0, jl = _text.length; j < jl; j++) {
-            this.tspan(_text[j]).newLine();
+          if (this.width() === 0 && this.height() === 0) {
+            this.size(img.width, img.height);
           }
-        } // disable build mode and rebuild lines
-
-
-        return this.build(false).rebuild();
-      } // Set / get leading
-
-    }, {
-      key: "leading",
-      value: function leading(value) {
-        // act as getter
-        if (value == null) {
-          return this.dom.leading;
-        } // act as setter
-
-
-        this.dom.leading = new SVGNumber(value);
-        return this.rebuild();
-      } // Rebuild appearance type
-
-    }, {
-      key: "rebuild",
-      value: function rebuild(_rebuild) {
-        // store new rebuild flag if given
-        if (typeof _rebuild === 'boolean') {
-          this._rebuild = _rebuild;
-        } // define position of all lines
-
-
-        if (this._rebuild) {
-          var self = this;
-          var blankLineOffset = 0;
-          var dy = this.dom.leading * new SVGNumber(this.attr('font-size'));
-          this.each(function () {
-            if (this.dom.newLined) {
-              this.attr('x', self.attr('x'));
 
-              if (this.text() === '\n') {
-                blankLineOffset += dy;
-              } else {
-                this.attr('dy', dy + blankLineOffset);
-                blankLineOffset = 0;
-              }
+          if (p instanceof Pattern) {
+            // ensure pattern size if not set
+            if (p.width() === 0 && p.height() === 0) {
+              p.size(this.width(), this.height());
             }
-          });
-          this.fire('rebuild');
-        }
-
-        return this;
-      } // Enable / disable build mode
+          }
 
+          if (typeof callback === 'function') {
+            callback.call(this, {
+              width: img.width,
+              height: img.height,
+              ratio: img.width / img.height,
+              url: url
+            });
+          }
+        }, this);
+        on(img, 'load error', function () {
+          // dont forget to unbind memory leaking events
+          off(img);
+        });
+        return this.attr('href', img.src = url, xlink);
+      }
     }, {
-      key: "build",
-      value: function build(_build) {
-        this._build = !!_build;
-        return this;
-      } // overwrite method from parent to set data properly
+      key: "attrHook",
+      value: function attrHook(obj) {
+        var _this = this;
 
-    }, {
-      key: "setData",
-      value: function setData(o) {
-        this.dom = o;
-        this.dom.leading = new SVGNumber(o.leading || 1.3);
-        return this;
+        return obj.doc().defs().pattern(0, 0, function (pattern) {
+          pattern.add(_this);
+        });
       }
     }]);
 
-    return Text;
+    return Image;
   }(Base$1);
-  extend$1(Text$1, textable);
-  Text$1.constructors = {
+  registerMethods({
     Container: {
-      // Create text element
-      text: function text(_text2) {
-        return this.put(new Text$1()).text(_text2);
-      },
-      // Create plain text element
-      plain: function plain$$1(text) {
-        return this.put(new Text$1()).plain(text);
+      // create image element, load image and set its size
+      image: function image(source, callback) {
+        return this.put(new Image()).size(0, 0).load(source, callback);
       }
     }
-  };
+  });
+  register(Image);
 
-  var TextPath =
+  var PointArray$1 =
   /*#__PURE__*/
-  function (_Text) {
-    _inherits(TextPath, _Text);
-
-    // Initialize node
-    function TextPath(node) {
-      _classCallCheck(this, TextPath);
+  function (_SVGArray) {
+    _inherits(PointArray, _SVGArray);
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(TextPath).call(this, nodeOrNew$1('textPath', node)));
-    } // return the array of the path track element
+    function PointArray(array) {
+      var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [[0, 0]];
 
+      _classCallCheck(this, PointArray);
 
-    _createClass(TextPath, [{
-      key: "array",
-      value: function array() {
-        var track = this.track();
-        return track ? track.array() : null;
-      } // Plot path if any
+      return _possibleConstructorReturn(this, _getPrototypeOf(PointArray).call(this, array, fallback));
+    } // Convert array to string
 
-    }, {
-      key: "plot",
-      value: function plot(d) {
-        var track = this.track();
-        var pathArray = null;
 
-        if (track) {
-          pathArray = track.plot(d);
+    _createClass(PointArray, [{
+      key: "toString",
+      value: function toString() {
+        // convert to a poly point string
+        for (var i = 0, il = this.value.length, array = []; i < il; i++) {
+          array.push(this.value[i].join(','));
         }
 
-        return d == null ? pathArray : this;
-      } // Get the path element
-
-    }, {
-      key: "track",
-      value: function track() {
-        return this.reference('href');
+        return array.join(' ');
       }
-    }]);
+    }, {
+      key: "toArray",
+      value: function toArray() {
+        return this.value.reduce(function (prev, curr) {
+          return [].concat.call(prev, curr);
+        }, []);
+      } // Convert array to line object
 
-    return TextPath;
-  }(Text$1);
-  TextPath.constructors = {
-    Container: {
-      textPath: function textPath(text, path) {
-        return this.defs().path(path).text(text).addTo(this);
-      }
-    },
-    Text: {
-      // Create path for text to run on
-      path: function path(track) {
-        var path = new TextPath(); // if d is a path, reuse it
+    }, {
+      key: "toLine",
+      value: function toLine() {
+        return {
+          x1: this.value[0][0],
+          y1: this.value[0][1],
+          x2: this.value[1][0],
+          y2: this.value[1][1]
+        };
+      } // Get morphed array at given position
 
-        if (!(track instanceof Path)) {
-          // create path element
-          track = this.doc().defs().path(track);
-        } // link textPath to path and add content
+    }, {
+      key: "at",
+      value: function at(pos) {
+        // make sure a destination is defined
+        if (!this.destination) return this; // generate morphed point string
 
+        for (var i = 0, il = this.value.length, array = []; i < il; i++) {
+          array.push([this.value[i][0] + (this.destination[i][0] - this.value[i][0]) * pos, this.value[i][1] + (this.destination[i][1] - this.value[i][1]) * pos]);
+        }
 
-        path.attr('href', '#' + track, xlink); // add textPath element as child node and return textPath
+        return new PointArray(array);
+      } // Parse point string and flat array
 
-        return this.put(path);
-      },
-      // FIXME: make this plural?
-      // Get the textPath children
-      textPath: function textPath() {
-        return this.select('textPath');
-      }
-    },
-    Path: {
-      // creates a textPath from this path
-      text: function text(_text) {
-        if (_text instanceof Text$1) {
-          var txt = _text.text();
-
-          return _text.clear().path(this).text(txt);
-        }
-
-        return this.parent().put(new Text$1()).path(this).text(_text);
-      } // FIXME: Maybe add `targets` to get all textPaths associated with this path
-
-    }
-  };
-  TextPath.prototype.MorphArray = PathArray;
+    }, {
+      key: "parse",
+      value: function parse(array) {
+        var points = [];
+        array = array.valueOf(); // if it is an array
 
-  var Use =
-  /*#__PURE__*/
-  function (_Base) {
-    _inherits(Use, _Base);
+        if (Array.isArray(array)) {
+          // and it is not flat, there is no need to parse it
+          if (Array.isArray(array[0])) {
+            return array;
+          }
+        } else {
+          // Else, it is considered as a string
+          // parse points
+          array = array.trim().split(delimiter).map(parseFloat);
+        } // validate points - https://svgwg.org/svg2-draft/shapes.html#DataTypePoints
+        // Odd number of coordinates is an error. In such cases, drop the last odd coordinate.
 
-    function Use(node) {
-      _classCallCheck(this, Use);
 
-      return _possibleConstructorReturn(this, _getPrototypeOf(Use).call(this, nodeOrNew('use', node), Use));
-    } // Use element as a reference
+        if (array.length % 2 !== 0) array.pop(); // wrap points in two-tuples and parse points as floats
 
+        for (var i = 0, len = array.length; i < len; i = i + 2) {
+          points.push([array[i], array[i + 1]]);
+        }
 
-    _createClass(Use, [{
-      key: "element",
-      value: function element(_element, file) {
-        // Set lined element
-        return this.attr('href', (file || '') + '#' + _element, xlink);
-      }
-    }]);
+        return points;
+      } // Move point string
 
-    return Use;
-  }(Base$1);
-  Use.constructors = {
-    Container: {
-      // Create a use element
-      use: function use(element, file) {
-        return this.put(new Use()).element(element, file);
-      }
-    }
-  };
+    }, {
+      key: "move",
+      value: function move(x, y) {
+        var box = this.bbox(); // get relative offset
 
+        x -= box.x;
+        y -= box.y; // move every point
 
+        if (!isNaN(x) && !isNaN(y)) {
+          for (var i = this.value.length - 1; i >= 0; i--) {
+            this.value[i] = [this.value[i][0] + x, this.value[i][1] + y];
+          }
+        }
 
-  var elements = /*#__PURE__*/Object.freeze({
-    Bare: Bare,
-    Circle: Circle,
-    ClipPath: ClipPath,
-    Defs: Defs,
-    Doc: Doc$1,
-    Ellipse: Ellipse,
-    Gradient: Gradient,
-    G: G,
-    HtmlNode: HtmlNode,
-    A: A,
-    Image: Image,
-    Line: Line,
-    Marker: Marker,
-    Mask: Mask,
-    Path: Path,
-    Pattern: Pattern,
-    Polygon: Polygon,
-    Polyline: Polyline,
-    Rect: Rect,
-    Stop: Stop,
-    Symbol: _Symbol,
-    Text: Text$1,
-    TextPath: TextPath,
-    Use: Use
-  });
+        return this;
+      } // Resize poly string
 
-  function makeInstance(element) {
-    if (element instanceof Base$1) return element;
+    }, {
+      key: "size",
+      value: function size(width, height) {
+        var i;
+        var box = this.bbox(); // recalculate position of all points according to new size
 
-    if (_typeof(element) === 'object') {
-      return adopt$1(element);
-    }
+        for (i = this.value.length - 1; i >= 0; i--) {
+          if (box.width) this.value[i][0] = (this.value[i][0] - box.x) * width / box.width + box.x;
+          if (box.height) this.value[i][1] = (this.value[i][1] - box.y) * height / box.height + box.y;
+        }
 
-    if (element == null) {
-      return new Doc();
-    }
+        return this;
+      } // Get bounding box of points
 
-    if (typeof element === 'string' && element.charAt(0) !== '<') {
-      return adopt$1(document.querySelector(element));
-    }
+    }, {
+      key: "bbox",
+      value: function bbox() {
+        var maxX = -Infinity;
+        var maxY = -Infinity;
+        var minX = Infinity;
+        var minY = Infinity;
+        this.value.forEach(function (el) {
+          maxX = Math.max(el[0], maxX);
+          maxY = Math.max(el[1], maxY);
+          minX = Math.min(el[0], minX);
+          minY = Math.min(el[1], minY);
+        });
+        return {
+          x: minX,
+          y: minY,
+          width: maxX - minX,
+          height: maxY - minY
+        };
+      }
+    }]);
 
-    var node = makeNode('svg');
-    node.innerHTML = element;
-    element = adopt$1(node.firstElementChild);
-    return element;
-  } // Adopt existing svg elements
+    return PointArray;
+  }(SVGArray);
 
-  function adopt$1(node) {
-    // check for presence of node
-    if (!node) return null; // make sure a node isn't already adopted
+  var Line =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Line, _Base);
 
-    if (node.instance instanceof Element) return node.instance;
+    // Initialize node
+    function Line(node) {
+      _classCallCheck(this, Line);
 
-    if (!(node instanceof window.SVGElement)) {
-      return new HtmlNode(node);
-    } // initialize variables
+      return _possibleConstructorReturn(this, _getPrototypeOf(Line).call(this, nodeOrNew$1('line', node), Line));
+    } // Get array
 
 
-    var element; // adopt with element-specific settings
+    _createClass(Line, [{
+      key: "array",
+      value: function array() {
+        return new PointArray$1([[this.attr('x1'), this.attr('y1')], [this.attr('x2'), this.attr('y2')]]);
+      } // Overwrite native plot() method
 
-    if (node.nodeName === 'svg') {
-      element = new Doc$1(node);
-    } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {
-      element = new Gradient(node);
-    } else if (elements[capitalize(node.nodeName)]) {
-      element = new elements[capitalize(node.nodeName)](node);
-    } else {
-      element = new Bare(node);
-    }
+    }, {
+      key: "plot",
+      value: function plot(x1, y1, x2, y2) {
+        if (x1 == null) {
+          return this.array();
+        } else if (typeof y1 !== 'undefined') {
+          x1 = {
+            x1: x1,
+            y1: y1,
+            x2: x2,
+            y2: y2
+          };
+        } else {
+          x1 = new PointArray$1(x1).toLine();
+        }
 
-    return element;
-  } // Element id sequence
+        return this.attr(x1);
+      } // Move by left top corner
 
-  var did = 1000; // Get next named element id
+    }, {
+      key: "move",
+      value: function move(x, y) {
+        return this.attr(this.array().move(x, y).toLine());
+      } // Set element size to given width and height
 
-  function eid(name) {
-    return 'Svgjs' + capitalize(name) + did++;
-  } // Deep new id assignment
+    }, {
+      key: "size",
+      value: function size(width, height) {
+        var p = proportionalSize$1(this, width, height);
+        return this.attr(this.array().size(p.width, p.height).toLine());
+      }
+    }]);
 
-  function assignNewId(node) {
-    // do the same for SVG child nodes as well
-    for (var i = node.children.length - 1; i >= 0; i--) {
-      assignNewId(node.children[i]);
-    }
+    return Line;
+  }(Base$1);
+  registerMethods({
+    Container: {
+      // Create a line element
+      line: function line() {
+        for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+          args[_key] = arguments[_key];
+        }
 
-    if (node.id) {
-      return adopt$1(node).id(eid(node.nodeName));
+        // make sure plot is called as a setter
+        // x1 is not necessarily a number, it can also be an array, a string and a PointArray
+        return Line.prototype.plot.apply(this.put(new Line()), args[0] != null ? args : [0, 0, 0, 0]);
+      }
     }
-
-    return adopt$1(node);
-  }
-
-  var adopter = /*#__PURE__*/Object.freeze({
-    makeInstance: makeInstance,
-    adopt: adopt$1,
-    eid: eid,
-    assignNewId: assignNewId
   });
+  register(Line);
 
-  var Queue =
+  var Marker =
   /*#__PURE__*/
-  function () {
-    function Queue() {
-      _classCallCheck(this, Queue);
+  function (_Base) {
+    _inherits(Marker, _Base);
 
-      this._first = null;
-      this._last = null;
-    }
+    // Initialize node
+    function Marker(node) {
+      _classCallCheck(this, Marker);
 
-    _createClass(Queue, [{
-      key: "push",
-      value: function push(value) {
-        // An item stores an id and the provided value
-        var item = value.next ? value : {
-          value: value,
-          next: null,
-          prev: null // Deal with the queue being empty or populated
-
-        };
+      return _possibleConstructorReturn(this, _getPrototypeOf(Marker).call(this, nodeOrNew('marker', node), Marker));
+    } // Set width of element
 
-        if (this._last) {
-          item.prev = this._last;
-          this._last.next = item;
-          this._last = item;
-        } else {
-          this._last = item;
-          this._first = item;
-        } // Update the length and return the current item
 
+    _createClass(Marker, [{
+      key: "width",
+      value: function width(_width) {
+        return this.attr('markerWidth', _width);
+      } // Set height of element
 
-        return item;
-      }
     }, {
-      key: "shift",
-      value: function shift() {
-        // Check if we have a value
-        var remove = this._first;
-        if (!remove) return null; // If we do, remove it and relink things
-
-        this._first = remove.next;
-        if (this._first) this._first.prev = null;
-        this._last = this._first ? this._last : null;
-        return remove.value;
-      } // Shows us the first item in the list
+      key: "height",
+      value: function height(_height) {
+        return this.attr('markerHeight', _height);
+      } // Set marker refX and refY
 
     }, {
-      key: "first",
-      value: function first() {
-        return this._first && this._first.value;
-      } // Shows us the last item in the list
+      key: "ref",
+      value: function ref(x, y) {
+        return this.attr('refX', x).attr('refY', y);
+      } // Update marker
 
     }, {
-      key: "last",
-      value: function last() {
-        return this._last && this._last.value;
-      } // Removes the item that was returned from the push
+      key: "update",
+      value: function update(block) {
+        // remove all content
+        this.clear(); // invoke passed block
 
-    }, {
-      key: "remove",
-      value: function remove(item) {
-        // Relink the previous item
-        if (item.prev) item.prev.next = item.next;
-        if (item.next) item.next.prev = item.prev;
-        if (item === this._last) this._last = item.prev;
-        if (item === this._first) this._first = item.next; // Invalidate item
+        if (typeof block === 'function') {
+          block.call(this, this);
+        }
 
-        item.prev = null;
-        item.next = null;
+        return this;
+      } // Return the fill id
+
+    }, {
+      key: "toString",
+      value: function toString() {
+        return 'url(#' + this.id() + ')';
       }
     }]);
 
-    return Queue;
-  }();
-
-  var Animator = {
-    nextDraw: null,
-    frames: new Queue(),
-    timeouts: new Queue(),
-    timer: window.performance || window.Date,
-    transforms: [],
-    frame: function frame(fn) {
-      // Store the node
-      var node = Animator.frames.push({
-        run: fn
-      }); // Request an animation frame if we don't have one
-
-      if (Animator.nextDraw === null) {
-        Animator.nextDraw = window.requestAnimationFrame(Animator._draw);
-      } // Return the node so we can remove it easily
-
-
-      return node;
-    },
-    transform_frame: function transform_frame(fn, id) {
-      Animator.transforms[id] = fn;
-    },
-    timeout: function timeout(fn, delay) {
-      delay = delay || 0; // Work out when the event should fire
-
-      var time = Animator.timer.now() + delay; // Add the timeout to the end of the queue
-
-      var node = Animator.timeouts.push({
-        run: fn,
-        time: time
-      }); // Request another animation frame if we need one
-
-      if (Animator.nextDraw === null) {
-        Animator.nextDraw = window.requestAnimationFrame(Animator._draw);
+    return Marker;
+  }(Base$1);
+  registerMethods({
+    Container: {
+      marker: function marker(width, height, block) {
+        // Create marker element in defs
+        return this.defs().marker(width, height, block);
       }
-
-      return node;
-    },
-    cancelFrame: function cancelFrame(node) {
-      Animator.frames.remove(node);
     },
-    clearTimeout: function clearTimeout(node) {
-      Animator.timeouts.remove(node);
+    Defs: {
+      // Create marker
+      marker: function marker(width, height, block) {
+        // Set default viewbox to match the width and height, set ref to cx and cy and set orient to auto
+        return this.put(new Marker()).size(width, height).ref(width / 2, height / 2).viewbox(0, 0, width, height).attr('orient', 'auto').update(block);
+      }
     },
-    _draw: function _draw(now) {
-      // Run all the timeouts we can run, if they are not ready yet, add them
-      // to the end of the queue immediately! (bad timeouts!!! [sarcasm])
-      var nextTimeout = null;
-      var lastTimeout = Animator.timeouts.last();
-
-      while (nextTimeout = Animator.timeouts.shift()) {
-        // Run the timeout if its time, or push it to the end
-        if (now >= nextTimeout.time) {
-          nextTimeout.run();
-        } else {
-          Animator.timeouts.push(nextTimeout);
-        } // If we hit the last item, we should stop shifting out more items
-
-
-        if (nextTimeout === lastTimeout) break;
-      } // Run all of the animation frames
-
+    marker: {
+      // Create and attach markers
+      marker: function marker(_marker, width, height, block) {
+        var attr = ['marker']; // Build attribute name
 
-      var nextFrame = null;
-      var lastFrame = Animator.frames.last();
+        if (_marker !== 'all') attr.push(_marker);
+        attr = attr.join('-'); // Set marker attribute
 
-      while (nextFrame !== lastFrame && (nextFrame = Animator.frames.shift())) {
-        nextFrame.run();
+        _marker = arguments[1] instanceof Marker ? arguments[1] : this.defs().marker(width, height, block);
+        return this.attr(attr, _marker);
       }
-
-      Animator.transforms.forEach(function (el) {
-        el();
-      }); // If we have remaining timeouts or frames, draw until we don't anymore
-
-      Animator.nextDraw = Animator.timeouts.first() || Animator.frames.first() ? window.requestAnimationFrame(Animator._draw) : null;
     }
-  };
+  });
+  register(Marker);
 
-  var Tspan =
+  var Mask =
   /*#__PURE__*/
   function (_Base) {
-    _inherits(Tspan, _Base);
+    _inherits(Mask, _Base);
 
     // Initialize node
-    function Tspan(node) {
-      _classCallCheck(this, Tspan);
-
-      return _possibleConstructorReturn(this, _getPrototypeOf(Tspan).call(this, nodeOrNew$1('tspan', node), Tspan));
-    } // Set text content
-
+    function Mask(node) {
+      _classCallCheck(this, Mask);
 
-    _createClass(Tspan, [{
-      key: "text",
-      value: function text(_text) {
-        if (_text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '');
-        typeof _text === 'function' ? _text.call(this, this) : this.plain(_text);
-        return this;
-      } // Shortcut dx
+      return _possibleConstructorReturn(this, _getPrototypeOf(Mask).call(this, nodeOrNew$1('mask', node)));
+    } // Unmask all masked elements and remove itself
 
-    }, {
-      key: "dx",
-      value: function dx(_dx) {
-        return this.attr('dx', _dx);
-      } // Shortcut dy
 
-    }, {
-      key: "dy",
-      value: function dy(_dy) {
-        return this.attr('dy', _dy);
-      } // Create new line
+    _createClass(Mask, [{
+      key: "remove",
+      value: function remove$$1() {
+        // unmask all targets
+        this.targets().forEach(function (el) {
+          el.unmask();
+        }); // remove mask from parent
 
+        return remove.call(this);
+      }
     }, {
-      key: "newLine",
-      value: function newLine() {
-        // fetch text parent
-        var t = this.parent(Text); // mark new line
-
-        this.dom.newLined = true; // apply new position
-
-        return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x());
+      key: "targets",
+      value: function targets() {
+        return baseFind('svg [mask*="' + this.id() + '"]');
       }
     }]);
 
-    return Tspan;
+    return Mask;
   }(Base$1);
-  extend$1(Tspan, textable);
-  Tspan.constructors = {
-    Tspan: {
-      tspan: function tspan(text) {
-        var tspan = new Tspan(); // clear if build mode is disabled
-
-        if (!this._build) {
-          this.clear();
-        } // add new tspan
-
-
-        this.node.appendChild(tspan.node);
-        return tspan.text(text);
+  registerMethods({
+    Container: {
+      mask: function mask() {
+        return this.defs().put(new Mask());
       }
-    }
-  };
-
-  // Map function
-  function map(array, block) {
-    var i;
-    var il = array.length;
-    var result = [];
+    },
+    Element: {
+      // Distribute mask to svg element
+      maskWith: function maskWith(element) {
+        // use given mask or create a new one
+        var masker = element instanceof Mask ? element : this.parent().mask().add(element); // apply mask
 
-    for (i = 0; i < il; i++) {
-      result.push(block(array[i]));
+        return this.attr('mask', 'url("#' + masker.id() + '")');
+      },
+      // Unmask element
+      unmask: function unmask() {
+        return this.attr('mask', null);
+      },
+      masker: function masker() {
+        return this.reference('mask');
+      }
     }
+  });
+  register(Mask);
 
-    return result;
-  } // Filter function
+  function parser() {
+    // Reuse cached element if possible
+    if (!parser.nodes) {
+      var svg = new Doc$1().size(2, 0).css({
+        opacity: 0,
+        position: 'absolute',
+        left: '-100%',
+        top: '-100%',
+        overflow: 'hidden'
+      });
+      var path = svg.path().node;
+      parser.nodes = {
+        svg: svg,
+        path: path
+      };
+    }
 
-  function radians(d) {
-    return d % 360 * Math.PI / 180;
-  } // Radians to degrees
+    if (!parser.nodes.svg.node.parentNode) {
+      var b = document.body || document.documentElement;
+      parser.nodes.svg.addTo(b);
+    }
 
-  var Matrix =
+    return parser.nodes;
+  }
+
+  var Point =
   /*#__PURE__*/
   function () {
-    function Matrix() {
-      _classCallCheck(this, Matrix);
-
-      this.init.apply(this, arguments);
-    } // Initialize
+    // Initialize
+    function Point(x, y, base) {
+      _classCallCheck(this, Point);
 
+      var source;
+      base = base || {
+        x: 0,
+        y: 0 // ensure source as object
 
-    _createClass(Matrix, [{
-      key: "init",
-      value: function init(source) {
-        var base = arrayToMatrix([1, 0, 0, 1, 0, 0]); // ensure source as object
+      };
+      source = Array.isArray(x) ? {
+        x: x[0],
+        y: x[1]
+      } : _typeof(x) === 'object' ? {
+        x: x.x,
+        y: x.y
+      } : {
+        x: x,
+        y: y // merge source
 
-        source = source instanceof Base$1 && source.is('Element') ? source.matrixify() : typeof source === 'string' ? arrayToMatrix(source.split(delimiter).map(parseFloat)) : Array.isArray(source) ? arrayToMatrix(source) : _typeof(source) === 'object' && isMatrixLike(source) ? source : _typeof(source) === 'object' ? new Matrix().transform(source) : arguments.length === 6 ? arrayToMatrix([].slice.call(arguments)) : base; // Merge the source matrix with the base matrix
+      };
+      this.x = source.x == null ? base.x : source.x;
+      this.y = source.y == null ? base.y : source.y;
+    } // Clone point
 
-        this.a = source.a != null ? source.a : base.a;
-        this.b = source.b != null ? source.b : base.b;
-        this.c = source.c != null ? source.c : base.c;
-        this.d = source.d != null ? source.d : base.d;
-        this.e = source.e != null ? source.e : base.e;
-        this.f = source.f != null ? source.f : base.f;
-      } // Clones this matrix
 
-    }, {
+    _createClass(Point, [{
       key: "clone",
       value: function clone() {
-        return new Matrix(this);
-      } // Transform a matrix into another matrix by manipulating the space
+        return new Point(this);
+      } // Convert to native SVGPoint
 
     }, {
-      key: "transform",
-      value: function transform(o) {
-        // Check if o is a matrix and then left multiply it directly
-        if (isMatrixLike(o)) {
-          var matrix = new Matrix(o);
-          return matrix.multiplyO(this);
-        } // Get the proposed transformations and the current transformations
-
-
-        var t = Matrix.formatTransforms(o);
-        var current = this;
+      key: "native",
+      value: function native() {
+        // create new point
+        var point = parser().svg.createSVGPoint(); // update with current values
 
-        var _transform = new Point(t.ox, t.oy).transform(current),
-            ox = _transform.x,
-            oy = _transform.y; // Construct the resulting matrix
+        point.x = this.x;
+        point.y = this.y;
+        return point;
+      } // transform point with matrix
 
+    }, {
+      key: "transform",
+      value: function transform(m) {
+        // Perform the matrix multiplication
+        var x = m.a * this.x + m.c * this.y + m.e;
+        var y = m.b * this.x + m.d * this.y + m.f; // Return the required point
 
-        var transformer = new Matrix().translateO(t.rx, t.ry).lmultiplyO(current).translateO(-ox, -oy).scaleO(t.scaleX, t.scaleY).skewO(t.skewX, t.skewY).shearO(t.shear).rotateO(t.theta).translateO(ox, oy); // If we want the origin at a particular place, we force it there
+        return new Point(x, y);
+      }
+    }]);
 
-        if (isFinite(t.px) || isFinite(t.py)) {
-          var origin = new Point(ox, oy).transform(transformer); // TODO: Replace t.px with isFinite(t.px)
+    return Point;
+  }();
+  registerMethods({
+    Element: {
+      // Get point
+      point: function point(x, y) {
+        return new Point(x, y).transform(this.screenCTM().inverse());
+      }
+    }
+  });
 
-          var dx = t.px ? t.px - origin.x : 0;
-          var dy = t.py ? t.py - origin.y : 0;
-          transformer.translateO(dx, dy);
-        } // Translate now after positioning
+  var pathHandlers = {
+    M: function M(c, p, p0) {
+      p.x = p0.x = c[0];
+      p.y = p0.y = c[1];
+      return ['M', p.x, p.y];
+    },
+    L: function L(c, p) {
+      p.x = c[0];
+      p.y = c[1];
+      return ['L', c[0], c[1]];
+    },
+    H: function H(c, p) {
+      p.x = c[0];
+      return ['H', c[0]];
+    },
+    V: function V(c, p) {
+      p.y = c[0];
+      return ['V', c[0]];
+    },
+    C: function C(c, p) {
+      p.x = c[4];
+      p.y = c[5];
+      return ['C', c[0], c[1], c[2], c[3], c[4], c[5]];
+    },
+    S: function S(c, p) {
+      p.x = c[2];
+      p.y = c[3];
+      return ['S', c[0], c[1], c[2], c[3]];
+    },
+    Q: function Q(c, p) {
+      p.x = c[2];
+      p.y = c[3];
+      return ['Q', c[0], c[1], c[2], c[3]];
+    },
+    T: function T(c, p) {
+      p.x = c[0];
+      p.y = c[1];
+      return ['T', c[0], c[1]];
+    },
+    Z: function Z(c, p, p0) {
+      p.x = p0.x;
+      p.y = p0.y;
+      return ['Z'];
+    },
+    A: function A(c, p) {
+      p.x = c[5];
+      p.y = c[6];
+      return ['A', c[0], c[1], c[2], c[3], c[4], c[5], c[6]];
+    }
+  };
+  var mlhvqtcsaz = 'mlhvqtcsaz'.split('');
 
+  for (var i = 0, il = mlhvqtcsaz.length; i < il; ++i) {
+    pathHandlers[mlhvqtcsaz[i]] = function (i) {
+      return function (c, p, p0) {
+        if (i === 'H') c[0] = c[0] + p.x;else if (i === 'V') c[0] = c[0] + p.y;else if (i === 'A') {
+          c[5] = c[5] + p.x;
+          c[6] = c[6] + p.y;
+        } else {
+          for (var j = 0, jl = c.length; j < jl; ++j) {
+            c[j] = c[j] + (j % 2 ? p.y : p.x);
+          }
+        }
+        return pathHandlers[i](c, p, p0);
+      };
+    }(mlhvqtcsaz[i].toUpperCase());
+  }
 
-        transformer.translateO(t.tx, t.ty);
-        return transformer;
-      } // Applies a matrix defined by its affine parameters
+  var PathArray =
+  /*#__PURE__*/
+  function (_SVGArray) {
+    _inherits(PathArray, _SVGArray);
 
-    }, {
-      key: "compose",
-      value: function compose(o) {
-        if (o.origin) {
-          o.originX = o.origin[0];
-          o.originY = o.origin[1];
-        } // Get the parameters
+    function PathArray(array) {
+      var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [['M', 0, 0]];
 
+      _classCallCheck(this, PathArray);
 
-        var ox = o.originX || 0;
-        var oy = o.originY || 0;
-        var sx = o.scaleX || 1;
-        var sy = o.scaleY || 1;
-        var lam = o.shear || 0;
-        var theta = o.rotate || 0;
-        var tx = o.translateX || 0;
-        var ty = o.translateY || 0; // Apply the standard matrix
+      return _possibleConstructorReturn(this, _getPrototypeOf(PathArray).call(this, array, fallback));
+    } // Convert array to string
 
-        var result = new Matrix().translateO(-ox, -oy).scaleO(sx, sy).shearO(lam).rotateO(theta).translateO(tx, ty).lmultiplyO(this).translateO(ox, oy);
-        return result;
-      } // Decomposes this matrix into its affine parameters
 
+    _createClass(PathArray, [{
+      key: "toString",
+      value: function toString() {
+        return arrayToString(this);
+      }
     }, {
-      key: "decompose",
-      value: function decompose() {
-        var cx = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
-        var cy = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
-        // Get the parameters from the matrix
-        var a = this.a;
-        var b = this.b;
-        var c = this.c;
-        var d = this.d;
-        var e = this.e;
-        var f = this.f; // Figure out if the winding direction is clockwise or counterclockwise
+      key: "toArray",
+      value: function toArray() {
+        return this.reduce(function (prev, curr) {
+          return [].concat.call(prev, curr);
+        }, []);
+      } // Move path string
 
-        var determinant = a * d - b * c;
-        var ccw = determinant > 0 ? 1 : -1; // Since we only shear in x, we can use the x basis to get the x scale
-        // and the rotation of the resulting matrix
+    }, {
+      key: "move",
+      value: function move(x, y) {
+        // get bounding box of current situation
+        var box = this.bbox(); // get relative offset
 
-        var sx = ccw * Math.sqrt(a * a + b * b);
-        var thetaRad = Math.atan2(ccw * b, ccw * a);
-        var theta = 180 / Math.PI * thetaRad;
-        var ct = Math.cos(thetaRad);
-        var st = Math.sin(thetaRad); // We can then solve the y basis vector simultaneously to get the other
-        // two affine parameters directly from these parameters
+        x -= box.x;
+        y -= box.y;
 
-        var lam = (a * c + b * d) / determinant;
-        var sy = c * sx / (lam * a - b) || d * sx / (lam * b + a); // Use the translations
+        if (!isNaN(x) && !isNaN(y)) {
+          // move every point
+          for (var l, i = this.length - 1; i >= 0; i--) {
+            l = this[i][0];
 
-        var tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy);
-        var ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy); // Construct the decomposition and return it
+            if (l === 'M' || l === 'L' || l === 'T') {
+              this[i][1] += x;
+              this[i][2] += y;
+            } else if (l === 'H') {
+              this[i][1] += x;
+            } else if (l === 'V') {
+              this[i][1] += y;
+            } else if (l === 'C' || l === 'S' || l === 'Q') {
+              this[i][1] += x;
+              this[i][2] += y;
+              this[i][3] += x;
+              this[i][4] += y;
 
-        return {
-          // Return the affine parameters
-          scaleX: sx,
-          scaleY: sy,
-          shear: lam,
-          rotate: theta,
-          translateX: tx,
-          translateY: ty,
-          originX: cx,
-          originY: cy,
-          // Return the matrix parameters
-          a: this.a,
-          b: this.b,
-          c: this.c,
-          d: this.d,
-          e: this.e,
-          f: this.f
-        };
-      } // Left multiplies by the given matrix
+              if (l === 'C') {
+                this[i][5] += x;
+                this[i][6] += y;
+              }
+            } else if (l === 'A') {
+              this[i][6] += x;
+              this[i][7] += y;
+            }
+          }
+        }
 
-    }, {
-      key: "multiply",
-      value: function multiply(matrix) {
-        return this.clone().multiplyO(matrix);
-      }
-    }, {
-      key: "multiplyO",
-      value: function multiplyO(matrix) {
-        // Get the matrices
-        var l = this;
-        var r = matrix instanceof Matrix ? matrix : new Matrix(matrix);
-        return Matrix.matrixMultiply(l, r, this);
-      }
-    }, {
-      key: "lmultiply",
-      value: function lmultiply(matrix) {
-        return this.clone().lmultiplyO(matrix);
-      }
-    }, {
-      key: "lmultiplyO",
-      value: function lmultiplyO(matrix) {
-        var r = this;
-        var l = matrix instanceof Matrix ? matrix : new Matrix(matrix);
-        return Matrix.matrixMultiply(l, r, this);
-      } // Inverses matrix
+        return this;
+      } // Resize path string
 
     }, {
-      key: "inverseO",
-      value: function inverseO() {
-        // Get the current parameters out of the matrix
-        var a = this.a;
-        var b = this.b;
-        var c = this.c;
-        var d = this.d;
-        var e = this.e;
-        var f = this.f; // Invert the 2x2 matrix in the top left
+      key: "size",
+      value: function size(width, height) {
+        // get bounding box of current situation
+        var box = this.bbox();
+        var i, l; // recalculate position of all points according to new size
 
-        var det = a * d - b * c;
-        if (!det) throw new Error('Cannot invert ' + this); // Calculate the top 2x2 matrix
+        for (i = this.length - 1; i >= 0; i--) {
+          l = this[i][0];
 
-        var na = d / det;
-        var nb = -b / det;
-        var nc = -c / det;
-        var nd = a / det; // Apply the inverted matrix to the top right
+          if (l === 'M' || l === 'L' || l === 'T') {
+            this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
+            this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;
+          } else if (l === 'H') {
+            this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
+          } else if (l === 'V') {
+            this[i][1] = (this[i][1] - box.y) * height / box.height + box.y;
+          } else if (l === 'C' || l === 'S' || l === 'Q') {
+            this[i][1] = (this[i][1] - box.x) * width / box.width + box.x;
+            this[i][2] = (this[i][2] - box.y) * height / box.height + box.y;
+            this[i][3] = (this[i][3] - box.x) * width / box.width + box.x;
+            this[i][4] = (this[i][4] - box.y) * height / box.height + box.y;
 
-        var ne = -(na * e + nc * f);
-        var nf = -(nb * e + nd * f); // Construct the inverted matrix
+            if (l === 'C') {
+              this[i][5] = (this[i][5] - box.x) * width / box.width + box.x;
+              this[i][6] = (this[i][6] - box.y) * height / box.height + box.y;
+            }
+          } else if (l === 'A') {
+            // resize radii
+            this[i][1] = this[i][1] * width / box.width;
+            this[i][2] = this[i][2] * height / box.height; // move position values
 
-        this.a = na;
-        this.b = nb;
-        this.c = nc;
-        this.d = nd;
-        this.e = ne;
-        this.f = nf;
-        return this;
-      }
-    }, {
-      key: "inverse",
-      value: function inverse() {
-        return this.clone().inverseO();
-      } // Translate matrix
+            this[i][6] = (this[i][6] - box.x) * width / box.width + box.x;
+            this[i][7] = (this[i][7] - box.y) * height / box.height + box.y;
+          }
+        }
 
-    }, {
-      key: "translate",
-      value: function translate(x, y) {
-        return this.clone().translateO(x, y);
-      }
-    }, {
-      key: "translateO",
-      value: function translateO(x, y) {
-        this.e += x || 0;
-        this.f += y || 0;
         return this;
-      } // Scale matrix
-
-    }, {
-      key: "scale",
-      value: function scale(x, y, cx, cy) {
-        var _this$clone;
+      } // Test if the passed path array use the same path data commands as this path array
 
-        return (_this$clone = this.clone()).scaleO.apply(_this$clone, arguments);
-      }
     }, {
-      key: "scaleO",
-      value: function scaleO(x) {
-        var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
-        var cx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
-        var cy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
+      key: "equalCommands",
+      value: function equalCommands(pathArray) {
+        var i, il, equalCommands;
+        pathArray = new PathArray(pathArray);
+        equalCommands = this.length === pathArray.value.length;
 
-        // Support uniform scaling
-        if (arguments.length === 3) {
-          cy = cx;
-          cx = y;
-          y = x;
+        for (i = 0, il = this.length; equalCommands && i < il; i++) {
+          equalCommands = this[i][0] === pathArray.value[i][0];
         }
 
-        var a = this.a,
-            b = this.b,
-            c = this.c,
-            d = this.d,
-            e = this.e,
-            f = this.f;
-        this.a = a * x;
-        this.b = b * y;
-        this.c = c * x;
-        this.d = d * y;
-        this.e = e * x - cx * x + cx;
-        this.f = f * y - cy * y + cy;
-        return this;
-      } // Rotate matrix
+        return equalCommands;
+      } // Make path array morphable
 
     }, {
-      key: "rotate",
-      value: function rotate(r, cx, cy) {
-        return this.clone().rotateO(r, cx, cy);
-      }
-    }, {
-      key: "rotateO",
-      value: function rotateO(r) {
-        var cx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
-        var cy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
-        // Convert degrees to radians
-        r = radians(r);
-        var cos = Math.cos(r);
-        var sin = Math.sin(r);
-        var a = this.a,
-            b = this.b,
-            c = this.c,
-            d = this.d,
-            e = this.e,
-            f = this.f;
-        this.a = a * cos - b * sin;
-        this.b = b * cos + a * sin;
-        this.c = c * cos - d * sin;
-        this.d = d * cos + c * sin;
-        this.e = e * cos - f * sin + cy * sin - cx * cos + cx;
-        this.f = f * cos + e * sin - cx * sin - cy * cos + cy;
-        return this;
-      } // Flip matrix on x or y, at a given offset
+      key: "morph",
+      value: function morph(pathArray) {
+        pathArray = new PathArray(pathArray);
 
-    }, {
-      key: "flip",
-      value: function flip(axis, around) {
-        return this.clone().flipO(axis, around);
-      }
-    }, {
-      key: "flipO",
-      value: function flipO(axis, around) {
-        return axis === 'x' ? this.scaleO(-1, 1, around, 0) : axis === 'y' ? this.scaleO(1, -1, 0, around) : this.scaleO(-1, -1, axis, around || axis); // Define an x, y flip point
-      } // Shear matrix
+        if (this.equalCommands(pathArray)) {
+          this.destination = pathArray;
+        } else {
+          this.destination = null;
+        }
 
-    }, {
-      key: "shear",
-      value: function shear(a, cx, cy) {
-        return this.clone().shearO(a, cx, cy);
-      }
-    }, {
-      key: "shearO",
-      value: function shearO(lx) {
-        var cy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
-        var a = this.a,
-            b = this.b,
-            c = this.c,
-            d = this.d,
-            e = this.e,
-            f = this.f;
-        this.a = a + b * lx;
-        this.c = c + d * lx;
-        this.e = e + f * lx - cy * lx;
         return this;
-      } // Skew Matrix
+      } // Get morphed path array at given position
 
     }, {
-      key: "skew",
-      value: function skew(x, y, cx, cy) {
-        var _this$clone2;
-
-        return (_this$clone2 = this.clone()).skewO.apply(_this$clone2, arguments);
-      }
-    }, {
-      key: "skewO",
-      value: function skewO(x) {
-        var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
-        var cx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
-        var cy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
+      key: "at",
+      value: function at(pos) {
+        // make sure a destination is defined
+        if (!this.destination) return this;
+        var sourceArray = this;
+        var destinationArray = this.destination.value;
+        var array = [];
+        var pathArray = new PathArray();
+        var i, il, j, jl; // Animate has specified in the SVG spec
+        // See: https://www.w3.org/TR/SVG11/paths.html#PathElement
 
-        // support uniformal skew
-        if (arguments.length === 3) {
-          cy = cx;
-          cx = y;
-          y = x;
-        } // Convert degrees to radians
+        for (i = 0, il = sourceArray.length; i < il; i++) {
+          array[i] = [sourceArray[i][0]];
+
+          for (j = 1, jl = sourceArray[i].length; j < jl; j++) {
+            array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos;
+          } // For the two flags of the elliptical arc command, the SVG spec say:
+          // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
+          // Elliptical arc command as an array followed by corresponding indexes:
+          // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
+          //   0    1   2        3                 4             5      6  7
 
 
-        x = radians(x);
-        y = radians(y);
-        var lx = Math.tan(x);
-        var ly = Math.tan(y);
-        var a = this.a,
-            b = this.b,
-            c = this.c,
-            d = this.d,
-            e = this.e,
-            f = this.f;
-        this.a = a + b * lx;
-        this.b = b + a * ly;
-        this.c = c + d * lx;
-        this.d = d + c * ly;
-        this.e = e + f * lx - cy * lx;
-        this.f = f + e * ly - cx * ly;
-        return this;
-      } // SkewX
+          if (array[i][0] === 'A') {
+            array[i][4] = +(array[i][4] !== 0);
+            array[i][5] = +(array[i][5] !== 0);
+          }
+        } // Directly modify the value of a path array, this is done this way for performance
+
+
+        pathArray.value = array;
+        return pathArray;
+      } // Absolutize and parse path to array
 
     }, {
-      key: "skewX",
-      value: function skewX(x, cx, cy) {
-        return this.skew(x, 0, cx, cy);
-      }
-    }, {
-      key: "skewXO",
-      value: function skewXO(x, cx, cy) {
-        return this.skewO(x, 0, cx, cy);
-      } // SkewY
+      key: "parse",
+      value: function parse(array) {
+        // if it's already a patharray, no need to parse it
+        if (array instanceof PathArray) return array.valueOf(); // prepare for parsing
+
+        var s;
+        var paramCnt = {
+          'M': 2,
+          'L': 2,
+          'H': 1,
+          'V': 1,
+          'C': 6,
+          'S': 4,
+          'Q': 4,
+          'T': 2,
+          'A': 7,
+          'Z': 0
+        };
+
+        if (typeof array === 'string') {
+          array = array.replace(numbersWithDots, pathRegReplace) // convert 45.123.123 to 45.123 .123
+          .replace(pathLetters, ' $& ') // put some room between letters and numbers
+          .replace(hyphen, '$1 -') // add space before hyphen
+          .trim() // trim
+          .split(delimiter); // split into array
+        } else {
+          array = array.reduce(function (prev, curr) {
+            return [].concat.call(prev, curr);
+          }, []);
+        } // array now is an array containing all parts of a path e.g. ['M', '0', '0', 'L', '30', '30' ...]
+
+
+        var result = [];
+        var p = new Point();
+        var p0 = new Point();
+        var index = 0;
+        var len = array.length;
+
+        do {
+          // Test if we have a path letter
+          if (isPathLetter.test(array[index])) {
+            s = array[index];
+            ++index; // If last letter was a move command and we got no new, it defaults to [L]ine
+          } else if (s === 'M') {
+            s = 'L';
+          } else if (s === 'm') {
+            s = 'l';
+          }
+
+          result.push(pathHandlers[s].call(null, array.slice(index, index = index + paramCnt[s.toUpperCase()]).map(parseFloat), p, p0));
+        } while (len > index);
+
+        return result;
+      } // Get bounding box of path
 
     }, {
-      key: "skewY",
-      value: function skewY(y, cx, cy) {
-        return this.skew(0, y, cx, cy);
+      key: "bbox",
+      value: function bbox() {
+        parser().path.setAttribute('d', this.toString());
+        return parser.nodes.path.getBBox();
       }
+    }]);
+
+    return PathArray;
+  }(SVGArray);
+
+  var Path =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Path, _Base);
+
+    // Initialize node
+    function Path(node) {
+      _classCallCheck(this, Path);
+
+      return _possibleConstructorReturn(this, _getPrototypeOf(Path).call(this, nodeOrNew$1('path', node), Path));
+    } // Get array
+
+
+    _createClass(Path, [{
+      key: "array",
+      value: function array() {
+        return this._array || (this._array = new PathArray(this.attr('d')));
+      } // Plot new path
+
     }, {
-      key: "skewYO",
-      value: function skewYO(y, cx, cy) {
-        return this.skewO(0, y, cx, cy);
-      } // Transform around a center point
+      key: "plot",
+      value: function plot(d) {
+        return d == null ? this.array() : this.clear().attr('d', typeof d === 'string' ? d : this._array = new PathArray(d));
+      } // Clear array cache
 
     }, {
-      key: "aroundO",
-      value: function aroundO(cx, cy, matrix) {
-        var dx = cx || 0;
-        var dy = cy || 0;
-        return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy);
-      }
+      key: "clear",
+      value: function clear() {
+        delete this._array;
+        return this;
+      } // Move by left top corner
+
     }, {
-      key: "around",
-      value: function around(cx, cy, matrix) {
-        return this.clone().aroundO(cx, cy, matrix);
-      } // Convert to native SVGMatrix
+      key: "move",
+      value: function move(x, y) {
+        return this.attr('d', this.array().move(x, y));
+      } // Move by left top corner over x-axis
 
     }, {
-      key: "native",
-      value: function native() {
-        // create new matrix
-        var matrix = parser().node.createSVGMatrix(); // update with current values
+      key: "x",
+      value: function x(_x) {
+        return _x == null ? this.bbox().x : this.move(_x, this.bbox().y);
+      } // Move by left top corner over y-axis
 
-        for (var i = abcdef.length - 1; i >= 0; i--) {
-          matrix[abcdef[i]] = this[abcdef[i]];
-        }
+    }, {
+      key: "y",
+      value: function y(_y) {
+        return _y == null ? this.bbox().y : this.move(this.bbox().x, _y);
+      } // Set element size to given width and height
 
-        return matrix;
-      } // Check if two matrices are equal
+    }, {
+      key: "size",
+      value: function size(width, height) {
+        var p = proportionalSize$1(this, width, height);
+        return this.attr('d', this.array().size(p.width, p.height));
+      } // Set width of element
 
     }, {
-      key: "equals",
-      value: function equals(other) {
-        var comp = new Matrix(other);
-        return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) && closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) && closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f);
-      } // Convert matrix to string
+      key: "width",
+      value: function width(_width) {
+        return _width == null ? this.bbox().width : this.size(_width, this.bbox().height);
+      } // Set height of element
 
     }, {
-      key: "toString",
-      value: function toString() {
-        return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')';
+      key: "height",
+      value: function height(_height) {
+        return _height == null ? this.bbox().height : this.size(this.bbox().width, _height);
       }
     }, {
-      key: "toArray",
-      value: function toArray() {
-        return [this.a, this.b, this.c, this.d, this.e, this.f];
+      key: "targets",
+      value: function targets() {
+        return baseFind('svg textpath [href*="' + this.id() + '"]');
       }
-    }, {
-      key: "valueOf",
-      value: function valueOf() {
-        return {
-          a: this.a,
-          b: this.b,
-          c: this.c,
-          d: this.d,
-          e: this.e,
-          f: this.f
-        };
-      } // TODO: Refactor this to a static function of matrix.js
+    }]);
 
-    }], [{
-      key: "formatTransforms",
-      value: function formatTransforms(o) {
-        // Get all of the parameters required to form the matrix
-        var flipBoth = o.flip === 'both' || o.flip === true;
-        var flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1;
-        var flipY = o.flip && (flipBoth || o.flip === 'y') ? -1 : 1;
-        var skewX = o.skew && o.skew.length ? o.skew[0] : isFinite(o.skew) ? o.skew : isFinite(o.skewX) ? o.skewX : 0;
-        var skewY = o.skew && o.skew.length ? o.skew[1] : isFinite(o.skew) ? o.skew : isFinite(o.skewY) ? o.skewY : 0;
-        var scaleX = o.scale && o.scale.length ? o.scale[0] * flipX : isFinite(o.scale) ? o.scale * flipX : isFinite(o.scaleX) ? o.scaleX * flipX : flipX;
-        var scaleY = o.scale && o.scale.length ? o.scale[1] * flipY : isFinite(o.scale) ? o.scale * flipY : isFinite(o.scaleY) ? o.scaleY * flipY : flipY;
-        var shear = o.shear || 0;
-        var theta = o.rotate || o.theta || 0;
-        var origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY);
-        var ox = origin.x;
-        var oy = origin.y;
-        var position = new Point(o.position || o.px || o.positionX, o.py || o.positionY);
-        var px = position.x;
-        var py = position.y;
-        var translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY);
-        var tx = translate.x;
-        var ty = translate.y;
-        var relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY);
-        var rx = relative.x;
-        var ry = relative.y; // Populate all of the values
+    return Path;
+  }(Base$1); // Define morphable array
+  Path.prototype.MorphArray = PathArray; // Add parent method
 
-        return {
-          scaleX: scaleX,
-          scaleY: scaleY,
-          skewX: skewX,
-          skewY: skewY,
-          shear: shear,
-          theta: theta,
-          rx: rx,
-          ry: ry,
-          tx: tx,
-          ty: ty,
-          ox: ox,
-          oy: oy,
-          px: px,
-          py: py
-        };
-      } // left matrix, right matrix, target matrix which is overwritten
+  registerMethods({
+    Container: {
+      // Create a wrapped path element
+      path: function path(d) {
+        // make sure plot is called as a setter
+        return this.put(new Path()).plot(d || new PathArray());
+      }
+    }
+  });
+  register(Path);
 
-    }, {
-      key: "matrixMultiply",
-      value: function matrixMultiply(l, r, o) {
-        // Work out the product directly
-        var a = l.a * r.a + l.c * r.b;
-        var b = l.b * r.a + l.d * r.b;
-        var c = l.a * r.c + l.c * r.d;
-        var d = l.b * r.c + l.d * r.d;
-        var e = l.e + l.a * r.e + l.c * r.f;
-        var f = l.f + l.b * r.e + l.d * r.f; // make sure to use local variables because l/r and o could be the same
+  var MorphArray = PointArray$1; // Move by left top corner over x-axis
 
-        o.a = a;
-        o.b = b;
-        o.c = c;
-        o.d = d;
-        o.e = e;
-        o.f = f;
-        return o;
-      }
-    }]);
+  function x$2(x) {
+    return x == null ? this.bbox().x : this.move(x, this.bbox().y);
+  } // Move by left top corner over y-axis
 
-    return Matrix;
-  }();
-  Matrix.constructors = {
-    Element: {
-      // Get current matrix
-      ctm: function ctm() {
-        return new Matrix(this.node.getCTM());
-      },
-      // Get current screen matrix
-      screenCTM: function screenCTM() {
-        /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537\r
-           This is needed because FF does not return the transformation matrix\r
-           for the inner coordinate system when getScreenCTM() is called on nested svgs.\r
-           However all other Browsers do that */
-        if (this instanceof Doc && !this.isRoot()) {
-          var rect = this.rect(1, 1);
-          var m = rect.node.getScreenCTM();
-          rect.remove();
-          return new Matrix(m);
-        }
+  function y$2(y) {
+    return y == null ? this.bbox().y : this.move(this.bbox().x, y);
+  } // Set width of element
 
-        return new Matrix(this.node.getScreenCTM());
-      }
-    }
-  };
+  function width$2(width) {
+    var b = this.bbox();
+    return width == null ? b.width : this.size(width, b.height);
+  } // Set height of element
 
-  var Box$1 =
-  /*#__PURE__*/
-  function () {
-    function Box() {
-      _classCallCheck(this, Box);
+  function height$2(height) {
+    var b = this.bbox();
+    return height == null ? b.height : this.size(b.width, height);
+  }
 
-      this.init.apply(this, arguments);
-    }
+  var pointed = /*#__PURE__*/Object.freeze({
+    MorphArray: MorphArray,
+    x: x$2,
+    y: y$2,
+    width: width$2,
+    height: height$2
+  });
 
-    _createClass(Box, [{
-      key: "init",
-      value: function init(source) {
-        var base = [0, 0, 0, 0];
-        source = typeof source === 'string' ? source.split(delimiter).map(parseFloat) : Array.isArray(source) ? source : _typeof(source) === 'object' ? [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] : arguments.length === 4 ? [].slice.call(arguments) : base;
-        this.x = source[0];
-        this.y = source[1];
-        this.width = source[2];
-        this.height = source[3]; // add center, right, bottom...
+  // Add polygon-specific functions
+  // Get array
+  function array() {
+    return this._array || (this._array = new PointArray(this.attr('points')));
+  } // Plot new path
 
-        fullBox(this);
-      } // Merge rect box with another, return a new instance
+  function plot(p) {
+    return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new PointArray(p));
+  } // Clear array cache
 
-    }, {
-      key: "merge",
-      value: function merge(box) {
-        var x = Math.min(this.x, box.x);
-        var y = Math.min(this.y, box.y);
-        var width = Math.max(this.x + this.width, box.x + box.width) - x;
-        var height = Math.max(this.y + this.height, box.y + box.height) - y;
-        return new Box(x, y, width, height);
-      }
-    }, {
-      key: "transform",
-      value: function transform(m) {
-        var xMin = Infinity;
-        var xMax = -Infinity;
-        var yMin = Infinity;
-        var yMax = -Infinity;
-        var pts = [new Point(this.x, this.y), new Point(this.x2, this.y), new Point(this.x, this.y2), new Point(this.x2, this.y2)];
-        pts.forEach(function (p) {
-          p = p.transform(m);
-          xMin = Math.min(xMin, p.x);
-          xMax = Math.max(xMax, p.x);
-          yMin = Math.min(yMin, p.y);
-          yMax = Math.max(yMax, p.y);
-        });
-        return new Box(xMin, yMin, xMax - xMin, yMax - yMin);
-      }
-    }, {
-      key: "addOffset",
-      value: function addOffset() {
-        // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
-        this.x += window.pageXOffset;
-        this.y += window.pageYOffset;
-        return this;
-      }
-    }, {
-      key: "toString",
-      value: function toString() {
-        return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height;
-      }
-    }, {
-      key: "toArray",
-      value: function toArray() {
-        return [this.x, this.y, this.width, this.height];
-      }
-    }]);
+  function clear() {
+    delete this._array;
+    return this;
+  } // Move by left top corner
 
-    return Box;
-  }();
+  function move$1(x, y) {
+    return this.attr('points', this.array().move(x, y));
+  } // Set element size to given width and height
 
-  function getBox(cb) {
-    var box;
+  function size$2(width, height) {
+    var p = proportionalSize(this, width, height);
+    return this.attr('points', this.array().size(p.width, p.height));
+  }
 
-    try {
-      box = cb(this.node);
+  var poly = /*#__PURE__*/Object.freeze({
+    array: array,
+    plot: plot,
+    clear: clear,
+    move: move$1,
+    size: size$2
+  });
 
-      if (isNulledBox(box) && !domContains(this.node)) {
-        throw new Error('Element not in the dom');
-      }
-    } catch (e) {
-      try {
-        var clone = this.clone(parser().svg).show();
-        box = cb(clone.node);
-        clone.remove();
-      } catch (e) {
-        throw e;
-        console.warn('Getting a bounding box of this element is not possible');
-      }
-    }
+  var Polygon =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Polygon, _Base);
 
-    return box;
-  }
+    // Initialize node
+    function Polygon(node) {
+      _classCallCheck(this, Polygon);
 
-  Box$1.constructors = {
-    Element: {
-      // Get bounding box
-      bbox: function bbox() {
-        return new Box$1(getBox.call(this, function (node) {
-          return node.getBBox();
-        }));
-      },
-      rbox: function rbox(el) {
-        var box = new Box$1(getBox.call(this, function (node) {
-          return node.getBoundingClientRect();
-        }));
-        if (el) return box.transform(el.screenCTM().inverse());
-        return box.addOffset();
-      }
-    },
-    viewbox: function viewbox(x, y, width, height) {
-      // act as getter
-      if (x == null) return new Box$1(this.attr('viewBox')); // act as setter
+      return _possibleConstructorReturn(this, _getPrototypeOf(Polygon).call(this, nodeOrNew$1('polygon', node), Polygon));
+    }
 
-      return this.attr('viewBox', new Box$1(x, y, width, height));
+    return Polygon;
+  }(Base$1);
+  registerMethods({
+    Parent: {
+      // Create a wrapped polygon element
+      polygon: function polygon(p) {
+        // make sure plot is called as a setter
+        return this.put(new Polygon()).plot(p || new PointArray$1());
+      }
     }
-  };
+  });
+  extend$1(Polygon, pointed);
+  extend$1(Polygon, poly);
+  register(Polygon);
 
-  var Color =
+  var Polyline =
   /*#__PURE__*/
-  function () {
-    function Color() {
-      _classCallCheck(this, Color);
+  function (_Base) {
+    _inherits(Polyline, _Base);
 
-      this.init.apply(this, arguments);
-    }
+    // Initialize node
+    function Polyline(node) {
+      _classCallCheck(this, Polyline);
 
-    _createClass(Color, [{
-      key: "init",
-      value: function init(color, g, b) {
-        var match; // initialize defaults
+      return _possibleConstructorReturn(this, _getPrototypeOf(Polyline).call(this, nodeOrNew$1('polyline', node), Polyline));
+    }
 
-        this.r = 0;
-        this.g = 0;
-        this.b = 0;
-        if (!color) return; // parse color
+    return Polyline;
+  }(Base$1);
+  registerMethods({
+    Parent: {
+      // Create a wrapped polygon element
+      polyline: function polyline(p) {
+        // make sure plot is called as a setter
+        return this.put(new Polyline()).plot(p || new PointArray$1());
+      }
+    }
+  });
+  extend$1(Polyline, pointed);
+  extend$1(Polyline, poly);
+  register(Polyline);
 
-        if (typeof color === 'string') {
-          if (isRgb.test(color)) {
-            // get rgb values
-            match = rgb.exec(color.replace(whitespace, '')); // parse numeric values
+  var Rect =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Rect, _Base);
 
-            this.r = parseInt(match[1]);
-            this.g = parseInt(match[2]);
-            this.b = parseInt(match[3]);
-          } else if (isHex.test(color)) {
-            // get hex values
-            match = hex.exec(fullHex(color)); // parse numeric values
+    // Initialize node
+    function Rect(node) {
+      _classCallCheck(this, Rect);
 
-            this.r = parseInt(match[1], 16);
-            this.g = parseInt(match[2], 16);
-            this.b = parseInt(match[3], 16);
-          }
-        } else if (Array.isArray(color)) {
-          this.r = color[0];
-          this.g = color[1];
-          this.b = color[2];
-        } else if (_typeof(color) === 'object') {
-          this.r = color.r;
-          this.g = color.g;
-          this.b = color.b;
-        } else if (arguments.length === 3) {
-          this.r = color;
-          this.g = g;
-          this.b = b;
-        }
-      } // Default to hex conversion
+      return _possibleConstructorReturn(this, _getPrototypeOf(Rect).call(this, nodeOrNew$1('rect', node), Rect));
+    }
 
-    }, {
-      key: "toString",
-      value: function toString() {
-        return this.toHex();
+    return Rect;
+  }(Base$1);
+  registerMethods({
+    Container: {
+      // Create a rect element
+      rect: function rect(width, height) {
+        return this.put(new Rect()).size(width, height);
       }
-    }, {
-      key: "toArray",
-      value: function toArray() {
-        return [this.r, this.g, this.b];
-      } // Build hex value
-
-    }, {
-      key: "toHex",
-      value: function toHex() {
-        return '#' + compToHex(Math.round(this.r)) + compToHex(Math.round(this.g)) + compToHex(Math.round(this.b));
-      } // Build rgb value
-
-    }, {
-      key: "toRgb",
-      value: function toRgb() {
-        return 'rgb(' + [this.r, this.g, this.b].join() + ')';
-      } // Calculate true brightness
+    }
+  });
+  register(Rect);
 
-    }, {
-      key: "brightness",
-      value: function brightness() {
-        return this.r / 255 * 0.30 + this.g / 255 * 0.59 + this.b / 255 * 0.11;
-      } // Testers
-      // Test if given value is a color string
+  var _Symbol =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(_Symbol, _Base);
 
-    }], [{
-      key: "test",
-      value: function test(color) {
-        color += '';
-        return isHex.test(color) || isRgb.test(color);
-      } // Test if given value is a rgb object
+    // Initialize node
+    function _Symbol(node) {
+      _classCallCheck(this, _Symbol);
 
-    }, {
-      key: "isRgb",
-      value: function isRgb$$1(color) {
-        return color && typeof color.r === 'number' && typeof color.g === 'number' && typeof color.b === 'number';
-      } // Test if given value is a color
+      return _possibleConstructorReturn(this, _getPrototypeOf(_Symbol).call(this, nodeOrNew$1('symbol', node), _Symbol));
+    }
 
-    }, {
-      key: "isColor",
-      value: function isColor(color) {
-        return this.isRgb(color) || this.test(color);
+    return _Symbol;
+  }(Base$1);
+  registerMethods({
+    Container: {
+      symbol: function symbol() {
+        return this.put(new _Symbol());
       }
-    }]);
-
-    return Color;
-  }();
+    }
+  });
+  register(_Symbol);
 
-  /***\r
-  Base Class\r
-  ==========\r
-  The base stepper class that will be\r
-  ***/
+  // Create plain text node
+  function plain(text) {
+    // clear if build mode is disabled
+    if (this._build === false) {
+      this.clear();
+    } // create text node
 
-  function makeSetterGetter(k, f) {
-    return function (v) {
-      if (v == null) return this[v];
-      this[k] = v;
-      if (f) f.call(this);
-      return this;
-    };
-  }
 
-  var easing = {
-    '-': function _(pos) {
-      return pos;
-    },
-    '<>': function _(pos) {
-      return -Math.cos(pos * Math.PI) / 2 + 0.5;
-    },
-    '>': function _(pos) {
-      return Math.sin(pos * Math.PI / 2);
-    },
-    '<': function _(pos) {
-      return -Math.cos(pos * Math.PI / 2) + 1;
-    },
-    bezier: function bezier(t0, x0, t1, x1) {
-      return function (t) {// TODO: FINISH
-      };
-    }
-  };
-  var Stepper =
-  /*#__PURE__*/
-  function () {
-    function Stepper() {
-      _classCallCheck(this, Stepper);
-    }
+    this.node.appendChild(document.createTextNode(text));
+    return this;
+  } // FIXME: Does this also work for textpath?
+  // Get length of text element
 
-    _createClass(Stepper, [{
-      key: "done",
-      value: function done() {
-        return false;
-      }
-    }]);
+  function length() {
+    return this.node.getComputedTextLength();
+  }
 
-    return Stepper;
-  }();
-  /***\r
-  Easing Functions\r
-  ================\r
-  ***/
+  var textable = /*#__PURE__*/Object.freeze({
+    plain: plain,
+    length: length
+  });
 
-  var Ease =
+  var Text$1 =
   /*#__PURE__*/
-  function (_Stepper) {
-    _inherits(Ease, _Stepper);
+  function (_Base) {
+    _inherits(Text, _Base);
 
-    function Ease(fn) {
+    // Initialize node
+    function Text(node) {
       var _this;
 
-      _classCallCheck(this, Ease);
-
-      _this = _possibleConstructorReturn(this, _getPrototypeOf(Ease).call(this));
-      _this.ease = easing[fn || timeline.ease] || fn;
-      return _this;
-    }
+      _classCallCheck(this, Text);
 
-    _createClass(Ease, [{
-      key: "step",
-      value: function step(from, to, pos) {
-        if (typeof from !== 'number') {
-          return pos < 1 ? from : to;
-        }
+      _this = _possibleConstructorReturn(this, _getPrototypeOf(Text).call(this, nodeOrNew$1('text', node), Text));
+      _this.dom.leading = new SVGNumber(1.3); // store leading value for rebuilding
 
-        return from + (to - from) * this.ease(pos);
-      }
-    }]);
+      _this._rebuild = true; // enable automatic updating of dy values
 
-    return Ease;
-  }(Stepper);
-  /***\r
-  Controller Types\r
-  ================\r
-  ***/
+      _this._build = false; // disable build mode for adding multiple lines
+      // set default font
 
-  var Controller =
-  /*#__PURE__*/
-  function (_Stepper2) {
-    _inherits(Controller, _Stepper2);
+      _this.attr('font-family', attrs['font-family']);
 
-    function Controller(fn) {
-      var _this2;
+      return _this;
+    } // Move over x-axis
 
-      _classCallCheck(this, Controller);
 
-      _this2 = _possibleConstructorReturn(this, _getPrototypeOf(Controller).call(this));
-      _this2.stepper = fn;
-      return _this2;
-    }
+    _createClass(Text, [{
+      key: "x",
+      value: function x(_x) {
+        // act as getter
+        if (_x == null) {
+          return this.attr('x');
+        }
+
+        return this.attr('x', _x);
+      } // Move over y-axis
 
-    _createClass(Controller, [{
-      key: "step",
-      value: function step(current, target, dt, c) {
-        return this.stepper(current, target, dt, c);
-      }
     }, {
-      key: "done",
-      value: function done(c) {
-        return c.done;
-      }
-    }]);
+      key: "y",
+      value: function y(_y) {
+        var oy = this.attr('y');
+        var o = typeof oy === 'number' ? oy - this.bbox().y : 0; // act as getter
 
-    return Controller;
-  }(Stepper);
+        if (_y == null) {
+          return typeof oy === 'number' ? oy - o : oy;
+        }
 
-  function recalculate() {
-    // Apply the default parameters
-    var duration = (this._duration || 500) / 1000;
-    var overshoot = this._overshoot || 0; // Calculate the PID natural response
+        return this.attr('y', typeof _y === 'number' ? _y + o : _y);
+      } // Move center over x-axis
 
-    var eps = 1e-10;
-    var pi = Math.PI;
-    var os = Math.log(overshoot / 100 + eps);
-    var zeta = -os / Math.sqrt(pi * pi + os * os);
-    var wn = 3.9 / (zeta * duration); // Calculate the Spring values
+    }, {
+      key: "cx",
+      value: function cx(x) {
+        return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2);
+      } // Move center over y-axis
 
-    this.d = 2 * zeta * wn;
-    this.k = wn * wn;
-  }
+    }, {
+      key: "cy",
+      value: function cy(y) {
+        return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2);
+      } // Set the text content
 
-  var Spring =
-  /*#__PURE__*/
-  function (_Controller) {
-    _inherits(Spring, _Controller);
+    }, {
+      key: "text",
+      value: function text(_text) {
+        // act as getter
+        if (_text === undefined) {
+          var children = this.node.childNodes;
+          var firstLine = 0;
+          _text = '';
 
-    function Spring(duration, overshoot) {
-      var _this3;
+          for (var i = 0, len = children.length; i < len; ++i) {
+            // skip textPaths - they are no lines
+            if (children[i].nodeName === 'textPath') {
+              if (i === 0) firstLine = 1;
+              continue;
+            } // add newline if its not the first child and newLined is set to true
 
-      _classCallCheck(this, Spring);
 
-      _this3 = _possibleConstructorReturn(this, _getPrototypeOf(Spring).call(this));
+            if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) {
+              _text += '\n';
+            } // add content of this node
 
-      _this3.duration(duration || 500).overshoot(overshoot || 0);
 
-      return _this3;
-    }
+            _text += children[i].textContent;
+          }
 
-    _createClass(Spring, [{
-      key: "step",
-      value: function step(current, target, dt, c) {
-        if (typeof current === 'string') return current;
-        c.done = dt === Infinity;
-        if (dt === Infinity) return target;
-        if (dt === 0) return current;
-        if (dt > 100) dt = 16;
-        dt /= 1000; // Get the previous velocity
+          return _text;
+        } // remove existing content
 
-        var velocity = c.velocity || 0; // Apply the control to get the new position and store it
 
-        var acceleration = -this.d * velocity - this.k * (current - target);
-        var newPosition = current + velocity * dt + acceleration * dt * dt / 2; // Store the velocity
+        this.clear().build(true);
 
-        c.velocity = velocity + acceleration * dt; // Figure out if we have converged, and if so, pass the value
+        if (typeof _text === 'function') {
+          // call block
+          _text.call(this, this);
+        } else {
+          // store text and make sure text is not blank
+          _text = _text.split('\n'); // build new lines
 
-        c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002;
-        return c.done ? target : newPosition;
-      }
-    }]);
+          for (var j = 0, jl = _text.length; j < jl; j++) {
+            this.tspan(_text[j]).newLine();
+          }
+        } // disable build mode and rebuild lines
 
-    return Spring;
-  }(Controller);
-  extend$1(Spring, {
-    duration: makeSetterGetter('_duration', recalculate),
-    overshoot: makeSetterGetter('_overshoot', recalculate)
-  });
-  var PID =
-  /*#__PURE__*/
-  function (_Controller2) {
-    _inherits(PID, _Controller2);
 
-    function PID(p, i, d, windup) {
-      var _this4;
+        return this.build(false).rebuild();
+      } // Set / get leading
 
-      _classCallCheck(this, PID);
+    }, {
+      key: "leading",
+      value: function leading(value) {
+        // act as getter
+        if (value == null) {
+          return this.dom.leading;
+        } // act as setter
 
-      _this4 = _possibleConstructorReturn(this, _getPrototypeOf(PID).call(this));
-      p = p == null ? 0.1 : p;
-      i = i == null ? 0.01 : i;
-      d = d == null ? 0 : d;
-      windup = windup == null ? 1000 : windup;
 
-      _this4.p(p).i(i).d(d).windup(windup);
+        this.dom.leading = new SVGNumber(value);
+        return this.rebuild();
+      } // Rebuild appearance type
 
-      return _this4;
-    }
+    }, {
+      key: "rebuild",
+      value: function rebuild(_rebuild) {
+        // store new rebuild flag if given
+        if (typeof _rebuild === 'boolean') {
+          this._rebuild = _rebuild;
+        } // define position of all lines
 
-    _createClass(PID, [{
-      key: "step",
-      value: function step(current, target, dt, c) {
-        if (typeof current === 'string') return current;
-        c.done = dt === Infinity;
-        if (dt === Infinity) return target;
-        if (dt === 0) return current;
-        var p = target - current;
-        var i = (c.integral || 0) + p * dt;
-        var d = (p - (c.error || 0)) / dt;
-        var windup = this.windup; // antiwindup
 
-        if (windup !== false) {
-          i = Math.max(-windup, Math.min(i, windup));
+        if (this._rebuild) {
+          var self = this;
+          var blankLineOffset = 0;
+          var dy = this.dom.leading * new SVGNumber(this.attr('font-size'));
+          this.each(function () {
+            if (this.dom.newLined) {
+              this.attr('x', self.attr('x'));
+
+              if (this.text() === '\n') {
+                blankLineOffset += dy;
+              } else {
+                this.attr('dy', dy + blankLineOffset);
+                blankLineOffset = 0;
+              }
+            }
+          });
+          this.fire('rebuild');
         }
 
-        c.error = p;
-        c.integral = i;
-        c.done = Math.abs(p) < 0.001;
-        return c.done ? target : current + (this.P * p + this.I * i + this.D * d);
+        return this;
+      } // Enable / disable build mode
+
+    }, {
+      key: "build",
+      value: function build(_build) {
+        this._build = !!_build;
+        return this;
+      } // overwrite method from parent to set data properly
+
+    }, {
+      key: "setData",
+      value: function setData(o) {
+        this.dom = o;
+        this.dom.leading = new SVGNumber(o.leading || 1.3);
+        return this;
       }
     }]);
 
-    return PID;
-  }(Controller);
-  extend$1(PID, {
-    windup: makeSetterGetter('windup'),
-    p: makeSetterGetter('P'),
-    i: makeSetterGetter('I'),
-    d: makeSetterGetter('D')
+    return Text;
+  }(Base$1);
+  extend$1(Text$1, textable);
+  registerMethods({
+    Container: {
+      // Create text element
+      text: function text(_text2) {
+        return this.put(new Text$1()).text(_text2);
+      },
+      // Create plain text element
+      plain: function plain$$1(text) {
+        return this.put(new Text$1()).plain(text);
+      }
+    }
   });
+  register(Text$1);
 
-  var Morphable =
+  var TextPath =
   /*#__PURE__*/
-  function () {
-    function Morphable(stepper) {
-      _classCallCheck(this, Morphable);
+  function (_Text) {
+    _inherits(TextPath, _Text);
 
-      // FIXME: the default stepper does not know about easing
-      this._stepper = stepper || new Ease('-');
-      this._from = null;
-      this._to = null;
-      this._type = null;
-      this._context = null;
-      this._morphObj = null;
-    }
+    // Initialize node
+    function TextPath(node) {
+      _classCallCheck(this, TextPath);
 
-    _createClass(Morphable, [{
-      key: "from",
-      value: function from(val) {
-        if (val == null) {
-          return this._from;
-        }
+      return _possibleConstructorReturn(this, _getPrototypeOf(TextPath).call(this, nodeOrNew$1('textPath', node)));
+    } // return the array of the path track element
 
-        this._from = this._set(val);
-        return this;
-      }
-    }, {
-      key: "to",
-      value: function to(val) {
-        if (val == null) {
-          return this._to;
-        }
-
-        this._to = this._set(val);
-        return this;
-      }
-    }, {
-      key: "type",
-      value: function type(_type) {
-        // getter
-        if (_type == null) {
-          return this._type;
-        } // setter
 
+    _createClass(TextPath, [{
+      key: "array",
+      value: function array() {
+        var track = this.track();
+        return track ? track.array() : null;
+      } // Plot path if any
 
-        this._type = _type;
-        return this;
-      }
     }, {
-      key: "_set",
-      value: function _set$$1(value) {
-        if (!this._type) {
-          var type = _typeof(value);
+      key: "plot",
+      value: function plot(d) {
+        var track = this.track();
+        var pathArray = null;
 
-          if (type === 'number') {
-            this.type(SVGNumber);
-          } else if (type === 'string') {
-            if (Color.isColor(value)) {
-              this.type(Color);
-            } else if (regex.delimiter.test(value)) {
-              this.type(regex.pathLetters.test(value) ? PathArray : SVGArray);
-            } else if (regex.numberAndUnit.test(value)) {
-              this.type(SVGNumber);
-            } else {
-              this.type(Morphable.NonMorphable);
-            }
-          } else if (MorphableTypes.indexOf(value.constructor) > -1) {
-            this.type(value.constructor);
-          } else if (Array.isArray(value)) {
-            this.type(SVGArray);
-          } else if (type === 'object') {
-            this.type(Morphable.ObjectBag);
-          } else {
-            this.type(Morphable.NonMorphable);
-          }
+        if (track) {
+          pathArray = track.plot(d);
         }
 
-        var result = new this._type(value).toArray();
-        this._morphObj = this._morphObj || new this._type();
-        this._context = this._context || Array.apply(null, Array(result.length)).map(Object);
-        return result;
-      }
-    }, {
-      key: "stepper",
-      value: function stepper(_stepper) {
-        if (_stepper == null) return this._stepper;
-        this._stepper = _stepper;
-        return this;
-      }
-    }, {
-      key: "done",
-      value: function done() {
-        var complete = this._context.map(this._stepper.done).reduce(function (last, curr) {
-          return last && curr;
-        }, true);
+        return d == null ? pathArray : this;
+      } // Get the path element
 
-        return complete;
-      }
     }, {
-      key: "at",
-      value: function at(pos) {
-        var _this = this;
-
-        return this._morphObj.fromArray(this._from.map(function (i, index) {
-          return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context);
-        }));
+      key: "track",
+      value: function track() {
+        return this.reference('href');
       }
     }]);
 
-    return Morphable;
-  }();
+    return TextPath;
+  }(Text$1);
+  registerMethods({
+    Container: {
+      textPath: function textPath(text, path) {
+        return this.defs().path(path).text(text).addTo(this);
+      }
+    },
+    Text: {
+      // Create path for text to run on
+      path: function path(track) {
+        var path = new TextPath(); // if d is a path, reuse it
 
-  Morphable.NonMorphable =
-  /*#__PURE__*/
-  function () {
-    function _class() {
-      _classCallCheck(this, _class);
+        if (!(track instanceof Path)) {
+          // create path element
+          track = this.doc().defs().path(track);
+        } // link textPath to path and add content
 
-      this.init.apply(this, arguments);
-    }
 
-    _createClass(_class, [{
-      key: "init",
-      value: function init(val) {
-        val = Array.isArray(val) ? val[0] : val;
-        this.value = val;
-      }
-    }, {
-      key: "valueOf",
-      value: function valueOf() {
-        return this.value;
-      }
-    }, {
-      key: "toArray",
-      value: function toArray() {
-        return [this.value];
+        path.attr('href', '#' + track, xlink); // add textPath element as child node and return textPath
+
+        return this.put(path);
+      },
+      // FIXME: make this plural?
+      // Get the textPath children
+      textPath: function textPath() {
+        return this.select('textPath');
       }
-    }]);
+    },
+    Path: {
+      // creates a textPath from this path
+      text: function text(_text) {
+        if (_text instanceof Text$1) {
+          var txt = _text.text();
 
-    return _class;
-  }();
+          return _text.clear().path(this).text(txt);
+        }
 
-  Morphable.TransformBag =
-  /*#__PURE__*/
-  function () {
-    function _class2() {
-      _classCallCheck(this, _class2);
+        return this.parent().put(new Text$1()).path(this).text(_text);
+      } // FIXME: Maybe add `targets` to get all textPaths associated with this path
 
-      this.init.apply(this, arguments);
     }
+  });
+  TextPath.prototype.MorphArray = PathArray;
+  register(TextPath);
 
-    _createClass(_class2, [{
-      key: "init",
-      value: function init(obj) {
-        if (Array.isArray(obj)) {
-          obj = {
-            scaleX: obj[0],
-            scaleY: obj[1],
-            shear: obj[2],
-            rotate: obj[3],
-            translateX: obj[4],
-            translateY: obj[5],
-            originX: obj[6],
-            originY: obj[7]
-          };
-        }
-
-        Object.assign(this, Morphable.TransformBag.defaults, obj);
-      }
-    }, {
-      key: "toArray",
-      value: function toArray() {
-        var v = this;
-        return [v.scaleX, v.scaleY, v.shear, v.rotate, v.translateX, v.translateY, v.originX, v.originY];
-      }
-    }]);
+  var Tspan =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Tspan, _Base);
 
-    return _class2;
-  }();
+    // Initialize node
+    function Tspan(node) {
+      _classCallCheck(this, Tspan);
 
-  Morphable.TransformBag.defaults = {
-    scaleX: 1,
-    scaleY: 1,
-    shear: 0,
-    rotate: 0,
-    translateX: 0,
-    translateY: 0,
-    originX: 0,
-    originY: 0
-  };
+      return _possibleConstructorReturn(this, _getPrototypeOf(Tspan).call(this, nodeOrNew$1('tspan', node), Tspan));
+    } // Set text content
 
-  Morphable.ObjectBag =
-  /*#__PURE__*/
-  function () {
-    function _class3() {
-      _classCallCheck(this, _class3);
 
-      this.init.apply(this, arguments);
-    }
+    _createClass(Tspan, [{
+      key: "text",
+      value: function text(_text) {
+        if (_text == null) return this.node.textContent + (this.dom.newLined ? '\n' : '');
+        typeof _text === 'function' ? _text.call(this, this) : this.plain(_text);
+        return this;
+      } // Shortcut dx
 
-    _createClass(_class3, [{
-      key: "init",
-      value: function init(objOrArr) {
-        this.values = [];
+    }, {
+      key: "dx",
+      value: function dx(_dx) {
+        return this.attr('dx', _dx);
+      } // Shortcut dy
 
-        if (Array.isArray(objOrArr)) {
-          this.values = objOrArr;
-          return;
-        }
+    }, {
+      key: "dy",
+      value: function dy(_dy) {
+        return this.attr('dy', _dy);
+      } // Create new line
 
-        var entries = Object.entries(objOrArr || {}).sort(function (a, b) {
-          return a[0] - b[0];
-        });
-        this.values = entries.reduce(function (last, curr) {
-          return last.concat(curr);
-        }, []);
-      }
     }, {
-      key: "valueOf",
-      value: function valueOf() {
-        var obj = {};
-        var arr = this.values;
+      key: "newLine",
+      value: function newLine() {
+        // fetch text parent
+        var t = this.parent(Text); // mark new line
 
-        for (var i = 0, len = arr.length; i < len; i += 2) {
-          obj[arr[i]] = arr[i + 1];
-        }
+        this.dom.newLined = true; // apply new position
 
-        return obj;
-      }
-    }, {
-      key: "toArray",
-      value: function toArray() {
-        return this.values;
+        return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x());
       }
     }]);
 
-    return _class3;
-  }();
-
-  var morphableTypes = [SVGNumber, Color, Box$1, Matrix, SVGArray, PointArray$1, PathArray, Morphable.NonMorphable, Morphable.TransformBag, Morphable.ObjectBag];
-  extend$1(morphableTypes, {
-    to: function to(val, args) {
-      return new Morphable().type(this.constructor).from(this.valueOf()).to(val, args);
-    },
-    fromArray: function fromArray(arr) {
-      this.init(arr);
-      return this;
+    return Tspan;
+  }(Base$1);
+  extend$1(Tspan, textable);
+  registerMethods({
+    Tspan: {
+      tspan: function tspan(text) {
+        var tspan = new Tspan(); // clear if build mode is disabled
+
+        if (!this._build) {
+          this.clear();
+        } // add new tspan
+
+
+        this.node.appendChild(tspan.node);
+        return tspan.text(text);
+      }
     }
   });
+  register(Tspan);
 
-  var time = window.performance || Date;
+  var Use =
+  /*#__PURE__*/
+  function (_Base) {
+    _inherits(Use, _Base);
 
-  var makeSchedule = function makeSchedule(runnerInfo) {
-    var start = runnerInfo.start;
-    var duration = runnerInfo.runner.duration();
-    var end = start + duration;
-    return {
-      start: start,
-      duration: duration,
-      end: end,
-      runner: runnerInfo.runner
-    };
-  };
+    function Use(node) {
+      _classCallCheck(this, Use);
 
-  var Timeline =
+      return _possibleConstructorReturn(this, _getPrototypeOf(Use).call(this, nodeOrNew('use', node), Use));
+    } // Use element as a reference
+
+
+    _createClass(Use, [{
+      key: "element",
+      value: function element(_element, file) {
+        // Set lined element
+        return this.attr('href', (file || '') + '#' + _element, xlink);
+      }
+    }]);
+
+    return Use;
+  }(Base$1);
+  registerMethods({
+    Container: {
+      // Create a use element
+      use: function use(element, file) {
+        return this.put(new Use()).element(element, file);
+      }
+    }
+  });
+  register(Use);
+
+  var Matrix =
   /*#__PURE__*/
   function () {
-    // Construct a new timeline on the given element
-    function Timeline() {
-      _classCallCheck(this, Timeline);
-
-      this._timeSource = function () {
-        return time.now();
-      };
+    function Matrix() {
+      _classCallCheck(this, Matrix);
 
-      this._dispatcher = document.createElement('div'); // Store the timing variables
+      this.init.apply(this, arguments);
+    } // Initialize
 
-      this._startTime = 0;
-      this._speed = 1.0; // Play control variables control how the animation proceeds
 
-      this._reverse = false;
-      this._persist = 0; // Keep track of the running animations and their starting parameters
+    _createClass(Matrix, [{
+      key: "init",
+      value: function init(source) {
+        var base = arrayToMatrix([1, 0, 0, 1, 0, 0]); // ensure source as object
 
-      this._nextFrame = null;
-      this._paused = false;
-      this._runners = [];
-      this._order = [];
-      this._time = 0;
-      this._lastSourceTime = 0;
-      this._lastStepTime = 0;
-    }
+        source = source instanceof Base$1 && source.is('Element') ? source.matrixify() : typeof source === 'string' ? arrayToMatrix(source.split(delimiter).map(parseFloat)) : Array.isArray(source) ? arrayToMatrix(source) : _typeof(source) === 'object' && isMatrixLike(source) ? source : _typeof(source) === 'object' ? new Matrix().transform(source) : arguments.length === 6 ? arrayToMatrix([].slice.call(arguments)) : base; // Merge the source matrix with the base matrix
 
-    _createClass(Timeline, [{
-      key: "getEventTarget",
-      value: function getEventTarget() {
-        return this._dispatcher;
-      }
-      /**\r
-       *\r
-       */
-      // schedules a runner on the timeline
+        this.a = source.a != null ? source.a : base.a;
+        this.b = source.b != null ? source.b : base.b;
+        this.c = source.c != null ? source.c : base.c;
+        this.d = source.d != null ? source.d : base.d;
+        this.e = source.e != null ? source.e : base.e;
+        this.f = source.f != null ? source.f : base.f;
+      } // Clones this matrix
 
     }, {
-      key: "schedule",
-      value: function schedule(runner, delay, when) {
-        if (runner == null) {
-          return this._runners.map(makeSchedule).sort(function (a, b) {
-            return a.start - b.start || a.duration - b.duration;
-          });
-        }
+      key: "clone",
+      value: function clone() {
+        return new Matrix(this);
+      } // Transform a matrix into another matrix by manipulating the space
 
-        if (!this.active()) {
-          this._step();
+    }, {
+      key: "transform",
+      value: function transform(o) {
+        // Check if o is a matrix and then left multiply it directly
+        if (isMatrixLike(o)) {
+          var matrix = new Matrix(o);
+          return matrix.multiplyO(this);
+        } // Get the proposed transformations and the current transformations
 
-          if (when == null) {
-            when = 'now';
-          }
-        } // The start time for the next animation can either be given explicitly,
-        // derived from the current timeline time or it can be relative to the
-        // last start time to chain animations direclty
 
+        var t = Matrix.formatTransforms(o);
+        var current = this;
 
-        var absoluteStartTime = 0;
-        delay = delay || 0; // Work out when to start the animation
+        var _transform = new Point(t.ox, t.oy).transform(current),
+            ox = _transform.x,
+            oy = _transform.y; // Construct the resulting matrix
 
-        if (when == null || when === 'last' || when === 'after') {
-          // Take the last time and increment
-          absoluteStartTime = this._startTime;
-        } else if (when === 'absolute' || when === 'start') {
-          absoluteStartTime = delay;
-          delay = 0;
-        } else if (when === 'now') {
-          absoluteStartTime = this._time;
-        } else if (when === 'relative') {
-          var runnerInfo = this._runners[runner.id];
 
-          if (runnerInfo) {
-            absoluteStartTime = runnerInfo.start + delay;
-            delay = 0;
-          }
-        } else {
-          throw new Error('Invalid value for the "when" parameter');
-        } // Manage runner
+        var transformer = new Matrix().translateO(t.rx, t.ry).lmultiplyO(current).translateO(-ox, -oy).scaleO(t.scaleX, t.scaleY).skewO(t.skewX, t.skewY).shearO(t.shear).rotateO(t.theta).translateO(ox, oy); // If we want the origin at a particular place, we force it there
 
+        if (isFinite(t.px) || isFinite(t.py)) {
+          var origin = new Point(ox, oy).transform(transformer); // TODO: Replace t.px with isFinite(t.px)
 
-        runner.unschedule();
-        runner.timeline(this);
-        runner.time(-delay); // Save startTime for next runner
+          var dx = t.px ? t.px - origin.x : 0;
+          var dy = t.py ? t.py - origin.y : 0;
+          transformer.translateO(dx, dy);
+        } // Translate now after positioning
 
-        this._startTime = absoluteStartTime + runner.duration() + delay; // Save runnerInfo
 
-        this._runners[runner.id] = {
-          persist: this.persist(),
-          runner: runner,
-          start: absoluteStartTime // Save order and continue
+        transformer.translateO(t.tx, t.ty);
+        return transformer;
+      } // Applies a matrix defined by its affine parameters
 
-        };
+    }, {
+      key: "compose",
+      value: function compose(o) {
+        if (o.origin) {
+          o.originX = o.origin[0];
+          o.originY = o.origin[1];
+        } // Get the parameters
 
-        this._order.push(runner.id);
 
-        this._continue();
+        var ox = o.originX || 0;
+        var oy = o.originY || 0;
+        var sx = o.scaleX || 1;
+        var sy = o.scaleY || 1;
+        var lam = o.shear || 0;
+        var theta = o.rotate || 0;
+        var tx = o.translateX || 0;
+        var ty = o.translateY || 0; // Apply the standard matrix
 
-        return this;
-      } // Remove the runner from this timeline
+        var result = new Matrix().translateO(-ox, -oy).scaleO(sx, sy).shearO(lam).rotateO(theta).translateO(tx, ty).lmultiplyO(this).translateO(ox, oy);
+        return result;
+      } // Decomposes this matrix into its affine parameters
 
     }, {
-      key: "unschedule",
-      value: function unschedule(runner) {
-        var index = this._order.indexOf(runner.id);
+      key: "decompose",
+      value: function decompose() {
+        var cx = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
+        var cy = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+        // Get the parameters from the matrix
+        var a = this.a;
+        var b = this.b;
+        var c = this.c;
+        var d = this.d;
+        var e = this.e;
+        var f = this.f; // Figure out if the winding direction is clockwise or counterclockwise
 
-        if (index < 0) return this;
-        delete this._runners[runner.id];
+        var determinant = a * d - b * c;
+        var ccw = determinant > 0 ? 1 : -1; // Since we only shear in x, we can use the x basis to get the x scale
+        // and the rotation of the resulting matrix
 
-        this._order.splice(index, 1);
+        var sx = ccw * Math.sqrt(a * a + b * b);
+        var thetaRad = Math.atan2(ccw * b, ccw * a);
+        var theta = 180 / Math.PI * thetaRad;
+        var ct = Math.cos(thetaRad);
+        var st = Math.sin(thetaRad); // We can then solve the y basis vector simultaneously to get the other
+        // two affine parameters directly from these parameters
+
+        var lam = (a * c + b * d) / determinant;
+        var sy = c * sx / (lam * a - b) || d * sx / (lam * b + a); // Use the translations
+
+        var tx = e - cx + cx * ct * sx + cy * (lam * ct * sx - st * sy);
+        var ty = f - cy + cx * st * sx + cy * (lam * st * sx + ct * sy); // Construct the decomposition and return it
+
+        return {
+          // Return the affine parameters
+          scaleX: sx,
+          scaleY: sy,
+          shear: lam,
+          rotate: theta,
+          translateX: tx,
+          translateY: ty,
+          originX: cx,
+          originY: cy,
+          // Return the matrix parameters
+          a: this.a,
+          b: this.b,
+          c: this.c,
+          d: this.d,
+          e: this.e,
+          f: this.f
+        };
+      } // Left multiplies by the given matrix
 
-        runner.timeline(null);
-        return this;
-      }
     }, {
-      key: "play",
-      value: function play() {
-        // Now make sure we are not paused and continue the animation
-        this._paused = false;
-        return this._continue();
+      key: "multiply",
+      value: function multiply(matrix) {
+        return this.clone().multiplyO(matrix);
       }
     }, {
-      key: "pause",
-      value: function pause() {
-        // Cancel the next animation frame and pause
-        this._nextFrame = null;
-        this._paused = true;
-        return this;
+      key: "multiplyO",
+      value: function multiplyO(matrix) {
+        // Get the matrices
+        var l = this;
+        var r = matrix instanceof Matrix ? matrix : new Matrix(matrix);
+        return Matrix.matrixMultiply(l, r, this);
       }
     }, {
-      key: "stop",
-      value: function stop() {
-        // Cancel the next animation frame and go to start
-        this.seek(-this._time);
-        return this.pause();
+      key: "lmultiply",
+      value: function lmultiply(matrix) {
+        return this.clone().lmultiplyO(matrix);
       }
     }, {
-      key: "finish",
-      value: function finish() {
-        this.seek(Infinity);
-        return this.pause();
-      }
+      key: "lmultiplyO",
+      value: function lmultiplyO(matrix) {
+        var r = this;
+        var l = matrix instanceof Matrix ? matrix : new Matrix(matrix);
+        return Matrix.matrixMultiply(l, r, this);
+      } // Inverses matrix
+
     }, {
-      key: "speed",
-      value: function speed(_speed) {
-        if (_speed == null) return this._speed;
-        this._speed = _speed;
+      key: "inverseO",
+      value: function inverseO() {
+        // Get the current parameters out of the matrix
+        var a = this.a;
+        var b = this.b;
+        var c = this.c;
+        var d = this.d;
+        var e = this.e;
+        var f = this.f; // Invert the 2x2 matrix in the top left
+
+        var det = a * d - b * c;
+        if (!det) throw new Error('Cannot invert ' + this); // Calculate the top 2x2 matrix
+
+        var na = d / det;
+        var nb = -b / det;
+        var nc = -c / det;
+        var nd = a / det; // Apply the inverted matrix to the top right
+
+        var ne = -(na * e + nc * f);
+        var nf = -(nb * e + nd * f); // Construct the inverted matrix
+
+        this.a = na;
+        this.b = nb;
+        this.c = nc;
+        this.d = nd;
+        this.e = ne;
+        this.f = nf;
         return this;
       }
     }, {
-      key: "reverse",
-      value: function reverse(yes) {
-        var currentSpeed = this.speed();
-        if (yes == null) return this.speed(-currentSpeed);
-        var positive = Math.abs(currentSpeed);
-        return this.speed(yes ? positive : -positive);
-      }
+      key: "inverse",
+      value: function inverse() {
+        return this.clone().inverseO();
+      } // Translate matrix
+
     }, {
-      key: "seek",
-      value: function seek(dt) {
-        this._time += dt;
-        return this._continue();
+      key: "translate",
+      value: function translate(x, y) {
+        return this.clone().translateO(x, y);
       }
     }, {
-      key: "time",
-      value: function time(_time) {
-        if (_time == null) return this._time;
-        this._time = _time;
+      key: "translateO",
+      value: function translateO(x, y) {
+        this.e += x || 0;
+        this.f += y || 0;
         return this;
+      } // Scale matrix
+
+    }, {
+      key: "scale",
+      value: function scale(x, y, cx, cy) {
+        var _this$clone;
+
+        return (_this$clone = this.clone()).scaleO.apply(_this$clone, arguments);
       }
     }, {
-      key: "persist",
-      value: function persist(dtOrForever) {
-        if (dtOrForever == null) return this._persist;
-        this._persist = dtOrForever;
+      key: "scaleO",
+      value: function scaleO(x) {
+        var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
+        var cx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
+        var cy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
+
+        // Support uniform scaling
+        if (arguments.length === 3) {
+          cy = cx;
+          cx = y;
+          y = x;
+        }
+
+        var a = this.a,
+            b = this.b,
+            c = this.c,
+            d = this.d,
+            e = this.e,
+            f = this.f;
+        this.a = a * x;
+        this.b = b * y;
+        this.c = c * x;
+        this.d = d * y;
+        this.e = e * x - cx * x + cx;
+        this.f = f * y - cy * y + cy;
         return this;
+      } // Rotate matrix
+
+    }, {
+      key: "rotate",
+      value: function rotate(r, cx, cy) {
+        return this.clone().rotateO(r, cx, cy);
       }
     }, {
-      key: "source",
-      value: function source(fn) {
-        if (fn == null) return this._timeSource;
-        this._timeSource = fn;
+      key: "rotateO",
+      value: function rotateO(r) {
+        var cx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
+        var cy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
+        // Convert degrees to radians
+        r = radians(r);
+        var cos = Math.cos(r);
+        var sin = Math.sin(r);
+        var a = this.a,
+            b = this.b,
+            c = this.c,
+            d = this.d,
+            e = this.e,
+            f = this.f;
+        this.a = a * cos - b * sin;
+        this.b = b * cos + a * sin;
+        this.c = c * cos - d * sin;
+        this.d = d * cos + c * sin;
+        this.e = e * cos - f * sin + cy * sin - cx * cos + cx;
+        this.f = f * cos + e * sin - cx * sin - cy * cos + cy;
         return this;
+      } // Flip matrix on x or y, at a given offset
+
+    }, {
+      key: "flip",
+      value: function flip(axis, around) {
+        return this.clone().flipO(axis, around);
       }
     }, {
-      key: "_step",
-      value: function _step() {
-        // If the timeline is paused, just do nothing
-        if (this._paused) return; // Get the time delta from the last time and update the time
-        // TODO: Deal with window.blur window.focus to pause animations
+      key: "flipO",
+      value: function flipO(axis, around) {
+        return axis === 'x' ? this.scaleO(-1, 1, around, 0) : axis === 'y' ? this.scaleO(1, -1, 0, around) : this.scaleO(-1, -1, axis, around || axis); // Define an x, y flip point
+      } // Shear matrix
 
-        var time = this._timeSource();
+    }, {
+      key: "shear",
+      value: function shear(a, cx, cy) {
+        return this.clone().shearO(a, cx, cy);
+      }
+    }, {
+      key: "shearO",
+      value: function shearO(lx) {
+        var cy = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
+        var a = this.a,
+            b = this.b,
+            c = this.c,
+            d = this.d,
+            e = this.e,
+            f = this.f;
+        this.a = a + b * lx;
+        this.c = c + d * lx;
+        this.e = e + f * lx - cy * lx;
+        return this;
+      } // Skew Matrix
 
-        var dtSource = time - this._lastSourceTime;
-        var dtTime = this._speed * dtSource + (this._time - this._lastStepTime);
-        this._lastSourceTime = time; // Update the time
+    }, {
+      key: "skew",
+      value: function skew(x, y, cx, cy) {
+        var _this$clone2;
 
-        this._time += dtTime;
-        this._lastStepTime = this._time; // this.fire('time', this._time)
-        // Run all of the runners directly
+        return (_this$clone2 = this.clone()).skewO.apply(_this$clone2, arguments);
+      }
+    }, {
+      key: "skewO",
+      value: function skewO(x) {
+        var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x;
+        var cx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
+        var cy = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 0;
 
-        var runnersLeft = false;
+        // support uniformal skew
+        if (arguments.length === 3) {
+          cy = cx;
+          cx = y;
+          y = x;
+        } // Convert degrees to radians
 
-        for (var i = 0, len = this._order.length; i < len; i++) {
-          // Get and run the current runner and ignore it if its inactive
-          var runnerInfo = this._runners[this._order[i]];
-          var runner = runnerInfo.runner;
-          var dt = dtTime; // Make sure that we give the actual difference
-          // between runner start time and now
 
-          var dtToStart = this._time - runnerInfo.start; // Dont run runner if not started yet
+        x = radians(x);
+        y = radians(y);
+        var lx = Math.tan(x);
+        var ly = Math.tan(y);
+        var a = this.a,
+            b = this.b,
+            c = this.c,
+            d = this.d,
+            e = this.e,
+            f = this.f;
+        this.a = a + b * lx;
+        this.b = b + a * ly;
+        this.c = c + d * lx;
+        this.d = d + c * ly;
+        this.e = e + f * lx - cy * lx;
+        this.f = f + e * ly - cx * ly;
+        return this;
+      } // SkewX
 
-          if (dtToStart < 0) {
-            runnersLeft = true;
-            continue;
-          } else if (dtToStart < dt) {
-            // Adjust dt to make sure that animation is on point
-            dt = dtToStart;
-          }
-
-          if (!runner.active()) continue; // If this runner is still going, signal that we need another animation
-          // frame, otherwise, remove the completed runner
-
-          var finished = runner.step(dt).done;
+    }, {
+      key: "skewX",
+      value: function skewX(x, cx, cy) {
+        return this.skew(x, 0, cx, cy);
+      }
+    }, {
+      key: "skewXO",
+      value: function skewXO(x, cx, cy) {
+        return this.skewO(x, 0, cx, cy);
+      } // SkewY
 
-          if (!finished) {
-            runnersLeft = true; // continue
-          } else if (runnerInfo.persist !== true) {
-            // runner is finished. And runner might get removed
-            // TODO: Figure out end time of runner
-            var endTime = runner.duration() - runner.time() + this._time;
+    }, {
+      key: "skewY",
+      value: function skewY(y, cx, cy) {
+        return this.skew(0, y, cx, cy);
+      }
+    }, {
+      key: "skewYO",
+      value: function skewYO(y, cx, cy) {
+        return this.skewO(0, y, cx, cy);
+      } // Transform around a center point
 
-            if (endTime + this._persist < this._time) {
-              // Delete runner and correct index
-              delete this._runners[this._order[i]];
-              this._order.splice(i--, 1) && --len;
-              runner.timeline(null);
-            }
-          }
-        } // Get the next animation frame to keep the simulation going
+    }, {
+      key: "aroundO",
+      value: function aroundO(cx, cy, matrix) {
+        var dx = cx || 0;
+        var dy = cy || 0;
+        return this.translateO(-dx, -dy).lmultiplyO(matrix).translateO(dx, dy);
+      }
+    }, {
+      key: "around",
+      value: function around(cx, cy, matrix) {
+        return this.clone().aroundO(cx, cy, matrix);
+      } // Convert to native SVGMatrix
 
+    }, {
+      key: "native",
+      value: function native() {
+        // create new matrix
+        var matrix = parser().node.createSVGMatrix(); // update with current values
 
-        if (runnersLeft) {
-          this._nextFrame = Animator.frame(this._step.bind(this));
-        } else {
-          this._nextFrame = null;
+        for (var i = abcdef.length - 1; i >= 0; i--) {
+          matrix[abcdef[i]] = this[abcdef[i]];
         }
 
-        return this;
-      } // Checks if we are running and continues the animation
+        return matrix;
+      } // Check if two matrices are equal
 
     }, {
-      key: "_continue",
-      value: function _continue() {
-        if (this._paused) return this;
-
-        if (!this._nextFrame) {
-          this._nextFrame = Animator.frame(this._step.bind(this));
-        }
+      key: "equals",
+      value: function equals(other) {
+        var comp = new Matrix(other);
+        return closeEnough(this.a, comp.a) && closeEnough(this.b, comp.b) && closeEnough(this.c, comp.c) && closeEnough(this.d, comp.d) && closeEnough(this.e, comp.e) && closeEnough(this.f, comp.f);
+      } // Convert matrix to string
 
-        return this;
+    }, {
+      key: "toString",
+      value: function toString() {
+        return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')';
       }
     }, {
-      key: "active",
-      value: function active() {
-        return !!this._nextFrame;
+      key: "toArray",
+      value: function toArray() {
+        return [this.a, this.b, this.c, this.d, this.e, this.f];
+      }
+    }, {
+      key: "valueOf",
+      value: function valueOf() {
+        return {
+          a: this.a,
+          b: this.b,
+          c: this.c,
+          d: this.d,
+          e: this.e,
+          f: this.f
+        };
+      } // TODO: Refactor this to a static function of matrix.js
+
+    }], [{
+      key: "formatTransforms",
+      value: function formatTransforms(o) {
+        // Get all of the parameters required to form the matrix
+        var flipBoth = o.flip === 'both' || o.flip === true;
+        var flipX = o.flip && (flipBoth || o.flip === 'x') ? -1 : 1;
+        var flipY = o.flip && (flipBoth || o.flip === 'y') ? -1 : 1;
+        var skewX = o.skew && o.skew.length ? o.skew[0] : isFinite(o.skew) ? o.skew : isFinite(o.skewX) ? o.skewX : 0;
+        var skewY = o.skew && o.skew.length ? o.skew[1] : isFinite(o.skew) ? o.skew : isFinite(o.skewY) ? o.skewY : 0;
+        var scaleX = o.scale && o.scale.length ? o.scale[0] * flipX : isFinite(o.scale) ? o.scale * flipX : isFinite(o.scaleX) ? o.scaleX * flipX : flipX;
+        var scaleY = o.scale && o.scale.length ? o.scale[1] * flipY : isFinite(o.scale) ? o.scale * flipY : isFinite(o.scaleY) ? o.scaleY * flipY : flipY;
+        var shear = o.shear || 0;
+        var theta = o.rotate || o.theta || 0;
+        var origin = new Point(o.origin || o.around || o.ox || o.originX, o.oy || o.originY);
+        var ox = origin.x;
+        var oy = origin.y;
+        var position = new Point(o.position || o.px || o.positionX, o.py || o.positionY);
+        var px = position.x;
+        var py = position.y;
+        var translate = new Point(o.translate || o.tx || o.translateX, o.ty || o.translateY);
+        var tx = translate.x;
+        var ty = translate.y;
+        var relative = new Point(o.relative || o.rx || o.relativeX, o.ry || o.relativeY);
+        var rx = relative.x;
+        var ry = relative.y; // Populate all of the values
+
+        return {
+          scaleX: scaleX,
+          scaleY: scaleY,
+          skewX: skewX,
+          skewY: skewY,
+          shear: shear,
+          theta: theta,
+          rx: rx,
+          ry: ry,
+          tx: tx,
+          ty: ty,
+          ox: ox,
+          oy: oy,
+          px: px,
+          py: py
+        };
+      } // left matrix, right matrix, target matrix which is overwritten
+
+    }, {
+      key: "matrixMultiply",
+      value: function matrixMultiply(l, r, o) {
+        // Work out the product directly
+        var a = l.a * r.a + l.c * r.b;
+        var b = l.b * r.a + l.d * r.b;
+        var c = l.a * r.c + l.c * r.d;
+        var d = l.b * r.c + l.d * r.d;
+        var e = l.e + l.a * r.e + l.c * r.f;
+        var f = l.f + l.b * r.e + l.d * r.f; // make sure to use local variables because l/r and o could be the same
+
+        o.a = a;
+        o.b = b;
+        o.c = c;
+        o.d = d;
+        o.e = e;
+        o.f = f;
+        return o;
       }
     }]);
 
-    return Timeline;
+    return Matrix;
   }();
-  Timeline.constructors = {
+  registerMethods({
     Element: {
-      timeline: function timeline() {
-        this._timeline = this._timeline || new Timeline();
-        return this._timeline;
+      // Get current matrix
+      ctm: function ctm() {
+        return new Matrix(this.node.getCTM());
+      },
+      // Get current screen matrix
+      screenCTM: function screenCTM() {
+        /* https://bugzilla.mozilla.org/show_bug.cgi?id=1344537\r
+           This is needed because FF does not return the transformation matrix\r
+           for the inner coordinate system when getScreenCTM() is called on nested svgs.\r
+           However all other Browsers do that */
+        if (this instanceof Doc && !this.isRoot()) {
+          var rect = this.rect(1, 1);
+          var m = rect.node.getScreenCTM();
+          rect.remove();
+          return new Matrix(m);
+        }
+
+        return new Matrix(this.node.getScreenCTM());
       }
     }
-  };
-
-  // easing = {
-  //   '-': function (pos) { return pos },
-  //   '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
-  //   '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
-  //   '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 }
-  // }
+  });
 
-  var Runner =
+  var Box$1 =
   /*#__PURE__*/
   function () {
-    function Runner(options) {
-      _classCallCheck(this, Runner);
-
-      // Store a unique id on the runner, so that we can identify it later
-      this.id = Runner.id++; // Ensure a default value
-
-      options = options == null ? timeline.duration : options; // Ensure that we get a controller
-
-      options = typeof options === 'function' ? new Controller(options) : options; // Declare all of the variables
-
-      this._element = null;
-      this._timeline = null;
-      this.done = false;
-      this._queue = []; // Work out the stepper and the duration
-
-      this._duration = typeof options === 'number' && options;
-      this._isDeclarative = options instanceof Controller;
-      this._stepper = this._isDeclarative ? options : new Ease(); // We copy the current values from the timeline because they can change
-
-      this._history = {}; // Store the state of the runner
-
-      this.enabled = true;
-      this._time = 0;
-      this._last = 0; // Save transforms applied to this runner
-
-      this.transforms = new Matrix();
-      this.transformId = 1; // Looping variables
+    function Box() {
+      _classCallCheck(this, Box);
 
-      this._haveReversed = false;
-      this._reverse = false;
-      this._loopsDone = 0;
-      this._swing = false;
-      this._wait = 0;
-      this._times = 1;
+      this.init.apply(this, arguments);
     }
-    /*\r
-    Runner Definitions\r
-    ==================\r
-    These methods help us define the runtime behaviour of the Runner or they\r
-    help us make new runners from the current runner\r
-    */
-
 
-    _createClass(Runner, [{
-      key: "element",
-      value: function element(_element) {
-        if (_element == null) return this._element;
-        this._element = _element;
+    _createClass(Box, [{
+      key: "init",
+      value: function init(source) {
+        var base = [0, 0, 0, 0];
+        source = typeof source === 'string' ? source.split(delimiter).map(parseFloat) : Array.isArray(source) ? source : _typeof(source) === 'object' ? [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] : arguments.length === 4 ? [].slice.call(arguments) : base;
+        this.x = source[0];
+        this.y = source[1];
+        this.width = source[2];
+        this.height = source[3]; // add center, right, bottom...
 
-        _element._prepareRunner();
+        fullBox(this);
+      } // Merge rect box with another, return a new instance
 
-        return this;
-      }
-    }, {
-      key: "timeline",
-      value: function timeline$$1(_timeline) {
-        // check explicitly for undefined so we can set the timeline to null
-        if (typeof _timeline === 'undefined') return this._timeline;
-        this._timeline = _timeline;
-        return this;
-      }
     }, {
-      key: "animate",
-      value: function animate(duration, delay, when) {
-        var o = Runner.sanitise(duration, delay, when);
-        var runner = new Runner(o.duration);
-        if (this._timeline) runner.timeline(this._timeline);
-        if (this._element) runner.element(this._element);
-        return runner.loop(o).schedule(delay, when);
+      key: "merge",
+      value: function merge(box) {
+        var x = Math.min(this.x, box.x);
+        var y = Math.min(this.y, box.y);
+        var width = Math.max(this.x + this.width, box.x + box.width) - x;
+        var height = Math.max(this.y + this.height, box.y + box.height) - y;
+        return new Box(x, y, width, height);
       }
     }, {
-      key: "schedule",
-      value: function schedule(timeline$$1, delay, when) {
-        // The user doesn't need to pass a timeline if we already have one
-        if (!(timeline$$1 instanceof Timeline)) {
-          when = delay;
-          delay = timeline$$1;
-          timeline$$1 = this.timeline();
-        } // If there is no timeline, yell at the user...
-
-
-        if (!timeline$$1) {
-          throw Error('Runner cannot be scheduled without timeline');
-        } // Schedule the runner on the timeline provided
-
-
-        timeline$$1.schedule(this, delay, when);
-        return this;
+      key: "transform",
+      value: function transform(m) {
+        var xMin = Infinity;
+        var xMax = -Infinity;
+        var yMin = Infinity;
+        var yMax = -Infinity;
+        var pts = [new Point(this.x, this.y), new Point(this.x2, this.y), new Point(this.x, this.y2), new Point(this.x2, this.y2)];
+        pts.forEach(function (p) {
+          p = p.transform(m);
+          xMin = Math.min(xMin, p.x);
+          xMax = Math.max(xMax, p.x);
+          yMin = Math.min(yMin, p.y);
+          yMax = Math.max(yMax, p.y);
+        });
+        return new Box(xMin, yMin, xMax - xMin, yMax - yMin);
       }
     }, {
-      key: "unschedule",
-      value: function unschedule() {
-        var timeline$$1 = this.timeline();
-        timeline$$1 && timeline$$1.unschedule(this);
+      key: "addOffset",
+      value: function addOffset() {
+        // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
+        this.x += window.pageXOffset;
+        this.y += window.pageYOffset;
         return this;
       }
     }, {
-      key: "loop",
-      value: function loop(times, swing, wait) {
-        // Deal with the user passing in an object
-        if (_typeof(times) === 'object') {
-          swing = times.swing;
-          wait = times.wait;
-          times = times.times;
-        } // Sanitise the values and store them
-
-
-        this._times = times || Infinity;
-        this._swing = swing || false;
-        this._wait = wait || 0;
-        return this;
+      key: "toString",
+      value: function toString() {
+        return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height;
       }
     }, {
-      key: "delay",
-      value: function delay(_delay) {
-        return this.animate(0, _delay);
+      key: "toArray",
+      value: function toArray() {
+        return [this.x, this.y, this.width, this.height];
       }
-      /*\r
-      Basic Functionality\r
-      ===================\r
-      These methods allow us to attach basic functions to the runner directly\r
-      */
+    }]);
 
-    }, {
-      key: "queue",
-      value: function queue(initFn, runFn, isTransform) {
-        this._queue.push({
-          initialiser: initFn || noop,
-          runner: runFn || noop,
-          isTransform: isTransform,
-          initialised: false,
-          finished: false
-        });
+    return Box;
+  }();
 
-        var timeline$$1 = this.timeline();
-        timeline$$1 && this.timeline()._continue();
-        return this;
-      }
-    }, {
-      key: "during",
-      value: function during(fn) {
-        return this.queue(null, fn);
-      }
-    }, {
-      key: "after",
-      value: function after(fn) {
-        return this.on('finish', fn);
-      }
-      /*\r
-      Runner animation methods\r
-      ========================\r
-      Control how the animation plays\r
-      */
+  function getBox(cb) {
+    var box;
 
-    }, {
-      key: "time",
-      value: function time(_time) {
-        if (_time == null) {
-          return this._time;
-        }
+    try {
+      box = cb(this.node);
 
-        var dt = _time - this._time;
-        this.step(dt);
-        return this;
+      if (isNulledBox(box) && !domContains(this.node)) {
+        throw new Error('Element not in the dom');
       }
-    }, {
-      key: "duration",
-      value: function duration() {
-        return this._times * (this._wait + this._duration) - this._wait;
+    } catch (e) {
+      try {
+        var clone = this.clone(parser().svg).show();
+        box = cb(clone.node);
+        clone.remove();
+      } catch (e) {
+        throw e;
+        console.warn('Getting a bounding box of this element is not possible');
       }
-    }, {
-      key: "loops",
-      value: function loops(p) {
-        var loopDuration = this._duration + this._wait;
+    }
 
-        if (p == null) {
-          var loopsDone = Math.floor(this._time / loopDuration);
-          var relativeTime = this._time - loopsDone * loopDuration;
-          var position = relativeTime / this._duration;
-          return Math.min(loopsDone + position, this._times);
-        }
+    return box;
+  }
 
-        var whole = Math.floor(p);
-        var partial = p % 1;
-        var time = loopDuration * whole + this._duration * partial;
-        return this.time(time);
+  registerMethods({
+    Element: {
+      // Get bounding box
+      bbox: function bbox() {
+        return new Box$1(getBox.call(this, function (node) {
+          return node.getBBox();
+        }));
+      },
+      rbox: function rbox(el) {
+        var box = new Box$1(getBox.call(this, function (node) {
+          return node.getBoundingClientRect();
+        }));
+        if (el) return box.transform(el.screenCTM().inverse());
+        return box.addOffset();
       }
-    }, {
-      key: "position",
-      value: function position(p) {
-        // Get all of the variables we need
-        var x = this._time;
-        var d = this._duration;
-        var w = this._wait;
-        var t = this._times;
-        var s = this._swing;
-        var r = this._reverse;
-        var position;
-
-        if (p == null) {
-          /*\r
-          This function converts a time to a position in the range [0, 1]\r
-          The full explanation can be found in this desmos demonstration\r
-            https://www.desmos.com/calculator/u4fbavgche\r
-          The logic is slightly simplified here because we can use booleans\r
-          */
-          // Figure out the value without thinking about the start or end time
-          var f = function f(x) {
-            var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d));
-            var backwards = swinging && !r || !swinging && r;
-            var uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards;
-            var clipped = Math.max(Math.min(uncliped, 1), 0);
-            return clipped;
-          }; // Figure out the value by incorporating the start time
-
+    },
+    viewbox: function viewbox(x, y, width, height) {
+      // act as getter
+      if (x == null) return new Box$1(this.attr('viewBox')); // act as setter
 
-          var endTime = t * (w + d) - w;
-          position = x <= 0 ? Math.round(f(1e-5)) : x < endTime ? f(x) : Math.round(f(endTime - 1e-5));
-          return position;
-        } // Work out the loops done and add the position to the loops done
+      return this.attr('viewBox', new Box$1(x, y, width, height));
+    }
+  });
 
+  /***\r
+  Base Class\r
+  ==========\r
+  The base stepper class that will be\r
+  ***/
 
-        var loopsDone = Math.floor(this.loops());
-        var swingForward = s && loopsDone % 2 === 0;
-        var forwards = swingForward && !r || r && swingForward;
-        position = loopsDone + (forwards ? p : 1 - p);
-        return this.loops(position);
-      }
-    }, {
-      key: "progress",
-      value: function progress(p) {
-        if (p == null) {
-          return Math.min(1, this._time / this.duration());
-        }
+  function makeSetterGetter(k, f) {
+    return function (v) {
+      if (v == null) return this[v];
+      this[k] = v;
+      if (f) f.call(this);
+      return this;
+    };
+  }
 
-        return this.time(p * this.duration());
-      }
-    }, {
-      key: "step",
-      value: function step(dt) {
-        // If we are inactive, this stepper just gets skipped
-        if (!this.enabled) return this; // Update the time and get the new position
+  var easing = {
+    '-': function _(pos) {
+      return pos;
+    },
+    '<>': function _(pos) {
+      return -Math.cos(pos * Math.PI) / 2 + 0.5;
+    },
+    '>': function _(pos) {
+      return Math.sin(pos * Math.PI / 2);
+    },
+    '<': function _(pos) {
+      return -Math.cos(pos * Math.PI / 2) + 1;
+    },
+    bezier: function bezier(t0, x0, t1, x1) {
+      return function (t) {// TODO: FINISH
+      };
+    }
+  };
+  var Stepper =
+  /*#__PURE__*/
+  function () {
+    function Stepper() {
+      _classCallCheck(this, Stepper);
+    }
 
-        dt = dt == null ? 16 : dt;
-        this._time += dt;
-        var position = this.position(); // Figure out if we need to run the stepper in this frame
+    _createClass(Stepper, [{
+      key: "done",
+      value: function done() {
+        return false;
+      }
+    }]);
 
-        var running = this._lastPosition !== position && this._time >= 0;
-        this._lastPosition = position; // Figure out if we just started
+    return Stepper;
+  }();
+  /***\r
+  Easing Functions\r
+  ================\r
+  ***/
 
-        var duration = this.duration();
-        var justStarted = this._lastTime < 0 && this._time > 0;
-        var justFinished = this._lastTime < this._time && this.time > duration;
-        this._lastTime = this._time;
-        // Work out if the runner is finished set the done flag here so animations
-        // know, that they are running in the last step (this is good for
-        // transformations which can be merged)
+  var Ease =
+  /*#__PURE__*/
+  function (_Stepper) {
+    _inherits(Ease, _Stepper);
 
+    function Ease(fn) {
+      var _this;
 
-        var declarative = this._isDeclarative;
-        this.done = !declarative && !justFinished && this._time >= duration; // Call initialise and the run function
+      _classCallCheck(this, Ease);
 
-        if (running || declarative) {
-          this._initialise(running); // clear the transforms on this runner so they dont get added again and again
+      _this = _possibleConstructorReturn(this, _getPrototypeOf(Ease).call(this));
+      _this.ease = easing[fn || timeline.ease] || fn;
+      return _this;
+    }
+
+    _createClass(Ease, [{
+      key: "step",
+      value: function step(from, to, pos) {
+        if (typeof from !== 'number') {
+          return pos < 1 ? from : to;
+        }
 
+        return from + (to - from) * this.ease(pos);
+      }
+    }]);
 
-          this.transforms = new Matrix();
+    return Ease;
+  }(Stepper);
+  /***\r
+  Controller Types\r
+  ================\r
+  ***/
 
-          var converged = this._run(declarative ? dt : position); // this.fire('step', this)
+  var Controller =
+  /*#__PURE__*/
+  function (_Stepper2) {
+    _inherits(Controller, _Stepper2);
 
-        } // correct the done flag here
-        // declaritive animations itself know when they converged
+    function Controller(fn) {
+      var _this2;
 
+      _classCallCheck(this, Controller);
 
-        this.done = this.done || converged && declarative; // if (this.done) {
-        //   this.fire('finish', this)
-        // }
+      _this2 = _possibleConstructorReturn(this, _getPrototypeOf(Controller).call(this));
+      _this2.stepper = fn;
+      return _this2;
+    }
 
-        return this;
-      }
-    }, {
-      key: "finish",
-      value: function finish() {
-        return this.step(Infinity);
-      }
-    }, {
-      key: "reverse",
-      value: function reverse(_reverse) {
-        this._reverse = _reverse == null ? !this._reverse : _reverse;
-        return this;
-      }
-    }, {
-      key: "ease",
-      value: function ease(fn) {
-        this._stepper = new Ease(fn);
-        return this;
+    _createClass(Controller, [{
+      key: "step",
+      value: function step(current, target, dt, c) {
+        return this.stepper(current, target, dt, c);
       }
     }, {
-      key: "active",
-      value: function active(enabled) {
-        if (enabled == null) return this.enabled;
-        this.enabled = enabled;
-        return this;
+      key: "done",
+      value: function done(c) {
+        return c.done;
       }
-      /*\r
-      Private Methods\r
-      ===============\r
-      Methods that shouldn't be used externally\r
-      */
-      // Save a morpher to the morpher list so that we can retarget it later
+    }]);
 
-    }, {
-      key: "_rememberMorpher",
-      value: function _rememberMorpher(method, morpher) {
-        this._history[method] = {
-          morpher: morpher,
-          caller: this._queue[this._queue.length - 1]
-        };
-      } // Try to set the target for a morpher if the morpher exists, otherwise
-      // do nothing and return false
+    return Controller;
+  }(Stepper);
 
-    }, {
-      key: "_tryRetarget",
-      value: function _tryRetarget(method, target) {
-        if (this._history[method]) {
-          // if the last method wasnt even initialised, throw it away
-          if (!this._history[method].caller.initialised) {
-            var index = this._queue.indexOf(this._history[method].caller);
+  function recalculate() {
+    // Apply the default parameters
+    var duration = (this._duration || 500) / 1000;
+    var overshoot = this._overshoot || 0; // Calculate the PID natural response
 
-            this._queue.splice(index, 1);
+    var eps = 1e-10;
+    var pi = Math.PI;
+    var os = Math.log(overshoot / 100 + eps);
+    var zeta = -os / Math.sqrt(pi * pi + os * os);
+    var wn = 3.9 / (zeta * duration); // Calculate the Spring values
 
-            return false;
-          } // for the case of transformations, we use the special retarget function
-          // which has access to the outer scope
+    this.d = 2 * zeta * wn;
+    this.k = wn * wn;
+  }
 
+  var Spring =
+  /*#__PURE__*/
+  function (_Controller) {
+    _inherits(Spring, _Controller);
 
-          if (this._history[method].caller.isTransform) {
-            this._history[method].caller.isTransform(target); // for everything else a simple morpher change is sufficient
+    function Spring(duration, overshoot) {
+      var _this3;
 
-          } else {
-            this._history[method].morpher.to(target);
-          }
+      _classCallCheck(this, Spring);
 
-          this._history[method].caller.finished = false;
-          var timeline$$1 = this.timeline();
-          timeline$$1 && timeline$$1._continue();
-          return true;
-        }
+      _this3 = _possibleConstructorReturn(this, _getPrototypeOf(Spring).call(this));
 
-        return false;
-      } // Run each initialise function in the runner if required
+      _this3.duration(duration || 500).overshoot(overshoot || 0);
 
-    }, {
-      key: "_initialise",
-      value: function _initialise(running) {
-        // If we aren't running, we shouldn't initialise when not declarative
-        if (!running && !this._isDeclarative) return; // Loop through all of the initialisers
+      return _this3;
+    }
 
-        for (var i = 0, len = this._queue.length; i < len; ++i) {
-          // Get the current initialiser
-          var current = this._queue[i]; // Determine whether we need to initialise
+    _createClass(Spring, [{
+      key: "step",
+      value: function step(current, target, dt, c) {
+        if (typeof current === 'string') return current;
+        c.done = dt === Infinity;
+        if (dt === Infinity) return target;
+        if (dt === 0) return current;
+        if (dt > 100) dt = 16;
+        dt /= 1000; // Get the previous velocity
 
-          var needsIt = this._isDeclarative || !current.initialised && running;
-          running = !current.finished; // Call the initialiser if we need to
+        var velocity = c.velocity || 0; // Apply the control to get the new position and store it
 
-          if (needsIt && running) {
-            current.initialiser.call(this);
-            current.initialised = true;
-          }
-        }
-      } // Run each run function for the position or dt given
+        var acceleration = -this.d * velocity - this.k * (current - target);
+        var newPosition = current + velocity * dt + acceleration * dt * dt / 2; // Store the velocity
 
-    }, {
-      key: "_run",
-      value: function _run(positionOrDt) {
-        // Run all of the _queue directly
-        var allfinished = true;
+        c.velocity = velocity + acceleration * dt; // Figure out if we have converged, and if so, pass the value
 
-        for (var i = 0, len = this._queue.length; i < len; ++i) {
-          // Get the current function to run
-          var current = this._queue[i]; // Run the function if its not finished, we keep track of the finished
-          // flag for the sake of declarative _queue
+        c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002;
+        return c.done ? target : newPosition;
+      }
+    }]);
 
-          var converged = current.runner.call(this, positionOrDt);
-          current.finished = current.finished || converged === true;
-          allfinished = allfinished && current.finished;
-        } // We report when all of the constructors are finished
+    return Spring;
+  }(Controller);
+  extend$1(Spring, {
+    duration: makeSetterGetter('_duration', recalculate),
+    overshoot: makeSetterGetter('_overshoot', recalculate)
+  });
+  var PID =
+  /*#__PURE__*/
+  function (_Controller2) {
+    _inherits(PID, _Controller2);
 
+    function PID(p, i, d, windup) {
+      var _this4;
 
-        return allfinished;
-      }
-    }, {
-      key: "addTransform",
-      value: function addTransform(transform, index) {
-        this.transforms.lmultiplyO(transform);
-        return this;
-      }
-    }, {
-      key: "clearTransform",
-      value: function clearTransform() {
-        this.transforms = new Matrix();
-        return this;
-      }
-    }], [{
-      key: "sanitise",
-      value: function sanitise(duration, delay, when) {
-        // Initialise the default parameters
-        var times = 1;
-        var swing = false;
-        var wait = 0;
-        duration = duration || timeline.duration;
-        delay = delay || timeline.delay;
-        when = when || 'last'; // If we have an object, unpack the values
-
-        if (_typeof(duration) === 'object' && !(duration instanceof Stepper)) {
-          delay = duration.delay || delay;
-          when = duration.when || when;
-          swing = duration.swing || swing;
-          times = duration.times || times;
-          wait = duration.wait || wait;
-          duration = duration.duration || timeline.duration;
-        }
-
-        return {
-          duration: duration,
-          delay: delay,
-          swing: swing,
-          times: times,
-          wait: wait,
-          when: when
-        };
-      }
-    }]);
-
-    return Runner;
-  }();
-  Runner.id = 0;
-
-  var FakeRunner = function FakeRunner() {
-    var transforms = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Matrix();
-    var id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
-    var done = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
+      _classCallCheck(this, PID);
 
-    _classCallCheck(this, FakeRunner);
+      _this4 = _possibleConstructorReturn(this, _getPrototypeOf(PID).call(this));
+      p = p == null ? 0.1 : p;
+      i = i == null ? 0.01 : i;
+      d = d == null ? 0 : d;
+      windup = windup == null ? 1000 : windup;
 
-    this.transforms = transforms;
-    this.id = id;
-    this.done = done;
-  };
+      _this4.p(p).i(i).d(d).windup(windup);
 
-  extend$1([Runner, FakeRunner], {
-    mergeWith: function mergeWith(runner) {
-      return new FakeRunner(runner.transforms.lmultiply(this.transforms), runner.id);
+      return _this4;
     }
-  }); // FakeRunner.emptyRunner = new FakeRunner()
-
-  var lmultiply = function lmultiply(last, curr) {
-    return last.lmultiplyO(curr);
-  };
 
-  var getRunnerTransform = function getRunnerTransform(runner) {
-    return runner.transforms;
-  };
+    _createClass(PID, [{
+      key: "step",
+      value: function step(current, target, dt, c) {
+        if (typeof current === 'string') return current;
+        c.done = dt === Infinity;
+        if (dt === Infinity) return target;
+        if (dt === 0) return current;
+        var p = target - current;
+        var i = (c.integral || 0) + p * dt;
+        var d = (p - (c.error || 0)) / dt;
+        var windup = this.windup; // antiwindup
 
-  function mergeTransforms() {
-    // Find the matrix to apply to the element and apply it
-    var runners = this._transformationRunners.runners;
-    var netTransform = runners.map(getRunnerTransform).reduce(lmultiply, new Matrix());
-    this.transform(netTransform);
+        if (windup !== false) {
+          i = Math.max(-windup, Math.min(i, windup));
+        }
 
-    this._transformationRunners.merge();
+        c.error = p;
+        c.integral = i;
+        c.done = Math.abs(p) < 0.001;
+        return c.done ? target : current + (this.P * p + this.I * i + this.D * d);
+      }
+    }]);
 
-    if (this._transformationRunners.length() === 1) {
-      this._frameId = null;
-    }
-  }
+    return PID;
+  }(Controller);
+  extend$1(PID, {
+    windup: makeSetterGetter('windup'),
+    p: makeSetterGetter('P'),
+    i: makeSetterGetter('I'),
+    d: makeSetterGetter('D')
+  });
 
-  var RunnerArray =
+  var Morphable =
   /*#__PURE__*/
   function () {
-    function RunnerArray() {
-      _classCallCheck(this, RunnerArray);
+    function Morphable(stepper) {
+      _classCallCheck(this, Morphable);
 
-      this.runners = [];
-      this.ids = [];
+      // FIXME: the default stepper does not know about easing
+      this._stepper = stepper || new Ease('-');
+      this._from = null;
+      this._to = null;
+      this._type = null;
+      this._context = null;
+      this._morphObj = null;
     }
 
-    _createClass(RunnerArray, [{
-      key: "add",
-      value: function add(runner) {
-        if (this.runners.includes(runner)) return;
-        var id = runner.id + 1;
-        var leftSibling = this.ids.reduce(function (last, curr) {
-          if (curr > last && curr < id) return curr;
-          return last;
-        }, 0);
-        var index = this.ids.indexOf(leftSibling) + 1;
-        this.ids.splice(index, 0, id);
-        this.runners.splice(index, 0, runner);
+    _createClass(Morphable, [{
+      key: "from",
+      value: function from(val) {
+        if (val == null) {
+          return this._from;
+        }
+
+        this._from = this._set(val);
         return this;
       }
     }, {
-      key: "getByID",
-      value: function getByID(id) {
-        return this.runners[this.ids.indexOf(id + 1)];
+      key: "to",
+      value: function to(val) {
+        if (val == null) {
+          return this._to;
+        }
+
+        this._to = this._set(val);
+        return this;
       }
     }, {
-      key: "remove",
-      value: function remove(id) {
-        var index = this.ids.indexOf(id + 1);
-        this.ids.splice(index, 1);
-        this.runners.splice(index, 1);
+      key: "type",
+      value: function type(_type) {
+        // getter
+        if (_type == null) {
+          return this._type;
+        } // setter
+
+
+        this._type = _type;
         return this;
       }
     }, {
-      key: "merge",
-      value: function merge() {
-        var _this = this;
-
-        var lastRunner = null;
-        this.runners.forEach(function (runner, i) {
-          if (lastRunner && runner.done && lastRunner.done) {
-            _this.remove(runner.id);
+      key: "_set",
+      value: function _set$$1(value) {
+        if (!this._type) {
+          var type = _typeof(value);
 
-            _this.edit(lastRunner.id, runner.mergeWith(lastRunner));
+          if (type === 'number') {
+            this.type(SVGNumber);
+          } else if (type === 'string') {
+            if (Color.isColor(value)) {
+              this.type(Color);
+            } else if (regex.delimiter.test(value)) {
+              this.type(regex.pathLetters.test(value) ? PathArray : SVGArray);
+            } else if (regex.numberAndUnit.test(value)) {
+              this.type(SVGNumber);
+            } else {
+              this.type(Morphable.NonMorphable);
+            }
+          } else if (MorphableTypes.indexOf(value.constructor) > -1) {
+            this.type(value.constructor);
+          } else if (Array.isArray(value)) {
+            this.type(SVGArray);
+          } else if (type === 'object') {
+            this.type(Morphable.ObjectBag);
+          } else {
+            this.type(Morphable.NonMorphable);
           }
+        }
 
-          lastRunner = runner;
-        });
-        return this;
+        var result = new this._type(value).toArray();
+        this._morphObj = this._morphObj || new this._type();
+        this._context = this._context || Array.apply(null, Array(result.length)).map(Object);
+        return result;
       }
     }, {
-      key: "edit",
-      value: function edit(id, newRunner) {
-        var index = this.ids.indexOf(id + 1);
-        this.ids.splice(index, 1, id);
-        this.runners.splice(index, 1, newRunner);
+      key: "stepper",
+      value: function stepper(_stepper) {
+        if (_stepper == null) return this._stepper;
+        this._stepper = _stepper;
         return this;
       }
     }, {
-      key: "length",
-      value: function length() {
-        return this.ids.length;
+      key: "done",
+      value: function done() {
+        var complete = this._context.map(this._stepper.done).reduce(function (last, curr) {
+          return last && curr;
+        }, true);
+
+        return complete;
       }
     }, {
-      key: "clearBefore",
-      value: function clearBefore(id) {
-        var deleteCnt = this.ids.indexOf(id + 1) || 1;
-        this.ids.splice(0, deleteCnt, 0);
-        this.runners.splice(0, deleteCnt, new FakeRunner());
-        return this;
+      key: "at",
+      value: function at(pos) {
+        var _this = this;
+
+        return this._morphObj.fromArray(this._from.map(function (i, index) {
+          return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context);
+        }));
       }
     }]);
 
-    return RunnerArray;
+    return Morphable;
   }();
 
-  var frameId = 0;
-  Runner.constructors = {
-    Element: {
-      animate: function animate(duration, delay, when) {
-        var o = Runner.sanitise(duration, delay, when);
-        var timeline$$1 = this.timeline();
-        return new Runner(o.duration).loop(o).element(this).timeline(timeline$$1).schedule(delay, when);
-      },
-      delay: function delay(by, when) {
-        return this.animate(0, by, when);
-      },
-      // this function searches for all runners on the element and deletes the ones
-      // which run before the current one. This is because absolute transformations
-      // overwfrite anything anyway so there is no need to waste time computing
-      // other runners
-      _clearTransformRunnersBefore: function _clearTransformRunnersBefore(currentRunner) {
-        this._transformationRunners.clearBefore(currentRunner.id);
-      },
-      _currentTransform: function _currentTransform(current) {
-        return this._transformationRunners.runners // we need the equal sign here to make sure, that also transformations
-        // on the same runner which execute before the current transformation are
-        // taken into account
-        .filter(function (runner) {
-          return runner.id <= current.id;
-        }).map(getRunnerTransform).reduce(lmultiply, new Matrix());
-      },
-      addRunner: function addRunner(runner) {
-        this._transformationRunners.add(runner);
+  Morphable.NonMorphable =
+  /*#__PURE__*/
+  function () {
+    function _class() {
+      _classCallCheck(this, _class);
 
-        Animator.transform_frame(mergeTransforms.bind(this), this._frameId);
-      },
-      _prepareRunner: function _prepareRunner() {
-        if (this._frameId == null) {
-          this._transformationRunners = new RunnerArray().add(new FakeRunner(new Matrix(this)));
-          this._frameId = frameId++;
-        }
-      }
+      this.init.apply(this, arguments);
     }
-  };
-  extend$1(Runner, {
-    attr: function attr(a, v) {
-      return this.styleAttr('attr', a, v);
-    },
-    // Add animatable styles
-    css: function css(s, v) {
-      return this.styleAttr('css', s, v);
-    },
-    styleAttr: function styleAttr(type, name, val) {
-      // apply attributes individually
-      if (_typeof(name) === 'object') {
-        for (var key in val) {
-          this.styleAttr(type, key, val[key]);
-        }
-      }
-
-      var morpher = new Morphable(this._stepper).to(val);
-      this.queue(function () {
-        morpher = morpher.from(this.element()[type](name));
-      }, function (pos) {
-        this.element()[type](name, morpher.at(pos));
-        return morpher.done();
-      });
-      return this;
-    },
-    zoom: function zoom(level, point) {
-      var morpher = new Morphable(this._stepper).to(new SVGNumber(level));
-      this.queue(function () {
-        morpher = morpher.from(this.zoom());
-      }, function (pos) {
-        this.element().zoom(morpher.at(pos), point);
-        return morpher.done();
-      });
-      return this;
-    },
 
-    /**\r
-     ** absolute transformations\r
-     **/
-    //
-    // M v -----|-----(D M v = F v)------|----->  T v
-    //
-    // 1. define the final state (T) and decompose it (once)
-    //    t = [tx, ty, the, lam, sy, sx]
-    // 2. on every frame: pull the current state of all previous transforms
-    //    (M - m can change)
-    //   and then write this as m = [tx0, ty0, the0, lam0, sy0, sx0]
-    // 3. Find the interpolated matrix F(pos) = m + pos * (t - m)
-    //   - Note F(0) = M
-    //   - Note F(1) = T
-    // 4. Now you get the delta matrix as a result: D = F * inv(M)
-    transform: function transform(transforms, relative, affine) {
-      // If we have a declarative function, we should retarget it if possible
-      relative = transforms.relative || relative;
-
-      if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) {
-        return this;
-      } // Parse the parameters
-
-
-      var isMatrix = isMatrixLike(transforms);
-      affine = transforms.affine != null ? transforms.affine : affine != null ? affine : !isMatrix; // Create a morepher and set its type
+    _createClass(_class, [{
+      key: "init",
+      value: function init(val) {
+        val = Array.isArray(val) ? val[0] : val;
+        this.value = val;
+      }
+    }, {
+      key: "valueOf",
+      value: function valueOf() {
+        return this.value;
+      }
+    }, {
+      key: "toArray",
+      value: function toArray() {
+        return [this.value];
+      }
+    }]);
 
-      var morpher = new Morphable().type(affine ? Morphable.TransformBag : Matrix).stepper(this._stepper);
-      var origin;
-      var element;
-      var current;
-      var currentAngle;
-      var startTransform;
+    return _class;
+  }();
 
-      function setup() {
-        // make sure element and origin is defined
-        element = element || this.element();
-        origin = origin || getOrigin(transforms, element);
-        startTransform = new Matrix(relative ? undefined : element); // add the runner to the element so it can merge transformations
+  Morphable.TransformBag =
+  /*#__PURE__*/
+  function () {
+    function _class2() {
+      _classCallCheck(this, _class2);
 
-        element.addRunner(this); // Deactivate all transforms that have run so far if we are absolute
+      this.init.apply(this, arguments);
+    }
 
-        if (!relative) {
-          element._clearTransformRunnersBefore(this);
+    _createClass(_class2, [{
+      key: "init",
+      value: function init(obj) {
+        if (Array.isArray(obj)) {
+          obj = {
+            scaleX: obj[0],
+            scaleY: obj[1],
+            shear: obj[2],
+            rotate: obj[3],
+            translateX: obj[4],
+            translateY: obj[5],
+            originX: obj[6],
+            originY: obj[7]
+          };
         }
+
+        Object.assign(this, Morphable.TransformBag.defaults, obj);
+      }
+    }, {
+      key: "toArray",
+      value: function toArray() {
+        var v = this;
+        return [v.scaleX, v.scaleY, v.shear, v.rotate, v.translateX, v.translateY, v.originX, v.originY];
       }
+    }]);
 
-      function run(pos) {
-        // clear all other transforms before this in case something is saved
-        // on this runner. We are absolute. We dont need these!
-        if (!relative) this.clearTransform();
+    return _class2;
+  }();
 
-        var _transform = new Point(origin).transform(element._currentTransform(this)),
-            x = _transform.x,
-            y = _transform.y;
+  Morphable.TransformBag.defaults = {
+    scaleX: 1,
+    scaleY: 1,
+    shear: 0,
+    rotate: 0,
+    translateX: 0,
+    translateY: 0,
+    originX: 0,
+    originY: 0
+  };
 
-        var target = new Matrix(_objectSpread({}, transforms, {
-          origin: [x, y]
-        }));
-        var start = this._isDeclarative && current ? current : startTransform;
+  Morphable.ObjectBag =
+  /*#__PURE__*/
+  function () {
+    function _class3() {
+      _classCallCheck(this, _class3);
 
-        if (affine) {
-          target = target.decompose(x, y);
-          start = start.decompose(x, y); // Get the current and target angle as it was set
+      this.init.apply(this, arguments);
+    }
 
-          var rTarget = target.rotate;
-          var rCurrent = start.rotate; // Figure out the shortest path to rotate directly
+    _createClass(_class3, [{
+      key: "init",
+      value: function init(objOrArr) {
+        this.values = [];
 
-          var possibilities = [rTarget - 360, rTarget, rTarget + 360];
-          var distances = possibilities.map(function (a) {
-            return Math.abs(a - rCurrent);
-          });
-          var shortest = Math.min.apply(Math, _toConsumableArray(distances));
-          var index = distances.indexOf(shortest);
-          target.rotate = possibilities[index];
+        if (Array.isArray(objOrArr)) {
+          this.values = objOrArr;
+          return;
         }
 
-        if (relative) {
-          // we have to be careful here not to overwrite the rotation
-          // with the rotate method of Matrix
-          if (!isMatrix) {
-            target.rotate = transforms.rotate || 0;
-          }
+        var entries = Object.entries(objOrArr || {}).sort(function (a, b) {
+          return a[0] - b[0];
+        });
+        this.values = entries.reduce(function (last, curr) {
+          return last.concat(curr);
+        }, []);
+      }
+    }, {
+      key: "valueOf",
+      value: function valueOf() {
+        var obj = {};
+        var arr = this.values;
 
-          if (this._isDeclarative && currentAngle) {
-            start.rotate = currentAngle;
-          }
+        for (var i = 0, len = arr.length; i < len; i += 2) {
+          obj[arr[i]] = arr[i + 1];
         }
 
-        morpher.from(start);
-        morpher.to(target);
-        var affineParameters = morpher.at(pos);
-        currentAngle = affineParameters.rotate;
-        current = new Matrix(affineParameters);
-        this.addTransform(current);
-        return morpher.done();
+        return obj;
+      }
+    }, {
+      key: "toArray",
+      value: function toArray() {
+        return this.values;
       }
+    }]);
 
-      function retarget(newTransforms) {
-        // only get a new origin if it changed since the last call
-        if ((newTransforms.origin || 'center').toString() !== (transforms.origin || 'center').toString()) {
-          origin = getOrigin(transforms, element);
-        } // overwrite the old transformations with the new ones
+    return _class3;
+  }();
 
+  var morphableTypes = [SVGNumber, Color, Box$1, Matrix, SVGArray, PointArray$1, PathArray, Morphable.NonMorphable, Morphable.TransformBag, Morphable.ObjectBag];
+  extend$1(morphableTypes, {
+    to: function to(val, args) {
+      return new Morphable().type(this.constructor).from(this.valueOf()).to(val, args);
+    },
+    fromArray: function fromArray(arr) {
+      this.init(arr);
+      return this;
+    }
+  });
 
-        transforms = _objectSpread({}, newTransforms, {
-          origin: origin
+  var time = window.performance || Date;
+
+  var makeSchedule = function makeSchedule(runnerInfo) {
+    var start = runnerInfo.start;
+    var duration = runnerInfo.runner.duration();
+    var end = start + duration;
+    return {
+      start: start,
+      duration: duration,
+      end: end,
+      runner: runnerInfo.runner
+    };
+  };
+
+  var Timeline =
+  /*#__PURE__*/
+  function () {
+    // Construct a new timeline on the given element
+    function Timeline() {
+      _classCallCheck(this, Timeline);
+
+      this._timeSource = function () {
+        return time.now();
+      };
+
+      this._dispatcher = document.createElement('div'); // Store the timing variables
+
+      this._startTime = 0;
+      this._speed = 1.0; // Play control variables control how the animation proceeds
+
+      this._reverse = false;
+      this._persist = 0; // Keep track of the running animations and their starting parameters
+
+      this._nextFrame = null;
+      this._paused = false;
+      this._runners = [];
+      this._order = [];
+      this._time = 0;
+      this._lastSourceTime = 0;
+      this._lastStepTime = 0;
+    }
+
+    _createClass(Timeline, [{
+      key: "getEventTarget",
+      value: function getEventTarget() {
+        return this._dispatcher;
+      }
+      /**\r
+       *\r
+       */
+      // schedules a runner on the timeline
+
+    }, {
+      key: "schedule",
+      value: function schedule(runner, delay, when) {
+        if (runner == null) {
+          return this._runners.map(makeSchedule).sort(function (a, b) {
+            return a.start - b.start || a.duration - b.duration;
+          });
+        }
+
+        if (!this.active()) {
+          this._step();
+
+          if (when == null) {
+            when = 'now';
+          }
+        } // The start time for the next animation can either be given explicitly,
+        // derived from the current timeline time or it can be relative to the
+        // last start time to chain animations direclty
+
+
+        var absoluteStartTime = 0;
+        delay = delay || 0; // Work out when to start the animation
+
+        if (when == null || when === 'last' || when === 'after') {
+          // Take the last time and increment
+          absoluteStartTime = this._startTime;
+        } else if (when === 'absolute' || when === 'start') {
+          absoluteStartTime = delay;
+          delay = 0;
+        } else if (when === 'now') {
+          absoluteStartTime = this._time;
+        } else if (when === 'relative') {
+          var runnerInfo = this._runners[runner.id];
+
+          if (runnerInfo) {
+            absoluteStartTime = runnerInfo.start + delay;
+            delay = 0;
+          }
+        } else {
+          throw new Error('Invalid value for the "when" parameter');
+        } // Manage runner
+
+
+        runner.unschedule();
+        runner.timeline(this);
+        runner.time(-delay); // Save startTime for next runner
+
+        this._startTime = absoluteStartTime + runner.duration() + delay; // Save runnerInfo
+
+        this._runners[runner.id] = {
+          persist: this.persist(),
+          runner: runner,
+          start: absoluteStartTime // Save order and continue
+
+        };
+
+        this._order.push(runner.id);
+
+        this._continue();
+
+        return this;
+      } // Remove the runner from this timeline
+
+    }, {
+      key: "unschedule",
+      value: function unschedule(runner) {
+        var index = this._order.indexOf(runner.id);
+
+        if (index < 0) return this;
+        delete this._runners[runner.id];
+
+        this._order.splice(index, 1);
+
+        runner.timeline(null);
+        return this;
+      }
+    }, {
+      key: "play",
+      value: function play() {
+        // Now make sure we are not paused and continue the animation
+        this._paused = false;
+        return this._continue();
+      }
+    }, {
+      key: "pause",
+      value: function pause() {
+        // Cancel the next animation frame and pause
+        this._nextFrame = null;
+        this._paused = true;
+        return this;
+      }
+    }, {
+      key: "stop",
+      value: function stop() {
+        // Cancel the next animation frame and go to start
+        this.seek(-this._time);
+        return this.pause();
+      }
+    }, {
+      key: "finish",
+      value: function finish() {
+        this.seek(Infinity);
+        return this.pause();
+      }
+    }, {
+      key: "speed",
+      value: function speed(_speed) {
+        if (_speed == null) return this._speed;
+        this._speed = _speed;
+        return this;
+      }
+    }, {
+      key: "reverse",
+      value: function reverse(yes) {
+        var currentSpeed = this.speed();
+        if (yes == null) return this.speed(-currentSpeed);
+        var positive = Math.abs(currentSpeed);
+        return this.speed(yes ? positive : -positive);
+      }
+    }, {
+      key: "seek",
+      value: function seek(dt) {
+        this._time += dt;
+        return this._continue();
+      }
+    }, {
+      key: "time",
+      value: function time(_time) {
+        if (_time == null) return this._time;
+        this._time = _time;
+        return this;
+      }
+    }, {
+      key: "persist",
+      value: function persist(dtOrForever) {
+        if (dtOrForever == null) return this._persist;
+        this._persist = dtOrForever;
+        return this;
+      }
+    }, {
+      key: "source",
+      value: function source(fn) {
+        if (fn == null) return this._timeSource;
+        this._timeSource = fn;
+        return this;
+      }
+    }, {
+      key: "_step",
+      value: function _step() {
+        // If the timeline is paused, just do nothing
+        if (this._paused) return; // Get the time delta from the last time and update the time
+        // TODO: Deal with window.blur window.focus to pause animations
+
+        var time = this._timeSource();
+
+        var dtSource = time - this._lastSourceTime;
+        var dtTime = this._speed * dtSource + (this._time - this._lastStepTime);
+        this._lastSourceTime = time; // Update the time
+
+        this._time += dtTime;
+        this._lastStepTime = this._time; // this.fire('time', this._time)
+        // Run all of the runners directly
+
+        var runnersLeft = false;
+
+        for (var i = 0, len = this._order.length; i < len; i++) {
+          // Get and run the current runner and ignore it if its inactive
+          var runnerInfo = this._runners[this._order[i]];
+          var runner = runnerInfo.runner;
+          var dt = dtTime; // Make sure that we give the actual difference
+          // between runner start time and now
+
+          var dtToStart = this._time - runnerInfo.start; // Dont run runner if not started yet
+
+          if (dtToStart < 0) {
+            runnersLeft = true;
+            continue;
+          } else if (dtToStart < dt) {
+            // Adjust dt to make sure that animation is on point
+            dt = dtToStart;
+          }
+
+          if (!runner.active()) continue; // If this runner is still going, signal that we need another animation
+          // frame, otherwise, remove the completed runner
+
+          var finished = runner.step(dt).done;
+
+          if (!finished) {
+            runnersLeft = true; // continue
+          } else if (runnerInfo.persist !== true) {
+            // runner is finished. And runner might get removed
+            // TODO: Figure out end time of runner
+            var endTime = runner.duration() - runner.time() + this._time;
+
+            if (endTime + this._persist < this._time) {
+              // Delete runner and correct index
+              delete this._runners[this._order[i]];
+              this._order.splice(i--, 1) && --len;
+              runner.timeline(null);
+            }
+          }
+        } // Get the next animation frame to keep the simulation going
+
+
+        if (runnersLeft) {
+          this._nextFrame = Animator.frame(this._step.bind(this));
+        } else {
+          this._nextFrame = null;
+        }
+
+        return this;
+      } // Checks if we are running and continues the animation
+
+    }, {
+      key: "_continue",
+      value: function _continue() {
+        if (this._paused) return this;
+
+        if (!this._nextFrame) {
+          this._nextFrame = Animator.frame(this._step.bind(this));
+        }
+
+        return this;
+      }
+    }, {
+      key: "active",
+      value: function active() {
+        return !!this._nextFrame;
+      }
+    }]);
+
+    return Timeline;
+  }();
+  registerMethods({
+    Element: {
+      timeline: function timeline() {
+        this._timeline = this._timeline || new Timeline();
+        return this._timeline;
+      }
+    }
+  });
+
+  // easing = {
+  //   '-': function (pos) { return pos },
+  //   '<>': function (pos) { return -Math.cos(pos * Math.PI) / 2 + 0.5 },
+  //   '>': function (pos) { return Math.sin(pos * Math.PI / 2) },
+  //   '<': function (pos) { return -Math.cos(pos * Math.PI / 2) + 1 }
+  // }
+
+  var Runner =
+  /*#__PURE__*/
+  function () {
+    function Runner(options) {
+      _classCallCheck(this, Runner);
+
+      // Store a unique id on the runner, so that we can identify it later
+      this.id = Runner.id++; // Ensure a default value
+
+      options = options == null ? timeline.duration : options; // Ensure that we get a controller
+
+      options = typeof options === 'function' ? new Controller(options) : options; // Declare all of the variables
+
+      this._element = null;
+      this._timeline = null;
+      this.done = false;
+      this._queue = []; // Work out the stepper and the duration
+
+      this._duration = typeof options === 'number' && options;
+      this._isDeclarative = options instanceof Controller;
+      this._stepper = this._isDeclarative ? options : new Ease(); // We copy the current values from the timeline because they can change
+
+      this._history = {}; // Store the state of the runner
+
+      this.enabled = true;
+      this._time = 0;
+      this._last = 0; // Save transforms applied to this runner
+
+      this.transforms = new Matrix();
+      this.transformId = 1; // Looping variables
+
+      this._haveReversed = false;
+      this._reverse = false;
+      this._loopsDone = 0;
+      this._swing = false;
+      this._wait = 0;
+      this._times = 1;
+    }
+    /*\r
+    Runner Definitions\r
+    ==================\r
+    These methods help us define the runtime behaviour of the Runner or they\r
+    help us make new runners from the current runner\r
+    */
+
+
+    _createClass(Runner, [{
+      key: "element",
+      value: function element(_element) {
+        if (_element == null) return this._element;
+        this._element = _element;
+
+        _element._prepareRunner();
+
+        return this;
+      }
+    }, {
+      key: "timeline",
+      value: function timeline$$1(_timeline) {
+        // check explicitly for undefined so we can set the timeline to null
+        if (typeof _timeline === 'undefined') return this._timeline;
+        this._timeline = _timeline;
+        return this;
+      }
+    }, {
+      key: "animate",
+      value: function animate(duration, delay, when) {
+        var o = Runner.sanitise(duration, delay, when);
+        var runner = new Runner(o.duration);
+        if (this._timeline) runner.timeline(this._timeline);
+        if (this._element) runner.element(this._element);
+        return runner.loop(o).schedule(delay, when);
+      }
+    }, {
+      key: "schedule",
+      value: function schedule(timeline$$1, delay, when) {
+        // The user doesn't need to pass a timeline if we already have one
+        if (!(timeline$$1 instanceof Timeline)) {
+          when = delay;
+          delay = timeline$$1;
+          timeline$$1 = this.timeline();
+        } // If there is no timeline, yell at the user...
+
+
+        if (!timeline$$1) {
+          throw Error('Runner cannot be scheduled without timeline');
+        } // Schedule the runner on the timeline provided
+
+
+        timeline$$1.schedule(this, delay, when);
+        return this;
+      }
+    }, {
+      key: "unschedule",
+      value: function unschedule() {
+        var timeline$$1 = this.timeline();
+        timeline$$1 && timeline$$1.unschedule(this);
+        return this;
+      }
+    }, {
+      key: "loop",
+      value: function loop(times, swing, wait) {
+        // Deal with the user passing in an object
+        if (_typeof(times) === 'object') {
+          swing = times.swing;
+          wait = times.wait;
+          times = times.times;
+        } // Sanitise the values and store them
+
+
+        this._times = times || Infinity;
+        this._swing = swing || false;
+        this._wait = wait || 0;
+        return this;
+      }
+    }, {
+      key: "delay",
+      value: function delay(_delay) {
+        return this.animate(0, _delay);
+      }
+      /*\r
+      Basic Functionality\r
+      ===================\r
+      These methods allow us to attach basic functions to the runner directly\r
+      */
+
+    }, {
+      key: "queue",
+      value: function queue(initFn, runFn, isTransform) {
+        this._queue.push({
+          initialiser: initFn || noop,
+          runner: runFn || noop,
+          isTransform: isTransform,
+          initialised: false,
+          finished: false
         });
+
+        var timeline$$1 = this.timeline();
+        timeline$$1 && this.timeline()._continue();
+        return this;
+      }
+    }, {
+      key: "during",
+      value: function during(fn) {
+        return this.queue(null, fn);
       }
+    }, {
+      key: "after",
+      value: function after(fn) {
+        return this.on('finish', fn);
+      }
+      /*\r
+      Runner animation methods\r
+      ========================\r
+      Control how the animation plays\r
+      */
 
-      this.queue(setup, run, retarget);
-      this._isDeclarative && this._rememberMorpher('transform', morpher);
-      return this;
-    },
-    // Animatable x-axis
-    x: function x(_x, relative) {
-      return this._queueNumber('x', _x);
-    },
-    // Animatable y-axis
-    y: function y(_y) {
-      return this._queueNumber('y', _y);
-    },
-    dx: function dx(x) {
-      return this._queueNumberDelta('dx', x);
-    },
-    dy: function dy(y) {
-      return this._queueNumberDelta('dy', y);
-    },
-    _queueNumberDelta: function _queueNumberDelta(method, to) {
-      to = new SVGNumber(to); // Try to change the target if we have this method already registerd
+    }, {
+      key: "time",
+      value: function time(_time) {
+        if (_time == null) {
+          return this._time;
+        }
 
-      if (this._tryRetargetDelta(method, to)) return this; // Make a morpher and queue the animation
+        var dt = _time - this._time;
+        this.step(dt);
+        return this;
+      }
+    }, {
+      key: "duration",
+      value: function duration() {
+        return this._times * (this._wait + this._duration) - this._wait;
+      }
+    }, {
+      key: "loops",
+      value: function loops(p) {
+        var loopDuration = this._duration + this._wait;
 
-      var morpher = new Morphable(this._stepper).to(to);
-      this.queue(function () {
-        var from = this.element()[method]();
-        morpher.from(from);
-        morpher.to(from + to);
-      }, function (pos) {
-        this.element()[method](morpher.at(pos));
-        return morpher.done();
-      }); // Register the morpher so that if it is changed again, we can retarget it
+        if (p == null) {
+          var loopsDone = Math.floor(this._time / loopDuration);
+          var relativeTime = this._time - loopsDone * loopDuration;
+          var position = relativeTime / this._duration;
+          return Math.min(loopsDone + position, this._times);
+        }
 
-      this._rememberMorpher(method, morpher);
+        var whole = Math.floor(p);
+        var partial = p % 1;
+        var time = loopDuration * whole + this._duration * partial;
+        return this.time(time);
+      }
+    }, {
+      key: "position",
+      value: function position(p) {
+        // Get all of the variables we need
+        var x = this._time;
+        var d = this._duration;
+        var w = this._wait;
+        var t = this._times;
+        var s = this._swing;
+        var r = this._reverse;
+        var position;
 
-      return this;
-    },
-    _queueObject: function _queueObject(method, to) {
-      // Try to change the target if we have this method already registerd
-      if (this._tryRetarget(method, to)) return this; // Make a morpher and queue the animation
+        if (p == null) {
+          /*\r
+          This function converts a time to a position in the range [0, 1]\r
+          The full explanation can be found in this desmos demonstration\r
+            https://www.desmos.com/calculator/u4fbavgche\r
+          The logic is slightly simplified here because we can use booleans\r
+          */
+          // Figure out the value without thinking about the start or end time
+          var f = function f(x) {
+            var swinging = s * Math.floor(x % (2 * (w + d)) / (w + d));
+            var backwards = swinging && !r || !swinging && r;
+            var uncliped = Math.pow(-1, backwards) * (x % (w + d)) / d + backwards;
+            var clipped = Math.max(Math.min(uncliped, 1), 0);
+            return clipped;
+          }; // Figure out the value by incorporating the start time
 
-      var morpher = new Morphable(this._stepper).to(to);
-      this.queue(function () {
-        morpher.from(this.element()[method]());
-      }, function (pos) {
-        this.element()[method](morpher.at(pos));
-        return morpher.done();
-      }); // Register the morpher so that if it is changed again, we can retarget it
 
-      this._rememberMorpher(method, morpher);
+          var endTime = t * (w + d) - w;
+          position = x <= 0 ? Math.round(f(1e-5)) : x < endTime ? f(x) : Math.round(f(endTime - 1e-5));
+          return position;
+        } // Work out the loops done and add the position to the loops done
 
-      return this;
-    },
-    _queueNumber: function _queueNumber(method, value) {
-      return this._queueObject(method, new SVGNumber(value));
-    },
-    // Animatable center x-axis
-    cx: function cx(x) {
-      return this._queueNumber('cx', x);
-    },
-    // Animatable center y-axis
-    cy: function cy(y) {
-      return this._queueNumber('cy', y);
-    },
-    // Add animatable move
-    move: function move(x, y) {
-      return this.x(x).y(y);
-    },
-    // Add animatable center
-    center: function center(x, y) {
-      return this.cx(x).cy(y);
-    },
-    // Add animatable size
-    size: function size(width, height) {
-      // animate bbox based size for all other elements
-      var box;
 
-      if (!width || !height) {
-        box = this._element.bbox();
+        var loopsDone = Math.floor(this.loops());
+        var swingForward = s && loopsDone % 2 === 0;
+        var forwards = swingForward && !r || r && swingForward;
+        position = loopsDone + (forwards ? p : 1 - p);
+        return this.loops(position);
       }
+    }, {
+      key: "progress",
+      value: function progress(p) {
+        if (p == null) {
+          return Math.min(1, this._time / this.duration());
+        }
 
-      if (!width) {
-        width = box.width / box.height * height;
+        return this.time(p * this.duration());
       }
+    }, {
+      key: "step",
+      value: function step(dt) {
+        // If we are inactive, this stepper just gets skipped
+        if (!this.enabled) return this; // Update the time and get the new position
 
-      if (!height) {
-        height = box.height / box.width * width;
-      }
+        dt = dt == null ? 16 : dt;
+        this._time += dt;
+        var position = this.position(); // Figure out if we need to run the stepper in this frame
 
-      return this.width(width).height(height);
-    },
-    // Add animatable width
-    width: function width(_width) {
-      return this._queueNumber('width', _width);
-    },
-    // Add animatable height
-    height: function height(_height) {
-      return this._queueNumber('height', _height);
-    },
-    // Add animatable plot
-    plot: function plot(a, b, c, d) {
-      // Lines can be plotted with 4 arguments
-      if (arguments.length === 4) {
-        return this.plot([a, b, c, d]);
-      } // FIXME: this needs to be rewritten such that the element is only accesed
-      // in the init function
+        var running = this._lastPosition !== position && this._time >= 0;
+        this._lastPosition = position; // Figure out if we just started
+
+        var duration = this.duration();
+        var justStarted = this._lastTime < 0 && this._time > 0;
+        var justFinished = this._lastTime < this._time && this.time > duration;
+        this._lastTime = this._time;
+        // Work out if the runner is finished set the done flag here so animations
+        // know, that they are running in the last step (this is good for
+        // transformations which can be merged)
 
 
-      return this._queueObject('plot', new this._element.MorphArray(a));
-      /*\r
-      var morpher = this._element.morphArray().to(a)\r
-        this.queue(function () {\r
-        morpher.from(this._element.array())\r
-      }, function (pos) {\r
-        this._element.plot(morpher.at(pos))\r
-      })\r
-        return this\r
-      */
-    },
-    // Add leading method
-    leading: function leading(value) {
-      return this._queueNumber('leading', value);
-    },
-    // Add animatable viewbox
-    viewbox: function viewbox(x, y, width, height) {
-      return this._queueObject('viewbox', new Box(x, y, width, height));
-    },
-    update: function update(o) {
-      if (_typeof(o) !== 'object') {
-        return this.update({
-          offset: arguments[0],
-          color: arguments[1],
-          opacity: arguments[2]
-        });
+        var declarative = this._isDeclarative;
+        this.done = !declarative && !justFinished && this._time >= duration; // Call initialise and the run function
+
+        if (running || declarative) {
+          this._initialise(running); // clear the transforms on this runner so they dont get added again and again
+
+
+          this.transforms = new Matrix();
+
+          var converged = this._run(declarative ? dt : position); // this.fire('step', this)
+
+        } // correct the done flag here
+        // declaritive animations itself know when they converged
+
+
+        this.done = this.done || converged && declarative; // if (this.done) {
+        //   this.fire('finish', this)
+        // }
+
+        return this;
+      }
+    }, {
+      key: "finish",
+      value: function finish() {
+        return this.step(Infinity);
+      }
+    }, {
+      key: "reverse",
+      value: function reverse(_reverse) {
+        this._reverse = _reverse == null ? !this._reverse : _reverse;
+        return this;
+      }
+    }, {
+      key: "ease",
+      value: function ease(fn) {
+        this._stepper = new Ease(fn);
+        return this;
       }
+    }, {
+      key: "active",
+      value: function active(enabled) {
+        if (enabled == null) return this.enabled;
+        this.enabled = enabled;
+        return this;
+      }
+      /*\r
+      Private Methods\r
+      ===============\r
+      Methods that shouldn't be used externally\r
+      */
+      // Save a morpher to the morpher list so that we can retarget it later
 
-      if (o.opacity != null) this.attr('stop-opacity', o.opacity);
-      if (o.color != null) this.attr('stop-color', o.color);
-      if (o.offset != null) this.attr('offset', o.offset);
-      return this;
-    }
-  });
+    }, {
+      key: "_rememberMorpher",
+      value: function _rememberMorpher(method, morpher) {
+        this._history[method] = {
+          morpher: morpher,
+          caller: this._queue[this._queue.length - 1]
+        };
+      } // Try to set the target for a morpher if the morpher exists, otherwise
+      // do nothing and return false
 
-  // export {default as SVGArray} from './SVGArray.js'
-  // export {default as Bare} from './Bare.js'
-  // export {default as Box} from './Box.js'
-  // export {default as Circle} from './Circle.js'
-  // export {default as ClipPath} from './ClipPath.js'
-  // export {default as Color} from './Color.js'
-  // export {default as Container} from './Container.js'
-  // export {Controller, Ease, PID, Spring} from './Controller.js'
-  // export {default as Defs} from './Defs.js'
-  // export {default as Doc} from './Doc.js'
-  // export {default as Element} from './Element.js'
-  // export {default as Ellipse} from './Ellipse.js'
-  // export {default as EventTarget} from './EventTarget.js'
-  // export {default as Gradient} from './Gradient.js'
-  // export {default as G} from './G.js'
-  // export {default as HtmlNode} from './HtmlNode.js'
-  // export {default as A} from './A.js'
-  // export {default as Image} from './Image.js'
-  // export {default as Line} from './Line.js'
-  // export {default as Marker} from './Marker.js'
-  // export {default as Mask} from './Mask.js'
-  // export {default as Matrix} from './Matrix.js'
-  // export {default as Morphable} from './Morphable.js'
-  // export {default as SVGNumber} from './SVGNumber.js'
-  // export {default as Parent} from './Parent.js'
-  // export {default as Path} from './Path.js'
-  // export {default as PathArray} from './PathArray.js'
-  // export {default as Pattern} from './Pattern.js'
-  // export {default as Point} from './Point.js'
-  // export {default as PointArray} from './PointArray.js'
-  // export {default as Polygon} from './Polygon.js'
-  // export {default as Polyline} from './Polyline.js'
-  // export {default as Queue} from './Queue.js'
-  // export {default as Rect} from './Rect.js'
-  // export {default as Runner} from './Runner.js'
-  // export {default as Shape} from './Shape.js'
-  // export {default as Stop} from './Stop.js'
-  // export {default as Symbol} from './Symbol.js'
-  // export {default as Text} from './Text.js'
-  // export {default as TextPath} from './TextPath.js'
-  // export {default as Timeline} from './Timeline.js'
-  // export {default as Use} from './Use.js'
+    }, {
+      key: "_tryRetarget",
+      value: function _tryRetarget(method, target) {
+        if (this._history[method]) {
+          // if the last method wasnt even initialised, throw it away
+          if (!this._history[method].caller.initialised) {
+            var index = this._queue.indexOf(this._history[method].caller);
 
-  var Classes = /*#__PURE__*/Object.freeze({
-    HtmlNode: HtmlNode,
-    Doc: Doc$1,
-    Defs: Defs,
-    G: G,
-    Animator: Animator,
-    Bare: Bare,
-    Circle: Circle,
-    ClipPath: ClipPath,
-    A: A,
-    Ellipse: Ellipse,
-    Stop: Stop,
-    Gradient: Gradient,
-    Image: Image,
-    Line: Line,
-    Marker: Marker,
-    Mask: Mask,
-    Path: Path,
-    Pattern: Pattern,
-    Polygon: Polygon,
-    Polyline: Polyline,
-    Rect: Rect,
-    Symbol: _Symbol,
-    Text: Text$1,
-    TextPath: TextPath,
-    Tspan: Tspan,
-    Use: Use,
-    SVGNumber: SVGNumber,
-    SVGArray: SVGArray,
-    PathArray: PathArray,
-    PointArray: PointArray$1,
-    Matrix: Matrix,
-    Point: Point,
-    Box: Box$1,
-    Color: Color,
-    Morphable: Morphable,
-    Queue: Queue,
-    Runner: Runner,
-    Timeline: Timeline,
-    Controller: Controller,
-    Ease: Ease,
-    PID: PID,
-    Spring: Spring
-  });
+            this._queue.splice(index, 1);
 
+            return false;
+          } // for the case of transformations, we use the special retarget function
+          // which has access to the outer scope
 
 
-  var containers = /*#__PURE__*/Object.freeze({
-    Bare: Bare,
-    ClipPath: ClipPath,
-    Defs: Defs,
-    Doc: Doc$1,
-    Gradient: Gradient,
-    G: G,
-    A: A,
-    Marker: Marker,
-    Mask: Mask,
-    Pattern: Pattern,
-    Symbol: _Symbol
-  });
+          if (this._history[method].caller.isTransform) {
+            this._history[method].caller.isTransform(target); // for everything else a simple morpher change is sufficient
 
-  // Get all siblings, including myself
+          } else {
+            this._history[method].morpher.to(target);
+          }
 
-  function siblings() {
-    return this.parent().children();
-  } // Get the curent position siblings
+          this._history[method].caller.finished = false;
+          var timeline$$1 = this.timeline();
+          timeline$$1 && timeline$$1._continue();
+          return true;
+        }
 
-  function position() {
-    return this.parent().index(this);
-  } // Get the next element (will return null if there is none)
+        return false;
+      } // Run each initialise function in the runner if required
 
-  function next() {
-    return this.siblings()[this.position() + 1];
-  } // Get the next element (will return null if there is none)
+    }, {
+      key: "_initialise",
+      value: function _initialise(running) {
+        // If we aren't running, we shouldn't initialise when not declarative
+        if (!running && !this._isDeclarative) return; // Loop through all of the initialisers
 
-  function prev() {
-    return this.siblings()[this.position() - 1];
-  } // Send given element one step forward
+        for (var i = 0, len = this._queue.length; i < len; ++i) {
+          // Get the current initialiser
+          var current = this._queue[i]; // Determine whether we need to initialise
 
-  function forward() {
-    var i = this.position() + 1;
-    var p = this.parent(); // move node one step forward
+          var needsIt = this._isDeclarative || !current.initialised && running;
+          running = !current.finished; // Call the initialiser if we need to
 
-    p.removeElement(this).add(this, i); // make sure defs node is always at the top
+          if (needsIt && running) {
+            current.initialiser.call(this);
+            current.initialised = true;
+          }
+        }
+      } // Run each run function for the position or dt given
 
-    if (p instanceof Doc$1) {
-      p.node.appendChild(p.defs().node);
-    }
+    }, {
+      key: "_run",
+      value: function _run(positionOrDt) {
+        // Run all of the _queue directly
+        var allfinished = true;
 
-    return this;
-  } // Send given element one step backward
+        for (var i = 0, len = this._queue.length; i < len; ++i) {
+          // Get the current function to run
+          var current = this._queue[i]; // Run the function if its not finished, we keep track of the finished
+          // flag for the sake of declarative _queue
 
-  function backward() {
-    var i = this.position();
+          var converged = current.runner.call(this, positionOrDt);
+          current.finished = current.finished || converged === true;
+          allfinished = allfinished && current.finished;
+        } // We report when all of the constructors are finished
 
-    if (i > 0) {
-      this.parent().removeElement(this).add(this, i - 1);
-    }
 
-    return this;
-  } // Send given element all the way to the front
+        return allfinished;
+      }
+    }, {
+      key: "addTransform",
+      value: function addTransform(transform, index) {
+        this.transforms.lmultiplyO(transform);
+        return this;
+      }
+    }, {
+      key: "clearTransform",
+      value: function clearTransform() {
+        this.transforms = new Matrix();
+        return this;
+      }
+    }], [{
+      key: "sanitise",
+      value: function sanitise(duration, delay, when) {
+        // Initialise the default parameters
+        var times = 1;
+        var swing = false;
+        var wait = 0;
+        duration = duration || timeline.duration;
+        delay = delay || timeline.delay;
+        when = when || 'last'; // If we have an object, unpack the values
 
-  function front() {
-    var p = this.parent(); // Move node forward
+        if (_typeof(duration) === 'object' && !(duration instanceof Stepper)) {
+          delay = duration.delay || delay;
+          when = duration.when || when;
+          swing = duration.swing || swing;
+          times = duration.times || times;
+          wait = duration.wait || wait;
+          duration = duration.duration || timeline.duration;
+        }
 
-    p.node.appendChild(this.node); // Make sure defs node is always at the top
+        return {
+          duration: duration,
+          delay: delay,
+          swing: swing,
+          times: times,
+          wait: wait,
+          when: when
+        };
+      }
+    }]);
 
-    if (p instanceof Doc$1) {
-      p.node.appendChild(p.defs().node);
-    }
+    return Runner;
+  }();
+  Runner.id = 0;
 
-    return this;
-  } // Send given element all the way to the back
+  var FakeRunner = function FakeRunner() {
+    var transforms = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new Matrix();
+    var id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : -1;
+    var done = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
 
-  function back() {
-    if (this.position() > 0) {
-      this.parent().removeElement(this).add(this, 0);
-    }
+    _classCallCheck(this, FakeRunner);
 
-    return this;
-  } // Inserts a given element before the targeted element
+    this.transforms = transforms;
+    this.id = id;
+    this.done = done;
+  };
 
-  function before(element) {
-    element.remove();
-    var i = this.position();
-    this.parent().add(element, i);
-    return this;
-  } // Inserts a given element after the targeted element
+  extend$1([Runner, FakeRunner], {
+    mergeWith: function mergeWith(runner) {
+      return new FakeRunner(runner.transforms.lmultiply(this.transforms), runner.id);
+    }
+  }); // FakeRunner.emptyRunner = new FakeRunner()
 
-  function after(element) {
-    element.remove();
-    var i = this.position();
-    this.parent().add(element, i + 1);
-    return this;
-  }
+  var lmultiply = function lmultiply(last, curr) {
+    return last.lmultiplyO(curr);
+  };
 
-  var arrange = /*#__PURE__*/Object.freeze({
-    siblings: siblings,
-    position: position,
-    next: next,
-    prev: prev,
-    forward: forward,
-    backward: backward,
-    front: front,
-    back: back,
-    before: before,
-    after: after
-  });
+  var getRunnerTransform = function getRunnerTransform(runner) {
+    return runner.transforms;
+  };
 
-  // SVG.get = function (id) {
-  //   var node = document.getElementById(idFromReference(id) || id)
-  //   return SVG.adopt(node)
-  // }
-  //
-  // // Select elements by query string
-  // SVG.select = function (query, parent) {
-  //   return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
-  //     return SVG.adopt(node)
-  //   })
-  // }
-  //
-  // SVG.$$ = function (query, parent) {
-  //   return SVG.utils.map((parent || document).querySelectorAll(query), function (node) {
-  //     return SVG.adopt(node)
-  //   })
-  // }
-  //
-  // SVG.$ = function (query, parent) {
-  //   return SVG.adopt((parent || document).querySelector(query))
-  // }
+  function mergeTransforms() {
+    // Find the matrix to apply to the element and apply it
+    var runners = this._transformationRunners.runners;
+    var netTransform = runners.map(getRunnerTransform).reduce(lmultiply, new Matrix());
+    this.transform(netTransform);
 
-  function baseFind(query, parent) {
-    return utils.map((parent || document).querySelectorAll(query), function (node) {
-      return adopt$1(node);
-    });
-  } // Scoped find method
+    this._transformationRunners.merge();
 
-  function find(query) {
-    return baseFind(query, this.node);
+    if (this._transformationRunners.length() === 1) {
+      this._frameId = null;
+    }
   }
 
-  function css(style, val) {
-    var ret = {};
+  var RunnerArray =
+  /*#__PURE__*/
+  function () {
+    function RunnerArray() {
+      _classCallCheck(this, RunnerArray);
 
-    if (arguments.length === 0) {
-      // get full style as object
-      this.node.style.cssText.split(/\s*;\s*/).filter(function (el) {
-        return !!el.length;
-      }).forEach(function (el) {
-        var t = el.split(/\s*:\s*/);
-        ret[t[0]] = t[1];
-      });
-      return ret;
+      this.runners = [];
+      this.ids = [];
     }
 
-    if (arguments.length < 2) {
-      // get style properties in the array
-      if (Array.isArray(style)) {
-        var _iteratorNormalCompletion = true;
-        var _didIteratorError = false;
-        var _iteratorError = undefined;
+    _createClass(RunnerArray, [{
+      key: "add",
+      value: function add(runner) {
+        if (this.runners.includes(runner)) return;
+        var id = runner.id + 1;
+        var leftSibling = this.ids.reduce(function (last, curr) {
+          if (curr > last && curr < id) return curr;
+          return last;
+        }, 0);
+        var index = this.ids.indexOf(leftSibling) + 1;
+        this.ids.splice(index, 0, id);
+        this.runners.splice(index, 0, runner);
+        return this;
+      }
+    }, {
+      key: "getByID",
+      value: function getByID(id) {
+        return this.runners[this.ids.indexOf(id + 1)];
+      }
+    }, {
+      key: "remove",
+      value: function remove(id) {
+        var index = this.ids.indexOf(id + 1);
+        this.ids.splice(index, 1);
+        this.runners.splice(index, 1);
+        return this;
+      }
+    }, {
+      key: "merge",
+      value: function merge() {
+        var _this = this;
 
-        try {
-          for (var _iterator = style[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
-            var _name = _step.value;
-            var cased = camelCase(_name);
-            ret[cased] = this.node.style(cased);
-          }
-        } catch (err) {
-          _didIteratorError = true;
-          _iteratorError = err;
-        } finally {
-          try {
-            if (!_iteratorNormalCompletion && _iterator.return != null) {
-              _iterator.return();
-            }
-          } finally {
-            if (_didIteratorError) {
-              throw _iteratorError;
-            }
-          }
-        }
+        var lastRunner = null;
+        this.runners.forEach(function (runner, i) {
+          if (lastRunner && runner.done && lastRunner.done) {
+            _this.remove(runner.id);
 
-        return ret;
-      } // get style for property
+            _this.edit(lastRunner.id, runner.mergeWith(lastRunner));
+          }
 
+          lastRunner = runner;
+        });
+        return this;
+      }
+    }, {
+      key: "edit",
+      value: function edit(id, newRunner) {
+        var index = this.ids.indexOf(id + 1);
+        this.ids.splice(index, 1, id);
+        this.runners.splice(index, 1, newRunner);
+        return this;
+      }
+    }, {
+      key: "length",
+      value: function length() {
+        return this.ids.length;
+      }
+    }, {
+      key: "clearBefore",
+      value: function clearBefore(id) {
+        var deleteCnt = this.ids.indexOf(id + 1) || 1;
+        this.ids.splice(0, deleteCnt, 0);
+        this.runners.splice(0, deleteCnt, new FakeRunner());
+        return this;
+      }
+    }]);
 
-      if (typeof style === 'string') {
-        return this.node.style[camelCase(style)];
-      } // set styles in object
+    return RunnerArray;
+  }();
 
+  var frameId = 0;
+  registerMethods({
+    Element: {
+      animate: function animate(duration, delay, when) {
+        var o = Runner.sanitise(duration, delay, when);
+        var timeline$$1 = this.timeline();
+        return new Runner(o.duration).loop(o).element(this).timeline(timeline$$1).schedule(delay, when);
+      },
+      delay: function delay(by, when) {
+        return this.animate(0, by, when);
+      },
+      // this function searches for all runners on the element and deletes the ones
+      // which run before the current one. This is because absolute transformations
+      // overwfrite anything anyway so there is no need to waste time computing
+      // other runners
+      _clearTransformRunnersBefore: function _clearTransformRunnersBefore(currentRunner) {
+        this._transformationRunners.clearBefore(currentRunner.id);
+      },
+      _currentTransform: function _currentTransform(current) {
+        return this._transformationRunners.runners // we need the equal sign here to make sure, that also transformations
+        // on the same runner which execute before the current transformation are
+        // taken into account
+        .filter(function (runner) {
+          return runner.id <= current.id;
+        }).map(getRunnerTransform).reduce(lmultiply, new Matrix());
+      },
+      addRunner: function addRunner(runner) {
+        this._transformationRunners.add(runner);
 
-      if (_typeof(style) === 'object') {
-        for (name in style) {
-          // set empty string if null/undefined/'' was given
-          this.node.style[camelCase(name)] = style[name] == null || isBlank.test(style[name]) ? '' : style[name];
+        Animator.transform_frame(mergeTransforms.bind(this), this._frameId);
+      },
+      _prepareRunner: function _prepareRunner() {
+        if (this._frameId == null) {
+          this._transformationRunners = new RunnerArray().add(new FakeRunner(new Matrix(this)));
+          this._frameId = frameId++;
         }
       }
-    } // set style for property
-
-
-    if (arguments.length === 2) {
-      this.node.style[camelCase(style)] = val == null || isBlank.test(val) ? '' : val;
     }
+  });
+  extend$1(Runner, {
+    attr: function attr(a, v) {
+      return this.styleAttr('attr', a, v);
+    },
+    // Add animatable styles
+    css: function css(s, v) {
+      return this.styleAttr('css', s, v);
+    },
+    styleAttr: function styleAttr(type, name, val) {
+      // apply attributes individually
+      if (_typeof(name) === 'object') {
+        for (var key in val) {
+          this.styleAttr(type, key, val[key]);
+        }
+      }
 
-    return this;
-  } // Show element
-
-  function show() {
-    return this.css('display', '');
-  } // Hide element
-
-  function hide() {
-    return this.css('display', 'none');
-  } // Is element visible?
+      var morpher = new Morphable(this._stepper).to(val);
+      this.queue(function () {
+        morpher = morpher.from(this.element()[type](name));
+      }, function (pos) {
+        this.element()[type](name, morpher.at(pos));
+        return morpher.done();
+      });
+      return this;
+    },
+    zoom: function zoom(level, point) {
+      var morpher = new Morphable(this._stepper).to(new SVGNumber(level));
+      this.queue(function () {
+        morpher = morpher.from(this.zoom());
+      }, function (pos) {
+        this.element().zoom(morpher.at(pos), point);
+        return morpher.done();
+      });
+      return this;
+    },
 
-  function visible() {
-    return this.css('display') !== 'none';
-  }
+    /**\r
+     ** absolute transformations\r
+     **/
+    //
+    // M v -----|-----(D M v = F v)------|----->  T v
+    //
+    // 1. define the final state (T) and decompose it (once)
+    //    t = [tx, ty, the, lam, sy, sx]
+    // 2. on every frame: pull the current state of all previous transforms
+    //    (M - m can change)
+    //   and then write this as m = [tx0, ty0, the0, lam0, sy0, sx0]
+    // 3. Find the interpolated matrix F(pos) = m + pos * (t - m)
+    //   - Note F(0) = M
+    //   - Note F(1) = T
+    // 4. Now you get the delta matrix as a result: D = F * inv(M)
+    transform: function transform(transforms, relative, affine) {
+      // If we have a declarative function, we should retarget it if possible
+      relative = transforms.relative || relative;
 
-  var css$1 = /*#__PURE__*/Object.freeze({
-    css: css,
-    show: show,
-    hide: hide,
-    visible: visible
-  });
+      if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) {
+        return this;
+      } // Parse the parameters
 
-  function untransform() {
-    return this.attr('transform', null);
-  } // merge the whole transformation chain into one matrix and returns it
 
-  function matrixify() {
-    var matrix = (this.attr('transform') || ''). // split transformations
-    split(transforms).slice(0, -1).map(function (str) {
-      // generate key => value pairs
-      var kv = str.trim().split('(');
-      return [kv[0], kv[1].split(delimiter).map(function (str) {
-        return parseFloat(str);
-      })];
-    }).reverse() // merge every transformation into one matrix
-    .reduce(function (matrix, transform) {
-      if (transform[0] === 'matrix') {
-        return matrix.lmultiply(arrayToMatrix(transform[1]));
-      }
+      var isMatrix = isMatrixLike(transforms);
+      affine = transforms.affine != null ? transforms.affine : affine != null ? affine : !isMatrix; // Create a morepher and set its type
 
-      return matrix[transform[0]].apply(matrix, transform[1]);
-    }, new Matrix());
-    return matrix;
-  } // add an element to another parent without changing the visual representation on the screen
+      var morpher = new Morphable().type(affine ? Morphable.TransformBag : Matrix).stepper(this._stepper);
+      var origin;
+      var element;
+      var current;
+      var currentAngle;
+      var startTransform;
 
-  function toParent(parent) {
-    if (this === parent) return this;
-    var ctm = this.screenCTM();
-    var pCtm = parent.screenCTM().inverse();
-    this.addTo(parent).untransform().transform(pCtm.multiply(ctm));
-    return this;
-  } // same as above with parent equals root-svg
+      function setup() {
+        // make sure element and origin is defined
+        element = element || this.element();
+        origin = origin || getOrigin(transforms, element);
+        startTransform = new Matrix(relative ? undefined : element); // add the runner to the element so it can merge transformations
 
-  function toDoc() {
-    return this.toParent(this.doc());
-  } // Add transformations
+        element.addRunner(this); // Deactivate all transforms that have run so far if we are absolute
 
-  function transform(o, relative) {
-    // Act as a getter if no object was passed
-    if (o == null || typeof o === 'string') {
-      var decomposed = new Matrix(this).decompose();
-      return decomposed[o] || decomposed;
-    }
+        if (!relative) {
+          element._clearTransformRunnersBefore(this);
+        }
+      }
 
-    if (!isMatrixLike(o)) {
-      // Set the origin according to the defined transform
-      o = _objectSpread({}, o, {
-        origin: getOrigin(o, this)
-      });
-    } // The user can pass a boolean, an Element or an Matrix or nothing
+      function run(pos) {
+        // clear all other transforms before this in case something is saved
+        // on this runner. We are absolute. We dont need these!
+        if (!relative) this.clearTransform();
 
+        var _transform = new Point(origin).transform(element._currentTransform(this)),
+            x = _transform.x,
+            y = _transform.y;
 
-    var cleanRelative = relative === true ? this : relative || false;
-    var result = new Matrix(cleanRelative).transform(o);
-    return this.attr('transform', result);
-  }
+        var target = new Matrix(_objectSpread({}, transforms, {
+          origin: [x, y]
+        }));
+        var start = this._isDeclarative && current ? current : startTransform;
 
-  var transform$1 = /*#__PURE__*/Object.freeze({
-    untransform: untransform,
-    matrixify: matrixify,
-    toParent: toParent,
-    toDoc: toDoc,
-    transform: transform
-  });
+        if (affine) {
+          target = target.decompose(x, y);
+          start = start.decompose(x, y); // Get the current and target angle as it was set
 
-  function attr(attr, val, ns) {
-    // act as full getter
-    if (attr == null) {
-      // get an object of attributes
-      attr = {};
-      val = this.node.attributes;
-      var _iteratorNormalCompletion = true;
-      var _didIteratorError = false;
-      var _iteratorError = undefined;
+          var rTarget = target.rotate;
+          var rCurrent = start.rotate; // Figure out the shortest path to rotate directly
 
-      try {
-        for (var _iterator = val[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
-          var node = _step.value;
-          attr[node.nodeName] = isNumer.test(node.nodeValue) ? parseFloat(node.nodeValue) : node.nodeValue;
+          var possibilities = [rTarget - 360, rTarget, rTarget + 360];
+          var distances = possibilities.map(function (a) {
+            return Math.abs(a - rCurrent);
+          });
+          var shortest = Math.min.apply(Math, _toConsumableArray(distances));
+          var index = distances.indexOf(shortest);
+          target.rotate = possibilities[index];
         }
-      } catch (err) {
-        _didIteratorError = true;
-        _iteratorError = err;
-      } finally {
-        try {
-          if (!_iteratorNormalCompletion && _iterator.return != null) {
-            _iterator.return();
+
+        if (relative) {
+          // we have to be careful here not to overwrite the rotation
+          // with the rotate method of Matrix
+          if (!isMatrix) {
+            target.rotate = transforms.rotate || 0;
           }
-        } finally {
-          if (_didIteratorError) {
-            throw _iteratorError;
+
+          if (this._isDeclarative && currentAngle) {
+            start.rotate = currentAngle;
           }
         }
-      }
 
-      return attr;
-    } else if (Array.isArray(attr)) ; else if (_typeof(attr) === 'object') {
-      // apply every attribute individually if an object is passed
-      for (val in attr) {
-        this.attr(val, attr[val]);
+        morpher.from(start);
+        morpher.to(target);
+        var affineParameters = morpher.at(pos);
+        currentAngle = affineParameters.rotate;
+        current = new Matrix(affineParameters);
+        this.addTransform(current);
+        return morpher.done();
       }
-    } else if (val === null) {
-      // remove value
-      this.node.removeAttribute(attr);
-    } else if (val == null) {
-      // act as a getter if the first and only argument is not an object
-      val = this.node.getAttribute(attr);
-      return val == null ? attrs[attr] // FIXME: do we need to return defaults?
-      : isNumber.test(val) ? parseFloat(val) : val;
-    } else {
-      // convert image fill and stroke to patterns
-      if (attr === 'fill' || attr === 'stroke') {
-        if (isImage.test(val)) {
-          val = this.doc().defs().image(val);
-        }
-
-        if (val instanceof Image) {
-          val = this.doc().defs().pattern(0, 0, function () {
-            this.add(val);
-          });
-        }
-      } // ensure correct numeric values (also accepts NaN and Infinity)
-
-
-      if (typeof val === 'number') {
-        val = new SVGNumber(val);
-      } else if (Color.isColor(val)) {
-        // ensure full hex color
-        val = new Color(val);
-      } else if (Array.isArray(val)) {
-        // parse array values
-        val = new SVGArray(val);
-      } // if the passed attribute is leading...
-
 
-      if (attr === 'leading') {
-        // ... call the leading method instead
-        if (this.leading) {
-          this.leading(val);
-        }
-      } else {
-        // set given attribute on node
-        typeof ns === 'string' ? this.node.setAttributeNS(ns, attr, val.toString()) : this.node.setAttribute(attr, val.toString());
-      } // rebuild if required
+      function retarget(newTransforms) {
+        // only get a new origin if it changed since the last call
+        if ((newTransforms.origin || 'center').toString() !== (transforms.origin || 'center').toString()) {
+          origin = getOrigin(transforms, element);
+        } // overwrite the old transformations with the new ones
 
 
-      if (this.rebuild && (attr === 'font-size' || attr === 'x')) {
-        this.rebuild();
+        transforms = _objectSpread({}, newTransforms, {
+          origin: origin
+        });
       }
-    }
-
-    return this;
-  }
-
-  var name$1 = 'Element';
-  function setup(node) {
-    // initialize data object
-    this.dom = {}; // create circular reference
 
-    this.node = node;
-    this.type = node.nodeName;
-    this.node.instance = this;
+      this.queue(setup, run, retarget);
+      this._isDeclarative && this._rememberMorpher('transform', morpher);
+      return this;
+    },
+    // Animatable x-axis
+    x: function x(_x, relative) {
+      return this._queueNumber('x', _x);
+    },
+    // Animatable y-axis
+    y: function y(_y) {
+      return this._queueNumber('y', _y);
+    },
+    dx: function dx(x) {
+      return this._queueNumberDelta('dx', x);
+    },
+    dy: function dy(y) {
+      return this._queueNumberDelta('dy', y);
+    },
+    _queueNumberDelta: function _queueNumberDelta(method, to) {
+      to = new SVGNumber(to); // Try to change the target if we have this method already registerd
 
-    if (node.hasAttribute('svgjs:data')) {
-      // pull svgjs data from the dom (getAttributeNS doesn't work in html5)
-      this.setData(JSON.parse(node.getAttribute('svgjs:data')) || {});
-    }
-  } // Move over x-axis
+      if (this._tryRetargetDelta(method, to)) return this; // Make a morpher and queue the animation
 
-  function x$2(x) {
-    return this.attr('x', x);
-  } // Move over y-axis
+      var morpher = new Morphable(this._stepper).to(to);
+      this.queue(function () {
+        var from = this.element()[method]();
+        morpher.from(from);
+        morpher.to(from + to);
+      }, function (pos) {
+        this.element()[method](morpher.at(pos));
+        return morpher.done();
+      }); // Register the morpher so that if it is changed again, we can retarget it
 
-  function y$2(y) {
-    return this.attr('y', y);
-  } // Move by center over x-axis
+      this._rememberMorpher(method, morpher);
 
-  function cx$1(x) {
-    return x == null ? this.x() + this.width() / 2 : this.x(x - this.width() / 2);
-  } // Move by center over y-axis
+      return this;
+    },
+    _queueObject: function _queueObject(method, to) {
+      // Try to change the target if we have this method already registerd
+      if (this._tryRetarget(method, to)) return this; // Make a morpher and queue the animation
 
-  function cy$1(y) {
-    return y == null ? this.y() + this.height() / 2 : this.y(y - this.height() / 2);
-  } // Move element to given x and y values
+      var morpher = new Morphable(this._stepper).to(to);
+      this.queue(function () {
+        morpher.from(this.element()[method]());
+      }, function (pos) {
+        this.element()[method](morpher.at(pos));
+        return morpher.done();
+      }); // Register the morpher so that if it is changed again, we can retarget it
 
-  function move$1(x, y) {
-    return this.x(x).y(y);
-  } // Move element by its center
+      this._rememberMorpher(method, morpher);
 
-  function center(x, y) {
-    return this.cx(x).cy(y);
-  } // Set width of element
+      return this;
+    },
+    _queueNumber: function _queueNumber(method, value) {
+      return this._queueObject(method, new SVGNumber(value));
+    },
+    // Animatable center x-axis
+    cx: function cx(x) {
+      return this._queueNumber('cx', x);
+    },
+    // Animatable center y-axis
+    cy: function cy(y) {
+      return this._queueNumber('cy', y);
+    },
+    // Add animatable move
+    move: function move(x, y) {
+      return this.x(x).y(y);
+    },
+    // Add animatable center
+    center: function center(x, y) {
+      return this.cx(x).cy(y);
+    },
+    // Add animatable size
+    size: function size(width, height) {
+      // animate bbox based size for all other elements
+      var box;
 
-  function width$2(width) {
-    return this.attr('width', width);
-  } // Set height of element
+      if (!width || !height) {
+        box = this._element.bbox();
+      }
 
-  function height$2(height) {
-    return this.attr('height', height);
-  } // Set element size to given width and height
+      if (!width) {
+        width = box.width / box.height * height;
+      }
 
-  function size$2(width, height) {
-    var p = proportionalSize$1(this, width, height);
-    return this.width(new SVGNumber(p.width)).height(new SVGNumber(p.height));
-  } // Clone element
+      if (!height) {
+        height = box.height / box.width * width;
+      }
 
-  function clone(parent) {
-    // write dom data to the dom so the clone can pickup the data
-    this.writeDataToDom(); // clone element and assign new id
+      return this.width(width).height(height);
+    },
+    // Add animatable width
+    width: function width(_width) {
+      return this._queueNumber('width', _width);
+    },
+    // Add animatable height
+    height: function height(_height) {
+      return this._queueNumber('height', _height);
+    },
+    // Add animatable plot
+    plot: function plot(a, b, c, d) {
+      // Lines can be plotted with 4 arguments
+      if (arguments.length === 4) {
+        return this.plot([a, b, c, d]);
+      } // FIXME: this needs to be rewritten such that the element is only accesed
+      // in the init function
 
-    var clone = assignNewId(this.node.cloneNode(true)); // insert the clone in the given parent or after myself
 
-    if (parent) parent.add(clone);else this.after(clone);
-    return clone;
-  } // Remove element
+      return this._queueObject('plot', new this._element.MorphArray(a));
+      /*\r
+      var morpher = this._element.morphArray().to(a)\r
+        this.queue(function () {\r
+        morpher.from(this._element.array())\r
+      }, function (pos) {\r
+        this._element.plot(morpher.at(pos))\r
+      })\r
+        return this\r
+      */
+    },
+    // Add leading method
+    leading: function leading(value) {
+      return this._queueNumber('leading', value);
+    },
+    // Add animatable viewbox
+    viewbox: function viewbox(x, y, width, height) {
+      return this._queueObject('viewbox', new Box(x, y, width, height));
+    },
+    update: function update(o) {
+      if (_typeof(o) !== 'object') {
+        return this.update({
+          offset: arguments[0],
+          color: arguments[1],
+          opacity: arguments[2]
+        });
+      }
 
-  function remove() {
-    if (this.parent()) {
-      this.parent().removeElement(this);
+      if (o.opacity != null) this.attr('stop-opacity', o.opacity);
+      if (o.color != null) this.attr('stop-color', o.color);
+      if (o.offset != null) this.attr('offset', o.offset);
+      return this;
     }
+  });
 
-    return this;
-  } // Replace element
+  // export {default as SVGArray} from './SVGArray.js'
+  // export {default as Bare} from './Bare.js'
+  // export {default as Box} from './Box.js'
+  // export {default as Circle} from './Circle.js'
+  // export {default as ClipPath} from './ClipPath.js'
+  // export {default as Color} from './Color.js'
+  // export {default as Container} from './Container.js'
+  // export {Controller, Ease, PID, Spring} from './Controller.js'
+  // export {default as Defs} from './Defs.js'
+  // export {default as Doc} from './Doc.js'
+  // export {default as Element} from './Element.js'
+  // export {default as Ellipse} from './Ellipse.js'
+  // export {default as EventTarget} from './EventTarget.js'
+  // export {default as Gradient} from './Gradient.js'
+  // export {default as G} from './G.js'
+  // export {default as HtmlNode} from './HtmlNode.js'
+  // export {default as A} from './A.js'
+  // export {default as Image} from './Image.js'
+  // export {default as Line} from './Line.js'
+  // export {default as Marker} from './Marker.js'
+  // export {default as Mask} from './Mask.js'
+  // export {default as Matrix} from './Matrix.js'
+  // export {default as Morphable} from './Morphable.js'
+  // export {default as SVGNumber} from './SVGNumber.js'
+  // export {default as Parent} from './Parent.js'
+  // export {default as Path} from './Path.js'
+  // export {default as PathArray} from './PathArray.js'
+  // export {default as Pattern} from './Pattern.js'
+  // export {default as Point} from './Point.js'
+  // export {default as PointArray} from './PointArray.js'
+  // export {default as Polygon} from './Polygon.js'
+  // export {default as Polyline} from './Polyline.js'
+  // export {default as Queue} from './Queue.js'
+  // export {default as Rect} from './Rect.js'
+  // export {default as Runner} from './Runner.js'
+  // export {default as Shape} from './Shape.js'
+  // export {default as Stop} from './Stop.js'
+  // export {default as Symbol} from './Symbol.js'
+  // export {default as Text} from './Text.js'
+  // export {default as TextPath} from './TextPath.js'
+  // export {default as Timeline} from './Timeline.js'
+  // export {default as Use} from './Use.js'
 
-  function replace(element) {
-    this.after(element).remove();
-    return element;
-  } // Add element to given container and return self
+  var Classes = /*#__PURE__*/Object.freeze({
+    HtmlNode: HtmlNode,
+    Doc: Doc$1,
+    Defs: Defs,
+    G: G,
+    Animator: Animator,
+    Bare: Bare,
+    Circle: Circle,
+    ClipPath: ClipPath,
+    A: A,
+    Ellipse: Ellipse,
+    Stop: Stop,
+    Gradient: Gradient,
+    Image: Image,
+    Line: Line,
+    Marker: Marker,
+    Mask: Mask,
+    Path: Path,
+    Pattern: Pattern,
+    Polygon: Polygon,
+    Polyline: Polyline,
+    Rect: Rect,
+    Symbol: _Symbol,
+    Text: Text$1,
+    TextPath: TextPath,
+    Tspan: Tspan,
+    Use: Use,
+    SVGNumber: SVGNumber,
+    SVGArray: SVGArray,
+    PathArray: PathArray,
+    PointArray: PointArray$1,
+    Matrix: Matrix,
+    Point: Point,
+    Box: Box$1,
+    Color: Color,
+    Morphable: Morphable,
+    Queue: Queue,
+    Runner: Runner,
+    Timeline: Timeline,
+    Controller: Controller,
+    Ease: Ease,
+    PID: PID,
+    Spring: Spring
+  });
 
-  function addTo(parent) {
-    return makeInstance(parent).put(this);
-  } // Add element to given container and return container
 
-  function putIn(parent) {
-    return makeInstance(parent).add(this);
-  } // Get / set id
 
-  function id$1(id) {
-    // generate new id if no id set
-    if (typeof id === 'undefined' && !this.node.id) {
-      this.node.id = eid(this.type);
-    } // dont't set directly width this.node.id to make `null` work correctly
+  var containers = /*#__PURE__*/Object.freeze({
+    Bare: Bare,
+    ClipPath: ClipPath,
+    Defs: Defs,
+    Doc: Doc$1,
+    Gradient: Gradient,
+    G: G,
+    A: A,
+    Marker: Marker,
+    Mask: Mask,
+    Pattern: Pattern,
+    Symbol: _Symbol
+  });
 
 
-    return this.attr('id', id);
-  } // Checks whether the given point inside the bounding box of the element
 
-  function inside(x, y) {
-    var box = this.bbox();
-    return x > box.x && y > box.y && x < box.x + box.width && y < box.y + box.height;
-  } // Return id on string conversion
+  var elements$1 = /*#__PURE__*/Object.freeze({
+    Bare: Bare,
+    Circle: Circle,
+    ClipPath: ClipPath,
+    Defs: Defs,
+    Doc: Doc$1,
+    Ellipse: Ellipse,
+    Gradient: Gradient,
+    G: G,
+    HtmlNode: HtmlNode,
+    A: A,
+    Image: Image,
+    Line: Line,
+    Marker: Marker,
+    Mask: Mask,
+    Path: Path,
+    Pattern: Pattern,
+    Polygon: Polygon,
+    Polyline: Polyline,
+    Rect: Rect,
+    Stop: Stop,
+    Symbol: _Symbol,
+    Text: Text$1,
+    TextPath: TextPath,
+    Use: Use
+  });
 
-  function toString() {
-    return this.id();
-  } // Return array of classes on the node
+  // ### This module adds backward / forward functionality to elements.
 
-  function classes() {
-    var attr$$1 = this.attr('class');
-    return attr$$1 == null ? [] : attr$$1.trim().split(delimiter);
-  } // Return true if class exists on the node, false otherwise
+  // Dynamic style generator
 
-  function hasClass(name) {
-    return this.classes().indexOf(name) !== -1;
-  } // Add class to the node
+  function css(style, val) {
+    var ret = {};
 
-  function addClass(name) {
-    if (!this.hasClass(name)) {
-      var array = this.classes();
-      array.push(name);
-      this.attr('class', array.join(' '));
+    if (arguments.length === 0) {
+      // get full style as object
+      this.node.style.cssText.split(/\s*;\s*/).filter(function (el) {
+        return !!el.length;
+      }).forEach(function (el) {
+        var t = el.split(/\s*:\s*/);
+        ret[t[0]] = t[1];
+      });
+      return ret;
     }
 
-    return this;
-  } // Remove class from the node
+    if (arguments.length < 2) {
+      // get style properties in the array
+      if (Array.isArray(style)) {
+        var _iteratorNormalCompletion = true;
+        var _didIteratorError = false;
+        var _iteratorError = undefined;
 
-  function removeClass(name) {
-    if (this.hasClass(name)) {
-      this.attr('class', this.classes().filter(function (c) {
-        return c !== name;
-      }).join(' '));
-    }
+        try {
+          for (var _iterator = style[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+            var _name = _step.value;
+            var cased = camelCase(_name);
+            ret[cased] = this.node.style(cased);
+          }
+        } catch (err) {
+          _didIteratorError = true;
+          _iteratorError = err;
+        } finally {
+          try {
+            if (!_iteratorNormalCompletion && _iterator.return != null) {
+              _iterator.return();
+            }
+          } finally {
+            if (_didIteratorError) {
+              throw _iteratorError;
+            }
+          }
+        }
 
-    return this;
-  } // Toggle the presence of a class on the node
+        return ret;
+      } // get style for property
 
-  function toggleClass(name) {
-    return this.hasClass(name) ? this.removeClass(name) : this.addClass(name);
-  } // FIXME: getIdFromReference
-  // Get referenced element form attribute value
 
-  function reference$1(attr$$1) {
-    return get(this.attr(attr$$1));
-  } // Returns the parent element instance
+      if (typeof style === 'string') {
+        return this.node.style[camelCase(style)];
+      } // set styles in object
 
-  function parent(type) {
-    var parent = this; // check for parent
 
-    if (!parent.node.parentNode) return null; // get parent element
+      if (_typeof(style) === 'object') {
+        for (name in style) {
+          // set empty string if null/undefined/'' was given
+          this.node.style[camelCase(name)] = style[name] == null || isBlank.test(style[name]) ? '' : style[name];
+        }
+      }
+    } // set style for property
 
-    parent = adopt$1(parent.node.parentNode);
-    if (!type) return parent; // loop trough ancestors if type is given
 
-    while (parent && parent.node instanceof window.SVGElement) {
-      if (typeof type === 'string' ? parent.matches(type) : parent instanceof type) return parent;
-      parent = adopt$1(parent.node.parentNode);
+    if (arguments.length === 2) {
+      this.node.style[camelCase(style)] = val == null || isBlank.test(val) ? '' : val;
     }
-  } // Get parent document
 
-  function doc() {
-    var p = this.parent(Doc$1);
-    return p && p.doc();
-  } // Get defs
+    return this;
+  } // Show element
 
-  function defs() {
-    return this.doc().defs();
-  } // return array of all ancestors of given type up to the root svg
+  function show() {
+    return this.css('display', '');
+  } // Hide element
 
-  function parents(type) {
-    var parents = [];
-    var parent = this;
+  function hide() {
+    return this.css('display', 'none');
+  } // Is element visible?
 
-    do {
-      parent = parent.parent(type);
-      if (!parent || !parent.node) break;
-      parents.push(parent);
-    } while (parent.parent);
+  function visible() {
+    return this.css('display') !== 'none';
+  }
+  registerMethods('Element', {
+    css: css,
+    show: show,
+    hide: hide,
+    visible: visible
+  });
 
-    return parents;
-  } // matches the element vs a css selector
+  function untransform() {
+    return this.attr('transform', null);
+  } // merge the whole transformation chain into one matrix and returns it
 
-  function matches(selector) {
-    return matches(this.node, selector);
-  } // Returns the svg node to call native svg methods on it
+  function matrixify() {
+    var matrix = (this.attr('transform') || ''). // split transformations
+    split(transforms).slice(0, -1).map(function (str) {
+      // generate key => value pairs
+      var kv = str.trim().split('(');
+      return [kv[0], kv[1].split(delimiter).map(function (str) {
+        return parseFloat(str);
+      })];
+    }).reverse() // merge every transformation into one matrix
+    .reduce(function (matrix, transform) {
+      if (transform[0] === 'matrix') {
+        return matrix.lmultiply(arrayToMatrix(transform[1]));
+      }
 
-  function native() {
-    return this.node;
-  } // Import raw svg
+      return matrix[transform[0]].apply(matrix, transform[1]);
+    }, new Matrix());
+    return matrix;
+  } // add an element to another parent without changing the visual representation on the screen
 
-  function svg() {
-    // write svgjs data to the dom
-    this.writeDataToDom();
-    return this.node.outerHTML;
-  } // write svgjs data to the dom
+  function toParent(parent) {
+    if (this === parent) return this;
+    var ctm = this.screenCTM();
+    var pCtm = parent.screenCTM().inverse();
+    this.addTo(parent).untransform().transform(pCtm.multiply(ctm));
+    return this;
+  } // same as above with parent equals root-svg
 
-  function writeDataToDom() {
-    // remove previously set data
-    this.node.removeAttribute('svgjs:data');
+  function toDoc() {
+    return this.toParent(this.doc());
+  } // Add transformations
 
-    if (Object.keys(this.dom).length) {
-      this.node.setAttribute('svgjs:data', JSON.stringify(this.dom)); // see #428
+  function transform(o, relative) {
+    // Act as a getter if no object was passed
+    if (o == null || typeof o === 'string') {
+      var decomposed = new Matrix(this).decompose();
+      return decomposed[o] || decomposed;
     }
 
-    return this;
-  } // set given data to the elements data property
-
-  function setData(o) {
-    this.dom = o;
-    return this;
-  }
-  function getEventTarget$1() {
-    return this.node;
-  }
-
-  var Element$1 = /*#__PURE__*/Object.freeze({
-    name: name$1,
-    setup: setup,
-    x: x$2,
-    y: y$2,
-    cx: cx$1,
-    cy: cy$1,
-    move: move$1,
-    center: center,
-    width: width$2,
-    height: height$2,
-    size: size$2,
-    clone: clone,
-    remove: remove,
-    replace: replace,
-    addTo: addTo,
-    putIn: putIn,
-    id: id$1,
-    inside: inside,
-    toString: toString,
-    classes: classes,
-    hasClass: hasClass,
-    addClass: addClass,
-    removeClass: removeClass,
-    toggleClass: toggleClass,
-    reference: reference$1,
-    parent: parent,
-    doc: doc,
-    defs: defs,
-    parents: parents,
-    matches: matches,
-    native: native,
-    svg: svg,
-    writeDataToDom: writeDataToDom,
-    setData: setData,
-    getEventTarget: getEventTarget$1,
-    attr: attr
-  });
+    if (!isMatrixLike(o)) {
+      // Set the origin according to the defined transform
+      o = _objectSpread({}, o, {
+        origin: getOrigin(o, this)
+      });
+    } // The user can pass a boolean, an Element or an Matrix or nothing
 
-  function clipPathRemove() {
-    // unclip all targets
-    this.targets().forEach(function (el) {
-      el.unclip();
-    }); // remove clipPath from parent
 
-    return remove.call(this);
+    var cleanRelative = relative === true ? this : relative || false;
+    var result = new Matrix(cleanRelative).transform(o);
+    return this.attr('transform', result);
   }
-  function clipPathTargets() {
-    return find('svg [clip-path*="' + this.id() + '"]');
-  } // Unclip all clipped elements and remove itself
-
-  function maskRemove() {
-    // unclip all targets
-    this.targets().forEach(function (el) {
-      el.unmask();
-    }); // remove clipPath from parent
+  registerMethods('Element', {
+    untransform: untransform,
+    matrixify: matrixify,
+    toParent: toParent,
+    toDoc: toDoc,
+    transform: transform
+  });
 
-    return remove.call(this);
-  }
-  function maskTargets() {
-    return find('svg [mask*="' + this.id() + '"]');
-  } // Unclip all clipped elements and remove itself
+  function setup$1(node) {
+    this._memory = {};
+  } // Remember arbitrary data
 
-  function patternGradientRemove() {
-    // unclip all targets
-    this.targets().forEach(function (el) {
-      el.unFill();
-    }); // remove clipPath from parent
+  function remember(k, v) {
+    // remember every item in an object individually
+    if (_typeof(arguments[0]) === 'object') {
+      for (var key in k) {
+        this.remember(key, k[key]);
+      }
+    } else if (arguments.length === 1) {
+      // retrieve memory
+      return this.memory()[k];
+    } else {
+      // store memory
+      this.memory()[k] = v;
+    }
 
-    return remove.call(this);
-  }
-  function unFill() {
-    this.attr('fill', null);
-  }
-  function patternGradientTargets() {
-    return find('svg [fill*="' + this.id() + '"]');
-  } // custom attr to handle transform
-
-  function patternAttr(a, b, c) {
-    if (a === 'transform') a = 'patternTransform';
-    return attr.call(this, a, b, c);
-  } // custom attr to handle transform
-
-  function gradientAttr(a, b, c) {
-    if (a === 'transform') a = 'gradientTransform';
-    return attr.call(this, a, b, c);
-  }
-  function pathTargets() {
-    return find('svg textpath [href*="' + this.id() + '"]');
-  }
-  function HtmlNodeAdd(element, i) {
-    element = makeInstance(element);
+    return this;
+  } // Erase a given memory
 
-    if (element.node !== this.node.children[i]) {
-      this.node.insertBefore(element.node, this.node.children[i] || null);
+  function forget() {
+    if (arguments.length === 0) {
+      this._memory = {};
+    } else {
+      for (var i = arguments.length - 1; i >= 0; i--) {
+        delete this.memory()[arguments[i]];
+      }
     }
 
     return this;
+  } // Initialize or return local memory object
+
+  function memory() {
+    return this._memory;
   }
+  registerMethods('Element', {
+    remember: remember,
+    forget: forget,
+    memory: memory
+  });
+  registerConstructor('Memory', setup$1);
 
-  var name$2 = 'EventTarget';
-  function setup$1() {
+  function setup$2() {
     var node = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
     this.events = node.events || {};
   } // Bind given event to listener
@@ -6439,15 +6444,14 @@ var SVG = (function () {
     this.dispatch(event, data);
     return this;
   }
-
-  var EventTarget = /*#__PURE__*/Object.freeze({
-    name: name$2,
-    setup: setup$1,
+  registerMethods('EventTarget', {
+    setup: setup$2,
     on: on$1,
     off: off$1,
     dispatch: dispatch$1,
     fire: fire
   });
+  registerConstructor('EventTarget', setup$2);
 
   function children() {
     return map(this.node.children, function (node) {
@@ -6576,8 +6580,7 @@ var SVG = (function () {
     this.remove();
     return this;
   }
-
-  var Parent = /*#__PURE__*/Object.freeze({
+  registerMethods('Container', {
     children: children,
     add: add,
     put: put,
@@ -6595,49 +6598,27 @@ var SVG = (function () {
     ungroup: ungroup
   });
 
+  // import {extend} from './tools.js'
   var extend$2 = extend$1;
-  extend$2([Doc$1, _Symbol, Image, Pattern, Marker], {
-    viewbox: Box$1.constructors.viewbox
-  });
-  extend$2([Line, Polyline, Polygon, Path], _objectSpread({}, Marker.constructors.marker));
-  extend$2(Text$1, TextPath.constructors.Text);
-  extend$2(Path, TextPath.constructors.Path);
-  extend$2(Defs, _objectSpread({}, Gradient.constructors.Defs, Marker.constructors.Defs, Pattern.constructors.Defs));
-  extend$2([Text$1, Tspan], Tspan.constructors.Tspan);
-  extend$2([Gradient, Pattern], {
-    remove: patternGradientRemove,
-    targets: patternGradientTargets,
-    unFill: unFill
-  });
-  extend$2(Gradient, {
-    attr: gradientAttr
-  });
-  extend$2(Pattern, {
-    attr: patternAttr
-  });
-  extend$2(ClipPath, {
-    remove: clipPathRemove,
-    targets: clipPathTargets
-  });
-  extend$2(Mask, {
-    remove: maskRemove,
-    targets: maskTargets
-  });
-  extend$2(Path, {
-    targets: pathTargets
-  });
-  extend$2(HtmlNode, {
-    add: HtmlNodeAdd
-  });
+  extend$2([Doc$1, _Symbol, Image, Pattern, Marker], getMethodsFor('viewbox'));
+  extend$2([Line, Polyline, Polygon, Path], getMethodsFor('marker'));
+  extend$2(Text$1, getMethodsFor('Text'));
+  extend$2(Path, getMethodsFor('Path'));
+  extend$2(Defs, getMethodsFor('Defs'));
+  extend$2([Text$1, Tspan], getMethodsFor('Tspan'));
+  var containerMethods = getMethodsFor('Container'); // FIXME: We need a container array
 
   for (var i$1 in containers) {
-    extend$2(containers[i$1], _objectSpread({}, A.constructors.Container, ClipPath.constructors.Container, Doc$1.constructors.Container, G.constructors.Container, Gradient.constructors.Container, Line.constructors.Container, Marker.constructors.Container, Mask.constructors.Container, Path.constructors.Container, Pattern.constructors.Container, Polygon.constructors.Container, Polyline.constructors.Container, Rect.constructors.Container, {
-      find: find
-    }, _Symbol.constructors.Container, Text$1.constructors.Container, TextPath.constructors.Container, Use.constructors.Container));
+    extend$2(containers[i$1], containerMethods);
   }
 
-  for (var _i in elements) {
-    extend$2(elements[_i], _objectSpread({}, EventTarget, Element$1, Parent, arrange, A.constructors.Element, Box$1.constructors.Element, Circle.constructors.Element, ClipPath.constructors.Element, css$1, Image.constructors.Element, Mask.constructors.Element, Matrix.constructors.Element, Point.constructors.Element, Runner.constructors.Element, Timeline.constructors.Element, transform$1));
+  var elementMethods = getMethodsFor('Element');
+
+  for (var _i in elements$1) {
+    extend$2(elements$1[_i], elementMethods);
+    extend$2(elements$1[_i], getConstructor('EventTarget'));
+    extend$2(elements$1[_i], getConstructor('Element'));
+    extend$2(elements$1[_i], getConstructor('Memory'));
   } // The main wrapping element
 
 
index bfb399c24a35c315377e1185cec1c1dea913e35b..9d05a1fcb94d086aa749ca9db40e87c50194af91 100644 (file)
@@ -1 +1 @@
-var SVG=function(){"use strict";function l(t){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function o(t,e,n){return e&&i(t.prototype,e),n&&i(t,n),t}function _(r){for(var t=1;t<arguments.length;t++){var s=null!=arguments[t]?arguments[t]:{},e=Object.keys(s);"function"==typeof Object.getOwnPropertySymbols&&(e=e.concat(Object.getOwnPropertySymbols(s).filter(function(t){return Object.getOwnPropertyDescriptor(s,t).enumerable}))),e.forEach(function(t){var e,n,i;e=r,i=s[n=t],n in e?Object.defineProperty(e,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[n]=i})}return r}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&n(t,e)}function a(t){return(a=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function n(t,e){return(n=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function f(t,e){return!e||"object"!=typeof e&&"function"!=typeof e?function(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}(t):e}function O(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e<t.length;e++)n[e]=t[e];return n}}(t)||function(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var r=function(){function l(t,e){var n=e.extensions,i=void 0===n?[]:n;c(this,l);var r=!0,s=!(this.tags=[]),u=void 0;try{for(var o,a=i[Symbol.iterator]();!(r=(o=a.next()).done);r=!0){var h=o.value;h.setup.call(this,t),this.tags.push(h.name)}}catch(t){s=!0,u=t}finally{try{r||null==a.return||a.return()}finally{if(s)throw u}}}return o(l,[{key:"is",value:function(t){return this.tags.includes(t)}}]),l}(),e="http://www.w3.org/2000/svg",s="http://www.w3.org/2000/xmlns/",h="http://www.w3.org/1999/xlink",d=/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,v=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,y=/rgb\((\d+),(\d+),(\d+)\)/,t=/\)\s*,?\s*/,p=/\s/g,m=/^#[a-f0-9]{3,6}$/i,g=/^rgb\(/,w=/^(\s+)?$/,x=/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,b=/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,k=/[\s,]+/,A=/([^e])-/gi,C=/[MLHVCSQTAZ]/gi,M=/[MLHVCSQTAZ]/i,j=/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,T=/\./g;function E(t,e,n,i){return n+i.replace(T," .")}function S(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function N(t){return t.charAt(0).toUpperCase()+t.slice(1)}function D(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function P(t,e,n){if(null==e||null==n){var i=t.bbox();null==e?e=i.width/i.height*n:null==n&&(n=i.height/i.width*e)}return{width:e,height:n}}function z(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}var q="abcdef".split("");function L(t,e,n){return Math.abs(e-t)<(n||1e-6)}function R(t){return null!=t.a||null!=t.b||null!=t.c||null!=t.d||null!=t.e||null!=t.f}function F(t,e){var n,i,r=t.origin;if("string"==typeof r||null==r){var s=(r||"center").toLowerCase().trim(),u=e.bbox(),o=u.height,a=u.width,h=u.x,l=u.y,c=s.includes("left")?h:s.includes("right")?h+a:h+a/2,f=s.includes("top")?l:s.includes("bottom")?l+o:l+o/2;n=null!=t.ox?t.ox:c,i=null!=t.oy?t.oy:f}else n=r[0],i=r[1];return[n,i]}function I(t,e){return e||X(t)}function X(t){return document.createElementNS(e,t)}function Y(e,t){var n,i;if(Array.isArray(t))t.forEach(function(t){Y(e,t)});else for(i=(e=Array.isArray(e)?e:[e]).length-1;0<=i;i--)for(n in t.name&&(e[i].extensions=(e[i].extensions||[]).concat(t)),t)e[i].prototype[n]||"name"==n||"setup"==n||(e[i].prototype[n]=t[n])}var B=Object.freeze({nodeOrNew:I,makeNode:X,extend:Y,addFactory:function(t,e){Y(t,e)},invent:function(e){var t="function"==typeof e.create?e.create:function(t){e.inherit.call(this,t||X(e.create))};return e.inherit&&(t.prototype=new e.inherit,t.prototype.constructor=t),e.extend&&Y(t,e.extend),e.construct&&Y(e.parent||Container,e.construct),t}});function G(n){var i=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{};extend(function(t){function e(t){return c(this,e),f(this,a(e).call(this,I(n,t),e))}return u(e,i),o(e,[{key:"words",value:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(document.createTextNode(t)),this}}]),e}(),i)}var V=function(){function n(){c(this,n),this.init.apply(this,arguments)}return o(n,[{key:"init",value:function(t,e){e=Array.isArray(t)?t[1]:e,t=Array.isArray(t)?t[0]:t,this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-34e37:34e37:"string"==typeof t?(e=t.match(d))&&(this.value=parseFloat(e[1]),"%"===e[5]?this.value/=100:"s"===e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof n&&(this.value=t.valueOf(),this.unit=t.unit)}},{key:"toString",value:function(){return("%"===this.unit?~~(1e8*this.value)/1e6:"s"===this.unit?this.value/1e3:this.value)+this.unit}},{key:"toJSON",value:function(){return this.toString()}},{key:"toArray",value:function(){return[this.value,this.unit]}},{key:"valueOf",value:function(){return this.value}},{key:"plus",value:function(t){return new n(this+(t=new n(t)),this.unit||t.unit)}},{key:"minus",value:function(t){return new n(this-(t=new n(t)),this.unit||t.unit)}},{key:"times",value:function(t){return new n(this*(t=new n(t)),this.unit||t.unit)}},{key:"divide",value:function(t){return new n(this/(t=new n(t)),this.unit||t.unit)}}]),n}();function H(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())}function U(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())}function Q(t){return null==t?this.attr("cx"):this.attr("cx",t)}function $(t){return null==t?this.attr("cy"):this.attr("cy",t)}function W(t){return null==t?2*this.rx():this.rx(new V(t).divide(2))}function Z(t){return null==t?2*this.ry():this.ry(new V(t).divide(2))}function J(t,e){var n=P(this,t,e);return this.rx(new V(n.width).divide(2)).ry(new V(n.height).divide(2))}var K=Object.freeze({rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)},x:H,y:U,cx:Q,cy:$,width:W,height:Z,size:J}),tt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("circle",t),e))}return u(e,r),o(e,[{key:"radius",value:function(t){return this.attr("r",t)}},{key:"rx",value:function(t){return this.attr("r",t)}},{key:"ry",value:function(t){return this.rx(t)}}]),e}();Y(tt,{x:H,y:U,cx:Q,cy:$,width:W,height:Z,size:J}),tt.constructors={Element:{circle:function(t){return this.put(new tt).radius(new V(t).divide(2)).move(0,0)}}};var et=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("clipPath",t),e))}return u(e,r),e}();et.constructors={Container:{clip:function(){return this.defs().put(new et)}},Element:{clipWith:function(t){var e=t instanceof et?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}};var nt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("defs",t),e))}return u(e,r),o(e,[{key:"flatten",value:function(){return this}},{key:"ungroup",value:function(){return this}}]),e}(),it=function(t){function n(t){var e;return c(this,n),(e=f(this,a(n).call(this,I("svg",t),n))).namespace(),e}return u(n,r),o(n,[{key:"isRoot",value:function(){return!(this.node.parentNode&&this.node.parentNode instanceof window.SVGElement&&"#document"!==this.node.parentNode.nodeName)}},{key:"doc",value:function(){return this.isRoot()?this:Element.doc.call(this)}},{key:"namespace",value:function(){return this.isRoot()?this.attr({xmlns:e,version:"1.1"}).attr("xmlns:xlink",h,s).attr("xmlns:svgjs","http://svgjs.com/svgjs",s):this.doc().namespace()}},{key:"defs",value:function(){if(!this.isRoot())return this.doc().defs();var t=this.node.getElementsByTagName("defs")[0];return t?t.instance||new nt(t):this.put(new nt)}},{key:"parent",value:function(t){return this.isRoot()?"#document"===this.node.parentNode.nodeName?null:this.node.parentNode:Element.parent.call(this,t)}},{key:"remove",value:function(){return this.isRoot()?(this.parent()&&this.parent().removeChild(this.node),this):Element.remove.call(this)}},{key:"clear",value:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this}}]),n}();it.constructors={Container:{nested:function(){return this.put(new it)}}};var rt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,nodeOrNew("ellipse",t),e))}return u(e,r),e}();Y(rt,K);var st=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("stop",t),e))}return u(e,r),o(e,[{key:"update",value:function(t){return("number"==typeof t||t instanceof V)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new V(t.offset)),this}}]),e}();var ut=Object.freeze({from:function(t,e){return"radialGradient"===(this._element||this).type?this.attr({fx:new V(t),fy:new V(e)}):this.attr({x1:new V(t),y1:new V(e)})},to:function(t,e){return"radialGradient"===(this._element||this).type?this.attr({cx:new V(t),cy:new V(e)}):this.attr({x2:new V(t),y2:new V(e)})}}),ot=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I(t+"Gradient","string"==typeof t?null:t),e))}return u(e,r),o(e,[{key:"stop",value:function(t,e,n){return this.put(new st).update(t,e,n)}},{key:"update",value:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this}},{key:"url",value:function(){return"url(#"+this.id()+")"}},{key:"toString",value:function(){return this.url()}}]),e}();Y(ot,ut),ot.constructors={Container:{gradient:function(t,e){return this.defs().gradient(t,e)}},Defs:{gradient:function(t,e){return this.put(new ot(t)).update(e)}}};var at=function(t){function e(t){return c(this,e),f(this,a(e).call(this,nodeorNew("g",t),e))}return u(e,r),e}();at.constructors={Element:{group:function(){return this.put(new at)}}};var ht=function(t){function n(t){var e;return c(this,n),(e=f(this,a(n).call(this,t,n))).node=t,e}return u(n,r),o(n,[{key:"put",value:function(t,e){return this.add(t,e),t}},{key:"getEventTarget",value:function(){return this.node}}]),n}(),lt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("a",t),e))}return u(e,r),o(e,[{key:"to",value:function(t){return this.attr("href",t,h)}},{key:"target",value:function(t){return this.attr("target",t)}}]),e}();lt.constructors={Container:{link:function(t){return this.put(new lt).to(t)}},Element:{linkTo:function(t){var e=new lt;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}};var ct=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("pattern",t)))}return u(e,r),o(e,[{key:"url",value:function(){return"url(#"+this.id()+")"}},{key:"update",value:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this}},{key:"toString",value:function(){return this.url()}}]),e}();ct.constructors={Container:{pattern:function(t,e,n){return this.defs().pattern(t,e,n)}},Defs:{pattern:function(t,e,n){return this.put(new ct).update(n).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}};var ft=0;function dt(t){return t instanceof Base&&t.is("EventTarget")?t.getEventTarget():t}function vt(t,e,i,n,r){var s=i.bind(n||t),u=dt(t);e=Array.isArray(e)?e:e.split(k),u.instance=u.instance||{events:{}};var o=u.instance.events;i._svgjsListenerId||(i._svgjsListenerId=++ft),e.forEach(function(t){var e=t.split(".")[0],n=t.split(".")[1]||"*";o[e]=o[e]||{},o[e][n]=o[e][n]||{},o[e][n][i._svgjsListenerId]=s,u.addEventListener(e,s,r||!1)})}function yt(t,e,s,u){var o=dt(t);if(o.instance&&("function"!=typeof s||(s=s._svgjsListenerId))){var a=o.instance.events;(e=Array.isArray(e)?e:(e||"").split(k)).forEach(function(t){var e,n,i=t&&t.split(".")[0],r=t&&t.split(".")[1];if(s)a[i]&&a[i][r||"*"]&&(o.removeEventListener(i,a[i][r||"*"][s],u||!1),delete a[i][r||"*"][s]);else if(i&&r){if(a[i]&&a[i][r]){for(n in a[i][r])yt(o,[i,r].join("."),n);delete a[i][r]}}else if(r)for(t in a)for(e in a[t])r===e&&yt(o,[t,r].join("."));else if(i){if(a[i]){for(e in a[i])yt(o,[i,e].join("."));delete a[i]}}else{for(t in a)yt(o,t);o.instance.events={}}})}}var pt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("image",t),e))}return u(e,r),o(e,[{key:"load",value:function(n,i){if(!n)return this;var r=new window.Image;return vt(r,"load",function(t){var e=this.parent(ct);0===this.width()&&0===this.height()&&this.size(r.width,r.height),e instanceof ct&&0===e.width()&&0===e.height()&&e.size(this.width(),this.height()),"function"==typeof i&&i.call(this,{width:r.width,height:r.height,ratio:r.width/r.height,url:n})},this),vt(r,"load error",function(){yt(r)}),this.attr("href",r.src=n,h)}}]),e}();pt.constructors={Container:{image:function(t,e){return this.put(new pt).size(0,0).load(t,e)}}};var mt=function(){try{return Array}catch(t){return Array}}(),gt=function(t){function n(){var t,e;return c(this,n),(t=e=f(this,a(n).call(this))).init.apply(t,arguments),e}return u(n,mt),o(n,[{key:"init",value:function(t,e){this.length=0,this.push.apply(this,O(this.parse(t||e)))}},{key:"toArray",value:function(){return Array.prototype.slice(this)}},{key:"toString",value:function(){this.join(" ")}},{key:"valueOf",value:function(){return this.toArray()}},{key:"parse",value:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(k).map(parseFloat)}},{key:"clone",value:function(){return new this.constructor(this)}},{key:"toSet",value:function(){return new Set(this)}}]),n}(),wt=function(t){function r(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[[0,0]];return c(this,r),f(this,a(r).call(this,t,e))}return u(r,gt),o(r,[{key:"toString",value:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)n.push(this.value[t].join(","));return n.join(" ")}},{key:"toArray",value:function(){return this.value.reduce(function(t,e){return[].concat.call(t,e)},[])}},{key:"toLine",value:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}}},{key:"at",value:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new r(i)}},{key:"parse",value:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(k).map(parseFloat);t.length%2!=0&&t.pop();for(var n=0,i=t.length;n<i;n+=2)e.push([t[n],t[n+1]]);return e}},{key:"move",value:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i=this.value.length-1;0<=i;i--)this.value[i]=[this.value[i][0]+t,this.value[i][1]+e];return this}},{key:"size",value:function(t,e){var n,i=this.bbox();for(n=this.value.length-1;0<=n;n--)i.width&&(this.value[n][0]=(this.value[n][0]-i.x)*t/i.width+i.x),i.height&&(this.value[n][1]=(this.value[n][1]-i.y)*e/i.height+i.y);return this}},{key:"bbox",value:function(){var e=-1/0,n=-1/0,i=1/0,r=1/0;return this.value.forEach(function(t){e=Math.max(t[0],e),n=Math.max(t[1],n),i=Math.min(t[0],i),r=Math.min(t[1],r)}),{x:i,y:r,width:e-i,height:n-r}}}]),r}(),xt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("line",t),e))}return u(e,r),o(e,[{key:"array",value:function(){return new wt([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])}},{key:"plot",value:function(t,e,n,i){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:n,y2:i}:new wt(t).toLine(),this.attr(t))}},{key:"move",value:function(t,e){return this.attr(this.array().move(t,e).toLine())}},{key:"size",value:function(t,e){var n=P(this,t,e);return this.attr(this.array().size(n.width,n.height).toLine())}}]),e}();xt.constructors={Container:{line:function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];return xt.prototype.plot.apply(this.put(new xt),null!=e[0]?e:[0,0,0,0])}}};var bt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,nodeOrNew("marker",t),e))}return u(e,r),o(e,[{key:"width",value:function(t){return this.attr("markerWidth",t)}},{key:"height",value:function(t){return this.attr("markerHeight",t)}},{key:"ref",value:function(t,e){return this.attr("refX",t).attr("refY",e)}},{key:"update",value:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this}},{key:"toString",value:function(){return"url(#"+this.id()+")"}}]),e}();bt.constructors={Container:{marker:function(t,e,n){return this.defs().marker(t,e,n)}},Defs:{marker:function(t,e,n){return this.put(new bt).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(n)}},marker:{marker:function(t,e,n,i){var r=["marker"];return"all"!==t&&r.push(t),r=r.join("-"),t=e instanceof bt?e:this.defs().marker(e,n,i),this.attr(r,t)}}};var kt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("mask",t)))}return u(e,r),e}();function _t(){if(!_t.nodes){var t=(new it).size(2,0).css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"}),e=t.path().node;_t.nodes={svg:t,path:e}}if(!_t.nodes.svg.node.parentNode){var n=document.body||document.documentElement;_t.nodes.svg.addTo(n)}return _t.nodes}kt.constructors={Container:{mask:function(){return this.defs().put(new kt)}},Element:{maskWith:function(t){var e=t instanceof kt?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}};var Ot=function(){function r(t,e,n){var i;c(this,r),n=n||{x:0,y:0},i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"===l(t)?{x:t.x,y:t.y}:{x:t,y:e},this.x=null==i.x?n.x:i.x,this.y=null==i.y?n.y:i.y}return o(r,[{key:"clone",value:function(){return new r(this)}},{key:"native",value:function(){var t=_t().svg.createSVGPoint();return t.x=this.x,t.y=this.y,t}},{key:"transform",value:function(t){return new r(t.a*this.x+t.c*this.y+t.e,t.b*this.x+t.d*this.y+t.f)}}]),r}();Ot.constructors={Element:{point:function(t,e){return new Ot(t,e).transform(this.screenCTM().inverse())}}};for(var At={M:function(t,e,n){return e.x=n.x=t[0],e.y=n.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,n){return e.x=n.x,e.y=n.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},Ct="mlhvqtcsaz".split(""),Mt=0,jt=Ct.length;Mt<jt;++Mt)At[Ct[Mt]]=function(s){return function(t,e,n){if("H"===s)t[0]=t[0]+e.x;else if("V"===s)t[0]=t[0]+e.y;else if("A"===s)t[5]=t[5]+e.x,t[6]=t[6]+e.y;else for(var i=0,r=t.length;i<r;++i)t[i]=t[i]+(i%2?e.y:e.x);return At[s](t,e,n)}}(Ct[Mt].toUpperCase());var Tt=function(t){function h(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[["M",0,0]];return c(this,h),f(this,a(h).call(this,t,e))}return u(h,gt),o(h,[{key:"toString",value:function(){return function(t){for(var e=0,n=t.length,i="";e<n;e++)i+=t[e][0],null!=t[e][1]&&(i+=t[e][1],null!=t[e][2]&&(i+=" ",i+=t[e][2],null!=t[e][3]&&(i+=" ",i+=t[e][3],i+=" ",i+=t[e][4],null!=t[e][5]&&(i+=" ",i+=t[e][5],i+=" ",i+=t[e][6],null!=t[e][7]&&(i+=" ",i+=t[e][7])))));return i+" "}(this)}},{key:"toArray",value:function(){return this.reduce(function(t,e){return[].concat.call(t,e)},[])}},{key:"move",value:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i,r=this.length-1;0<=r;r--)"M"===(i=this[r][0])||"L"===i||"T"===i?(this[r][1]+=t,this[r][2]+=e):"H"===i?this[r][1]+=t:"V"===i?this[r][1]+=e:"C"===i||"S"===i||"Q"===i?(this[r][1]+=t,this[r][2]+=e,this[r][3]+=t,this[r][4]+=e,"C"===i&&(this[r][5]+=t,this[r][6]+=e)):"A"===i&&(this[r][6]+=t,this[r][7]+=e);return this}},{key:"size",value:function(t,e){var n,i,r=this.bbox();for(n=this.length-1;0<=n;n--)"M"===(i=this[n][0])||"L"===i||"T"===i?(this[n][1]=(this[n][1]-r.x)*t/r.width+r.x,this[n][2]=(this[n][2]-r.y)*e/r.height+r.y):"H"===i?this[n][1]=(this[n][1]-r.x)*t/r.width+r.x:"V"===i?this[n][1]=(this[n][1]-r.y)*e/r.height+r.y:"C"===i||"S"===i||"Q"===i?(this[n][1]=(this[n][1]-r.x)*t/r.width+r.x,this[n][2]=(this[n][2]-r.y)*e/r.height+r.y,this[n][3]=(this[n][3]-r.x)*t/r.width+r.x,this[n][4]=(this[n][4]-r.y)*e/r.height+r.y,"C"===i&&(this[n][5]=(this[n][5]-r.x)*t/r.width+r.x,this[n][6]=(this[n][6]-r.y)*e/r.height+r.y)):"A"===i&&(this[n][1]=this[n][1]*t/r.width,this[n][2]=this[n][2]*e/r.height,this[n][6]=(this[n][6]-r.x)*t/r.width+r.x,this[n][7]=(this[n][7]-r.y)*e/r.height+r.y);return this}},{key:"equalCommands",value:function(t){var e,n,i;for(t=new h(t),i=this.length===t.value.length,e=0,n=this.length;i&&e<n;e++)i=this[e][0]===t.value[e][0];return i}},{key:"morph",value:function(t){return t=new h(t),this.equalCommands(t)?this.destination=t:this.destination=null,this}},{key:"at",value:function(t){if(!this.destination)return this;var e,n,i,r,s=this,u=this.destination.value,o=[],a=new h;for(e=0,n=s.length;e<n;e++){for(o[e]=[s[e][0]],i=1,r=s[e].length;i<r;i++)o[e][i]=s[e][i]+(u[e][i]-s[e][i])*t;"A"===o[e][0]&&(o[e][4]=+(0!==o[e][4]),o[e][5]=+(0!==o[e][5]))}return a.value=o,a}},{key:"parse",value:function(t){if(t instanceof h)return t.valueOf();var e,n={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(j,E).replace(C," $& ").replace(A,"$1 -").trim().split(k):t.reduce(function(t,e){return[].concat.call(t,e)},[]);for(var i=[],r=new Ot,s=new Ot,u=0,o=t.length;M.test(t[u])?(e=t[u],++u):"M"===e?e="L":"m"===e&&(e="l"),i.push(At[e].call(null,t.slice(u,u+=n[e.toUpperCase()]).map(parseFloat),r,s)),u<o;);return i}},{key:"bbox",value:function(){return _t().path.setAttribute("d",this.toString()),_t.nodes.path.getBBox()}}]),h}(),Et=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("path",t),e))}return u(e,r),o(e,[{key:"array",value:function(){return this._array||(this._array=new Tt(this.attr("d")))}},{key:"plot",value:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new Tt(t))}},{key:"clear",value:function(){return delete this._array,this}},{key:"move",value:function(t,e){return this.attr("d",this.array().move(t,e))}},{key:"x",value:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)}},{key:"y",value:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)}},{key:"size",value:function(t,e){var n=P(this,t,e);return this.attr("d",this.array().size(n.width,n.height))}},{key:"width",value:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)}},{key:"height",value:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}}]),e}();Et.prototype.MorphArray=Tt,Et.constructors={Container:{path:function(t){return this.put(new Et).plot(t||new Tt)}}};var St=wt;var Nt=Object.freeze({MorphArray:St,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}});var Dt=Object.freeze({array:function(){return this._array||(this._array=new PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var n=proportionalSize(this,t,e);return this.attr("points",this.array().size(n.width,n.height))}}),Pt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("polygon",t),e))}return u(e,r),e}();Pt.constructors={Parent:{polygon:function(t){return this.put(new Pt).plot(t||new wt)}}},Y(Pt,Nt),Y(Pt,Dt);var zt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("polyline",t),e))}return u(e,r),e}();zt.constructors={Parent:{polyline:function(t){return this.put(new zt).plot(t||new wt)}}},Y(zt,Nt),Y(zt,Dt);var qt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("rect",t),e))}return u(e,r),e}();qt.constructors={Container:{rect:function(t,e){return this.put(new qt).size(t,e)}}};var Lt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("symbol",t),e))}return u(e,r),e}();function Rt(){}Lt.constructors={Container:{symbol:function(){return this.put(new Lt)}}};var Ft=400,It=">",Xt=0,Yt={"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"};var Bt=Object.freeze({plain:function(t){return!1===this._build&&this.clear(),this.node.appendChild(document.createTextNode(t)),this},length:function(){return this.node.getComputedTextLength()}}),Gt=function(t){function n(t){var e;return c(this,n),(e=f(this,a(n).call(this,I("text",t),n))).dom.leading=new V(1.3),e._rebuild=!0,e._build=!1,e.attr("font-family",Yt["font-family"]),e}return u(n,r),o(n,[{key:"x",value:function(t){return null==t?this.attr("x"):this.attr("x",t)}},{key:"y",value:function(t){var e=this.attr("y"),n="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-n:e:this.attr("y","number"==typeof t?t+n:t)}},{key:"cx",value:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)}},{key:"cy",value:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)}},{key:"text",value:function(t){if(void 0===t){var e=this.node.childNodes,n=0;t="";for(var i=0,r=e.length;i<r;++i)"textPath"!==e[i].nodeName?(i!==n&&3!==e[i].nodeType&&!0===adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent):0===i&&(n=1);return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else for(var s=0,u=(t=t.split("\n")).length;s<u;s++)this.tspan(t[s]).newLine();return this.build(!1).rebuild()}},{key:"leading",value:function(t){return null==t?this.dom.leading:(this.dom.leading=new V(t),this.rebuild())}},{key:"rebuild",value:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,n=0,i=this.dom.leading*new V(this.attr("font-size"));this.each(function(){this.dom.newLined&&(this.attr("x",e.attr("x")),"\n"===this.text()?n+=i:(this.attr("dy",i+n),n=0))}),this.fire("rebuild")}return this}},{key:"build",value:function(t){return this._build=!!t,this}},{key:"setData",value:function(t){return this.dom=t,this.dom.leading=new V(t.leading||1.3),this}}]),n}();Y(Gt,Bt),Gt.constructors={Container:{text:function(t){return this.put(new Gt).text(t)},plain:function(t){return this.put(new Gt).plain(t)}}};var Vt=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("textPath",t)))}return u(e,Gt),o(e,[{key:"array",value:function(){var t=this.track();return t?t.array():null}},{key:"plot",value:function(t){var e=this.track(),n=null;return e&&(n=e.plot(t)),null==t?n:this}},{key:"track",value:function(){return this.reference("href")}}]),e}();Vt.constructors={Container:{textPath:function(t,e){return this.defs().path(e).text(t).addTo(this)}},Text:{path:function(t){var e=new Vt;return t instanceof Et||(t=this.doc().defs().path(t)),e.attr("href","#"+t,h),this.put(e)},textPath:function(){return this.select("textPath")}},Path:{text:function(t){if(t instanceof Gt){var e=t.text();return t.clear().path(this).text(e)}return this.parent().put(new Gt).path(this).text(t)}}},Vt.prototype.MorphArray=Tt;var Ht=function(t){function e(t){return c(this,e),f(this,a(e).call(this,nodeOrNew("use",t),e))}return u(e,r),o(e,[{key:"element",value:function(t,e){return this.attr("href",(e||"")+"#"+t,h)}}]),e}();Ht.constructors={Container:{use:function(t,e){return this.put(new Ht).element(t,e)}}};var Ut=Object.freeze({Bare:G,Circle:tt,ClipPath:et,Defs:nt,Doc:it,Ellipse:rt,Gradient:ot,G:at,HtmlNode:ht,A:lt,Image:pt,Line:xt,Marker:bt,Mask:kt,Path:Et,Pattern:ct,Polygon:Pt,Polyline:zt,Rect:qt,Stop:st,Symbol:Lt,Text:Gt,TextPath:Vt,Use:Ht});function Qt(t){if(t instanceof r)return t;if("object"===l(t))return $t(t);if(null==t)return new Doc;if("string"==typeof t&&"<"!==t.charAt(0))return $t(document.querySelector(t));var e=makeNode("svg");return e.innerHTML=t,t=$t(e.firstElementChild)}function $t(t){return t?t.instance instanceof Element?t.instance:t instanceof window.SVGElement?"svg"===t.nodeName?new it(t):"linearGradient"===t.nodeName||"radialGradient"===t.nodeName?new ot(t):Ut[N(t.nodeName)]?new(Ut[N(t.nodeName)])(t):new G(t):new ht(t):null}var Wt=1e3;function Zt(t){return"Svgjs"+N(t)+Wt++}function Jt(t){for(var e=t.children.length-1;0<=e;e--)Jt(t.children[e]);return t.id?$t(t).id(Zt(t.nodeName)):$t(t)}var Kt=Object.freeze({makeInstance:Qt,adopt:$t,eid:Zt,assignNewId:Jt}),te=function(){function t(){c(this,t),this._first=null,this._last=null}return o(t,[{key:"push",value:function(t){var e=t.next?t:{value:t,next:null,prev:null};return this._last?(e.prev=this._last,this._last.next=e,this._last=e):(this._last=e,this._first=e),e}},{key:"shift",value:function(){var t=this._first;return t?(this._first=t.next,this._first&&(this._first.prev=null),this._last=this._first?this._last:null,t.value):null}},{key:"first",value:function(){return this._first&&this._first.value}},{key:"last",value:function(){return this._last&&this._last.value}},{key:"remove",value:function(t){t.prev&&(t.prev.next=t.next),t.next&&(t.next.prev=t.prev),t===this._last&&(this._last=t.prev),t===this._first&&(this._first=t.next),t.prev=null,t.next=null}}]),t}(),ee={nextDraw:null,frames:new te,timeouts:new te,timer:window.performance||window.Date,transforms:[],frame:function(t){var e=ee.frames.push({run:t});return null===ee.nextDraw&&(ee.nextDraw=window.requestAnimationFrame(ee._draw)),e},transform_frame:function(t,e){ee.transforms[e]=t},timeout:function(t,e){e=e||0;var n=ee.timer.now()+e,i=ee.timeouts.push({run:t,time:n});return null===ee.nextDraw&&(ee.nextDraw=window.requestAnimationFrame(ee._draw)),i},cancelFrame:function(t){ee.frames.remove(t)},clearTimeout:function(t){ee.timeouts.remove(t)},_draw:function(t){for(var e=null,n=ee.timeouts.last();(e=ee.timeouts.shift())&&(t>=e.time?e.run():ee.timeouts.push(e),e!==n););for(var i=null,r=ee.frames.last();i!==r&&(i=ee.frames.shift());)i.run();ee.transforms.forEach(function(t){t()}),ee.nextDraw=ee.timeouts.first()||ee.frames.first()?window.requestAnimationFrame(ee._draw):null}},ne=function(t){function e(t){return c(this,e),f(this,a(e).call(this,I("tspan",t),e))}return u(e,r),o(e,[{key:"text",value:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)}},{key:"dx",value:function(t){return this.attr("dx",t)}},{key:"dy",value:function(t){return this.attr("dy",t)}},{key:"newLine",value:function(){var t=this.parent(Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}]),e}();function ie(t){return t%360*Math.PI/180}Y(ne,Bt),ne.constructors={Tspan:{tspan:function(t){var e=new ne;return this._build||this.clear(),this.node.appendChild(e.node),e.text(t)}}};var re=function(){function h(){c(this,h),this.init.apply(this,arguments)}return o(h,[{key:"init",value:function(t){var e=z([1,0,0,1,0,0]);t=t instanceof r&&t.is("Element")?t.matrixify():"string"==typeof t?z(t.split(k).map(parseFloat)):Array.isArray(t)?z(t):"object"===l(t)&&R(t)?t:"object"===l(t)?(new h).transform(t):6===arguments.length?z([].slice.call(arguments)):e,this.a=null!=t.a?t.a:e.a,this.b=null!=t.b?t.b:e.b,this.c=null!=t.c?t.c:e.c,this.d=null!=t.d?t.d:e.d,this.e=null!=t.e?t.e:e.e,this.f=null!=t.f?t.f:e.f}},{key:"clone",value:function(){return new h(this)}},{key:"transform",value:function(t){if(R(t))return new h(t).multiplyO(this);var e=h.formatTransforms(t),n=new Ot(e.ox,e.oy).transform(this),i=n.x,r=n.y,s=(new h).translateO(e.rx,e.ry).lmultiplyO(this).translateO(-i,-r).scaleO(e.scaleX,e.scaleY).skewO(e.skewX,e.skewY).shearO(e.shear).rotateO(e.theta).translateO(i,r);if(isFinite(e.px)||isFinite(e.py)){var u=new Ot(i,r).transform(s),o=e.px?e.px-u.x:0,a=e.py?e.py-u.y:0;s.translateO(o,a)}return s.translateO(e.tx,e.ty),s}},{key:"compose",value:function(t){t.origin&&(t.originX=t.origin[0],t.originY=t.origin[1]);var e=t.originX||0,n=t.originY||0,i=t.scaleX||1,r=t.scaleY||1,s=t.shear||0,u=t.rotate||0,o=t.translateX||0,a=t.translateY||0;return(new h).translateO(-e,-n).scaleO(i,r).shearO(s).rotateO(u).translateO(o,a).lmultiplyO(this).translateO(e,n)}},{key:"decompose",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:0,e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0,n=this.a,i=this.b,r=this.c,s=this.d,u=this.e,o=this.f,a=n*s-i*r,h=0<a?1:-1,l=h*Math.sqrt(n*n+i*i),c=Math.atan2(h*i,h*n),f=180/Math.PI*c,d=Math.cos(c),v=Math.sin(c),y=(n*r+i*s)/a,p=r*l/(y*n-i)||s*l/(y*i+n);return{scaleX:l,scaleY:p,shear:y,rotate:f,translateX:u-t+t*d*l+e*(y*d*l-v*p),translateY:o-e+t*v*l+e*(y*v*l+d*p),originX:t,originY:e,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}}},{key:"multiply",value:function(t){return this.clone().multiplyO(t)}},{key:"multiplyO",value:function(t){var e=t instanceof h?t:new h(t);return h.matrixMultiply(this,e,this)}},{key:"lmultiply",value:function(t){return this.clone().lmultiplyO(t)}},{key:"lmultiplyO",value:function(t){var e=t instanceof h?t:new h(t);return h.matrixMultiply(e,this,this)}},{key:"inverseO",value:function(){var t=this.a,e=this.b,n=this.c,i=this.d,r=this.e,s=this.f,u=t*i-e*n;if(!u)throw new Error("Cannot invert "+this);var o=i/u,a=-e/u,h=-n/u,l=t/u,c=-(o*r+h*s),f=-(a*r+l*s);return this.a=o,this.b=a,this.c=h,this.d=l,this.e=c,this.f=f,this}},{key:"inverse",value:function(){return this.clone().inverseO()}},{key:"translate",value:function(t,e){return this.clone().translateO(t,e)}},{key:"translateO",value:function(t,e){return this.e+=t||0,this.f+=e||0,this}},{key:"scale",value:function(t,e,n,i){var r;return(r=this.clone()).scaleO.apply(r,arguments)}},{key:"scaleO",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:t,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0,i=3<arguments.length&&void 0!==arguments[3]?arguments[3]:0;3===arguments.length&&(i=n,n=e,e=t);var r=this.a,s=this.b,u=this.c,o=this.d,a=this.e,h=this.f;return this.a=r*t,this.b=s*e,this.c=u*t,this.d=o*e,this.e=a*t-n*t+n,this.f=h*e-i*e+i,this}},{key:"rotate",value:function(t,e,n){return this.clone().rotateO(t,e,n)}},{key:"rotateO",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0;t=ie(t);var i=Math.cos(t),r=Math.sin(t),s=this.a,u=this.b,o=this.c,a=this.d,h=this.e,l=this.f;return this.a=s*i-u*r,this.b=u*i+s*r,this.c=o*i-a*r,this.d=a*i+o*r,this.e=h*i-l*r+n*r-e*i+e,this.f=l*i+h*r-e*r-n*i+n,this}},{key:"flip",value:function(t,e){return this.clone().flipO(t,e)}},{key:"flipO",value:function(t,e){return"x"===t?this.scaleO(-1,1,e,0):"y"===t?this.scaleO(1,-1,0,e):this.scaleO(-1,-1,t,e||t)}},{key:"shear",value:function(t,e,n){return this.clone().shearO(t,e,n)}},{key:"shearO",value:function(t){var e=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0,n=this.a,i=this.b,r=this.c,s=this.d,u=this.e,o=this.f;return this.a=n+i*t,this.c=r+s*t,this.e=u+o*t-e*t,this}},{key:"skew",value:function(t,e,n,i){var r;return(r=this.clone()).skewO.apply(r,arguments)}},{key:"skewO",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:t,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0,i=3<arguments.length&&void 0!==arguments[3]?arguments[3]:0;3===arguments.length&&(i=n,n=e,e=t),t=ie(t),e=ie(e);var r=Math.tan(t),s=Math.tan(e),u=this.a,o=this.b,a=this.c,h=this.d,l=this.e,c=this.f;return this.a=u+o*r,this.b=o+u*s,this.c=a+h*r,this.d=h+a*s,this.e=l+c*r-i*r,this.f=c+l*s-n*s,this}},{key:"skewX",value:function(t,e,n){return this.skew(t,0,e,n)}},{key:"skewXO",value:function(t,e,n){return this.skewO(t,0,e,n)}},{key:"skewY",value:function(t,e,n){return this.skew(0,t,e,n)}},{key:"skewYO",value:function(t,e,n){return this.skewO(0,t,e,n)}},{key:"aroundO",value:function(t,e,n){var i=t||0,r=e||0;return this.translateO(-i,-r).lmultiplyO(n).translateO(i,r)}},{key:"around",value:function(t,e,n){return this.clone().aroundO(t,e,n)}},{key:"native",value:function(){for(var t=_t().node.createSVGMatrix(),e=q.length-1;0<=e;e--)t[q[e]]=this[q[e]];return t}},{key:"equals",value:function(t){var e=new h(t);return L(this.a,e.a)&&L(this.b,e.b)&&L(this.c,e.c)&&L(this.d,e.d)&&L(this.e,e.e)&&L(this.f,e.f)}},{key:"toString",value:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},{key:"toArray",value:function(){return[this.a,this.b,this.c,this.d,this.e,this.f]}},{key:"valueOf",value:function(){return{a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}}}],[{key:"formatTransforms",value:function(t){var e="both"===t.flip||!0===t.flip,n=t.flip&&(e||"x"===t.flip)?-1:1,i=t.flip&&(e||"y"===t.flip)?-1:1,r=t.skew&&t.skew.length?t.skew[0]:isFinite(t.skew)?t.skew:isFinite(t.skewX)?t.skewX:0,s=t.skew&&t.skew.length?t.skew[1]:isFinite(t.skew)?t.skew:isFinite(t.skewY)?t.skewY:0,u=t.scale&&t.scale.length?t.scale[0]*n:isFinite(t.scale)?t.scale*n:isFinite(t.scaleX)?t.scaleX*n:n,o=t.scale&&t.scale.length?t.scale[1]*i:isFinite(t.scale)?t.scale*i:isFinite(t.scaleY)?t.scaleY*i:i,a=t.shear||0,h=t.rotate||t.theta||0,l=new Ot(t.origin||t.around||t.ox||t.originX,t.oy||t.originY),c=l.x,f=l.y,d=new Ot(t.position||t.px||t.positionX,t.py||t.positionY),v=d.x,y=d.y,p=new Ot(t.translate||t.tx||t.translateX,t.ty||t.translateY),m=p.x,g=p.y,w=new Ot(t.relative||t.rx||t.relativeX,t.ry||t.relativeY);return{scaleX:u,scaleY:o,skewX:r,skewY:s,shear:a,theta:h,rx:w.x,ry:w.y,tx:m,ty:g,ox:c,oy:f,px:v,py:y}}},{key:"matrixMultiply",value:function(t,e,n){var i=t.a*e.a+t.c*e.b,r=t.b*e.a+t.d*e.b,s=t.a*e.c+t.c*e.d,u=t.b*e.c+t.d*e.d,o=t.e+t.a*e.e+t.c*e.f,a=t.f+t.b*e.e+t.d*e.f;return n.a=i,n.b=r,n.c=s,n.d=u,n.e=o,n.f=a,n}}]),h}();re.constructors={Element:{ctm:function(){return new re(this.node.getCTM())},screenCTM:function(){if(this instanceof Doc&&!this.isRoot()){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new re(e)}return new re(this.node.getScreenCTM())}}};var se=function(){function u(){c(this,u),this.init.apply(this,arguments)}return o(u,[{key:"init",value:function(t){var e;t="string"==typeof t?t.split(k).map(parseFloat):Array.isArray(t)?t:"object"===l(t)?[null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height]:4===arguments.length?[].slice.call(arguments):[0,0,0,0],this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],null==(e=this).x&&(e.x=0,e.y=0,e.width=0,e.height=0),e.w=e.width,e.h=e.height,e.x2=e.x+e.width,e.y2=e.y+e.height,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2}},{key:"merge",value:function(t){var e=Math.min(this.x,t.x),n=Math.min(this.y,t.y);return new u(e,n,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-n)}},{key:"transform",value:function(e){var n=1/0,i=-1/0,r=1/0,s=-1/0;return[new Ot(this.x,this.y),new Ot(this.x2,this.y),new Ot(this.x,this.y2),new Ot(this.x2,this.y2)].forEach(function(t){t=t.transform(e),n=Math.min(n,t.x),i=Math.max(i,t.x),r=Math.min(r,t.y),s=Math.max(s,t.y)}),new u(n,r,i-n,s-r)}},{key:"addOffset",value:function(){return this.x+=window.pageXOffset,this.y+=window.pageYOffset,this}},{key:"toString",value:function(){return this.x+" "+this.y+" "+this.width+" "+this.height}},{key:"toArray",value:function(){return[this.x,this.y,this.width,this.height]}}]),u}();function ue(e){var n,t,i;try{if(n=e(this.node),!((i=n).w||i.h||i.x||i.y||(t=this.node,(document.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t===document}).call(document.documentElement,t))))throw new Error("Element not in the dom")}catch(t){try{var r=this.clone(_t().svg).show();n=e(r.node),r.remove()}catch(t){throw t}}return n}se.constructors={Element:{bbox:function(){return new se(ue.call(this,function(t){return t.getBBox()}))},rbox:function(t){var e=new se(ue.call(this,function(t){return t.getBoundingClientRect()}));return t?e.transform(t.screenCTM().inverse()):e.addOffset()}},viewbox:function(t,e,n,i){return null==t?new se(this.attr("viewBox")):this.attr("viewBox",new se(t,e,n,i))}};var oe=function(){function t(){c(this,t),this.init.apply(this,arguments)}return o(t,[{key:"init",value:function(t,e,n){var i,r;(this.r=0,this.g=0,this.b=0,t)&&("string"==typeof t?g.test(t)?(i=y.exec(t.replace(p,"")),this.r=parseInt(i[1]),this.g=parseInt(i[2]),this.b=parseInt(i[3])):m.test(t)&&(i=v.exec(4===(r=t).length?["#",r.substring(1,2),r.substring(1,2),r.substring(2,3),r.substring(2,3),r.substring(3,4),r.substring(3,4)].join(""):r),this.r=parseInt(i[1],16),this.g=parseInt(i[2],16),this.b=parseInt(i[3],16)):Array.isArray(t)?(this.r=t[0],this.g=t[1],this.b=t[2]):"object"===l(t)?(this.r=t.r,this.g=t.g,this.b=t.b):3===arguments.length&&(this.r=t,this.g=e,this.b=n))}},{key:"toString",value:function(){return this.toHex()}},{key:"toArray",value:function(){return[this.r,this.g,this.b]}},{key:"toHex",value:function(){return"#"+D(Math.round(this.r))+D(Math.round(this.g))+D(Math.round(this.b))}},{key:"toRgb",value:function(){return"rgb("+[this.r,this.g,this.b].join()+")"}},{key:"brightness",value:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11}}],[{key:"test",value:function(t){return t+="",m.test(t)||g.test(t)}},{key:"isRgb",value:function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b}},{key:"isColor",value:function(t){return this.isRgb(t)||this.test(t)}}]),t}();function ae(e,n){return function(t){return null==t?this[t]:(this[e]=t,n&&n.call(this),this)}}var he={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)},bezier:function(t,e,n,i){return function(t){}}},le=function(){function t(){c(this,t)}return o(t,[{key:"done",value:function(){return!1}}]),t}(),ce=function(t){function n(t){var e;return c(this,n),(e=f(this,a(n).call(this))).ease=he[t||It]||t,e}return u(n,le),o(n,[{key:"step",value:function(t,e,n){return"number"!=typeof t?n<1?t:e:t+(e-t)*this.ease(n)}}]),n}(),fe=function(t){function n(t){var e;return c(this,n),(e=f(this,a(n).call(this))).stepper=t,e}return u(n,le),o(n,[{key:"step",value:function(t,e,n,i){return this.stepper(t,e,n,i)}},{key:"done",value:function(t){return t.done}}]),n}();function de(){var t=(this._duration||500)/1e3,e=this._overshoot||0,n=Math.PI,i=Math.log(e/100+1e-10),r=-i/Math.sqrt(n*n+i*i),s=3.9/(r*t);this.d=2*r*s,this.k=s*s}var ve=function(t){function i(t,e){var n;return c(this,i),(n=f(this,a(i).call(this))).duration(t||500).overshoot(e||0),n}return u(i,fe),o(i,[{key:"step",value:function(t,e,n,i){if("string"==typeof t)return t;if(i.done=n===1/0,n===1/0)return e;if(0===n)return t;100<n&&(n=16),n/=1e3;var r=i.velocity||0,s=-this.d*r-this.k*(t-e),u=t+r*n+s*n*n/2;return i.velocity=r+s*n,i.done=Math.abs(e-u)+Math.abs(r)<.002,i.done?e:u}}]),i}();Y(ve,{duration:ae("_duration",de),overshoot:ae("_overshoot",de)});var ye=function(t){function s(t,e,n,i){var r;return c(this,s),t=null==t?.1:t,e=null==e?.01:e,n=null==n?0:n,i=null==i?1e3:i,(r=f(this,a(s).call(this))).p(t).i(e).d(n).windup(i),r}return u(s,fe),o(s,[{key:"step",value:function(t,e,n,i){if("string"==typeof t)return t;if(i.done=n===1/0,n===1/0)return e;if(0===n)return t;var r=e-t,s=(i.integral||0)+r*n,u=(r-(i.error||0))/n,o=this.windup;return!1!==o&&(s=Math.max(-o,Math.min(s,o))),i.error=r,i.integral=s,i.done=Math.abs(r)<.001,i.done?e:t+(this.P*r+this.I*s+this.D*u)}}]),s}();Y(ye,{windup:ae("windup"),p:ae("P"),i:ae("I"),d:ae("D")});var pe=function(){function i(t){c(this,i),this._stepper=t||new ce("-"),this._from=null,this._to=null,this._type=null,this._context=null,this._morphObj=null}return o(i,[{key:"from",value:function(t){return null==t?this._from:(this._from=this._set(t),this)}},{key:"to",value:function(t){return null==t?this._to:(this._to=this._set(t),this)}},{key:"type",value:function(t){return null==t?this._type:(this._type=t,this)}},{key:"_set",value:function(t){if(!this._type){var e=l(t);"number"===e?this.type(V):"string"===e?oe.isColor(t)?this.type(oe):regex.delimiter.test(t)?this.type(regex.pathLetters.test(t)?Tt:gt):regex.numberAndUnit.test(t)?this.type(V):this.type(i.NonMorphable):-1<MorphableTypes.indexOf(t.constructor)?this.type(t.constructor):Array.isArray(t)?this.type(gt):"object"===e?this.type(i.ObjectBag):this.type(i.NonMorphable)}var n=new this._type(t).toArray();return this._morphObj=this._morphObj||new this._type,this._context=this._context||Array.apply(null,Array(n.length)).map(Object),n}},{key:"stepper",value:function(t){return null==t?this._stepper:(this._stepper=t,this)}},{key:"done",value:function(){return this._context.map(this._stepper.done).reduce(function(t,e){return t&&e},!0)}},{key:"at",value:function(n){var i=this;return this._morphObj.fromArray(this._from.map(function(t,e){return i._stepper.step(t,i._to[e],n,i._context[e],i._context)}))}}]),i}();pe.NonMorphable=function(){function t(){c(this,t),this.init.apply(this,arguments)}return o(t,[{key:"init",value:function(t){t=Array.isArray(t)?t[0]:t,this.value=t}},{key:"valueOf",value:function(){return this.value}},{key:"toArray",value:function(){return[this.value]}}]),t}(),pe.TransformBag=function(){function t(){c(this,t),this.init.apply(this,arguments)}return o(t,[{key:"init",value:function(t){Array.isArray(t)&&(t={scaleX:t[0],scaleY:t[1],shear:t[2],rotate:t[3],translateX:t[4],translateY:t[5],originX:t[6],originY:t[7]}),Object.assign(this,pe.TransformBag.defaults,t)}},{key:"toArray",value:function(){var t=this;return[t.scaleX,t.scaleY,t.shear,t.rotate,t.translateX,t.translateY,t.originX,t.originY]}}]),t}(),pe.TransformBag.defaults={scaleX:1,scaleY:1,shear:0,rotate:0,translateX:0,translateY:0,originX:0,originY:0},pe.ObjectBag=function(){function t(){c(this,t),this.init.apply(this,arguments)}return o(t,[{key:"init",value:function(t){if(this.values=[],Array.isArray(t))this.values=t;else{var e=Object.entries(t||{}).sort(function(t,e){return t[0]-e[0]});this.values=e.reduce(function(t,e){return t.concat(e)},[])}}},{key:"valueOf",value:function(){for(var t={},e=this.values,n=0,i=e.length;n<i;n+=2)t[e[n]]=e[n+1];return t}},{key:"toArray",value:function(){return this.values}}]),t}(),Y([V,oe,se,re,gt,wt,Tt,pe.NonMorphable,pe.TransformBag,pe.ObjectBag],{to:function(t,e){return(new pe).type(this.constructor).from(this.valueOf()).to(t,e)},fromArray:function(t){return this.init(t),this}});var me=window.performance||Date,ge=function(t){var e=t.start,n=t.runner.duration();return{start:e,duration:n,end:e+n,runner:t.runner}},we=function(){function t(){c(this,t),this._timeSource=function(){return me.now()},this._dispatcher=document.createElement("div"),this._startTime=0,this._speed=1,this._reverse=!1,this._persist=0,this._nextFrame=null,this._paused=!1,this._runners=[],this._order=[],this._time=0,this._lastSourceTime=0,this._lastStepTime=0}return o(t,[{key:"getEventTarget",value:function(){return this._dispatcher}},{key:"schedule",value:function(t,e,n){if(null==t)return this._runners.map(ge).sort(function(t,e){return t.start-e.start||t.duration-e.duration});this.active()||(this._step(),null==n&&(n="now"));var i=0;if(e=e||0,null==n||"last"===n||"after"===n)i=this._startTime;else if("absolute"===n||"start"===n)i=e,e=0;else if("now"===n)i=this._time;else{if("relative"!==n)throw new Error('Invalid value for the "when" parameter');var r=this._runners[t.id];r&&(i=r.start+e,e=0)}return t.unschedule(),t.timeline(this),t.time(-e),this._startTime=i+t.duration()+e,this._runners[t.id]={persist:this.persist(),runner:t,start:i},this._order.push(t.id),this._continue(),this}},{key:"unschedule",value:function(t){var e=this._order.indexOf(t.id);return e<0||(delete this._runners[t.id],this._order.splice(e,1),t.timeline(null)),this}},{key:"play",value:function(){return this._paused=!1,this._continue()}},{key:"pause",value:function(){return this._nextFrame=null,this._paused=!0,this}},{key:"stop",value:function(){return this.seek(-this._time),this.pause()}},{key:"finish",value:function(){return this.seek(1/0),this.pause()}},{key:"speed",value:function(t){return null==t?this._speed:(this._speed=t,this)}},{key:"reverse",value:function(t){var e=this.speed();if(null==t)return this.speed(-e);var n=Math.abs(e);return this.speed(t?n:-n)}},{key:"seek",value:function(t){return this._time+=t,this._continue()}},{key:"time",value:function(t){return null==t?this._time:(this._time=t,this)}},{key:"persist",value:function(t){return null==t?this._persist:(this._persist=t,this)}},{key:"source",value:function(t){return null==t?this._timeSource:(this._timeSource=t,this)}},{key:"_step",value:function(){if(!this._paused){var t=this._timeSource(),e=t-this._lastSourceTime,n=this._speed*e+(this._time-this._lastStepTime);this._lastSourceTime=t,this._time+=n,this._lastStepTime=this._time;for(var i=!1,r=0,s=this._order.length;r<s;r++){var u=this._runners[this._order[r]],o=u.runner,a=n,h=this._time-u.start;if(h<0)i=!0;else if(h<a&&(a=h),o.active())if(o.step(a).done){if(!0!==u.persist){o.duration()-o.time()+this._time+this._persist<this._time&&(delete this._runners[this._order[r]],this._order.splice(r--,1)&&--s,o.timeline(null))}}else i=!0}return this._nextFrame=i?ee.frame(this._step.bind(this)):null,this}}},{key:"_continue",value:function(){return this._paused||this._nextFrame||(this._nextFrame=ee.frame(this._step.bind(this))),this}},{key:"active",value:function(){return!!this._nextFrame}}]),t}();we.constructors={Element:{timeline:function(){return this._timeline=this._timeline||new we,this._timeline}}};var xe=function(){function s(t){c(this,s),this.id=s.id++,t="function"==typeof(t=null==t?Ft:t)?new fe(t):t,this._element=null,this._timeline=null,this.done=!1,this._queue=[],this._duration="number"==typeof t&&t,this._isDeclarative=t instanceof fe,this._stepper=this._isDeclarative?t:new ce,this._history={},this.enabled=!0,this._time=0,this._last=0,this.transforms=new re,this.transformId=1,this._haveReversed=!1,this._reverse=!1,this._loopsDone=0,this._swing=!1,this._wait=0,this._times=1}return o(s,[{key:"element",value:function(t){return null==t?this._element:((this._element=t)._prepareRunner(),this)}},{key:"timeline",value:function(t){return void 0===t?this._timeline:(this._timeline=t,this)}},{key:"animate",value:function(t,e,n){var i=s.sanitise(t,e,n),r=new s(i.duration);return this._timeline&&r.timeline(this._timeline),this._element&&r.element(this._element),r.loop(i).schedule(e,n)}},{key:"schedule",value:function(t,e,n){if(t instanceof we||(n=e,e=t,t=this.timeline()),!t)throw Error("Runner cannot be scheduled without timeline");return t.schedule(this,e,n),this}},{key:"unschedule",value:function(){var t=this.timeline();return t&&t.unschedule(this),this}},{key:"loop",value:function(t,e,n){return"object"===l(t)&&(e=t.swing,n=t.wait,t=t.times),this._times=t||1/0,this._swing=e||!1,this._wait=n||0,this}},{key:"delay",value:function(t){return this.animate(0,t)}},{key:"queue",value:function(t,e,n){return this._queue.push({initialiser:t||Rt,runner:e||Rt,isTransform:n,initialised:!1,finished:!1}),this.timeline()&&this.timeline()._continue(),this}},{key:"during",value:function(t){return this.queue(null,t)}},{key:"after",value:function(t){return this.on("finish",t)}},{key:"time",value:function(t){if(null==t)return this._time;var e=t-this._time;return this.step(e),this}},{key:"duration",value:function(){return this._times*(this._wait+this._duration)-this._wait}},{key:"loops",value:function(t){var e=this._duration+this._wait;if(null==t){var n=Math.floor(this._time/e),i=(this._time-n*e)/this._duration;return Math.min(n+i,this._times)}var r=t%1,s=e*Math.floor(t)+this._duration*r;return this.time(s)}},{key:"position",value:function(t){var e,n=this._time,r=this._duration,s=this._wait,i=this._times,u=this._swing,o=this._reverse;if(null==t){var a=function(t){var e=u*Math.floor(t%(2*(s+r))/(s+r)),n=e&&!o||!e&&o,i=Math.pow(-1,n)*(t%(s+r))/r+n;return Math.max(Math.min(i,1),0)},h=i*(s+r)-s;return e=n<=0?Math.round(a(1e-5)):n<h?a(n):Math.round(a(h-1e-5)),e}var l=Math.floor(this.loops()),c=u&&l%2==0;return e=l+(c&&!o||o&&c?t:1-t),this.loops(e)}},{key:"progress",value:function(t){return null==t?Math.min(1,this._time/this.duration()):this.time(t*this.duration())}},{key:"step",value:function(t){if(!this.enabled)return this;t=null==t?16:t,this._time+=t;var e=this.position(),n=this._lastPosition!==e&&0<=this._time;this._lastPosition=e;var i=this.duration(),r=(this._lastTime<0&&this._time,this._lastTime<this._time&&this.time>i);this._lastTime=this._time;var s=this._isDeclarative;if(this.done=!s&&!r&&this._time>=i,n||s){this._initialise(n),this.transforms=new re;var u=this._run(s?t:e)}return this.done=this.done||u&&s,this}},{key:"finish",value:function(){return this.step(1/0)}},{key:"reverse",value:function(t){return this._reverse=null==t?!this._reverse:t,this}},{key:"ease",value:function(t){return this._stepper=new ce(t),this}},{key:"active",value:function(t){return null==t?this.enabled:(this.enabled=t,this)}},{key:"_rememberMorpher",value:function(t,e){this._history[t]={morpher:e,caller:this._queue[this._queue.length-1]}}},{key:"_tryRetarget",value:function(t,e){if(this._history[t]){if(!this._history[t].caller.initialised){var n=this._queue.indexOf(this._history[t].caller);return this._queue.splice(n,1),!1}this._history[t].caller.isTransform?this._history[t].caller.isTransform(e):this._history[t].morpher.to(e),this._history[t].caller.finished=!1;var i=this.timeline();return i&&i._continue(),!0}return!1}},{key:"_initialise",value:function(t){if(t||this._isDeclarative)for(var e=0,n=this._queue.length;e<n;++e){var i=this._queue[e],r=this._isDeclarative||!i.initialised&&t;t=!i.finished,r&&t&&(i.initialiser.call(this),i.initialised=!0)}}},{key:"_run",value:function(t){for(var e=!0,n=0,i=this._queue.length;n<i;++n){var r=this._queue[n],s=r.runner.call(this,t);r.finished=r.finished||!0===s,e=e&&r.finished}return e}},{key:"addTransform",value:function(t,e){return this.transforms.lmultiplyO(t),this}},{key:"clearTransform",value:function(){return this.transforms=new re,this}}],[{key:"sanitise",value:function(t,e,n){var i=1,r=!1,s=0;return e=e||Xt,n=n||"last","object"!==l(t=t||Ft)||t instanceof le||(e=t.delay||e,n=t.when||n,r=t.swing||r,i=t.times||i,s=t.wait||s,t=t.duration||Ft),{duration:t,delay:e,swing:r,times:i,wait:s,when:n}}}]),s}();xe.id=0;var be=function t(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:new re,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:-1,i=!(2<arguments.length&&void 0!==arguments[2])||arguments[2];c(this,t),this.transforms=e,this.id=n,this.done=i};Y([xe,be],{mergeWith:function(t){return new be(t.transforms.lmultiply(this.transforms),t.id)}});var ke=function(t,e){return t.lmultiplyO(e)},_e=function(t){return t.transforms};var Oe=function(){function t(){c(this,t),this.runners=[],this.ids=[]}return o(t,[{key:"add",value:function(t){if(!this.runners.includes(t)){var n=t.id+1,e=this.ids.reduce(function(t,e){return t<e&&e<n?e:t},0),i=this.ids.indexOf(e)+1;return this.ids.splice(i,0,n),this.runners.splice(i,0,t),this}}},{key:"getByID",value:function(t){return this.runners[this.ids.indexOf(t+1)]}},{key:"remove",value:function(t){var e=this.ids.indexOf(t+1);return this.ids.splice(e,1),this.runners.splice(e,1),this}},{key:"merge",value:function(){var n=this,i=null;return this.runners.forEach(function(t,e){i&&t.done&&i.done&&(n.remove(t.id),n.edit(i.id,t.mergeWith(i))),i=t}),this}},{key:"edit",value:function(t,e){var n=this.ids.indexOf(t+1);return this.ids.splice(n,1,t),this.runners.splice(n,1,e),this}},{key:"length",value:function(){return this.ids.length}},{key:"clearBefore",value:function(t){var e=this.ids.indexOf(t+1)||1;return this.ids.splice(0,e,0),this.runners.splice(0,e,new be),this}}]),t}(),Ae=0;xe.constructors={Element:{animate:function(t,e,n){var i=xe.sanitise(t,e,n),r=this.timeline();return new xe(i.duration).loop(i).element(this).timeline(r).schedule(e,n)},delay:function(t,e){return this.animate(0,t,e)},_clearTransformRunnersBefore:function(t){this._transformationRunners.clearBefore(t.id)},_currentTransform:function(e){return this._transformationRunners.runners.filter(function(t){return t.id<=e.id}).map(_e).reduce(ke,new re)},addRunner:function(t){this._transformationRunners.add(t),ee.transform_frame(function(){var t=this._transformationRunners.runners.map(_e).reduce(ke,new re);this.transform(t),this._transformationRunners.merge(),1===this._transformationRunners.length()&&(this._frameId=null)}.bind(this),this._frameId)},_prepareRunner:function(){null==this._frameId&&(this._transformationRunners=(new Oe).add(new be(new re(this))),this._frameId=Ae++)}}},Y(xe,{attr:function(t,e){return this.styleAttr("attr",t,e)},css:function(t,e){return this.styleAttr("css",t,e)},styleAttr:function(e,n,t){if("object"===l(n))for(var i in t)this.styleAttr(e,i,t[i]);var r=new pe(this._stepper).to(t);return this.queue(function(){r=r.from(this.element()[e](n))},function(t){return this.element()[e](n,r.at(t)),r.done()}),this},zoom:function(t,e){var n=new pe(this._stepper).to(new V(t));return this.queue(function(){n=n.from(this.zoom())},function(t){return this.element().zoom(n.at(t),e),n.done()}),this},transform:function(d,v,y){if(v=d.relative||v,this._isDeclarative&&!v&&this._tryRetarget("transform",d))return this;var p=R(d);y=null!=d.affine?d.affine:null!=y?y:!p;var m,g,w,x,b,k=(new pe).type(y?pe.TransformBag:re).stepper(this._stepper);return this.queue(function(){g=g||this.element(),m=m||F(d,g),b=new re(v?void 0:g),g.addRunner(this),v||g._clearTransformRunnersBefore(this)},function(t){v||this.clearTransform();var e=new Ot(m).transform(g._currentTransform(this)),n=e.x,i=e.y,r=new re(_({},d,{origin:[n,i]})),s=this._isDeclarative&&w?w:b;if(y){r=r.decompose(n,i),s=s.decompose(n,i);var u=r.rotate,o=s.rotate,a=[u-360,u,u+360],h=a.map(function(t){return Math.abs(t-o)}),l=Math.min.apply(Math,O(h)),c=h.indexOf(l);r.rotate=a[c]}v&&(p||(r.rotate=d.rotate||0),this._isDeclarative&&x&&(s.rotate=x)),k.from(s),k.to(r);var f=k.at(t);return x=f.rotate,w=new re(f),this.addTransform(w),k.done()},function(t){(t.origin||"center").toString()!==(d.origin||"center").toString()&&(m=F(d,g)),d=_({},t,{origin:m})}),this._isDeclarative&&this._rememberMorpher("transform",k),this},x:function(t,e){return this._queueNumber("x",t)},y:function(t){return this._queueNumber("y",t)},dx:function(t){return this._queueNumberDelta("dx",t)},dy:function(t){return this._queueNumberDelta("dy",t)},_queueNumberDelta:function(e,n){if(n=new V(n),this._tryRetargetDelta(e,n))return this;var i=new pe(this._stepper).to(n);return this.queue(function(){var t=this.element()[e]();i.from(t),i.to(t+n)},function(t){return this.element()[e](i.at(t)),i.done()}),this._rememberMorpher(e,i),this},_queueObject:function(e,t){if(this._tryRetarget(e,t))return this;var n=new pe(this._stepper).to(t);return this.queue(function(){n.from(this.element()[e]())},function(t){return this.element()[e](n.at(t)),n.done()}),this._rememberMorpher(e,n),this},_queueNumber:function(t,e){return this._queueObject(t,new V(e))},cx:function(t){return this._queueNumber("cx",t)},cy:function(t){return this._queueNumber("cy",t)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){var n;return t&&e||(n=this._element.bbox()),t||(t=n.width/n.height*e),e||(e=n.height/n.width*t),this.width(t).height(e)},width:function(t){return this._queueNumber("width",t)},height:function(t){return this._queueNumber("height",t)},plot:function(t,e,n,i){return 4===arguments.length?this.plot([t,e,n,i]):this._queueObject("plot",new this._element.MorphArray(t))},leading:function(t){return this._queueNumber("leading",t)},viewbox:function(t,e,n,i){return this._queueObject("viewbox",new Box(t,e,n,i))},update:function(t){return"object"!==l(t)?this.update({offset:t,color:arguments[1],opacity:arguments[2]}):(null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset),this)}});var Ce=Object.freeze({HtmlNode:ht,Doc:it,Defs:nt,G:at,Animator:ee,Bare:G,Circle:tt,ClipPath:et,A:lt,Ellipse:rt,Stop:st,Gradient:ot,Image:pt,Line:xt,Marker:bt,Mask:kt,Path:Et,Pattern:ct,Polygon:Pt,Polyline:zt,Rect:qt,Symbol:Lt,Text:Gt,TextPath:Vt,Tspan:ne,Use:Ht,SVGNumber:V,SVGArray:gt,PathArray:Tt,PointArray:wt,Matrix:re,Point:Ot,Box:se,Color:oe,Morphable:pe,Queue:te,Runner:xe,Timeline:we,Controller:fe,Ease:ce,PID:ye,Spring:ve}),Me=Object.freeze({Bare:G,ClipPath:et,Defs:nt,Doc:it,Gradient:ot,G:at,A:lt,Marker:bt,Mask:kt,Pattern:ct,Symbol:Lt});var je=Object.freeze({siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},prev:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof it&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return 0<t&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof it&&t.node.appendChild(t.defs().node),this},back:function(){return 0<this.position()&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}});function Te(t){return e=t,n=this.node,utils.map((n||document).querySelectorAll(e),function(t){return $t(t)});var e,n}var Ee=Object.freeze({css:function(t,e){var n={};if(0===arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){var e=t.split(/\s*:\s*/);n[e[0]]=e[1]}),n;if(arguments.length<2){if(Array.isArray(t)){var i=!0,r=!1,s=void 0;try{for(var u,o=t[Symbol.iterator]();!(i=(u=o.next()).done);i=!0){var a=S(u.value);n[a]=this.node.style(a)}}catch(t){r=!0,s=t}finally{try{i||null==o.return||o.return()}finally{if(r)throw s}}return n}if("string"==typeof t)return this.node.style[S(t)];if("object"===l(t))for(name in t)this.node.style[S(name)]=null==t[name]||w.test(t[name])?"":t[name]}return 2===arguments.length&&(this.node.style[S(t)]=null==e||w.test(e)?"":e),this},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!==this.css("display")}});var Se=Object.freeze({untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(t).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(k).map(function(t){return parseFloat(t)})]}).reverse().reduce(function(t,e){return"matrix"===e[0]?t.lmultiply(z(e[1])):t[e[0]].apply(t,e[1])},new re)},toParent:function(t){if(this===t)return this;var e=this.screenCTM(),n=t.screenCTM().inverse();return this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())},transform:function(t,e){if(null==t||"string"==typeof t){var n=new re(this).decompose();return n[t]||n}R(t)||(t=_({},t,{origin:F(t,this)}));var i=new re(!0===e?this:e||!1).transform(t);return this.attr("transform",i)}});function Ne(t,e,n){if(null==t){t={},e=this.node.attributes;var i=!0,r=!1,s=void 0;try{for(var u,o=e[Symbol.iterator]();!(i=(u=o.next()).done);i=!0){var a=u.value;t[a.nodeName]=isNumer.test(a.nodeValue)?parseFloat(a.nodeValue):a.nodeValue}}catch(t){r=!0,s=t}finally{try{i||null==o.return||o.return()}finally{if(r)throw s}}return t}if(Array.isArray(t));else if("object"===l(t))for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return null==(e=this.node.getAttribute(t))?Yt[t]:x.test(e)?parseFloat(e):e;"fill"!==t&&"stroke"!==t||(b.test(e)&&(e=this.doc().defs().image(e)),e instanceof pt&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new V(e):oe.isColor(e)?e=new oe(e):Array.isArray(e)&&(e=new gt(e)),"leading"===t?this.leading&&this.leading(e):"string"==typeof n?this.node.setAttributeNS(n,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!==t&&"x"!==t||this.rebuild()}return this}function De(){return this.parent()&&this.parent().removeElement(this),this}var Pe=Object.freeze({name:"Element",setup:function(t){this.dom={},this.node=t,this.type=t.nodeName,this.node.instance=this,t.hasAttribute("svgjs:data")&&this.setData(JSON.parse(t.getAttribute("svgjs:data"))||{})},x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var n=P(this,t,e);return this.width(new V(n.width)).height(new V(n.height))},clone:function(t){this.writeDataToDom();var e=Jt(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:De,replace:function(t){return this.after(t).remove(),t},addTo:function(t){return Qt(t).put(this)},putIn:function(t){return Qt(t).add(this)},id:function(t){return void 0!==t||this.node.id||(this.node.id=Zt(this.type)),this.attr("id",t)},inside:function(t,e){var n=this.bbox();return t>n.x&&e>n.y&&t<n.x+n.width&&e<n.y+n.height},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(k)},hasClass:function(t){return-1!==this.classes().indexOf(t)},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(e){return this.hasClass(e)&&this.attr("class",this.classes().filter(function(t){return t!==e}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return get(this.attr(t))},parent:function(t){var e=this;if(!e.node.parentNode)return null;if(e=$t(e.node.parentNode),!t)return e;for(;e&&e.node instanceof window.SVGElement;){if("string"==typeof t?e.matches(t):e instanceof t)return e;e=$t(e.node.parentNode)}},doc:function(){var t=this.parent(it);return t&&t.doc()},defs:function(){return this.doc().defs()},parents:function(t){var e=[],n=this;do{if(!(n=n.parent(t))||!n.node)break;e.push(n)}while(n.parent);return e},matches:function t(e){return t(this.node)},native:function(){return this.node},svg:function(){return this.writeDataToDom(),this.node.outerHTML},writeDataToDom:function(){return this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},getEventTarget:function(){return this.node},attr:Ne});var ze=Object.freeze({name:"EventTarget",setup:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.events=t.events||{}},on:function(t,e,n,i){return vt(this,t,e,n,i),this},off:function(t,e){return yt(this,t,e),this},dispatch:function(t,e){return n=t,i=e,r=dt(this),n instanceof window.Event||(n=new window.CustomEvent(n,{detail:i,cancelable:!0})),r.dispatchEvent(n),n;var n,i,r},fire:function(t,e){return this.dispatch(t,e),this}});var qe=Object.freeze({children:function(){return function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)r.push(e(t[n]));return r}(this.node.children,function(t){return $t(t)})},add:function(t,e){return(t=Qt(t)).node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t.instance||t},has:function(t){return 0<=this.index(t)},index:function(t){return[].slice.call(this.node.children).indexOf(t.node)},get:function(t){return $t(this.node.children[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.children.length-1)},each:function(t,e){var n,i,r=this.children();for(n=0,i=r.length;n<i;n++)r[n]instanceof Base&&t.apply(r[n],[n,r]),e&&r[n]instanceof Base&&r[n].is("Parent")&&r[n].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},svg:function(t){var e,n;if(!t)return this.writeDataToDom(),this.node.outerHTML;for((e=document.createElementNS(ns,"svg")).innerHTML=t,n=e.children.length;n--;)this.node.appendChild(e.firstElementChild);return this},writeDataToDom:function(){return this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},flatten:function(t){return this.each(function(){return this.is("Parent")?this.flatten(t).ungroup(t):this.toParent(t)}),this.node.firstElementChild||this.remove(),this},ungroup:function(t){return t=t||this.parent(),this.each(function(){return this.toParent(t)}),this.remove(),this}}),Le=Y;for(var Re in Le([it,Lt,pt,ct,bt],{viewbox:se.constructors.viewbox}),Le([xt,zt,Pt,Et],_({},bt.constructors.marker)),Le(Gt,Vt.constructors.Text),Le(Et,Vt.constructors.Path),Le(nt,_({},ot.constructors.Defs,bt.constructors.Defs,ct.constructors.Defs)),Le([Gt,ne],ne.constructors.Tspan),Le([ot,ct],{remove:function(){return this.targets().forEach(function(t){t.unFill()}),De.call(this)},targets:function(){return Te('svg [fill*="'+this.id()+'"]')},unFill:function(){this.attr("fill",null)}}),Le(ot,{attr:function(t,e,n){return"transform"===t&&(t="gradientTransform"),Ne.call(this,t,e,n)}}),Le(ct,{attr:function(t,e,n){return"transform"===t&&(t="patternTransform"),Ne.call(this,t,e,n)}}),Le(et,{remove:function(){return this.targets().forEach(function(t){t.unclip()}),De.call(this)},targets:function(){return Te('svg [clip-path*="'+this.id()+'"]')}}),Le(kt,{remove:function(){return this.targets().forEach(function(t){t.unmask()}),De.call(this)},targets:function(){return Te('svg [mask*="'+this.id()+'"]')}}),Le(Et,{targets:function(){return Te('svg textpath [href*="'+this.id()+'"]')}}),Le(ht,{add:function(t,e){return(t=Qt(t)).node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this}}),Me)Le(Me[Re],_({},lt.constructors.Container,et.constructors.Container,it.constructors.Container,at.constructors.Container,ot.constructors.Container,xt.constructors.Container,bt.constructors.Container,kt.constructors.Container,Et.constructors.Container,ct.constructors.Container,Pt.constructors.Container,zt.constructors.Container,qt.constructors.Container,{find:Te},Lt.constructors.Container,Gt.constructors.Container,Vt.constructors.Container,Ht.constructors.Container));for(var Fe in Ut)Le(Ut[Fe],_({},ze,Pe,qe,je,lt.constructors.Element,se.constructors.Element,tt.constructors.Element,et.constructors.Element,Ee,pt.constructors.Element,kt.constructors.Element,re.constructors.Element,Ot.constructors.Element,xe.constructors.Element,we.constructors.Element,Se));function Ie(t){return Qt(t)}return Object.assign(Ie,Ce),Object.assign(Ie,B),Object.assign(Ie,Kt),Ie}();
+var SVG=function(){"use strict";function l(t){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function c(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(t,e){for(var n=0;n<e.length;n++){var i=e[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(t,i.key,i)}}function a(t,e,n){return e&&i(t.prototype,e),n&&i(t,n),t}function _(r){for(var t=1;t<arguments.length;t++){var s=null!=arguments[t]?arguments[t]:{},e=Object.keys(s);"function"==typeof Object.getOwnPropertySymbols&&(e=e.concat(Object.getOwnPropertySymbols(s).filter(function(t){return Object.getOwnPropertyDescriptor(s,t).enumerable}))),e.forEach(function(t){var e,n,i;e=r,i=s[n=t],n in e?Object.defineProperty(e,n,{value:i,enumerable:!0,configurable:!0,writable:!0}):e[n]=i})}return r}function u(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&n(t,e)}function o(t){return(o=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function n(t,e){return(n=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function r(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function f(t,e){return!e||"object"!=typeof e&&"function"!=typeof e?r(t):e}function s(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=[],i=!0,r=!1,s=void 0;try{for(var u,a=t[Symbol.iterator]();!(i=(u=a.next()).done)&&(n.push(u.value),!e||n.length!==e);i=!0);}catch(t){r=!0,s=t}finally{try{i||null==a.return||a.return()}finally{if(r)throw s}}return n}(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}()}function O(t){return function(t){if(Array.isArray(t)){for(var e=0,n=new Array(t.length);e<t.length;e++)n[e]=t[e];return n}}(t)||function(t){if(Symbol.iterator in Object(t)||"[object Arguments]"===Object.prototype.toString.call(t))return Array.from(t)}(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}var d=function(){function l(t,e){var n=e.extensions,i=void 0===n?[]:n;c(this,l);var r=!0,s=!(this.tags=[]),u=void 0;try{for(var a,o=i[Symbol.iterator]();!(r=(a=o.next()).done);r=!0){var h=a.value;h.setup.call(this,t),this.tags.push(h.name)}}catch(t){s=!0,u=t}finally{try{r||null==o.return||o.return()}finally{if(s)throw u}}}return a(l,[{key:"is",value:function(t){return this.tags.includes(t)}}]),l}(),h=/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,v=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,y=/rgb\((\d+),(\d+),(\d+)\)/,t=/\)\s*,?\s*/,p=/\s/g,m=/^#[a-f0-9]{3,6}$/i,g=/^rgb\(/,w=/^(\s+)?$/,k=/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,x=/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,b=/[\s,]+/,A=/([^e])-/gi,M=/[MLHVCSQTAZ]/gi,T=/[MLHVCSQTAZ]/i,C=/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,j=/\./g;function S(t,e,n,i){return n+i.replace(j," .")}function E(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function e(t){return t.charAt(0).toUpperCase()+t.slice(1)}function N(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function P(t,e,n){if(null==e||null==n){var i=t.bbox();null==e?e=i.width/i.height*n:null==n&&(n=i.height/i.width*e)}return{width:e,height:n}}function D(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}var z="abcdef".split("");function q(t,e,n){return Math.abs(e-t)<(n||1e-6)}function I(t){return null!=t.a||null!=t.b||null!=t.c||null!=t.d||null!=t.e||null!=t.f}function L(t,e){var n,i,r=t.origin;if("string"==typeof r||null==r){var s=(r||"center").toLowerCase().trim(),u=e.bbox(),a=u.height,o=u.width,h=u.x,l=u.y,c=s.includes("left")?h:s.includes("right")?h+o:h+o/2,f=s.includes("top")?l:s.includes("bottom")?l+a:l+a/2;n=null!=t.ox?t.ox:c,i=null!=t.oy?t.oy:f}else n=r[0],i=r[1];return[n,i]}var R="http://www.w3.org/2000/svg",B="http://www.w3.org/2000/xmlns/",X="http://www.w3.org/1999/xlink";function Y(t,e){return e||F(t)}function F(t){return document.createElementNS(R,t)}function H(e,t){var n,i;if(Array.isArray(t))t.forEach(function(t){H(e,t)});else for(i=(e=Array.isArray(e)?e:[e]).length-1;0<=i;i--)for(n in t.name&&(e[i].extensions=(e[i].extensions||[]).concat(t)),t)e[i].prototype[n]||"name"==n||"setup"==n||(e[i].prototype[n]=t[n])}var G=Object.freeze({nodeOrNew:Y,makeNode:F,extend:H,addFactory:function(t,e){H(t,e)},invent:function(e){var t="function"==typeof e.create?e.create:function(t){e.inherit.call(this,t||F(e.create))};return e.inherit&&(t.prototype=new e.inherit,t.prototype.constructor=t),e.extend&&H(t,e.extend),e.construct&&H(e.parent||Container,e.construct),t}}),V={},U=Symbol("root");function Q(t){if(t instanceof d)return t;if("object"===l(t))return $(t);if(null==t)return new V[U];if("string"==typeof t&&"<"!==t.charAt(0))return $(document.querySelector(t));var e=F("svg");return e.innerHTML=t,t=$(e.firstElementChild)}function $(t){return t?t.instance instanceof d?t.instance:t instanceof window.SVGElement?"svg"===t.nodeName?new V[U](t):"linearGradient"===t.nodeName||"radialGradient"===t.nodeName?new V.Gradient(t):V[e(t.nodeName)]?new(V[e(t.nodeName)])(t):new V.Bare(t):new V.HtmlNode(t):null}function W(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:t.name,n=2<arguments.length&&void 0!==arguments[2]&&arguments[2];return V[e]=t,n&&(V[U]=t),t}function Z(t){return V[t]}var J=1e3;function K(t){return"Svgjs"+e(t)+J++}function tt(t){for(var e=t.children.length-1;0<=e;e--)tt(t.children[e]);return t.id?$(t).id(K(t.nodeName)):$(t)}var et=Object.freeze({root:U,makeInstance:Q,adopt:$,register:W,getClass:Z,eid:K,assignNewId:tt}),nt=function(t){function n(t){var e;return c(this,n),(e=f(this,o(n).call(this,t,n))).node=t,e}return u(n,d),a(n,[{key:"add",value:function(t,e){return(t=Q(t)).node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this}},{key:"put",value:function(t,e){return this.add(t,e),t}},{key:"getEventTarget",value:function(){return this.node}}]),n}();W(nt);var it=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("defs",t),e))}return u(e,d),a(e,[{key:"flatten",value:function(){return this}},{key:"ungroup",value:function(){return this}}]),e}();W(it);var rt={},st={};function ut(t,e){if("object"==l(t))for(var n=Object.entries(t),i=0;i<n.length;i++){var r=s(n[i],2);ut(r[0],r[1])}rt[t]=Object.assign(rt[t]||{},e)}function at(t){return rt[t]}function ot(t,e){st[t]=e}function ht(t){return{setup:st[t],name:t}}var lt=function(t){function n(t){var e;return c(this,n),(e=f(this,o(n).call(this,Y("svg",t),n))).namespace(),e}return u(n,d),a(n,[{key:"isRoot",value:function(){return!(this.node.parentNode&&this.node.parentNode instanceof window.SVGElement&&"#document"!==this.node.parentNode.nodeName)}},{key:"doc",value:function(){return this.isRoot()?this:Element.doc.call(this)}},{key:"namespace",value:function(){return this.isRoot()?this.attr({xmlns:R,version:"1.1"}).attr("xmlns:xlink",X,B).attr("xmlns:svgjs","http://svgjs.com/svgjs",B):this.doc().namespace()}},{key:"defs",value:function(){return this.isRoot()?$(this.node.getElementsByTagName("defs")[0])||this.put(new it):this.doc().defs()}},{key:"parent",value:function(t){return this.isRoot()?"#document"===this.node.parentNode.nodeName?null:this.node.parentNode:Element.parent.call(this,t)}},{key:"remove",value:function(){return this.isRoot()?(this.parent()&&this.parent().removeChild(this.node),this):Element.remove.call(this)}},{key:"clear",value:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this}}]),n}();ut({Container:{nested:function(){return this.put(new lt)}}}),W(lt,"Doc",!0);var ct=function(t){function e(t){return c(this,e),f(this,o(e).call(this,nodeorNew("g",t),e))}return u(e,d),e}();ut({Element:{group:function(){return this.put(new ct)}}}),W(ct);var ft=function(){function t(){c(this,t),this._first=null,this._last=null}return a(t,[{key:"push",value:function(t){var e=t.next?t:{value:t,next:null,prev:null};return this._last?(e.prev=this._last,this._last.next=e,this._last=e):(this._last=e,this._first=e),e}},{key:"shift",value:function(){var t=this._first;return t?(this._first=t.next,this._first&&(this._first.prev=null),this._last=this._first?this._last:null,t.value):null}},{key:"first",value:function(){return this._first&&this._first.value}},{key:"last",value:function(){return this._last&&this._last.value}},{key:"remove",value:function(t){t.prev&&(t.prev.next=t.next),t.next&&(t.next.prev=t.prev),t===this._last&&(this._last=t.prev),t===this._first&&(this._first=t.next),t.prev=null,t.next=null}}]),t}(),dt={nextDraw:null,frames:new ft,timeouts:new ft,timer:window.performance||window.Date,transforms:[],frame:function(t){var e=dt.frames.push({run:t});return null===dt.nextDraw&&(dt.nextDraw=window.requestAnimationFrame(dt._draw)),e},transform_frame:function(t,e){dt.transforms[e]=t},timeout:function(t,e){e=e||0;var n=dt.timer.now()+e,i=dt.timeouts.push({run:t,time:n});return null===dt.nextDraw&&(dt.nextDraw=window.requestAnimationFrame(dt._draw)),i},cancelFrame:function(t){dt.frames.remove(t)},clearTimeout:function(t){dt.timeouts.remove(t)},_draw:function(t){for(var e=null,n=dt.timeouts.last();(e=dt.timeouts.shift())&&(t>=e.time?e.run():dt.timeouts.push(e),e!==n););for(var i=null,r=dt.frames.last();i!==r&&(i=dt.frames.shift());)i.run();dt.transforms.forEach(function(t){t()}),dt.nextDraw=dt.timeouts.first()||dt.frames.first()?window.requestAnimationFrame(dt._draw):null}},vt=function(t){function i(t,e){var n;return c(this,i),n=f(this,o(i).call(this,Y(null,t),i)),extend(r(r(n)),e),n}return u(i,d),a(i,[{key:"words",value:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(document.createTextNode(t)),this}}]),i}();W(vt),ut("Bare",{element:function(t,e){var n=createCustom(t,e);return this.put(new n)}});var yt=function(){function n(){c(this,n),this.init.apply(this,arguments)}return a(n,[{key:"init",value:function(t,e){e=Array.isArray(t)?t[1]:e,t=Array.isArray(t)?t[0]:t,this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-34e37:34e37:"string"==typeof t?(e=t.match(h))&&(this.value=parseFloat(e[1]),"%"===e[5]?this.value/=100:"s"===e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof n&&(this.value=t.valueOf(),this.unit=t.unit)}},{key:"toString",value:function(){return("%"===this.unit?~~(1e8*this.value)/1e6:"s"===this.unit?this.value/1e3:this.value)+this.unit}},{key:"toJSON",value:function(){return this.toString()}},{key:"toArray",value:function(){return[this.value,this.unit]}},{key:"valueOf",value:function(){return this.value}},{key:"plus",value:function(t){return new n(this+(t=new n(t)),this.unit||t.unit)}},{key:"minus",value:function(t){return new n(this-(t=new n(t)),this.unit||t.unit)}},{key:"times",value:function(t){return new n(this*(t=new n(t)),this.unit||t.unit)}},{key:"divide",value:function(t){return new n(this/(t=new n(t)),this.unit||t.unit)}}]),n}();function pt(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())}function mt(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())}function gt(t){return null==t?this.attr("cx"):this.attr("cx",t)}function wt(t){return null==t?this.attr("cy"):this.attr("cy",t)}function kt(t){return null==t?2*this.rx():this.rx(new yt(t).divide(2))}function xt(t){return null==t?2*this.ry():this.ry(new yt(t).divide(2))}function bt(t,e){var n=P(this,t,e);return this.rx(new yt(n.width).divide(2)).ry(new yt(n.height).divide(2))}var _t=Object.freeze({rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)},x:pt,y:mt,cx:gt,cy:wt,width:kt,height:xt,size:bt}),Ot=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("circle",t),e))}return u(e,d),a(e,[{key:"radius",value:function(t){return this.attr("r",t)}},{key:"rx",value:function(t){return this.attr("r",t)}},{key:"ry",value:function(t){return this.rx(t)}}]),e}();function At(t){return t%360*Math.PI/180}function Mt(t,e){return utils.map((e||document).querySelectorAll(t),function(t){return $(t)})}H(Ot,{x:pt,y:mt,cx:gt,cy:wt,width:kt,height:xt,size:bt}),ut({Element:{circle:function(t){return this.put(new Ot).radius(new yt(t).divide(2)).move(0,0)}}}),W(Ot),ut("Container",{find:function(t){return Mt(t,this.node)}});var Tt=Z(U);function Ct(){return this.parent()&&this.parent().removeElement(this),this}ut("Element",{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var n=P(this,t,e);return this.width(new yt(n.width)).height(new yt(n.height))},clone:function(t){this.writeDataToDom();var e=tt(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:Ct,replace:function(t){return this.after(t).remove(),t},putIn:function(t){return Q(t).add(this)},id:function(t){return void 0!==t||this.node.id||(this.node.id=K(this.type)),this.attr("id",t)},inside:function(t,e){var n=this.bbox();return t>n.x&&e>n.y&&t<n.x+n.width&&e<n.y+n.height},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(b)},hasClass:function(t){return-1!==this.classes().indexOf(t)},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(e){return this.hasClass(e)&&this.attr("class",this.classes().filter(function(t){return t!==e}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return get(this.attr(t))},doc:function(){var t=this.parent(Tt);return t&&t.doc()},defs:function(){return this.doc().defs()},parents:function(t){var e=[],n=this;do{if(!(n=n.parent(t))||!n.node)break;e.push(n)}while(n.parent);return e},matches:function t(e){return t(this.node)},native:function(){return this.node},svg:function(){return this.writeDataToDom(),this.node.outerHTML},writeDataToDom:function(){return this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},getEventTarget:function(){return this.node}}),ot("Element",function(t){this.dom={},this.node=t,this.type=t.nodeName,this.node.instance=this,t.hasAttribute("svgjs:data")&&this.setData(JSON.parse(t.getAttribute("svgjs:data"))||{})});var jt=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("clipPath",t),e))}return u(e,d),a(e,[{key:"remove",value:function(){return this.targets().forEach(function(t){t.unclip()}),Ct.call(this)}},{key:"targets",value:function(){return Mt('svg [clip-path*="'+this.id()+'"]')}}]),e}();ut({Container:{clip:function(){return this.defs().put(new jt)}},Element:{clipWith:function(t){var e=t instanceof jt?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}}),W(jt);var St=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("a",t),e))}return u(e,d),a(e,[{key:"to",value:function(t){return this.attr("href",t,X)}},{key:"target",value:function(t){return this.attr("target",t)}}]),e}();ut({Container:{link:function(t){return this.put(new St).to(t)}},Element:{linkTo:function(t){var e=new St;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}}),W(St);var Et=function(t){function e(t){return c(this,e),f(this,o(e).call(this,nodeOrNew("ellipse",t),e))}return u(e,d),e}();H(Et,_t),ut("Container",{ellipse:function(t,e){return this.put(new Et).size(t,e).move(0,0)}}),W(Et);var Nt=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("stop",t),e))}return u(e,d),a(e,[{key:"update",value:function(t){return("number"==typeof t||t instanceof yt)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new yt(t.offset)),this}}]),e}();W(Nt);var Pt=Object.freeze({from:function(t,e){return"radialGradient"===(this._element||this).type?this.attr({fx:new yt(t),fy:new yt(e)}):this.attr({x1:new yt(t),y1:new yt(e)})},to:function(t,e){return"radialGradient"===(this._element||this).type?this.attr({cx:new yt(t),cy:new yt(e)}):this.attr({x2:new yt(t),y2:new yt(e)})}});function Dt(){}var zt=400,qt=">",It=0,Lt={"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"},Rt=function(){function t(){c(this,t),this.init.apply(this,arguments)}return a(t,[{key:"init",value:function(t,e,n){var i,r;(this.r=0,this.g=0,this.b=0,t)&&("string"==typeof t?g.test(t)?(i=y.exec(t.replace(p,"")),this.r=parseInt(i[1]),this.g=parseInt(i[2]),this.b=parseInt(i[3])):m.test(t)&&(i=v.exec(4===(r=t).length?["#",r.substring(1,2),r.substring(1,2),r.substring(2,3),r.substring(2,3),r.substring(3,4),r.substring(3,4)].join(""):r),this.r=parseInt(i[1],16),this.g=parseInt(i[2],16),this.b=parseInt(i[3],16)):Array.isArray(t)?(this.r=t[0],this.g=t[1],this.b=t[2]):"object"===l(t)?(this.r=t.r,this.g=t.g,this.b=t.b):3===arguments.length&&(this.r=t,this.g=e,this.b=n))}},{key:"toString",value:function(){return this.toHex()}},{key:"toArray",value:function(){return[this.r,this.g,this.b]}},{key:"toHex",value:function(){return"#"+N(Math.round(this.r))+N(Math.round(this.g))+N(Math.round(this.b))}},{key:"toRgb",value:function(){return"rgb("+[this.r,this.g,this.b].join()+")"}},{key:"brightness",value:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11}}],[{key:"test",value:function(t){return t+="",m.test(t)||g.test(t)}},{key:"isRgb",value:function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b}},{key:"isColor",value:function(t){return this.isRgb(t)||this.test(t)}}]),t}(),Bt=function(){try{return Array}catch(t){return Array}}(),Xt=function(t){function n(){var t,e;return c(this,n),(t=e=f(this,o(n).call(this))).init.apply(t,arguments),e}return u(n,Bt),a(n,[{key:"init",value:function(t,e){this.length=0,this.push.apply(this,O(this.parse(t||e)))}},{key:"toArray",value:function(){return Array.prototype.slice(this)}},{key:"toString",value:function(){this.join(" ")}},{key:"valueOf",value:function(){return this.toArray()}},{key:"parse",value:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(b).map(parseFloat)}},{key:"clone",value:function(){return new this.constructor(this)}},{key:"toSet",value:function(){return new Set(this)}}]),n}();function Yt(t,e,n){if(null==t){t={},e=this.node.attributes;var i=!0,r=!1,s=void 0;try{for(var u,a=e[Symbol.iterator]();!(i=(u=a.next()).done);i=!0){var o=u.value;t[o.nodeName]=isNumer.test(o.nodeValue)?parseFloat(o.nodeValue):o.nodeValue}}catch(t){r=!0,s=t}finally{try{i||null==a.return||a.return()}finally{if(r)throw s}}return t}if(Array.isArray(t));else if("object"===l(t))for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return null==(e=this.node.getAttribute(t))?Lt[t]:k.test(e)?parseFloat(e):e;for("fill"!==t&&"stroke"!==t||x.test(e)&&(e=this.doc().defs().image(e));"function"==typeof e.attrHook;)e=e.attrHook(this,t);"number"==typeof e?e=new yt(e):Rt.isColor(e)?e=new Rt(e):Array.isArray(e)&&(e=new Xt(e)),"leading"===t?this.leading&&this.leading(e):"string"==typeof n?this.node.setAttributeNS(n,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!==t&&"x"!==t||this.rebuild()}return this}ut("Element",{attr:Yt});var Ft=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y(t+"Gradient","string"==typeof t?null:t),e))}return u(e,d),a(e,[{key:"stop",value:function(t,e,n){return this.put(new Nt).update(t,e,n)}},{key:"update",value:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this}},{key:"url",value:function(){return"url(#"+this.id()+")"}},{key:"toString",value:function(){return this.url()}},{key:"attr",value:function(t,e,n){return"transform"===t&&(t="gradientTransform"),Yt.call(this,t,e,n)}},{key:"targets",value:function(){return find('svg [fill*="'+this.id()+'"]')}}]),e}();H(Ft,Pt),ut({Container:{gradient:function(t,e){return this.defs().gradient(t,e)}},Defs:{gradient:function(t,e){return this.put(new Ft(t)).update(e)}}}),W(Ft);var Ht=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("pattern",t)))}return u(e,d),a(e,[{key:"url",value:function(){return"url(#"+this.id()+")"}},{key:"update",value:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this}},{key:"toString",value:function(){return this.url()}},{key:"attr",value:function(t,e,n){return"transform"===t&&(t="patternTransform"),Yt.call(this,t,e,n)}},{key:"targets",value:function(){return find('svg [fill*="'+this.id()+'"]')}}]),e}();ut({Container:{pattern:function(t,e,n){return this.defs().pattern(t,e,n)}},Defs:{pattern:function(t,e,n){return this.put(new Ht).update(n).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}}),W(Ht);var Gt=0;function Vt(t){return t instanceof Base&&t.is("EventTarget")?t.getEventTarget():t}function Ut(t,e,i,n,r){var s=i.bind(n||t),u=Vt(t);e=Array.isArray(e)?e:e.split(b),u.instance=u.instance||{events:{}};var a=u.instance.events;i._svgjsListenerId||(i._svgjsListenerId=++Gt),e.forEach(function(t){var e=t.split(".")[0],n=t.split(".")[1]||"*";a[e]=a[e]||{},a[e][n]=a[e][n]||{},a[e][n][i._svgjsListenerId]=s,u.addEventListener(e,s,r||!1)})}function Qt(t,e,s,u){var a=Vt(t);if(a.instance&&("function"!=typeof s||(s=s._svgjsListenerId))){var o=a.instance.events;(e=Array.isArray(e)?e:(e||"").split(b)).forEach(function(t){var e,n,i=t&&t.split(".")[0],r=t&&t.split(".")[1];if(s)o[i]&&o[i][r||"*"]&&(a.removeEventListener(i,o[i][r||"*"][s],u||!1),delete o[i][r||"*"][s]);else if(i&&r){if(o[i]&&o[i][r]){for(n in o[i][r])Qt(a,[i,r].join("."),n);delete o[i][r]}}else if(r)for(t in o)for(e in o[t])r===e&&Qt(a,[t,r].join("."));else if(i){if(o[i]){for(e in o[i])Qt(a,[i,e].join("."));delete o[i]}}else{for(t in o)Qt(a,t);a.instance.events={}}})}}var $t=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("image",t),e))}return u(e,d),a(e,[{key:"load",value:function(n,i){if(!n)return this;var r=new window.Image;return Ut(r,"load",function(t){var e=this.parent(Ht);0===this.width()&&0===this.height()&&this.size(r.width,r.height),e instanceof Ht&&0===e.width()&&0===e.height()&&e.size(this.width(),this.height()),"function"==typeof i&&i.call(this,{width:r.width,height:r.height,ratio:r.width/r.height,url:n})},this),Ut(r,"load error",function(){Qt(r)}),this.attr("href",r.src=n,X)}},{key:"attrHook",value:function(t){var e=this;return t.doc().defs().pattern(0,0,function(t){t.add(e)})}}]),e}();ut({Container:{image:function(t,e){return this.put(new $t).size(0,0).load(t,e)}}}),W($t);var Wt=function(t){function r(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[[0,0]];return c(this,r),f(this,o(r).call(this,t,e))}return u(r,Xt),a(r,[{key:"toString",value:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)n.push(this.value[t].join(","));return n.join(" ")}},{key:"toArray",value:function(){return this.value.reduce(function(t,e){return[].concat.call(t,e)},[])}},{key:"toLine",value:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}}},{key:"at",value:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new r(i)}},{key:"parse",value:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(b).map(parseFloat);t.length%2!=0&&t.pop();for(var n=0,i=t.length;n<i;n+=2)e.push([t[n],t[n+1]]);return e}},{key:"move",value:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i=this.value.length-1;0<=i;i--)this.value[i]=[this.value[i][0]+t,this.value[i][1]+e];return this}},{key:"size",value:function(t,e){var n,i=this.bbox();for(n=this.value.length-1;0<=n;n--)i.width&&(this.value[n][0]=(this.value[n][0]-i.x)*t/i.width+i.x),i.height&&(this.value[n][1]=(this.value[n][1]-i.y)*e/i.height+i.y);return this}},{key:"bbox",value:function(){var e=-1/0,n=-1/0,i=1/0,r=1/0;return this.value.forEach(function(t){e=Math.max(t[0],e),n=Math.max(t[1],n),i=Math.min(t[0],i),r=Math.min(t[1],r)}),{x:i,y:r,width:e-i,height:n-r}}}]),r}(),Zt=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("line",t),e))}return u(e,d),a(e,[{key:"array",value:function(){return new Wt([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])}},{key:"plot",value:function(t,e,n,i){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:n,y2:i}:new Wt(t).toLine(),this.attr(t))}},{key:"move",value:function(t,e){return this.attr(this.array().move(t,e).toLine())}},{key:"size",value:function(t,e){var n=P(this,t,e);return this.attr(this.array().size(n.width,n.height).toLine())}}]),e}();ut({Container:{line:function(){for(var t=arguments.length,e=new Array(t),n=0;n<t;n++)e[n]=arguments[n];return Zt.prototype.plot.apply(this.put(new Zt),null!=e[0]?e:[0,0,0,0])}}}),W(Zt);var Jt=function(t){function e(t){return c(this,e),f(this,o(e).call(this,nodeOrNew("marker",t),e))}return u(e,d),a(e,[{key:"width",value:function(t){return this.attr("markerWidth",t)}},{key:"height",value:function(t){return this.attr("markerHeight",t)}},{key:"ref",value:function(t,e){return this.attr("refX",t).attr("refY",e)}},{key:"update",value:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this}},{key:"toString",value:function(){return"url(#"+this.id()+")"}}]),e}();ut({Container:{marker:function(t,e,n){return this.defs().marker(t,e,n)}},Defs:{marker:function(t,e,n){return this.put(new Jt).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(n)}},marker:{marker:function(t,e,n,i){var r=["marker"];return"all"!==t&&r.push(t),r=r.join("-"),t=e instanceof Jt?e:this.defs().marker(e,n,i),this.attr(r,t)}}}),W(Jt);var Kt=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("mask",t)))}return u(e,d),a(e,[{key:"remove",value:function(){return this.targets().forEach(function(t){t.unmask()}),Ct.call(this)}},{key:"targets",value:function(){return Mt('svg [mask*="'+this.id()+'"]')}}]),e}();function te(){if(!te.nodes){var t=(new lt).size(2,0).css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"}),e=t.path().node;te.nodes={svg:t,path:e}}if(!te.nodes.svg.node.parentNode){var n=document.body||document.documentElement;te.nodes.svg.addTo(n)}return te.nodes}ut({Container:{mask:function(){return this.defs().put(new Kt)}},Element:{maskWith:function(t){var e=t instanceof Kt?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}}),W(Kt);var ee=function(){function r(t,e,n){var i;c(this,r),n=n||{x:0,y:0},i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"===l(t)?{x:t.x,y:t.y}:{x:t,y:e},this.x=null==i.x?n.x:i.x,this.y=null==i.y?n.y:i.y}return a(r,[{key:"clone",value:function(){return new r(this)}},{key:"native",value:function(){var t=te().svg.createSVGPoint();return t.x=this.x,t.y=this.y,t}},{key:"transform",value:function(t){return new r(t.a*this.x+t.c*this.y+t.e,t.b*this.x+t.d*this.y+t.f)}}]),r}();ut({Element:{point:function(t,e){return new ee(t,e).transform(this.screenCTM().inverse())}}});for(var ne={M:function(t,e,n){return e.x=n.x=t[0],e.y=n.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,n){return e.x=n.x,e.y=n.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},ie="mlhvqtcsaz".split(""),re=0,se=ie.length;re<se;++re)ne[ie[re]]=function(s){return function(t,e,n){if("H"===s)t[0]=t[0]+e.x;else if("V"===s)t[0]=t[0]+e.y;else if("A"===s)t[5]=t[5]+e.x,t[6]=t[6]+e.y;else for(var i=0,r=t.length;i<r;++i)t[i]=t[i]+(i%2?e.y:e.x);return ne[s](t,e,n)}}(ie[re].toUpperCase());var ue=function(t){function h(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:[["M",0,0]];return c(this,h),f(this,o(h).call(this,t,e))}return u(h,Xt),a(h,[{key:"toString",value:function(){return function(t){for(var e=0,n=t.length,i="";e<n;e++)i+=t[e][0],null!=t[e][1]&&(i+=t[e][1],null!=t[e][2]&&(i+=" ",i+=t[e][2],null!=t[e][3]&&(i+=" ",i+=t[e][3],i+=" ",i+=t[e][4],null!=t[e][5]&&(i+=" ",i+=t[e][5],i+=" ",i+=t[e][6],null!=t[e][7]&&(i+=" ",i+=t[e][7])))));return i+" "}(this)}},{key:"toArray",value:function(){return this.reduce(function(t,e){return[].concat.call(t,e)},[])}},{key:"move",value:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i,r=this.length-1;0<=r;r--)"M"===(i=this[r][0])||"L"===i||"T"===i?(this[r][1]+=t,this[r][2]+=e):"H"===i?this[r][1]+=t:"V"===i?this[r][1]+=e:"C"===i||"S"===i||"Q"===i?(this[r][1]+=t,this[r][2]+=e,this[r][3]+=t,this[r][4]+=e,"C"===i&&(this[r][5]+=t,this[r][6]+=e)):"A"===i&&(this[r][6]+=t,this[r][7]+=e);return this}},{key:"size",value:function(t,e){var n,i,r=this.bbox();for(n=this.length-1;0<=n;n--)"M"===(i=this[n][0])||"L"===i||"T"===i?(this[n][1]=(this[n][1]-r.x)*t/r.width+r.x,this[n][2]=(this[n][2]-r.y)*e/r.height+r.y):"H"===i?this[n][1]=(this[n][1]-r.x)*t/r.width+r.x:"V"===i?this[n][1]=(this[n][1]-r.y)*e/r.height+r.y:"C"===i||"S"===i||"Q"===i?(this[n][1]=(this[n][1]-r.x)*t/r.width+r.x,this[n][2]=(this[n][2]-r.y)*e/r.height+r.y,this[n][3]=(this[n][3]-r.x)*t/r.width+r.x,this[n][4]=(this[n][4]-r.y)*e/r.height+r.y,"C"===i&&(this[n][5]=(this[n][5]-r.x)*t/r.width+r.x,this[n][6]=(this[n][6]-r.y)*e/r.height+r.y)):"A"===i&&(this[n][1]=this[n][1]*t/r.width,this[n][2]=this[n][2]*e/r.height,this[n][6]=(this[n][6]-r.x)*t/r.width+r.x,this[n][7]=(this[n][7]-r.y)*e/r.height+r.y);return this}},{key:"equalCommands",value:function(t){var e,n,i;for(t=new h(t),i=this.length===t.value.length,e=0,n=this.length;i&&e<n;e++)i=this[e][0]===t.value[e][0];return i}},{key:"morph",value:function(t){return t=new h(t),this.equalCommands(t)?this.destination=t:this.destination=null,this}},{key:"at",value:function(t){if(!this.destination)return this;var e,n,i,r,s=this,u=this.destination.value,a=[],o=new h;for(e=0,n=s.length;e<n;e++){for(a[e]=[s[e][0]],i=1,r=s[e].length;i<r;i++)a[e][i]=s[e][i]+(u[e][i]-s[e][i])*t;"A"===a[e][0]&&(a[e][4]=+(0!==a[e][4]),a[e][5]=+(0!==a[e][5]))}return o.value=a,o}},{key:"parse",value:function(t){if(t instanceof h)return t.valueOf();var e,n={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(C,S).replace(M," $& ").replace(A,"$1 -").trim().split(b):t.reduce(function(t,e){return[].concat.call(t,e)},[]);for(var i=[],r=new ee,s=new ee,u=0,a=t.length;T.test(t[u])?(e=t[u],++u):"M"===e?e="L":"m"===e&&(e="l"),i.push(ne[e].call(null,t.slice(u,u+=n[e.toUpperCase()]).map(parseFloat),r,s)),u<a;);return i}},{key:"bbox",value:function(){return te().path.setAttribute("d",this.toString()),te.nodes.path.getBBox()}}]),h}(),ae=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("path",t),e))}return u(e,d),a(e,[{key:"array",value:function(){return this._array||(this._array=new ue(this.attr("d")))}},{key:"plot",value:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new ue(t))}},{key:"clear",value:function(){return delete this._array,this}},{key:"move",value:function(t,e){return this.attr("d",this.array().move(t,e))}},{key:"x",value:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)}},{key:"y",value:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)}},{key:"size",value:function(t,e){var n=P(this,t,e);return this.attr("d",this.array().size(n.width,n.height))}},{key:"width",value:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)}},{key:"height",value:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},{key:"targets",value:function(){return Mt('svg textpath [href*="'+this.id()+'"]')}}]),e}();ae.prototype.MorphArray=ue,ut({Container:{path:function(t){return this.put(new ae).plot(t||new ue)}}}),W(ae);var oe=Wt;var he=Object.freeze({MorphArray:oe,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}});var le=Object.freeze({array:function(){return this._array||(this._array=new PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var n=proportionalSize(this,t,e);return this.attr("points",this.array().size(n.width,n.height))}}),ce=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("polygon",t),e))}return u(e,d),e}();ut({Parent:{polygon:function(t){return this.put(new ce).plot(t||new Wt)}}}),H(ce,he),H(ce,le),W(ce);var fe=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("polyline",t),e))}return u(e,d),e}();ut({Parent:{polyline:function(t){return this.put(new fe).plot(t||new Wt)}}}),H(fe,he),H(fe,le),W(fe);var de=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("rect",t),e))}return u(e,d),e}();ut({Container:{rect:function(t,e){return this.put(new de).size(t,e)}}}),W(de);var ve=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("symbol",t),e))}return u(e,d),e}();ut({Container:{symbol:function(){return this.put(new ve)}}}),W(ve);var ye=Object.freeze({plain:function(t){return!1===this._build&&this.clear(),this.node.appendChild(document.createTextNode(t)),this},length:function(){return this.node.getComputedTextLength()}}),pe=function(t){function n(t){var e;return c(this,n),(e=f(this,o(n).call(this,Y("text",t),n))).dom.leading=new yt(1.3),e._rebuild=!0,e._build=!1,e.attr("font-family",Lt["font-family"]),e}return u(n,d),a(n,[{key:"x",value:function(t){return null==t?this.attr("x"):this.attr("x",t)}},{key:"y",value:function(t){var e=this.attr("y"),n="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-n:e:this.attr("y","number"==typeof t?t+n:t)}},{key:"cx",value:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)}},{key:"cy",value:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)}},{key:"text",value:function(t){if(void 0===t){var e=this.node.childNodes,n=0;t="";for(var i=0,r=e.length;i<r;++i)"textPath"!==e[i].nodeName?(i!==n&&3!==e[i].nodeType&&!0===adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent):0===i&&(n=1);return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else for(var s=0,u=(t=t.split("\n")).length;s<u;s++)this.tspan(t[s]).newLine();return this.build(!1).rebuild()}},{key:"leading",value:function(t){return null==t?this.dom.leading:(this.dom.leading=new yt(t),this.rebuild())}},{key:"rebuild",value:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,n=0,i=this.dom.leading*new yt(this.attr("font-size"));this.each(function(){this.dom.newLined&&(this.attr("x",e.attr("x")),"\n"===this.text()?n+=i:(this.attr("dy",i+n),n=0))}),this.fire("rebuild")}return this}},{key:"build",value:function(t){return this._build=!!t,this}},{key:"setData",value:function(t){return this.dom=t,this.dom.leading=new yt(t.leading||1.3),this}}]),n}();H(pe,ye),ut({Container:{text:function(t){return this.put(new pe).text(t)},plain:function(t){return this.put(new pe).plain(t)}}}),W(pe);var me=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("textPath",t)))}return u(e,pe),a(e,[{key:"array",value:function(){var t=this.track();return t?t.array():null}},{key:"plot",value:function(t){var e=this.track(),n=null;return e&&(n=e.plot(t)),null==t?n:this}},{key:"track",value:function(){return this.reference("href")}}]),e}();ut({Container:{textPath:function(t,e){return this.defs().path(e).text(t).addTo(this)}},Text:{path:function(t){var e=new me;return t instanceof ae||(t=this.doc().defs().path(t)),e.attr("href","#"+t,X),this.put(e)},textPath:function(){return this.select("textPath")}},Path:{text:function(t){if(t instanceof pe){var e=t.text();return t.clear().path(this).text(e)}return this.parent().put(new pe).path(this).text(t)}}}),me.prototype.MorphArray=ue,W(me);var ge=function(t){function e(t){return c(this,e),f(this,o(e).call(this,Y("tspan",t),e))}return u(e,d),a(e,[{key:"text",value:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)}},{key:"dx",value:function(t){return this.attr("dx",t)}},{key:"dy",value:function(t){return this.attr("dy",t)}},{key:"newLine",value:function(){var t=this.parent(Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}]),e}();H(ge,ye),ut({Tspan:{tspan:function(t){var e=new ge;return this._build||this.clear(),this.node.appendChild(e.node),e.text(t)}}}),W(ge);var we=function(t){function e(t){return c(this,e),f(this,o(e).call(this,nodeOrNew("use",t),e))}return u(e,d),a(e,[{key:"element",value:function(t,e){return this.attr("href",(e||"")+"#"+t,X)}}]),e}();ut({Container:{use:function(t,e){return this.put(new we).element(t,e)}}}),W(we);var ke=function(){function h(){c(this,h),this.init.apply(this,arguments)}return a(h,[{key:"init",value:function(t){var e=D([1,0,0,1,0,0]);t=t instanceof d&&t.is("Element")?t.matrixify():"string"==typeof t?D(t.split(b).map(parseFloat)):Array.isArray(t)?D(t):"object"===l(t)&&I(t)?t:"object"===l(t)?(new h).transform(t):6===arguments.length?D([].slice.call(arguments)):e,this.a=null!=t.a?t.a:e.a,this.b=null!=t.b?t.b:e.b,this.c=null!=t.c?t.c:e.c,this.d=null!=t.d?t.d:e.d,this.e=null!=t.e?t.e:e.e,this.f=null!=t.f?t.f:e.f}},{key:"clone",value:function(){return new h(this)}},{key:"transform",value:function(t){if(I(t))return new h(t).multiplyO(this);var e=h.formatTransforms(t),n=new ee(e.ox,e.oy).transform(this),i=n.x,r=n.y,s=(new h).translateO(e.rx,e.ry).lmultiplyO(this).translateO(-i,-r).scaleO(e.scaleX,e.scaleY).skewO(e.skewX,e.skewY).shearO(e.shear).rotateO(e.theta).translateO(i,r);if(isFinite(e.px)||isFinite(e.py)){var u=new ee(i,r).transform(s),a=e.px?e.px-u.x:0,o=e.py?e.py-u.y:0;s.translateO(a,o)}return s.translateO(e.tx,e.ty),s}},{key:"compose",value:function(t){t.origin&&(t.originX=t.origin[0],t.originY=t.origin[1]);var e=t.originX||0,n=t.originY||0,i=t.scaleX||1,r=t.scaleY||1,s=t.shear||0,u=t.rotate||0,a=t.translateX||0,o=t.translateY||0;return(new h).translateO(-e,-n).scaleO(i,r).shearO(s).rotateO(u).translateO(a,o).lmultiplyO(this).translateO(e,n)}},{key:"decompose",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:0,e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0,n=this.a,i=this.b,r=this.c,s=this.d,u=this.e,a=this.f,o=n*s-i*r,h=0<o?1:-1,l=h*Math.sqrt(n*n+i*i),c=Math.atan2(h*i,h*n),f=180/Math.PI*c,d=Math.cos(c),v=Math.sin(c),y=(n*r+i*s)/o,p=r*l/(y*n-i)||s*l/(y*i+n);return{scaleX:l,scaleY:p,shear:y,rotate:f,translateX:u-t+t*d*l+e*(y*d*l-v*p),translateY:a-e+t*v*l+e*(y*v*l+d*p),originX:t,originY:e,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}}},{key:"multiply",value:function(t){return this.clone().multiplyO(t)}},{key:"multiplyO",value:function(t){var e=t instanceof h?t:new h(t);return h.matrixMultiply(this,e,this)}},{key:"lmultiply",value:function(t){return this.clone().lmultiplyO(t)}},{key:"lmultiplyO",value:function(t){var e=t instanceof h?t:new h(t);return h.matrixMultiply(e,this,this)}},{key:"inverseO",value:function(){var t=this.a,e=this.b,n=this.c,i=this.d,r=this.e,s=this.f,u=t*i-e*n;if(!u)throw new Error("Cannot invert "+this);var a=i/u,o=-e/u,h=-n/u,l=t/u,c=-(a*r+h*s),f=-(o*r+l*s);return this.a=a,this.b=o,this.c=h,this.d=l,this.e=c,this.f=f,this}},{key:"inverse",value:function(){return this.clone().inverseO()}},{key:"translate",value:function(t,e){return this.clone().translateO(t,e)}},{key:"translateO",value:function(t,e){return this.e+=t||0,this.f+=e||0,this}},{key:"scale",value:function(t,e,n,i){var r;return(r=this.clone()).scaleO.apply(r,arguments)}},{key:"scaleO",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:t,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0,i=3<arguments.length&&void 0!==arguments[3]?arguments[3]:0;3===arguments.length&&(i=n,n=e,e=t);var r=this.a,s=this.b,u=this.c,a=this.d,o=this.e,h=this.f;return this.a=r*t,this.b=s*e,this.c=u*t,this.d=a*e,this.e=o*t-n*t+n,this.f=h*e-i*e+i,this}},{key:"rotate",value:function(t,e,n){return this.clone().rotateO(t,e,n)}},{key:"rotateO",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:0,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0;t=At(t);var i=Math.cos(t),r=Math.sin(t),s=this.a,u=this.b,a=this.c,o=this.d,h=this.e,l=this.f;return this.a=s*i-u*r,this.b=u*i+s*r,this.c=a*i-o*r,this.d=o*i+a*r,this.e=h*i-l*r+n*r-e*i+e,this.f=l*i+h*r-e*r-n*i+n,this}},{key:"flip",value:function(t,e){return this.clone().flipO(t,e)}},{key:"flipO",value:function(t,e){return"x"===t?this.scaleO(-1,1,e,0):"y"===t?this.scaleO(1,-1,0,e):this.scaleO(-1,-1,t,e||t)}},{key:"shear",value:function(t,e,n){return this.clone().shearO(t,e,n)}},{key:"shearO",value:function(t){var e=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0,n=this.a,i=this.b,r=this.c,s=this.d,u=this.e,a=this.f;return this.a=n+i*t,this.c=r+s*t,this.e=u+a*t-e*t,this}},{key:"skew",value:function(t,e,n,i){var r;return(r=this.clone()).skewO.apply(r,arguments)}},{key:"skewO",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:t,n=2<arguments.length&&void 0!==arguments[2]?arguments[2]:0,i=3<arguments.length&&void 0!==arguments[3]?arguments[3]:0;3===arguments.length&&(i=n,n=e,e=t),t=At(t),e=At(e);var r=Math.tan(t),s=Math.tan(e),u=this.a,a=this.b,o=this.c,h=this.d,l=this.e,c=this.f;return this.a=u+a*r,this.b=a+u*s,this.c=o+h*r,this.d=h+o*s,this.e=l+c*r-i*r,this.f=c+l*s-n*s,this}},{key:"skewX",value:function(t,e,n){return this.skew(t,0,e,n)}},{key:"skewXO",value:function(t,e,n){return this.skewO(t,0,e,n)}},{key:"skewY",value:function(t,e,n){return this.skew(0,t,e,n)}},{key:"skewYO",value:function(t,e,n){return this.skewO(0,t,e,n)}},{key:"aroundO",value:function(t,e,n){var i=t||0,r=e||0;return this.translateO(-i,-r).lmultiplyO(n).translateO(i,r)}},{key:"around",value:function(t,e,n){return this.clone().aroundO(t,e,n)}},{key:"native",value:function(){for(var t=te().node.createSVGMatrix(),e=z.length-1;0<=e;e--)t[z[e]]=this[z[e]];return t}},{key:"equals",value:function(t){var e=new h(t);return q(this.a,e.a)&&q(this.b,e.b)&&q(this.c,e.c)&&q(this.d,e.d)&&q(this.e,e.e)&&q(this.f,e.f)}},{key:"toString",value:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},{key:"toArray",value:function(){return[this.a,this.b,this.c,this.d,this.e,this.f]}},{key:"valueOf",value:function(){return{a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}}}],[{key:"formatTransforms",value:function(t){var e="both"===t.flip||!0===t.flip,n=t.flip&&(e||"x"===t.flip)?-1:1,i=t.flip&&(e||"y"===t.flip)?-1:1,r=t.skew&&t.skew.length?t.skew[0]:isFinite(t.skew)?t.skew:isFinite(t.skewX)?t.skewX:0,s=t.skew&&t.skew.length?t.skew[1]:isFinite(t.skew)?t.skew:isFinite(t.skewY)?t.skewY:0,u=t.scale&&t.scale.length?t.scale[0]*n:isFinite(t.scale)?t.scale*n:isFinite(t.scaleX)?t.scaleX*n:n,a=t.scale&&t.scale.length?t.scale[1]*i:isFinite(t.scale)?t.scale*i:isFinite(t.scaleY)?t.scaleY*i:i,o=t.shear||0,h=t.rotate||t.theta||0,l=new ee(t.origin||t.around||t.ox||t.originX,t.oy||t.originY),c=l.x,f=l.y,d=new ee(t.position||t.px||t.positionX,t.py||t.positionY),v=d.x,y=d.y,p=new ee(t.translate||t.tx||t.translateX,t.ty||t.translateY),m=p.x,g=p.y,w=new ee(t.relative||t.rx||t.relativeX,t.ry||t.relativeY);return{scaleX:u,scaleY:a,skewX:r,skewY:s,shear:o,theta:h,rx:w.x,ry:w.y,tx:m,ty:g,ox:c,oy:f,px:v,py:y}}},{key:"matrixMultiply",value:function(t,e,n){var i=t.a*e.a+t.c*e.b,r=t.b*e.a+t.d*e.b,s=t.a*e.c+t.c*e.d,u=t.b*e.c+t.d*e.d,a=t.e+t.a*e.e+t.c*e.f,o=t.f+t.b*e.e+t.d*e.f;return n.a=i,n.b=r,n.c=s,n.d=u,n.e=a,n.f=o,n}}]),h}();ut({Element:{ctm:function(){return new ke(this.node.getCTM())},screenCTM:function(){if(this instanceof Doc&&!this.isRoot()){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new ke(e)}return new ke(this.node.getScreenCTM())}}});var xe=function(){function u(){c(this,u),this.init.apply(this,arguments)}return a(u,[{key:"init",value:function(t){var e;t="string"==typeof t?t.split(b).map(parseFloat):Array.isArray(t)?t:"object"===l(t)?[null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height]:4===arguments.length?[].slice.call(arguments):[0,0,0,0],this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],null==(e=this).x&&(e.x=0,e.y=0,e.width=0,e.height=0),e.w=e.width,e.h=e.height,e.x2=e.x+e.width,e.y2=e.y+e.height,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2}},{key:"merge",value:function(t){var e=Math.min(this.x,t.x),n=Math.min(this.y,t.y);return new u(e,n,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-n)}},{key:"transform",value:function(e){var n=1/0,i=-1/0,r=1/0,s=-1/0;return[new ee(this.x,this.y),new ee(this.x2,this.y),new ee(this.x,this.y2),new ee(this.x2,this.y2)].forEach(function(t){t=t.transform(e),n=Math.min(n,t.x),i=Math.max(i,t.x),r=Math.min(r,t.y),s=Math.max(s,t.y)}),new u(n,r,i-n,s-r)}},{key:"addOffset",value:function(){return this.x+=window.pageXOffset,this.y+=window.pageYOffset,this}},{key:"toString",value:function(){return this.x+" "+this.y+" "+this.width+" "+this.height}},{key:"toArray",value:function(){return[this.x,this.y,this.width,this.height]}}]),u}();function be(e){var n,t,i;try{if(n=e(this.node),!((i=n).w||i.h||i.x||i.y||(t=this.node,(document.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t===document}).call(document.documentElement,t))))throw new Error("Element not in the dom")}catch(t){try{var r=this.clone(te().svg).show();n=e(r.node),r.remove()}catch(t){throw t}}return n}function _e(e,n){return function(t){return null==t?this[t]:(this[e]=t,n&&n.call(this),this)}}ut({Element:{bbox:function(){return new xe(be.call(this,function(t){return t.getBBox()}))},rbox:function(t){var e=new xe(be.call(this,function(t){return t.getBoundingClientRect()}));return t?e.transform(t.screenCTM().inverse()):e.addOffset()}},viewbox:function(t,e,n,i){return null==t?new xe(this.attr("viewBox")):this.attr("viewBox",new xe(t,e,n,i))}});var Oe={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)},bezier:function(t,e,n,i){return function(t){}}},Ae=function(){function t(){c(this,t)}return a(t,[{key:"done",value:function(){return!1}}]),t}(),Me=function(t){function n(t){var e;return c(this,n),(e=f(this,o(n).call(this))).ease=Oe[t||qt]||t,e}return u(n,Ae),a(n,[{key:"step",value:function(t,e,n){return"number"!=typeof t?n<1?t:e:t+(e-t)*this.ease(n)}}]),n}(),Te=function(t){function n(t){var e;return c(this,n),(e=f(this,o(n).call(this))).stepper=t,e}return u(n,Ae),a(n,[{key:"step",value:function(t,e,n,i){return this.stepper(t,e,n,i)}},{key:"done",value:function(t){return t.done}}]),n}();function Ce(){var t=(this._duration||500)/1e3,e=this._overshoot||0,n=Math.PI,i=Math.log(e/100+1e-10),r=-i/Math.sqrt(n*n+i*i),s=3.9/(r*t);this.d=2*r*s,this.k=s*s}var je=function(t){function i(t,e){var n;return c(this,i),(n=f(this,o(i).call(this))).duration(t||500).overshoot(e||0),n}return u(i,Te),a(i,[{key:"step",value:function(t,e,n,i){if("string"==typeof t)return t;if(i.done=n===1/0,n===1/0)return e;if(0===n)return t;100<n&&(n=16),n/=1e3;var r=i.velocity||0,s=-this.d*r-this.k*(t-e),u=t+r*n+s*n*n/2;return i.velocity=r+s*n,i.done=Math.abs(e-u)+Math.abs(r)<.002,i.done?e:u}}]),i}();H(je,{duration:_e("_duration",Ce),overshoot:_e("_overshoot",Ce)});var Se=function(t){function s(t,e,n,i){var r;return c(this,s),t=null==t?.1:t,e=null==e?.01:e,n=null==n?0:n,i=null==i?1e3:i,(r=f(this,o(s).call(this))).p(t).i(e).d(n).windup(i),r}return u(s,Te),a(s,[{key:"step",value:function(t,e,n,i){if("string"==typeof t)return t;if(i.done=n===1/0,n===1/0)return e;if(0===n)return t;var r=e-t,s=(i.integral||0)+r*n,u=(r-(i.error||0))/n,a=this.windup;return!1!==a&&(s=Math.max(-a,Math.min(s,a))),i.error=r,i.integral=s,i.done=Math.abs(r)<.001,i.done?e:t+(this.P*r+this.I*s+this.D*u)}}]),s}();H(Se,{windup:_e("windup"),p:_e("P"),i:_e("I"),d:_e("D")});var Ee=function(){function i(t){c(this,i),this._stepper=t||new Me("-"),this._from=null,this._to=null,this._type=null,this._context=null,this._morphObj=null}return a(i,[{key:"from",value:function(t){return null==t?this._from:(this._from=this._set(t),this)}},{key:"to",value:function(t){return null==t?this._to:(this._to=this._set(t),this)}},{key:"type",value:function(t){return null==t?this._type:(this._type=t,this)}},{key:"_set",value:function(t){if(!this._type){var e=l(t);"number"===e?this.type(yt):"string"===e?Rt.isColor(t)?this.type(Rt):regex.delimiter.test(t)?this.type(regex.pathLetters.test(t)?ue:Xt):regex.numberAndUnit.test(t)?this.type(yt):this.type(i.NonMorphable):-1<MorphableTypes.indexOf(t.constructor)?this.type(t.constructor):Array.isArray(t)?this.type(Xt):"object"===e?this.type(i.ObjectBag):this.type(i.NonMorphable)}var n=new this._type(t).toArray();return this._morphObj=this._morphObj||new this._type,this._context=this._context||Array.apply(null,Array(n.length)).map(Object),n}},{key:"stepper",value:function(t){return null==t?this._stepper:(this._stepper=t,this)}},{key:"done",value:function(){return this._context.map(this._stepper.done).reduce(function(t,e){return t&&e},!0)}},{key:"at",value:function(n){var i=this;return this._morphObj.fromArray(this._from.map(function(t,e){return i._stepper.step(t,i._to[e],n,i._context[e],i._context)}))}}]),i}();Ee.NonMorphable=function(){function t(){c(this,t),this.init.apply(this,arguments)}return a(t,[{key:"init",value:function(t){t=Array.isArray(t)?t[0]:t,this.value=t}},{key:"valueOf",value:function(){return this.value}},{key:"toArray",value:function(){return[this.value]}}]),t}(),Ee.TransformBag=function(){function t(){c(this,t),this.init.apply(this,arguments)}return a(t,[{key:"init",value:function(t){Array.isArray(t)&&(t={scaleX:t[0],scaleY:t[1],shear:t[2],rotate:t[3],translateX:t[4],translateY:t[5],originX:t[6],originY:t[7]}),Object.assign(this,Ee.TransformBag.defaults,t)}},{key:"toArray",value:function(){var t=this;return[t.scaleX,t.scaleY,t.shear,t.rotate,t.translateX,t.translateY,t.originX,t.originY]}}]),t}(),Ee.TransformBag.defaults={scaleX:1,scaleY:1,shear:0,rotate:0,translateX:0,translateY:0,originX:0,originY:0},Ee.ObjectBag=function(){function t(){c(this,t),this.init.apply(this,arguments)}return a(t,[{key:"init",value:function(t){if(this.values=[],Array.isArray(t))this.values=t;else{var e=Object.entries(t||{}).sort(function(t,e){return t[0]-e[0]});this.values=e.reduce(function(t,e){return t.concat(e)},[])}}},{key:"valueOf",value:function(){for(var t={},e=this.values,n=0,i=e.length;n<i;n+=2)t[e[n]]=e[n+1];return t}},{key:"toArray",value:function(){return this.values}}]),t}(),H([yt,Rt,xe,ke,Xt,Wt,ue,Ee.NonMorphable,Ee.TransformBag,Ee.ObjectBag],{to:function(t,e){return(new Ee).type(this.constructor).from(this.valueOf()).to(t,e)},fromArray:function(t){return this.init(t),this}});var Ne=window.performance||Date,Pe=function(t){var e=t.start,n=t.runner.duration();return{start:e,duration:n,end:e+n,runner:t.runner}},De=function(){function t(){c(this,t),this._timeSource=function(){return Ne.now()},this._dispatcher=document.createElement("div"),this._startTime=0,this._speed=1,this._reverse=!1,this._persist=0,this._nextFrame=null,this._paused=!1,this._runners=[],this._order=[],this._time=0,this._lastSourceTime=0,this._lastStepTime=0}return a(t,[{key:"getEventTarget",value:function(){return this._dispatcher}},{key:"schedule",value:function(t,e,n){if(null==t)return this._runners.map(Pe).sort(function(t,e){return t.start-e.start||t.duration-e.duration});this.active()||(this._step(),null==n&&(n="now"));var i=0;if(e=e||0,null==n||"last"===n||"after"===n)i=this._startTime;else if("absolute"===n||"start"===n)i=e,e=0;else if("now"===n)i=this._time;else{if("relative"!==n)throw new Error('Invalid value for the "when" parameter');var r=this._runners[t.id];r&&(i=r.start+e,e=0)}return t.unschedule(),t.timeline(this),t.time(-e),this._startTime=i+t.duration()+e,this._runners[t.id]={persist:this.persist(),runner:t,start:i},this._order.push(t.id),this._continue(),this}},{key:"unschedule",value:function(t){var e=this._order.indexOf(t.id);return e<0||(delete this._runners[t.id],this._order.splice(e,1),t.timeline(null)),this}},{key:"play",value:function(){return this._paused=!1,this._continue()}},{key:"pause",value:function(){return this._nextFrame=null,this._paused=!0,this}},{key:"stop",value:function(){return this.seek(-this._time),this.pause()}},{key:"finish",value:function(){return this.seek(1/0),this.pause()}},{key:"speed",value:function(t){return null==t?this._speed:(this._speed=t,this)}},{key:"reverse",value:function(t){var e=this.speed();if(null==t)return this.speed(-e);var n=Math.abs(e);return this.speed(t?n:-n)}},{key:"seek",value:function(t){return this._time+=t,this._continue()}},{key:"time",value:function(t){return null==t?this._time:(this._time=t,this)}},{key:"persist",value:function(t){return null==t?this._persist:(this._persist=t,this)}},{key:"source",value:function(t){return null==t?this._timeSource:(this._timeSource=t,this)}},{key:"_step",value:function(){if(!this._paused){var t=this._timeSource(),e=t-this._lastSourceTime,n=this._speed*e+(this._time-this._lastStepTime);this._lastSourceTime=t,this._time+=n,this._lastStepTime=this._time;for(var i=!1,r=0,s=this._order.length;r<s;r++){var u=this._runners[this._order[r]],a=u.runner,o=n,h=this._time-u.start;if(h<0)i=!0;else if(h<o&&(o=h),a.active())if(a.step(o).done){if(!0!==u.persist){a.duration()-a.time()+this._time+this._persist<this._time&&(delete this._runners[this._order[r]],this._order.splice(r--,1)&&--s,a.timeline(null))}}else i=!0}return this._nextFrame=i?dt.frame(this._step.bind(this)):null,this}}},{key:"_continue",value:function(){return this._paused||this._nextFrame||(this._nextFrame=dt.frame(this._step.bind(this))),this}},{key:"active",value:function(){return!!this._nextFrame}}]),t}();ut({Element:{timeline:function(){return this._timeline=this._timeline||new De,this._timeline}}});var ze=function(){function s(t){c(this,s),this.id=s.id++,t="function"==typeof(t=null==t?zt:t)?new Te(t):t,this._element=null,this._timeline=null,this.done=!1,this._queue=[],this._duration="number"==typeof t&&t,this._isDeclarative=t instanceof Te,this._stepper=this._isDeclarative?t:new Me,this._history={},this.enabled=!0,this._time=0,this._last=0,this.transforms=new ke,this.transformId=1,this._haveReversed=!1,this._reverse=!1,this._loopsDone=0,this._swing=!1,this._wait=0,this._times=1}return a(s,[{key:"element",value:function(t){return null==t?this._element:((this._element=t)._prepareRunner(),this)}},{key:"timeline",value:function(t){return void 0===t?this._timeline:(this._timeline=t,this)}},{key:"animate",value:function(t,e,n){var i=s.sanitise(t,e,n),r=new s(i.duration);return this._timeline&&r.timeline(this._timeline),this._element&&r.element(this._element),r.loop(i).schedule(e,n)}},{key:"schedule",value:function(t,e,n){if(t instanceof De||(n=e,e=t,t=this.timeline()),!t)throw Error("Runner cannot be scheduled without timeline");return t.schedule(this,e,n),this}},{key:"unschedule",value:function(){var t=this.timeline();return t&&t.unschedule(this),this}},{key:"loop",value:function(t,e,n){return"object"===l(t)&&(e=t.swing,n=t.wait,t=t.times),this._times=t||1/0,this._swing=e||!1,this._wait=n||0,this}},{key:"delay",value:function(t){return this.animate(0,t)}},{key:"queue",value:function(t,e,n){return this._queue.push({initialiser:t||Dt,runner:e||Dt,isTransform:n,initialised:!1,finished:!1}),this.timeline()&&this.timeline()._continue(),this}},{key:"during",value:function(t){return this.queue(null,t)}},{key:"after",value:function(t){return this.on("finish",t)}},{key:"time",value:function(t){if(null==t)return this._time;var e=t-this._time;return this.step(e),this}},{key:"duration",value:function(){return this._times*(this._wait+this._duration)-this._wait}},{key:"loops",value:function(t){var e=this._duration+this._wait;if(null==t){var n=Math.floor(this._time/e),i=(this._time-n*e)/this._duration;return Math.min(n+i,this._times)}var r=t%1,s=e*Math.floor(t)+this._duration*r;return this.time(s)}},{key:"position",value:function(t){var e,n=this._time,r=this._duration,s=this._wait,i=this._times,u=this._swing,a=this._reverse;if(null==t){var o=function(t){var e=u*Math.floor(t%(2*(s+r))/(s+r)),n=e&&!a||!e&&a,i=Math.pow(-1,n)*(t%(s+r))/r+n;return Math.max(Math.min(i,1),0)},h=i*(s+r)-s;return e=n<=0?Math.round(o(1e-5)):n<h?o(n):Math.round(o(h-1e-5)),e}var l=Math.floor(this.loops()),c=u&&l%2==0;return e=l+(c&&!a||a&&c?t:1-t),this.loops(e)}},{key:"progress",value:function(t){return null==t?Math.min(1,this._time/this.duration()):this.time(t*this.duration())}},{key:"step",value:function(t){if(!this.enabled)return this;t=null==t?16:t,this._time+=t;var e=this.position(),n=this._lastPosition!==e&&0<=this._time;this._lastPosition=e;var i=this.duration(),r=(this._lastTime<0&&this._time,this._lastTime<this._time&&this.time>i);this._lastTime=this._time;var s=this._isDeclarative;if(this.done=!s&&!r&&this._time>=i,n||s){this._initialise(n),this.transforms=new ke;var u=this._run(s?t:e)}return this.done=this.done||u&&s,this}},{key:"finish",value:function(){return this.step(1/0)}},{key:"reverse",value:function(t){return this._reverse=null==t?!this._reverse:t,this}},{key:"ease",value:function(t){return this._stepper=new Me(t),this}},{key:"active",value:function(t){return null==t?this.enabled:(this.enabled=t,this)}},{key:"_rememberMorpher",value:function(t,e){this._history[t]={morpher:e,caller:this._queue[this._queue.length-1]}}},{key:"_tryRetarget",value:function(t,e){if(this._history[t]){if(!this._history[t].caller.initialised){var n=this._queue.indexOf(this._history[t].caller);return this._queue.splice(n,1),!1}this._history[t].caller.isTransform?this._history[t].caller.isTransform(e):this._history[t].morpher.to(e),this._history[t].caller.finished=!1;var i=this.timeline();return i&&i._continue(),!0}return!1}},{key:"_initialise",value:function(t){if(t||this._isDeclarative)for(var e=0,n=this._queue.length;e<n;++e){var i=this._queue[e],r=this._isDeclarative||!i.initialised&&t;t=!i.finished,r&&t&&(i.initialiser.call(this),i.initialised=!0)}}},{key:"_run",value:function(t){for(var e=!0,n=0,i=this._queue.length;n<i;++n){var r=this._queue[n],s=r.runner.call(this,t);r.finished=r.finished||!0===s,e=e&&r.finished}return e}},{key:"addTransform",value:function(t,e){return this.transforms.lmultiplyO(t),this}},{key:"clearTransform",value:function(){return this.transforms=new ke,this}}],[{key:"sanitise",value:function(t,e,n){var i=1,r=!1,s=0;return e=e||It,n=n||"last","object"!==l(t=t||zt)||t instanceof Ae||(e=t.delay||e,n=t.when||n,r=t.swing||r,i=t.times||i,s=t.wait||s,t=t.duration||zt),{duration:t,delay:e,swing:r,times:i,wait:s,when:n}}}]),s}();ze.id=0;var qe=function t(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:new ke,n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:-1,i=!(2<arguments.length&&void 0!==arguments[2])||arguments[2];c(this,t),this.transforms=e,this.id=n,this.done=i};H([ze,qe],{mergeWith:function(t){return new qe(t.transforms.lmultiply(this.transforms),t.id)}});var Ie=function(t,e){return t.lmultiplyO(e)},Le=function(t){return t.transforms};var Re=function(){function t(){c(this,t),this.runners=[],this.ids=[]}return a(t,[{key:"add",value:function(t){if(!this.runners.includes(t)){var n=t.id+1,e=this.ids.reduce(function(t,e){return t<e&&e<n?e:t},0),i=this.ids.indexOf(e)+1;return this.ids.splice(i,0,n),this.runners.splice(i,0,t),this}}},{key:"getByID",value:function(t){return this.runners[this.ids.indexOf(t+1)]}},{key:"remove",value:function(t){var e=this.ids.indexOf(t+1);return this.ids.splice(e,1),this.runners.splice(e,1),this}},{key:"merge",value:function(){var n=this,i=null;return this.runners.forEach(function(t,e){i&&t.done&&i.done&&(n.remove(t.id),n.edit(i.id,t.mergeWith(i))),i=t}),this}},{key:"edit",value:function(t,e){var n=this.ids.indexOf(t+1);return this.ids.splice(n,1,t),this.runners.splice(n,1,e),this}},{key:"length",value:function(){return this.ids.length}},{key:"clearBefore",value:function(t){var e=this.ids.indexOf(t+1)||1;return this.ids.splice(0,e,0),this.runners.splice(0,e,new qe),this}}]),t}(),Be=0;ut({Element:{animate:function(t,e,n){var i=ze.sanitise(t,e,n),r=this.timeline();return new ze(i.duration).loop(i).element(this).timeline(r).schedule(e,n)},delay:function(t,e){return this.animate(0,t,e)},_clearTransformRunnersBefore:function(t){this._transformationRunners.clearBefore(t.id)},_currentTransform:function(e){return this._transformationRunners.runners.filter(function(t){return t.id<=e.id}).map(Le).reduce(Ie,new ke)},addRunner:function(t){this._transformationRunners.add(t),dt.transform_frame(function(){var t=this._transformationRunners.runners.map(Le).reduce(Ie,new ke);this.transform(t),this._transformationRunners.merge(),1===this._transformationRunners.length()&&(this._frameId=null)}.bind(this),this._frameId)},_prepareRunner:function(){null==this._frameId&&(this._transformationRunners=(new Re).add(new qe(new ke(this))),this._frameId=Be++)}}}),H(ze,{attr:function(t,e){return this.styleAttr("attr",t,e)},css:function(t,e){return this.styleAttr("css",t,e)},styleAttr:function(e,n,t){if("object"===l(n))for(var i in t)this.styleAttr(e,i,t[i]);var r=new Ee(this._stepper).to(t);return this.queue(function(){r=r.from(this.element()[e](n))},function(t){return this.element()[e](n,r.at(t)),r.done()}),this},zoom:function(t,e){var n=new Ee(this._stepper).to(new yt(t));return this.queue(function(){n=n.from(this.zoom())},function(t){return this.element().zoom(n.at(t),e),n.done()}),this},transform:function(d,v,y){if(v=d.relative||v,this._isDeclarative&&!v&&this._tryRetarget("transform",d))return this;var p=I(d);y=null!=d.affine?d.affine:null!=y?y:!p;var m,g,w,k,x,b=(new Ee).type(y?Ee.TransformBag:ke).stepper(this._stepper);return this.queue(function(){g=g||this.element(),m=m||L(d,g),x=new ke(v?void 0:g),g.addRunner(this),v||g._clearTransformRunnersBefore(this)},function(t){v||this.clearTransform();var e=new ee(m).transform(g._currentTransform(this)),n=e.x,i=e.y,r=new ke(_({},d,{origin:[n,i]})),s=this._isDeclarative&&w?w:x;if(y){r=r.decompose(n,i),s=s.decompose(n,i);var u=r.rotate,a=s.rotate,o=[u-360,u,u+360],h=o.map(function(t){return Math.abs(t-a)}),l=Math.min.apply(Math,O(h)),c=h.indexOf(l);r.rotate=o[c]}v&&(p||(r.rotate=d.rotate||0),this._isDeclarative&&k&&(s.rotate=k)),b.from(s),b.to(r);var f=b.at(t);return k=f.rotate,w=new ke(f),this.addTransform(w),b.done()},function(t){(t.origin||"center").toString()!==(d.origin||"center").toString()&&(m=L(d,g)),d=_({},t,{origin:m})}),this._isDeclarative&&this._rememberMorpher("transform",b),this},x:function(t,e){return this._queueNumber("x",t)},y:function(t){return this._queueNumber("y",t)},dx:function(t){return this._queueNumberDelta("dx",t)},dy:function(t){return this._queueNumberDelta("dy",t)},_queueNumberDelta:function(e,n){if(n=new yt(n),this._tryRetargetDelta(e,n))return this;var i=new Ee(this._stepper).to(n);return this.queue(function(){var t=this.element()[e]();i.from(t),i.to(t+n)},function(t){return this.element()[e](i.at(t)),i.done()}),this._rememberMorpher(e,i),this},_queueObject:function(e,t){if(this._tryRetarget(e,t))return this;var n=new Ee(this._stepper).to(t);return this.queue(function(){n.from(this.element()[e]())},function(t){return this.element()[e](n.at(t)),n.done()}),this._rememberMorpher(e,n),this},_queueNumber:function(t,e){return this._queueObject(t,new yt(e))},cx:function(t){return this._queueNumber("cx",t)},cy:function(t){return this._queueNumber("cy",t)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){var n;return t&&e||(n=this._element.bbox()),t||(t=n.width/n.height*e),e||(e=n.height/n.width*t),this.width(t).height(e)},width:function(t){return this._queueNumber("width",t)},height:function(t){return this._queueNumber("height",t)},plot:function(t,e,n,i){return 4===arguments.length?this.plot([t,e,n,i]):this._queueObject("plot",new this._element.MorphArray(t))},leading:function(t){return this._queueNumber("leading",t)},viewbox:function(t,e,n,i){return this._queueObject("viewbox",new Box(t,e,n,i))},update:function(t){return"object"!==l(t)?this.update({offset:t,color:arguments[1],opacity:arguments[2]}):(null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset),this)}});var Xe=Object.freeze({HtmlNode:nt,Doc:lt,Defs:it,G:ct,Animator:dt,Bare:vt,Circle:Ot,ClipPath:jt,A:St,Ellipse:Et,Stop:Nt,Gradient:Ft,Image:$t,Line:Zt,Marker:Jt,Mask:Kt,Path:ae,Pattern:Ht,Polygon:ce,Polyline:fe,Rect:de,Symbol:ve,Text:pe,TextPath:me,Tspan:ge,Use:we,SVGNumber:yt,SVGArray:Xt,PathArray:ue,PointArray:Wt,Matrix:ke,Point:ee,Box:xe,Color:Rt,Morphable:Ee,Queue:ft,Runner:ze,Timeline:De,Controller:Te,Ease:Me,PID:Se,Spring:je}),Ye=Object.freeze({Bare:vt,ClipPath:jt,Defs:it,Doc:lt,Gradient:Ft,G:ct,A:St,Marker:Jt,Mask:Kt,Pattern:Ht,Symbol:ve}),Fe=Object.freeze({Bare:vt,Circle:Ot,ClipPath:jt,Defs:it,Doc:lt,Ellipse:Et,Gradient:Ft,G:ct,HtmlNode:nt,A:St,Image:$t,Line:Zt,Marker:Jt,Mask:Kt,Path:ae,Pattern:Ht,Polygon:ce,Polyline:fe,Rect:de,Stop:Nt,Symbol:ve,Text:pe,TextPath:me,Use:we});function He(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.events=t.events||{}}ut("Element",{css:function(t,e){var n={};if(0===arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){var e=t.split(/\s*:\s*/);n[e[0]]=e[1]}),n;if(arguments.length<2){if(Array.isArray(t)){var i=!0,r=!1,s=void 0;try{for(var u,a=t[Symbol.iterator]();!(i=(u=a.next()).done);i=!0){var o=E(u.value);n[o]=this.node.style(o)}}catch(t){r=!0,s=t}finally{try{i||null==a.return||a.return()}finally{if(r)throw s}}return n}if("string"==typeof t)return this.node.style[E(t)];if("object"===l(t))for(name in t)this.node.style[E(name)]=null==t[name]||w.test(t[name])?"":t[name]}return 2===arguments.length&&(this.node.style[E(t)]=null==e||w.test(e)?"":e),this},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!==this.css("display")}}),ut("Element",{untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(t).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(b).map(function(t){return parseFloat(t)})]}).reverse().reduce(function(t,e){return"matrix"===e[0]?t.lmultiply(D(e[1])):t[e[0]].apply(t,e[1])},new ke)},toParent:function(t){if(this===t)return this;var e=this.screenCTM(),n=t.screenCTM().inverse();return this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())},transform:function(t,e){if(null==t||"string"==typeof t){var n=new ke(this).decompose();return n[t]||n}I(t)||(t=_({},t,{origin:L(t,this)}));var i=new ke(!0===e?this:e||!1).transform(t);return this.attr("transform",i)}}),ut("Element",{remember:function(t,e){if("object"===l(t))for(var n in t)this.remember(n,t[n]);else{if(1===arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0===arguments.length)this._memory={};else for(var t=arguments.length-1;0<=t;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory}}),ot("Memory",function(t){this._memory={}}),ut("EventTarget",{setup:He,on:function(t,e,n,i){return Ut(this,t,e,n,i),this},off:function(t,e){return Qt(this,t,e),this},dispatch:function(t,e){return n=t,i=e,r=Vt(this),n instanceof window.Event||(n=new window.CustomEvent(n,{detail:i,cancelable:!0})),r.dispatchEvent(n),n;var n,i,r},fire:function(t,e){return this.dispatch(t,e),this}}),ot("EventTarget",He),ut("Container",{children:function(){return function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)r.push(e(t[n]));return r}(this.node.children,function(t){return $(t)})},add:function(t,e){return(t=Q(t)).node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t.instance||t},has:function(t){return 0<=this.index(t)},index:function(t){return[].slice.call(this.node.children).indexOf(t.node)},get:function(t){return $(this.node.children[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.children.length-1)},each:function(t,e){var n,i,r=this.children();for(n=0,i=r.length;n<i;n++)r[n]instanceof Base&&t.apply(r[n],[n,r]),e&&r[n]instanceof Base&&r[n].is("Parent")&&r[n].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},svg:function(t){var e,n;if(!t)return this.writeDataToDom(),this.node.outerHTML;for((e=document.createElementNS(ns,"svg")).innerHTML=t,n=e.children.length;n--;)this.node.appendChild(e.firstElementChild);return this},writeDataToDom:function(){return this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},flatten:function(t){return this.each(function(){return this.is("Parent")?this.flatten(t).ungroup(t):this.toParent(t)}),this.node.firstElementChild||this.remove(),this},ungroup:function(t){return t=t||this.parent(),this.each(function(){return this.toParent(t)}),this.remove(),this}});var Ge=H;Ge([lt,ve,$t,Ht,Jt],at("viewbox")),Ge([Zt,fe,ce,ae],at("marker")),Ge(pe,at("Text")),Ge(ae,at("Path")),Ge(it,at("Defs")),Ge([pe,ge],at("Tspan"));var Ve=at("Container");for(var Ue in Ye)Ge(Ye[Ue],Ve);var Qe=at("Element");for(var $e in Fe)Ge(Fe[$e],Qe),Ge(Fe[$e],ht("EventTarget")),Ge(Fe[$e],ht("Element")),Ge(Fe[$e],ht("Memory"));function We(t){return Q(t)}return Object.assign(We,Xe),Object.assign(We,G),Object.assign(We,et),We}();
index eb95dc0acf2fdf6190286e08eb6ee41b1c0727de..eff76d21321e6ff1abe55715dd308d0cbc746ccc 100644 (file)
--- a/src/A.js
+++ b/src/A.js
@@ -1,6 +1,8 @@
 import Base from './Base.js'
 import {nodeOrNew} from './tools.js'
 import {xlink} from './namespaces.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class A extends Base{
   constructor (node) {
@@ -18,7 +20,7 @@ export default class A extends Base{
   }
 }
 
-A.constructors = {
+registerMethods({
   Container: {
     // Create a hyperlink element
     link: function (url) {
@@ -37,4 +39,6 @@ A.constructors = {
       return this.parent().put(link).put(this)
     }
   }
-}
+})
+
+register(A)
index b70f3297b36a3bd1a3a3bae6f1b8e64dd70d5842..5dde370056113084ac2b0e83a801ac3f18cca3aa 100644 (file)
@@ -1,39 +1,34 @@
 import {nodeOrNew} from './tools.js'
+import {register} from './adopter.js'
+import Base from './Base.js'
+import {registerMethods} from './methods.js'
 
-export default function Bare (element, inherit = {}) {
-  let custom =  class Custom extends inherit {
-    constructor (node) {
-      super(nodeOrNew(element, node), Custom)
-    }
-
-    words (text) {
-      // remove contents
-      while (this.node.hasChildNodes()) {
-        this.node.removeChild(this.node.lastChild)
-      }
 
-      // create text node
-      this.node.appendChild(document.createTextNode(text))
+export default class Bare extends Base {
+  constructor (node, inherit) {
+    super(nodeOrNew(null, node), Bare)
+    extend(this, inherit)
+  }
 
-      return this
+  words (text) {
+    // remove contents
+    while (this.node.hasChildNodes()) {
+      this.node.removeChild(this.node.lastChild)
     }
-  }
 
-  extend(custom, inherit)
+    // create text node
+    this.node.appendChild(document.createTextNode(text))
+
+    return this
+  }
 }
 
-// export let constructors = {
-//   // Create an element that is not described by SVG.js
-//   element: function (element, inherit) {
-//     let custom = createCustom(element, inherit)
-//     return this.put(new custom())
-//   }
-// }
+register(Bare)
 
-// extend(Parent, {
-//   // Create an element that is not described by SVG.js
-//   element: function (element, inherit) {
-//     let custom = createCustom(element, inherit)
-//     return this.put(new custom())
-//   }
-// })
+registerMethods('Bare', {
+  // Create an element that is not described by SVG.js
+  element (element, inherit) {
+    let custom = createCustom(element, inherit)
+    return this.put(new custom())
+  }
+})
index 36ee7f8835c3fdb557fcf4df38d7acc8a9027f5b..478f971198f69367c56130b49925b199dbd21b72 100644 (file)
@@ -4,6 +4,7 @@ import parser from './parser.js'
 import {fullBox, domContains, isNulledBox} from './helpers.js'
 import {extend} from './tools.js'
 import {delimiter} from './regex.js'
+import {registerMethods} from './methods.js'
 
 export default class Box {
   constructor (...args) {
@@ -104,7 +105,7 @@ function getBox(cb) {
   return box
 }
 
-Box.constructors = {
+registerMethods({
   Element: {
     // Get bounding box
     bbox () {
@@ -124,4 +125,4 @@ Box.constructors = {
     // act as setter
     return this.attr('viewBox', new Box(x, y, width, height))
   }
-}
+})
index 6d4b12ba824ddf4d56116204caa856615c8c27db..d19b75947e6fb2d2d2f0e1e5eedabebac64b365d 100644 (file)
@@ -2,6 +2,8 @@ import Base from './Base.js'
 import {nodeOrNew, extend} from './tools.js'
 import {x, y, cx, cy, width, height, size} from './circled.js'
 import SVGNumber from './SVGNumber.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Circle extends Base {
   constructor (node) {
@@ -25,7 +27,7 @@ export default class Circle extends Base {
 
 extend(Circle, {x, y, cx, cy, width, height, size})
 
-Circle.constructors = {
+registerMethods({
   Element: {
     // Create circle element
     circle (size) {
@@ -34,4 +36,6 @@ Circle.constructors = {
         .move(0, 0)
     }
   }
-}
+})
+
+register(Circle)
index aeb129fb576c0454302fba1a9c461933f3494f83..4989d6d6deb340abe20d5b881f74466b68f7853a 100644 (file)
@@ -1,31 +1,33 @@
 import Base from './Base.js'
 import {nodeOrNew, extend} from './tools.js'
-//import find from './selector.js'
-//import {remove} from './Element.js'
+import find from './selector.js'
+import {remove} from './Element.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class ClipPath extends Base {
   constructor (node) {
     super(nodeOrNew('clipPath', node), ClipPath)
   }
 
-  // // Unclip all clipped elements and remove itself
-  // remove () {
-  //   // unclip all targets
-  //   this.targets().forEach(function (el) {
-  //     el.unclip()
-  //   })
-  //
-  //   // remove clipPath from parent
-  //   return remove.call(this)
-  // }
-  //
-  // targets () {
-  //   return find('svg [clip-path*="' + this.id() + '"]')
-  // }
+  // Unclip all clipped elements and remove itself
+  remove () {
+    // unclip all targets
+    this.targets().forEach(function (el) {
+      el.unclip()
+    })
+
+    // remove clipPath from parent
+    return remove.call(this)
+  }
+
+  targets () {
+    return find('svg [clip-path*="' + this.id() + '"]')
+  }
 }
 
 
-ClipPath.constructors = {
+registerMethods({
   Container: {
     // Create clipping element
     clip: function() {
@@ -53,4 +55,6 @@ ClipPath.constructors = {
       return this.reference('clip-path')
     }
   }
-}
+})
+
+register(ClipPath)
index e8c5ac277bf9f2ba13371321ad1c6c39e8677321..68c5755878d0ac076cb69bf14e147a3c2c0b0e51 100644 (file)
@@ -1,5 +1,6 @@
 import Base from './Base.js'
 import {nodeOrNew} from './tools.js'
+import {register} from './adopter.js'
 
 export default class Defs extends Base {
   constructor (node) {
@@ -9,3 +10,5 @@ export default class Defs extends Base {
   flatten () { return this }
   ungroup () { return this }
 }
+
+register(Defs)
index 7e31c7f961213d2d5e891d69fad9e5f955bbbc24..5ccb8311f7b793984fb12fc0585ffd330e4209ca 100644 (file)
@@ -2,7 +2,8 @@ import Base from './Base.js'
 import Defs from './Defs.js'
 import { extend, nodeOrNew } from './tools.js'
 import { ns, xlink, xmlns, svgjs } from './namespaces.js'
-//import {adopt} from './adopter.js'
+import {adopt, register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Doc extends Base {
   constructor(node) {
@@ -36,11 +37,8 @@ export default class Doc extends Base {
   defs() {
     if (!this.isRoot()) return this.doc().defs()
 
-    let node = this.node.getElementsByTagName('defs')[0]
-    return node ? (node.instance || new Defs(node)) : this.put(new Defs())
-    // 
-    // return adopt(this.node.getElementsByTagName('defs')[0]) ||
-    //   this.put(new Defs())
+    return adopt(this.node.getElementsByTagName('defs')[0]) ||
+      this.put(new Defs())
   }
 
   // custom parent method
@@ -76,11 +74,13 @@ export default class Doc extends Base {
   }
 }
 
-Doc.constructors = {
+registerMethods({
   Container: {
     // Create nested svg document
     nested() {
       return this.put(new Doc())
     }
   }
-}
+})
+
+register(Doc, 'Doc', true)
index 2b57af8214f8932124c09a45137649c8ca08eca9..71b158b104ad827e24039c57e9fac628f1fdc5ce 100644 (file)
@@ -1,9 +1,12 @@
 import {proportionalSize, matcher} from './helpers.js'
-import {makeInstance, adopt, assignNewId, eid} from './adopter.js'
+import {makeInstance, adopt, assignNewId, eid, root, getClass} from './adopter.js'
 import {delimiter} from './regex.js'
 import {ns} from './namespaces.js'
-import Doc from './Doc.js'
 import SVGNumber from './SVGNumber.js'
+import {registerMethods} from './methods.js'
+import {registerConstructor} from './methods.js'
+
+const Doc = getClass(root)
 
 export const name = 'Element'
 
@@ -202,7 +205,7 @@ export function parent (type) {
   }
 }
 
-  // Get parent document
+// Get parent document
 export function doc () {
   let p = this.parent(Doc)
   return p && p.doc()
@@ -267,4 +270,11 @@ export function getEventTarget () {
   return this.node
 }
 
-export {default as attr} from './attr.js'
+registerMethods('Element', {
+  x, y, cx, cy, move, center, width, height, size, clone, remove, replace,
+  putIn, id, inside, toString, classes, hasClass, addClass, removeClass,
+  toggleClass, reference, doc, defs, parents, matches, native, svg,
+  writeDataToDom, setData, getEventTarget
+})
+
+registerConstructor('Element', setup)
index cb025bba88260f56462584eb558757fcd704915d..c38d322b4d010972b4280183a30c4627c5ba11f0 100644 (file)
@@ -1,6 +1,8 @@
 import Base from './Base.js'
 import * as circled from './circled.js'
 import {extend} from './tools.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Ellipse extends Base {
   constructor (node) {
@@ -10,9 +12,11 @@ export default class Ellipse extends Base {
 
 extend(Ellipse, circled)
 
-// addFactory(Container, {
-//   // Create an ellipse
-//   ellipse: function (width, height) {
-//     return this.put(new Ellipse()).size(width, height).move(0, 0)
-//   }
-// })
+registerMethods('Container', {
+  // Create an ellipse
+  ellipse: function (width, height) {
+    return this.put(new Ellipse()).size(width, height).move(0, 0)
+  }
+})
+
+register(Ellipse)
index ce18d1f4720345fcb38672db9fc363257c1f5c90..b4496ff6f261aedc23ed627ed796008a2b71a634 100644 (file)
@@ -1,4 +1,6 @@
 import {on as _on, off as _off, dispatch as _dispatch} from './event.js'
+import {registerMethods} from './methods.js'
+import {registerConstructor} from './methods.js'
 
 export const name = 'EventTarget'
 
@@ -27,3 +29,9 @@ export function fire (event, data) {
   this.dispatch(event, data)
   return this
 }
+
+registerMethods('EventTarget', {
+  setup, on, off, dispatch, fire
+})
+
+registerConstructor('EventTarget', setup)
index 93d2b7f18184e2e865a14efce79954f887a1fb1c..d6d16ed7fc70e8c9623ae84c7b6613dd667a320e 100644 (file)
--- a/src/G.js
+++ b/src/G.js
@@ -1,4 +1,6 @@
 import Base from './Base.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class G extends Base {
   constructor (node) {
@@ -6,11 +8,13 @@ export default class G extends Base {
   }
 }
 
-G.constructors = {
+registerMethods({
   Element: {
     // Create a group element
     group: function () {
       return this.put(new G())
     }
   }
-}
+})
+
+register(G)
index 9751848e3d2778ba76eee11b488b0d316b877e42..e6aa36240b26e526079cbb64c78079684443060e 100644 (file)
@@ -2,7 +2,9 @@ import Stop from './Stop.js'
 import Base from './Base.js'
 import * as gradiented from './gradiented.js'
 import {nodeOrNew, extend} from './tools.js'
-//import attr from './attr.js'
+import attr from './attr.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Gradient extends Base {
   constructor (type) {
@@ -40,16 +42,20 @@ export default class Gradient extends Base {
     return this.url()
   }
 
-  // // custom attr to handle transform
-  // attr (a, b, c) {
-  //   if (a === 'transform') a = 'gradientTransform'
-  //   return attr.call(this, a, b, c)
-  // }
+  // custom attr to handle transform
+  attr (a, b, c) {
+    if (a === 'transform') a = 'gradientTransform'
+    return attr.call(this, a, b, c)
+  }
+
+  targets () {
+    return find('svg [fill*="' + this.id() + '"]')
+  }
 }
 
 extend(Gradient, gradiented)
 
-Gradient.constructors = {
+registerMethods({
   Container: {
     // Create gradient element in defs
     gradient (type, block) {
@@ -62,4 +68,6 @@ Gradient.constructors = {
       return this.put(new Gradient(type)).update(block)
     }
   }
-}
+})
+
+register(Gradient)
index 374796023c2be584b00e1393fd26d7bcfd0d9132..8488edf92909312ecd3bc03fd22c53ac664abe50 100644 (file)
@@ -1,5 +1,6 @@
-//import {makeInstance} from './adopter.js'
+import {makeInstance} from './adopter.js'
 import Base from './Base.js'
+import {register} from './adopter.js'
 
 export default class HtmlNode extends Base {
   constructor (element) {
@@ -7,15 +8,15 @@ export default class HtmlNode extends Base {
     this.node = element
   }
 
-  // add (element, i) {
-  //   element = makeInstance(element)
-  //
-  //   if (element.node !== this.node.children[i]) {
-  //     this.node.insertBefore(element.node, this.node.children[i] || null)
-  //   }
-  //
-  //   return this
-  // }
+  add (element, i) {
+    element = makeInstance(element)
+
+    if (element.node !== this.node.children[i]) {
+      this.node.insertBefore(element.node, this.node.children[i] || null)
+    }
+
+    return this
+  }
 
   put (element, i) {
     this.add(element, i)
@@ -26,3 +27,5 @@ export default class HtmlNode extends Base {
     return this.node
   }
 }
+
+register(HtmlNode)
index 389a38d8dfb5a4b9adab06fd1e4fd8fa55959bf8..69eede512f9dd44d1a2a4564536f0d30dddf1861 100644 (file)
@@ -3,6 +3,8 @@ import Pattern from './Pattern.js'
 import {on, off} from './event.js'
 import {nodeOrNew} from './tools.js'
 import {xlink} from './namespaces.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Image extends Base {
   constructor (node) {
@@ -47,13 +49,21 @@ export default class Image extends Base {
 
     return this.attr('href', (img.src = url), xlink)
   }
+
+  attrHook (obj) {
+    return obj.doc().defs().pattern(0, 0, (pattern) => {
+      pattern.add(this)
+    })
+  }
 }
 
-Image.constructors = {
+registerMethods({
   Container: {
     // create image element, load image and set its size
     image (source, callback) {
       return this.put(new Image()).size(0, 0).load(source, callback)
     }
   }
-}
+})
+
+register(Image)
index 930820b962ca2120f41ec6288bf6077556c487aa..550c0de07ed2f73fa40099b62f9b3206822a9aa1 100644 (file)
@@ -2,6 +2,8 @@ import {proportionalSize} from './helpers.js'
 import {nodeOrNew} from './tools.js'
 import PointArray from './PointArray.js'
 import Base from './Base.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Line extends Base {
   // Initialize node
@@ -43,7 +45,7 @@ export default class Line extends Base {
 
 }
 
-Line.constructors = {
+registerMethods({
   Container: {
     // Create a line element
     line (...args) {
@@ -55,4 +57,6 @@ Line.constructors = {
       )
     }
   }
-}
+})
+
+register(Line)
index dfba967019937c4129e94c235e89d3c0138f6e5b..bf2b854aee0d20e9d7359d9002e831098ae47579 100644 (file)
@@ -1,9 +1,6 @@
 import Base from './Base.js'
-// import Defs from './Defs.js'
-// import Line from './Line.js'
-// import Polyline from './Polyline.js'
-// import Polygon from './Polygon.js'
-// import Path from './Path.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Marker extends Base {
   // Initialize node
@@ -43,7 +40,7 @@ export default class Marker extends Base {
   }
 }
 
-Marker.constructors = {
+registerMethods({
   Container: {
     marker (width, height, block) {
       // Create marker element in defs
@@ -79,4 +76,6 @@ Marker.constructors = {
       return this.attr(attr, marker)
     }
   }
-}
+})
+
+register(Marker)
index ed8555200c5e258c1bc431a170ee851c8338e728..8edf4ec08e1f4cb4f8e63a9a8213fbc957f37c98 100644 (file)
@@ -1,7 +1,9 @@
 import Base from './Base.js'
 import {nodeOrNew} from './tools.js'
-// import find from './selector.js'
-// import {remove} from  './Element.js'
+import find from './selector.js'
+import {remove} from  './Element.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Mask extends Base {
   // Initialize node
@@ -9,25 +11,25 @@ export default class Mask extends Base {
     super(nodeOrNew('mask', node))
   }
 
-  // // Unmask all masked elements and remove itself
-  // remove () {
-  //   // unmask all targets
-  //   this.targets().forEach(function (el) {
-  //     el.unmask()
-  //   })
-  //
-  //   // remove mask from parent
-  //   return remove.call(this)
-  // }
-  //
-  // targets () {
-  //   return find('svg [mask*="' + this.id() + '"]')
-  // }
+  // Unmask all masked elements and remove itself
+  remove () {
+    // unmask all targets
+    this.targets().forEach(function (el) {
+      el.unmask()
+    })
+
+    // remove mask from parent
+    return remove.call(this)
+  }
+
+  targets () {
+    return find('svg [mask*="' + this.id() + '"]')
+  }
 
 }
 
 
-Mask.constructors = {
+registerMethods({
   Container: {
     mask () {
       return this.defs().put(new Mask())
@@ -54,4 +56,6 @@ Mask.constructors = {
       return this.reference('mask')
     }
   }
-}
+})
+
+register(Mask)
index 09dc568afc502055592606b59819d91346858a01..11ec53e02c85f14c1ba53b2ce9fb410d8427ae6e 100644 (file)
@@ -4,6 +4,7 @@ import {delimiter} from './regex.js'
 import {radians} from './utils.js'
 import parser from './parser.js'
 import Base from './Base.js'
+import {registerMethods} from './methods.js'
 
 export default class Matrix {
   constructor (...args) {
@@ -478,7 +479,7 @@ export default class Matrix {
   }
 }
 
-Matrix.constructors = {
+registerMethods({
   Element: {
     // Get current matrix
     ctm () {
@@ -500,4 +501,4 @@ Matrix.constructors = {
       return new Matrix(this.node.getScreenCTM())
     }
   }
-}
+})
index e2c725c0e7abdfdbfe31852e720bc37003137fe5..1a1136f7f119d0e91bee9d72144e0f88499d5930 100644 (file)
@@ -1,6 +1,6 @@
 import {makeInstance, adopt} from './adopter.js'
 import {map} from './utils.js'
-
+import {registerMethods} from './methods.js'
 
 // Returns all child elements
 export function children () {
@@ -155,3 +155,8 @@ export function ungroup (parent) {
 
   return this
 }
+
+registerMethods('Container', {
+  children, add, put, has, index, get, first, last, each,
+  removeElement, clear, svg, writeDataToDom, flatten, ungroup
+})
index b06da5b06a49ee3604d69b4855e5b81808cb75f7..7ed3c13e2182d9456dd4393d082c9b15456026ce 100644 (file)
@@ -2,6 +2,9 @@ import {proportionalSize} from './helpers.js'
 import {nodeOrNew} from './tools.js'
 import Base from './Base.js'
 import PathArray from './PathArray.js'
+import find from './selector.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Path extends Base {
   // Initialize node
@@ -56,13 +59,17 @@ export default class Path extends Base {
   height (height) {
     return height == null ? this.bbox().height : this.size(this.bbox().width, height)
   }
+
+  targets () {
+    return find('svg textpath [href*="' + this.id() + '"]')
+  }
 }
 
 // Define morphable array
 Path.prototype.MorphArray = PathArray
 
 // Add parent method
-Path.constructors = {
+registerMethods({
   Container: {
     // Create a wrapped path element
     path (d) {
@@ -70,4 +77,6 @@ Path.constructors = {
       return this.put(new Path()).plot(d || new PathArray())
     }
   }
-}
+})
+
+register(Path)
index 0c1b2cf193af456c79d298e65dac1d1f23005534..eca2355853a33922b2c7b83158e01dd5db1bc1a6 100644 (file)
@@ -1,6 +1,8 @@
 import Base from './Base.js'
 import {nodeOrNew} from './tools.js'
-//import attr from './attr.js'
+import attr from './attr.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Pattern extends Base {
   // Initialize node
@@ -31,14 +33,18 @@ export default class Pattern extends Base {
     return this.url()
   }
 
-  // // custom attr to handle transform
-  // attr (a, b, c) {
-  //   if (a === 'transform') a = 'patternTransform'
-  //   return attr.call(this, a, b, c)
-  // }
+  // custom attr to handle transform
+  attr (a, b, c) {
+    if (a === 'transform') a = 'patternTransform'
+    return attr.call(this, a, b, c)
+  }
+
+  targets () {
+    return find('svg [fill*="' + this.id() + '"]')
+  }
 }
 
-Pattern.constructors = {
+registerMethods({
   Container: {
     // Create pattern element in defs
     pattern (width, height, block) {
@@ -56,4 +62,6 @@ Pattern.constructors = {
       })
     }
   }
-}
+})
+
+register(Pattern)
index 588016884c29f0475b91dd8bd880248dbd8fd533..7919d025476bc9cc90e81c59f23f8da941b0a255 100644 (file)
@@ -1,4 +1,5 @@
 import parser from './parser.js'
+import {registerMethods} from './methods.js'
 
 export default class Point {
   // Initialize
@@ -43,11 +44,11 @@ export default class Point {
   }
 }
 
-Point.constructors = {
+registerMethods({
   Element: {
     // Get point
     point: function (x, y) {
       return new Point(x, y).transform(this.screenCTM().inverse())
     }
   }
-}
+})
index 3f7f9487c3593dc86ae0a76c1a564900c21c7b17..208adcaf1026232159a246ce0cfa41ca9548c5ed 100644 (file)
@@ -4,6 +4,8 @@ import {nodeOrNew, extend} from './tools.js'
 import * as pointed from './pointed.js'
 import * as poly from './poly.js'
 import PointArray from './PointArray.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Polygon extends Base {
   // Initialize node
@@ -12,7 +14,7 @@ export default class Polygon extends Base {
   }
 }
 
-Polygon.constructors = {
+registerMethods({
   Parent: {
     // Create a wrapped polygon element
     polygon (p) {
@@ -20,7 +22,8 @@ Polygon.constructors = {
       return this.put(new Polygon()).plot(p || new PointArray())
     }
   }
-}
+})
 
 extend(Polygon, pointed)
 extend(Polygon, poly)
+register(Polygon)
index c3c8c0c38c3a134e5d516026eee3e9a555d110ac..a4c7a235496097e7eef48a8c03fcde8b83d68912 100644 (file)
@@ -3,6 +3,8 @@ import {nodeOrNew, extend} from './tools.js'
 import PointArray from './PointArray.js'
 import * as pointed from './pointed.js'
 import * as poly from './poly.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Polyline extends Base {
   // Initialize node
@@ -11,7 +13,7 @@ export default class Polyline extends Base {
   }
 }
 
-Polyline.constructors = {
+registerMethods({
   Parent: {
     // Create a wrapped polygon element
     polyline (p) {
@@ -19,7 +21,8 @@ Polyline.constructors = {
       return this.put(new Polyline()).plot(p || new PointArray())
     }
   }
-}
+})
 
 extend(Polyline, pointed)
 extend(Polyline, poly)
+register(Polyline)
index 2e4e100133e9ab3db31b8a5f9393ee9453d495da..037064ca0cdfaff5092b1f8bb9305a6243475fb2 100644 (file)
@@ -1,5 +1,7 @@
 import Base from './Base.js'
 import {nodeOrNew, extend} from './tools.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Rect extends Base {
   // Initialize node
@@ -8,11 +10,13 @@ export default class Rect extends Base {
   }
 }
 
-Rect.constructors = {
+registerMethods({
   Container: {
     // Create a rect element
     rect (width, height) {
       return this.put(new Rect()).size(width, height)
     }
   }
-}
+})
+
+register(Rect)
index 9633c90cc961fd7964ab1ee8a2583e9e7ce26bbd..04b2a9ca8bc51cee0253b74cb9a418329944ac35 100644 (file)
@@ -8,6 +8,7 @@ import {noop, timeline} from './defaults.js'
 import {extend} from './tools.js'
 import Animator from './Animator.js'
 import Point from './Point.js'
+import {registerMethods} from './methods.js'
 
 // FIXME: What is this doing here?
 // easing = {
@@ -544,7 +545,7 @@ class RunnerArray {
 }
 
 let frameId = 0
-Runner.constructors = {
+registerMethods({
   Element: {
     animate (duration, delay, when) {
       var o = Runner.sanitise(duration, delay, when)
@@ -595,7 +596,7 @@ Runner.constructors = {
       }
     }
   }
-}
+})
 
 
 extend(Runner, {
index 1631b4a8abaa6d20dc652746fe44f50fd6363d47..0cd21e694db83abdb34bed1c6553fd0fbfce7420 100644 (file)
@@ -1,6 +1,7 @@
 import Base from './Base.js'
 import SVGNumber from './SVGNumber.js'
 import {nodeOrNew} from './tools.js'
+import {register} from './adopter.js'
 
 export default class Stop extends Base {
   constructor (node) {
@@ -25,3 +26,5 @@ export default class Stop extends Base {
     return this
   }
 }
+
+register(Stop)
index e9936e2d5c66f2828687d8144fbf343a39491c56..fbd4f3be33bed4a43446f0765e42e384f4e758f4 100644 (file)
@@ -1,5 +1,7 @@
 import Base from './Base.js'
 import {nodeOrNew} from './tools.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Symbol extends Base {
   // Initialize node
@@ -8,10 +10,12 @@ export default class Symbol extends Base {
   }
 }
 
-Symbol.constructors = {
+registerMethods({
   Container: {
     symbol () {
       return this.put(new Symbol())
     }
   }
-}
+})
+
+register(Symbol)
index 3d7fd1de0018e14ae5879a8c71b529dc56d1e92c..fabdbe577e4f461c831b0aeb44e234961c5ef6a4 100644 (file)
@@ -3,6 +3,8 @@ import SVGNumber from './SVGNumber.js'
 import {nodeOrNew, extend} from './tools.js'
 import {attrs} from './defaults.js'
 import * as textable from './textable.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Text extends Base {
   // Initialize node
@@ -158,7 +160,7 @@ export default class Text extends Base {
 
 extend(Text, textable)
 
-Text.constructors = {
+registerMethods({
   Container: {
     // Create text element
     text (text) {
@@ -170,4 +172,6 @@ Text.constructors = {
       return this.put(new Text()).plain(text)
     }
   }
-}
+})
+
+register(Text)
index 6c1ca56e91955a47c27b1f11720f1eceea4446cb..ac9b9b69c72cb34f33966fb50ea6bf6b57819dc6 100644 (file)
@@ -3,6 +3,8 @@ import Text from './Text.js'
 import PathArray from './PathArray.js'
 import {nodeOrNew} from './tools.js'
 import {xlink} from './namespaces.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class TextPath extends Text {
   // Initialize node
@@ -35,7 +37,7 @@ export default class TextPath extends Text {
   }
 }
 
-TextPath.constructors = {
+registerMethods({
   Container: {
     textPath (text, path) {
       return this.defs().path(path).text(text).addTo(this)
@@ -76,6 +78,7 @@ TextPath.constructors = {
     }
     // FIXME: Maybe add `targets` to get all textPaths associated with this path
   }
-}
+})
 
 TextPath.prototype.MorphArray = PathArray
+register(TextPath)
index fc19db86fdee8579aae6323461f08db798fa5d9c..e6e9e439c6efb4a915f300ddbeefe6b4df434fb5 100644 (file)
@@ -1,4 +1,5 @@
 import Animator from './Animator.js'
+import {registerMethods} from './methods.js'
 
 var time = window.performance || Date
 
@@ -260,11 +261,11 @@ export default class Timeline {
   }
 }
 
-Timeline.constructors = {
+registerMethods({
   Element: {
     timeline: function () {
       this._timeline = (this._timeline || new Timeline())
       return this._timeline
     }
   }
-}
+})
index 811c4b1459a22ecdf8f805c3212702e8bbc95e2d..aa052695eb884dda5e6d82e15573e43a1759a76b 100644 (file)
@@ -1,6 +1,8 @@
 import Base from './Base.js'
 import {nodeOrNew, extend} from './tools.js'
 import * as textable from './textable.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Tspan extends Base {
   // Initialize node
@@ -42,7 +44,7 @@ export default class Tspan extends Base {
 
 extend(Tspan, textable)
 
-Tspan.constructors = {
+registerMethods({
   Tspan: {
     tspan (text) {
       var tspan = new Tspan()
@@ -58,4 +60,6 @@ Tspan.constructors = {
       return tspan.text(text)
     }
   }
-}
+})
+
+register(Tspan)
index 5c4fe8e163ff8200ebb769839fede4366a20475d..d01db5a938bd4f585cd87125a03c91f93b3a2b31 100644 (file)
@@ -1,5 +1,7 @@
 import Base from './Base.js'
 import {xlink} from './namespaces.js'
+import {register} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 export default class Use extends Base {
   constructor (node) {
@@ -13,11 +15,13 @@ export default class Use extends Base {
   }
 }
 
-Use.constructors = {
+registerMethods({
   Container: {
     // Create a use element
     use: function (element, file) {
       return this.put(new Use()).element(element, file)
     }
   }
-}
+})
+
+register(Use)
index 9285a5f1a71cf07b4851a7660387e819bc6b7d14..8b25718dc98eb80750b1375e991b38bdc3bb1607 100644 (file)
@@ -1,6 +1,9 @@
 import Base from './Base.js'
-import * as elements from './elements.js'
 import {capitalize} from './helpers.js'
+import {makeNode} from './tools.js'
+
+const elements = {}
+export const root = Symbol('root')
 
 export function makeInstance (element) {
   if (element instanceof Base) return element
@@ -10,7 +13,7 @@ export function makeInstance (element) {
   }
 
   if (element == null) {
-    return new Doc()
+    return new elements[root]()
   }
 
   if (typeof element === 'string' && element.charAt(0) !== '<') {
@@ -25,13 +28,14 @@ export function makeInstance (element) {
   return element
 }
 
+
 // Adopt existing svg elements
 export function adopt (node) {
   // check for presence of node
   if (!node) return null
 
   // make sure a node isn't already adopted
-  if (node.instance instanceof Element) return node.instance
+  if (node.instance instanceof Base) return node.instance
 
   if (!(node instanceof window.SVGElement)) {
     return new elements.HtmlNode(node)
@@ -42,7 +46,7 @@ export function adopt (node) {
 
   // adopt with element-specific settings
   if (node.nodeName === 'svg') {
-    element = new elements.Doc(node)
+    element = new elements[root](node)
   } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') {
     element = new elements.Gradient(node)
   } else if (elements[capitalize(node.nodeName)]) {
@@ -54,6 +58,16 @@ export function adopt (node) {
   return element
 }
 
+export function register (element, name = element.name, asRoot = false) {
+  elements[name] = element
+  if (asRoot) elements[root] = element
+  return element
+}
+
+export function getClass(name) {
+  return elements[name]
+}
+
 // Element id sequence
 let did = 1000
 
index b6d5e26f24350e89301686f2b29d43a6fdd59f1f..3668f87f2ea39eb4f33736e660688dd012ad0369 100644 (file)
@@ -1,5 +1,3 @@
-import Doc from './Doc.js'
-
 // ### This module adds backward / forward functionality to elements.
 
 // Get all siblings, including myself
@@ -31,7 +29,7 @@ export function forward () {
   p.removeElement(this).add(this, i)
 
   // make sure defs node is always at the top
-  if (p instanceof Doc) {
+  if (typeof p.isRoot == 'function' && p.isRoot()) {
     p.node.appendChild(p.defs().node)
   }
 
index ddf4de267b959869efee33dcd23bfe528cc97868..912bb0759dbea2a9b4e473d95503a23f25fe0931 100644 (file)
@@ -2,8 +2,8 @@ import {isNumber, isImage} from './regex.js'
 import {attrs as defaults} from './defaults.js'
 import Color from './Color.js'
 import SVGArray from './SVGArray.js'
-import Image from './Image.js'
 import SVGNumber from './SVGNumber.js'
+import {registerMethods} from './methods.js'
 
 // Set svg element attribute
 export default function attr (attr, val, ns) {
@@ -40,12 +40,12 @@ export default function attr (attr, val, ns) {
       if (isImage.test(val)) {
         val = this.doc().defs().image(val)
       }
+    }
 
-      if (val instanceof Image) {
-        val = this.doc().defs().pattern(0, 0, function () {
-          this.add(val)
-        })
-      }
+    // FIXME: This is fine, but what about the lines above?
+    // How does attr know about image()?
+    while (typeof val.attrHook == 'function') {
+      val = val.attrHook(this, attr)
     }
 
     // ensure correct numeric values (also accepts NaN and Infinity)
@@ -79,3 +79,5 @@ export default function attr (attr, val, ns) {
 
   return this
 }
+
+registerMethods('Element', {attr})
index b85c0fe751e44d70d24e9dc5ff8462469e1eaefb..7a3bfbe968954b28a7ed7273f95ba788be8921b0 100644 (file)
@@ -1,5 +1,8 @@
 import {camelCase} from './helpers.js'
 import {isBlank} from './regex.js'
+import {registerMethods} from './methods.js'
+
+// FIXME: We dont need exports
 
   // Dynamic style generator
 export function css (style, val) {
@@ -64,3 +67,7 @@ export function hide () {
 export function visible () {
   return this.css('display') !== 'none'
 }
+
+registerMethods('Element', {
+  css, show, hide, visible
+})
index c1437728c10abc1240dda8ee5090adbdcd9dc06b..c49f6a984fc8217e10f6e1765c0d74160c9019a7 100644 (file)
@@ -1,3 +1,5 @@
+import {registerMethods} from './methods.js'
+
 // Store data values on svg nodes
 export function data (a, v, r) {
   if (typeof a === 'object') {
@@ -20,3 +22,5 @@ export function data (a, v, r) {
 
   return this
 }
+
+registerMethods('Element', {data})
index c7832aa66480e9e868d8cb59b6ca17599ec04ae0..8d8737ad18d06747ff65a56be241cd5a1162bfdd 100644 (file)
@@ -1,4 +1,5 @@
 import {delimiter} from './regex.js'
+import {registerMethods} from './methods.js'
 
 // // Add events to elements
 // ;[ 'click',
index 76bcfa6591d958a1588ccb2f81e7d2cb87c85c0e..def59690c689815eac88f3254a9dc66f2a308e39 100644 (file)
@@ -1,3 +1,5 @@
+import {registerMethods} from './methods.js'
+import {registerConstructor} from './methods.js'
 
 export const name = 'Memory'
 
@@ -21,7 +23,7 @@ export function remember (k, v) {
   }
 
   return this
-},
+}
 
   // Erase a given memory
 export function forget () {
@@ -39,3 +41,6 @@ export function forget () {
 export function memory () {
   return this._memory
 }
+
+registerMethods('Element', {remember, forget, memory})
+registerConstructor('Memory', setup)
diff --git a/src/methods.js b/src/methods.js
new file mode 100644 (file)
index 0000000..4a51faa
--- /dev/null
@@ -0,0 +1,30 @@
+const methods = {}
+const constructors = {}
+
+export function registerMethods (name, m) {
+  if (typeof name == 'object') {
+    for (let [_name, _m] of Object.entries(name)) {
+      registerMethods(_name, _m)
+    }
+  }
+
+  methods[name] = Object.assign(methods[name] || {}, m)
+}
+
+export function getMethodsFor (name) {
+  return methods[name]
+}
+
+// FIXME: save memory?
+export function cleanMethods () {
+  methods = {}
+}
+
+
+export function registerConstructor (name, setup) {
+  constructors[name] = setup
+}
+
+export function getConstructor (name) {
+  return {setup: constructors[name], name}
+}
index 660b4d97a759ee77f975e1ee26a04b8e0d11d2c9..7d6901a9fa65adc584791b3507e366fbda30ec17 100644 (file)
@@ -1,6 +1,7 @@
 import {idFromReference} from './helpers.js'
 import {map} from './utils.js'
 import {adopt} from './adopter.js'
+import {registerMethods} from './methods.js'
 
 // // Method for getting an element by id
 // SVG.get = function (id) {
@@ -35,3 +36,5 @@ export default function baseFind (query, parent) {
 export function find (query) {
   return baseFind(query, this.node)
 }
+
+registerMethods('Container', {find})
diff --git a/src/specialNeeds.js b/src/specialNeeds.js
deleted file mode 100644 (file)
index c9d74d4..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-import {remove, attr} from './Element.js'
-import {find} from './selector.js'
-import {makeInstance} from './adopter.js'
-
-// Unclip all clipped elements and remove itself
-export function clipPathRemove () {
-  // unclip all targets
-  this.targets().forEach(function (el) {
-    el.unclip()
-  })
-
-  // remove clipPath from parent
-  return remove.call(this)
-}
-
-export function clipPathTargets () {
-  return find('svg [clip-path*="' + this.id() + '"]')
-}
-
-// Unclip all clipped elements and remove itself
-export function maskRemove () {
-  // unclip all targets
-  this.targets().forEach(function (el) {
-    el.unmask()
-  })
-
-  // remove clipPath from parent
-  return remove.call(this)
-}
-
-export function maskTargets () {
-  return find('svg [mask*="' + this.id() + '"]')
-}
-
-// Unclip all clipped elements and remove itself
-export function patternGradientRemove () {
-  // unclip all targets
-  this.targets().forEach(function (el) {
-    el.unFill()
-  })
-
-  // remove clipPath from parent
-  return remove.call(this)
-}
-
-export function unFill () {
-  this.attr('fill', null)
-}
-
-export function patternGradientTargets () {
-  return find('svg [fill*="' + this.id() + '"]')
-}
-
-// custom attr to handle transform
-export function patternAttr (a, b, c) {
-  if (a === 'transform') a = 'patternTransform'
-  return attr.call(this, a, b, c)
-}
-
-// custom attr to handle transform
-export function gradientAttr (a, b, c) {
-  if (a === 'transform') a = 'gradientTransform'
-  return attr.call(this, a, b, c)
-}
-
-export function pathTargets () {
-  return find('svg textpath [href*="' + this.id() + '"]')
-}
-
-export function HtmlNodeAdd (element, i) {
-  element = makeInstance(element)
-
-  if (element.node !== this.node.children[i]) {
-    this.node.insertBefore(element.node, this.node.children[i] || null)
-  }
-
-  return this
-}
index 55988da7cb1765af531a360c0bfc06f084f5a59d..a58c127175e301ec6a02b467e932670bdf063a69 100644 (file)
@@ -10,16 +10,18 @@ import * as adopter from './adopter.js'
 import * as tools from './tools.js'
 import * as containers from './containers.js'
 import * as elements from './elements.js'
-import * as arrange from './arrange.js'
-import {find} from './selector.js'
-import * as css from './css.js'
-import * as transform from './transform.js'
-import * as specialNeeds from './specialNeeds.js'
+import './attr.js'
+import './arrange.js'
+import './selector.js'
+import './css.js'
+import './transform.js'
+import './memory.js'
+import {getMethodsFor, getConstructor} from './methods.js'
 const extend = tools.extend
 
-import * as EventTarget from './EventTarget.js'
-import * as Element from './Element.js'
-import * as Parent from './Parent.js'
+import './EventTarget.js'
+import './Element.js'
+import './Parent.js'
 
 extend([
   Classes.Doc,
@@ -27,93 +29,39 @@ extend([
   Classes.Image,
   Classes.Pattern,
   Classes.Marker
-], {viewbox: Classes.Box.constructors.viewbox})
+], getMethodsFor('viewbox'))
 
-extend([Classes.Line, Classes.Polyline, Classes.Polygon, Classes.Path], {
-  ...Classes.Marker.constructors.marker
-})
-
-extend(Classes.Text, Classes.TextPath.constructors.Text)
-extend(Classes.Path, Classes.TextPath.constructors.Path)
-
-extend(Classes.Defs, {
-  ...Classes.Gradient.constructors.Defs,
-  ...Classes.Marker.constructors.Defs,
-  ...Classes.Pattern.constructors.Defs,
-})
-
-extend([Classes.Text, Classes.Tspan], Classes.Tspan.constructors.Tspan)
-
-extend([Classes.Gradient, Classes.Pattern], {
-  remove: specialNeeds.patternGradientRemove,
-  targets: specialNeeds.patternGradientTargets,
-  unFill: specialNeeds.unFill,
-})
-
-extend(Classes.Gradient, {attr: specialNeeds.gradientAttr})
-extend(Classes.Pattern, {attr: specialNeeds.patternAttr})
-
-extend(Classes.ClipPath, {
-  remove: specialNeeds.clipPathRemove,
-  targets: specialNeeds.clipPathTargets
-})
+extend([
+  Classes.Line,
+  Classes.Polyline,
+  Classes.Polygon,
+  Classes.Path
+], getMethodsFor('marker'))
 
-extend(Classes.Mask, {
-  remove: specialNeeds.maskRemove,
-  targets: specialNeeds.maskTargets
-})
+extend(Classes.Text, getMethodsFor('Text'))
+extend(Classes.Path, getMethodsFor('Path'))
 
-extend(Classes.Path, {targets: specialNeeds.pathTargets})
+extend(Classes.Defs, getMethodsFor('Defs'))
 
-extend(Classes.HtmlNode, {
-  add: specialNeeds.HtmlNodeAdd
-})
+extend([
+  Classes.Text,
+  Classes.Tspan
+], getMethodsFor('Tspan'))
 
+const containerMethods = getMethodsFor('Container')
+// FIXME: We need a container array
 for (let i in containers) {
-  extend(containers[i], {
-    ...Classes.A.constructors.Container,
-    ...Classes.ClipPath.constructors.Container,
-    ...Classes.Doc.constructors.Container,
-    ...Classes.G.constructors.Container,
-    ...Classes.Gradient.constructors.Container,
-    ...Classes.Line.constructors.Container,
-    ...Classes.Marker.constructors.Container,
-    ...Classes.Mask.constructors.Container,
-    ...Classes.Path.constructors.Container,
-    ...Classes.Pattern.constructors.Container,
-    ...Classes.Polygon.constructors.Container,
-    ...Classes.Polyline.constructors.Container,
-    ...Classes.Rect.constructors.Container,
-    find,
-    ...Classes.Symbol.constructors.Container,
-    ...Classes.Text.constructors.Container,
-    ...Classes.TextPath.constructors.Container,
-    ...Classes.Use.constructors.Container,
-  })
+  extend(containers[i], containerMethods)
 }
 
+const elementMethods = getMethodsFor('Element')
 for (let i in elements) {
-  extend(elements[i], {
-    ...EventTarget,
-    ...Element,
-    ...Parent,
-    ...arrange,
-    ...Classes.A.constructors.Element,
-    ...Classes.Box.constructors.Element,
-    ...Classes.Circle.constructors.Element,
-    ...Classes.ClipPath.constructors.Element,
-    ...css,
-    ...Classes.Image.constructors.Element,
-    ...Classes.Mask.constructors.Element,
-    ...Classes.Matrix.constructors.Element,
-    ...Classes.Point.constructors.Element,
-    ...Classes.Runner.constructors.Element,
-    ...Classes.Timeline.constructors.Element,
-    ...transform,
-  })
+  extend(elements[i], elementMethods)
+  extend(elements[i], getConstructor('EventTarget'))
+  extend(elements[i], getConstructor('Element'))
+  extend(elements[i], getConstructor('Memory'))
 }
 
-
 // The main wrapping element
 export default function SVG (element) {
   return makeInstance(element)
index d6516a2a43959aef162a61eec11ce1cc93784888..907bbfadc5cccfb23217d6a338966a8b317239d6 100644 (file)
@@ -1,6 +1,7 @@
 import {arrayToMatrix, getOrigin, isMatrixLike} from './helpers.js'
 import Matrix from './Matrix.js'
 import {delimiter, transforms} from './regex.js'
+import {registerMethods} from './methods.js'
 
 // Reset all transformations
 export function untransform () {
@@ -65,3 +66,7 @@ export function transform (o, relative) {
   var result = new Matrix(cleanRelative).transform(o)
   return this.attr('transform', result)
 }
+
+registerMethods('Element', {
+  untransform, matrixify, toParent, toDoc, transform
+})