From 9f2696e8a2cf7e4eebc1cc7e31027fe2070094fa Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Mon, 5 Nov 2018 21:53:40 +0100 Subject: [PATCH] removed unused comments and files --- dist/svg.js | 7355 +++++++++++++++++++++----------------------- dist/svg.min.js | 2 +- src/ClipPath.js | 1 - src/Doc.js | 15 - src/Dom.js | 3 +- src/Element.js | 9 - src/EventTarget.js | 10 +- src/Gradient.js | 1 - src/Mask.js | 1 - src/PathArray.js | 217 -- src/Pattern.js | 1 - src/PointArray.js | 124 - src/SVGArray.js | 50 - src/attr.js | 2 - src/classes.js | 91 +- src/containers.js | 15 - src/elements.js | 25 - src/event.js | 12 - src/memory.js | 7 +- src/methods.js | 5 - src/selector.js | 23 - 21 files changed, 3471 insertions(+), 4498 deletions(-) delete mode 100644 src/containers.js delete mode 100644 src/elements.js diff --git a/dist/svg.js b/dist/svg.js index 3b71aea..946db81 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -6,7 +6,7 @@ * @copyright Wout Fierens * @license MIT * -* BUILT: Mon Nov 05 2018 18:59:11 GMT+0100 (GMT+01:00) +* BUILT: Mon Nov 05 2018 21:52:42 GMT+0100 (GMT+01:00) */; var SVG = (function () { 'use strict'; @@ -216,8 +216,157 @@ var SVG = (function () { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } - var Base = function Base() { - _classCallCheck(this, Base); + var Queue = + /*#__PURE__*/ + function () { + function Queue() { + _classCallCheck(this, Queue); + + this._first = null; + this._last = null; + } + + _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 + + }; + + 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 + + + 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: "first", + value: function first() { + return this._first && this._first.value; + } // Shows us the last item in the list + + }, { + key: "last", + value: function last() { + return this._last && this._last.value; + } // Removes the item that was returned from the push + + }, { + 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; + } + }]); + + 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 node; + }, + 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(); + + 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 + + + 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; + } }; // Parse unit value @@ -282,6 +431,47 @@ var SVG = (function () { dots: dots }); + /* eslint no-new-func: "off" */ + var subClassArray = function () { + try { + // try es6 subclassing + return Function('name', 'baseClass', '_constructor', ['baseClass = baseClass || Array', 'return {', '[name]: class extends baseClass {', 'constructor (...args) {', 'super(...args)', '_constructor && _constructor.apply(this, args)', '}', '}', '}[name]'].join('\n')); + } catch (e) { + // Use es5 approach + return function (name) { + var baseClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Array; + + var _constructor = arguments.length > 2 ? arguments[2] : undefined; + + var Arr = function Arr() { + baseClass.apply(this, arguments); + _constructor && _constructor.apply(this, arguments); + }; + + Arr.prototype = Object.create(baseClass.prototype); + Arr.prototype.constructor = Arr; + return Arr; + }; + } + }(); + + // Default namespaces + var ns = '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'; + + var ns$1 = /*#__PURE__*/Object.freeze({ + ns: ns, + xmlns: xmlns, + xlink: xlink, + svgjs: svgjs + }); + + var Base = function Base() { + _classCallCheck(this, Base); + }; + function isNulledBox(box) { return !box.w && !box.h && !box.x && !box.y; } @@ -447,104 +637,34 @@ var SVG = (function () { return [ox, oy]; } - // Default namespaces - var ns = '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'; - - var ns$1 = /*#__PURE__*/Object.freeze({ - ns: ns, - xmlns: xmlns, - xlink: xlink, - svgjs: svgjs - }); - - function nodeOrNew(name, node) { - return node || makeNode(name); - } // Method for element creation + var elements = {}; + var root = Symbol('root'); + function makeInstance(element) { + if (element instanceof Base) return element; - function makeNode(name) { - // create element - return document.createElementNS(ns, name); - } // Method for extending objects + if (_typeof(element) === 'object') { + return adopt(element); + } - function extend(modules, methods) { - var key, i; - modules = Array.isArray(modules) ? modules : [modules]; + if (element == null) { + return new elements[root](); + } - for (i = modules.length - 1; i >= 0; i--) { - for (key in methods) { - modules[i].prototype[key] = methods[key]; - } + if (typeof element === 'string' && element.charAt(0) !== '<') { + return adopt(document.querySelector(element)); } - } // FIXME: enhanced constructors here - function addFactory(modules, methods) { - extend(modules, methods); - } // Invent new element + var node = makeNode('svg'); + node.innerHTML = element; // We can use firstChild here because we know, + // that the first char is < and thus an element - function invent(config) { - // Create element initializer - var initializer = typeof config.create === 'function' ? config.create : function (node) { - config.inherit.call(this, node || makeNode(config.create)); - }; // Inherit prototype + element = adopt(node.firstChild); + return element; + } // Adopt existing svg elements - if (config.inherit) { - /* eslint new-cap: "off" */ - initializer.prototype = new config.inherit(); - initializer.prototype.constructor = initializer; - } // Extend with methods - - - if (config.extend) { - extend(initializer, config.extend); - } // Attach construct method to parent - - - if (config.construct) { - extend(config.parent || getClass('Container'), config.construct); - } - - return initializer; - } - - var tools = /*#__PURE__*/Object.freeze({ - nodeOrNew: nodeOrNew, - makeNode: makeNode, - extend: extend, - addFactory: addFactory, - invent: invent - }); - - var elements = {}; - var root = Symbol('root'); - function makeInstance(element) { - if (element instanceof Base) return element; - - if (_typeof(element) === 'object') { - return adopt(element); - } - - if (element == null) { - return new elements[root](); - } - - if (typeof element === 'string' && element.charAt(0) !== '<') { - return adopt(document.querySelector(element)); - } - - var node = makeNode('svg'); - node.innerHTML = element; // We can use firstChild here because we know, - // that the first char is < and thus an element - - element = adopt(node.firstChild); - return element; - } // Adopt existing svg elements - - function adopt(node) { - // check for presence of node - if (!node) return null; // make sure a node isn't already adopted + function adopt(node) { + // check for presence of node + if (!node) return null; // make sure a node isn't already adopted if (node.instance instanceof Base) return node.instance; @@ -607,6 +727,196 @@ var SVG = (function () { assignNewId: assignNewId }); + function nodeOrNew(name, node) { + return node || makeNode(name); + } // Method for element creation + + function makeNode(name) { + // create element + return document.createElementNS(ns, name); + } // Method for extending objects + + function extend(modules, methods) { + var key, i; + modules = Array.isArray(modules) ? modules : [modules]; + + for (i = modules.length - 1; i >= 0; i--) { + for (key in methods) { + modules[i].prototype[key] = methods[key]; + } + } + } // FIXME: enhanced constructors here + + function addFactory(modules, methods) { + extend(modules, methods); + } // Invent new element + + function invent(config) { + // Create element initializer + var initializer = typeof config.create === 'function' ? config.create : function (node) { + config.inherit.call(this, node || makeNode(config.create)); + }; // Inherit prototype + + if (config.inherit) { + /* eslint new-cap: "off" */ + initializer.prototype = new config.inherit(); + initializer.prototype.constructor = initializer; + } // Extend with methods + + + if (config.extend) { + extend(initializer, config.extend); + } // Attach construct method to parent + + + if (config.construct) { + extend(config.parent || getClass('Container'), config.construct); + } + + return initializer; + } + + var tools = /*#__PURE__*/Object.freeze({ + nodeOrNew: nodeOrNew, + makeNode: makeNode, + extend: extend, + addFactory: addFactory, + invent: invent + }); + + var SVGArray = subClassArray('SVGArray', Array, function () { + this.init.apply(this, arguments); + }); + extend(SVGArray, { + init: function init() { + this.length = 0; + this.push.apply(this, _toConsumableArray(this.parse.apply(this, arguments))); + }, + toArray: function toArray() { + return Array.prototype.concat.apply([], this); + }, + toString: function toString() { + return this.join(' '); + }, + // Flattens the array if needed + valueOf: function valueOf() { + var ret = []; + ret.push.apply(ret, _toConsumableArray(this)); + return ret; + }, + // Parse whitespace separated string + parse: function parse() { + var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + // If already is an array, no need to parse it + if (array instanceof Array) return array; + return array.trim().split(delimiter).map(parseFloat); + }, + clone: function clone() { + return new this.constructor(this); + }, + toSet: function toSet() { + return new Set(this); + } + }); + + var SVGNumber = + /*#__PURE__*/ + function () { + // Initialize + function SVGNumber() { + _classCallCheck(this, SVGNumber); + + this.init.apply(this, arguments); + } + + _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 + + 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); + + if (unit) { + // make value numeric + this.value = parseFloat(unit[1]); // normalize + + if (unit[5] === '%') { + this.value /= 100; + } else if (unit[5] === 's') { + this.value *= 1000; + } // store unit + + + this.unit = unit[5]; + } + } else { + if (value instanceof SVGNumber) { + this.value = value.valueOf(); + this.unit = value.unit; + } + } + } + }, { + 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: "toArray", + value: function toArray() { + return [this.value, this.unit]; + } + }, { + 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 + + }, { + key: "minus", + value: function minus(number) { + number = new SVGNumber(number); + return new SVGNumber(this - number, this.unit || number.unit); + } // Multiply number + + }, { + key: "times", + value: function times(number) { + number = new SVGNumber(number); + return new SVGNumber(this * number, this.unit || number.unit); + } // Divide number + + }, { + key: "divide", + value: function divide(number) { + number = new SVGNumber(number); + return new SVGNumber(this / number, this.unit || number.unit); + } + }]); + + return SVGNumber; + }(); + var listenerId = 0; function getEvents(node) { @@ -630,11 +940,7 @@ var SVG = (function () { var bag = getEvents(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 + events = Array.isArray(events) ? events : events.split(delimiter); // add id to listener if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++listenerId; @@ -655,16 +961,12 @@ var SVG = (function () { function off(node, events, listener, options) { var bag = getEvents(node); - var n = getEventTarget(node); // we cannot remove an event if its not an svg.js instance - // if (!n.instance) return - // listener can be a function or a number + var n = getEventTarget(node); // listener can be a function or a number if (typeof listener === 'function') { listener = listener._svgjsListenerId; if (!listener) return; - } // pull event handlers from the element - // var bag = n.instance.events - // events can be an array of events or a string or undefined + } // events can be an array of events or a string or undefined events = Array.isArray(events) ? events : (events || '').split(delimiter); @@ -739,17 +1041,67 @@ var SVG = (function () { dispatch: dispatch }); - var EventTarget = - /*#__PURE__*/ - function (_Base) { - _inherits(EventTarget, _Base); - - function EventTarget() { - var _this; - - var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, - _ref$events = _ref.events, - events = _ref$events === void 0 ? {} : _ref$events; + var methods = {}; + function registerMethods(name, m) { + if (Array.isArray(name)) { + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = name[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var _name = _step.value; + registerMethods(_name, m); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return != null) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + return; + } + + if (_typeof(name) === 'object') { + var _arr = Object.entries(name); + + for (var _i = 0; _i < _arr.length; _i++) { + var _arr$_i = _slicedToArray(_arr[_i], 2), + _name2 = _arr$_i[0], + _m = _arr$_i[1]; + + registerMethods(_name2, _m); + } + + return; + } + + methods[name] = Object.assign(methods[name] || {}, m); + } + function getMethodsFor(name) { + return methods[name] || {}; + } + + var EventTarget = + /*#__PURE__*/ + function (_Base) { + _inherits(EventTarget, _Base); + + function EventTarget() { + var _this; + + var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}, + _ref$events = _ref.events, + events = _ref$events === void 0 ? {} : _ref$events; _classCallCheck(this, EventTarget); @@ -821,7 +1173,7 @@ var SVG = (function () { return EventTarget; }(Base); // Add events to elements - var methods = ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'mouseenter', 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'touchend', 'touchcancel'].reduce(function (last, event) { + var methods$1 = ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout', 'mousemove', 'mouseenter', 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'touchend', 'touchcancel'].reduce(function (last, event) { // add event to Element var fn = function fn(f) { if (f === null) { @@ -836,11 +1188,7 @@ var SVG = (function () { last[event] = fn; return last; }, {}); - extend(EventTarget, methods); // registerMethods('EventTarget', { - // on, off, dispatch, fire - // }) - // - // registerConstructor('EventTarget', setup) + registerMethods('Element', methods$1); // Map function function map(array, block) { @@ -1039,209 +1387,6 @@ var SVG = (function () { return Color; }(); - /* eslint no-new-func: "off" */ - var subClassArray = function () { - try { - // try es6 subclassing - return Function('name', 'baseClass', '_constructor', ['baseClass = baseClass || Array', 'return {', '[name]: class extends baseClass {', 'constructor (...args) {', 'super(...args)', '_constructor && _constructor.apply(this, args)', '}', '}', '}[name]'].join('\n')); - } catch (e) { - // Use es5 approach - return function (name) { - var baseClass = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Array; - - var _constructor = arguments.length > 2 ? arguments[2] : undefined; - - var Arr = function Arr() { - baseClass.apply(this, arguments); - _constructor && _constructor.apply(this, arguments); - }; - - Arr.prototype = Object.create(baseClass.prototype); - Arr.prototype.constructor = Arr; - return Arr; - }; - } - }(); - - var SVGArray = subClassArray('SVGArray', Array, function () { - this.init.apply(this, arguments); - }); - extend(SVGArray, { - init: function init() { - // this.splice(0, this.length) - this.length = 0; - this.push.apply(this, _toConsumableArray(this.parse.apply(this, arguments))); - }, - toArray: function toArray() { - // const ret = [] - // ret.push(...this) - // return ret - return Array.prototype.concat.apply([], this); - }, - toString: function toString() { - return this.join(' '); - }, - // Flattens the array if needed - valueOf: function valueOf() { - var ret = []; - ret.push.apply(ret, _toConsumableArray(this)); - return ret; // return this.toArray() - }, - // Parse whitespace separated string - parse: function parse() { - var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; - // array = array.valueOf() - // If already is an array, no need to parse it - if (array instanceof Array) return array; - return array.trim().split(delimiter).map(parseFloat); - }, - clone: function clone() { - return new this.constructor(this); - }, - toSet: function toSet() { - return new Set(this); - } - }); // export default class SVGArray extends BaseArray { - // constructor (...args) { - // super() - // this.init(...args) - // } - // - // init (array, fallback = []) { - // //this.splice(0, this.length) - // this.length = 0 - // this.push(...this.parse(array || fallback)) - // } - // - // toArray () { - // return [].concat(this) - // } - // - // toString () { - // return this.join(' ') - // } - // - // valueOf () { - // return this.toArray() - // } - // - // // Parse whitespace separated string - // parse (array) { - // 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) - // } - // - // clone () { - // return new this.constructor(this) - // } - // - // toSet () { - // return new Set(this) - // } - // } - - var SVGNumber = - /*#__PURE__*/ - function () { - // Initialize - function SVGNumber() { - _classCallCheck(this, SVGNumber); - - this.init.apply(this, arguments); - } - - _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 - - 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); - - if (unit) { - // make value numeric - this.value = parseFloat(unit[1]); // normalize - - if (unit[5] === '%') { - this.value /= 100; - } else if (unit[5] === 's') { - this.value *= 1000; - } // store unit - - - this.unit = unit[5]; - } - } else { - if (value instanceof SVGNumber) { - this.value = value.valueOf(); - this.unit = value.unit; - } - } - } - }, { - 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: "toArray", - value: function toArray() { - return [this.value, this.unit]; - } - }, { - 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 - - }, { - key: "minus", - value: function minus(number) { - number = new SVGNumber(number); - return new SVGNumber(this - number, this.unit || number.unit); - } // Multiply number - - }, { - key: "times", - value: function times(number) { - number = new SVGNumber(number); - return new SVGNumber(this * number, this.unit || number.unit); - } // Divide number - - }, { - key: "divide", - value: function divide(number) { - number = new SVGNumber(number); - return new SVGNumber(this / number, this.unit || number.unit); - } - }]); - - return SVGNumber; - }(); - // Set svg element attribute function attr(attr, val, ns) { @@ -1331,7 +1476,7 @@ var SVG = (function () { } return this; - } // registerMethods('Element', {attr}) + } var Dom = /*#__PURE__*/ @@ -1534,7 +1679,7 @@ var SVG = (function () { }, { key: "replace", value: function replace(element) { - // FIXME: after might not be available here + // FIXME: after() might not be available here this.after(element).remove(); return element; } // Return id on string conversion @@ -1737,21 +1882,7 @@ var SVG = (function () { }]); return Element; - }(Dom); // registerMethods('Element', { - - var Shape = - /*#__PURE__*/ - function (_Element) { - _inherits(Shape, _Element); - - function Shape() { - _classCallCheck(this, Shape); - - return _possibleConstructorReturn(this, _getPrototypeOf(Shape).apply(this, arguments)); - } - - return Shape; - }(Element); + }(Dom); var Container = /*#__PURE__*/ @@ -1790,31 +1921,51 @@ var SVG = (function () { return Container; }(Element); - var HtmlNode = + var Bare = /*#__PURE__*/ - function (_Dom) { - _inherits(HtmlNode, _Dom); + function (_Container) { + _inherits(Bare, _Container); - function HtmlNode(node) { - _classCallCheck(this, HtmlNode); + function Bare(node) { + _classCallCheck(this, Bare); - return _possibleConstructorReturn(this, _getPrototypeOf(HtmlNode).call(this, node, HtmlNode)); + return _possibleConstructorReturn(this, _getPrototypeOf(Bare).call(this, nodeOrNew(node, typeof node === 'string' ? null : node), Bare)); } - return HtmlNode; - }(Dom); - register(HtmlNode); - - var Defs = - /*#__PURE__*/ - function (_Container) { - _inherits(Defs, _Container); + _createClass(Bare, [{ + key: "words", + value: function words(text) { + // remove contents + while (this.node.hasChildNodes()) { + this.node.removeChild(this.node.lastChild); + } // create text node - function Defs(node) { - _classCallCheck(this, Defs); - return _possibleConstructorReturn(this, _getPrototypeOf(Defs).call(this, nodeOrNew('defs', node), Defs)); - } + this.node.appendChild(document.createTextNode(text)); + return this; + } + }]); + + return Bare; + }(Container); + register(Bare); + registerMethods('Container', { + // Create an element that is not described by SVG.js + element: function element(node, inherit) { + return this.put(new Bare(node, inherit)); + } + }); + + var Defs = + /*#__PURE__*/ + function (_Container) { + _inherits(Defs, _Container); + + function Defs(node) { + _classCallCheck(this, Defs); + + return _possibleConstructorReturn(this, _getPrototypeOf(Defs).call(this, nodeOrNew('defs', node), Defs)); + } _createClass(Defs, [{ key: "flatten", @@ -1832,56 +1983,6 @@ var SVG = (function () { }(Container); register(Defs); - var methods$1 = {}; - function registerMethods(name, m) { - if (Array.isArray(name)) { - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = name[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var _name = _step.value; - registerMethods(_name, m); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return != null) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - return; - } - - if (_typeof(name) === 'object') { - var _arr = Object.entries(name); - - for (var _i = 0; _i < _arr.length; _i++) { - var _arr$_i = _slicedToArray(_arr[_i], 2), - _name2 = _arr$_i[0], - _m = _arr$_i[1]; - - registerMethods(_name2, _m); - } - - return; - } - - methods$1[name] = Object.assign(methods$1[name] || {}, m); - } - function getMethodsFor(name) { - return methods$1[name] || {}; - } // FIXME: save memory? - var Doc$1 = /*#__PURE__*/ function (_Container) { @@ -1910,7 +2011,7 @@ var SVG = (function () { key: "doc", value: function doc() { if (this.isRoot()) return this; - return _get(_getPrototypeOf(Doc.prototype), "doc", this).call(this); // return doc.call(this) + return _get(_getPrototypeOf(Doc.prototype), "doc", this).call(this); } // Add namespaces }, { @@ -1937,20 +2038,8 @@ var SVG = (function () { return this.node.parentNode.nodeName === '#document' ? null : adopt(this.node.parentNode); } - return _get(_getPrototypeOf(Doc.prototype), "parent", this).call(this, type); // return parent.call(this, type) - } // Removes the doc from the DOM - // remove() { - // if (!this.isRoot()) { - // return super.remove() - // } - // - // if (this.parent()) { - // this.parent().remove(this) - // } - // - // return this - // } - + return _get(_getPrototypeOf(Doc.prototype), "parent", this).call(this, type); + } }, { key: "clear", value: function clear() { @@ -1975,216 +2064,231 @@ var SVG = (function () { }); register(Doc$1, 'Doc', true); - var G = - /*#__PURE__*/ - function (_Container) { - _inherits(G, _Container); - - function G(node) { - _classCallCheck(this, G); - - return _possibleConstructorReturn(this, _getPrototypeOf(G).call(this, nodeOrNew('g', node), G)); + 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 + }; } - return G; - }(Container); - registerMethods({ - Element: { - // Create a group element - group: function group() { - return this.put(new G()); - } + if (!parser.nodes.svg.node.parentNode) { + var b = document.body || document.documentElement; + parser.nodes.svg.addTo(b); } - }); - register(G); - var Queue = + return parser.nodes; + } + + var Point = /*#__PURE__*/ function () { - function Queue() { - _classCallCheck(this, Queue); - - this._first = null; - this._last = null; - } - - _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 + // Initialize + function Point(x, y, base) { + _classCallCheck(this, Point); - }; + var source; + base = base || { + x: 0, + y: 0 // ensure source as object - 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 + }; + 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 - 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 + _createClass(Point, [{ + key: "clone", + value: function clone() { + return new Point(this); + } // Convert to native SVGPoint }, { - key: "first", - value: function first() { - return this._first && this._first.value; - } // Shows us the last item in the list + key: "native", + value: function native() { + // create new point + var point = parser().svg.node.createSVGPoint(); // update with current values - }, { - key: "last", - value: function last() { - return this._last && this._last.value; - } // Removes the item that was returned from the push + point.x = this.x; + point.y = this.y; + return point; + } // transform point with matrix }, { - 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 + 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 - item.prev = null; - item.next = null; + return new Point(x, y); } }]); - return Queue; + return Point; }(); + registerMethods({ + Element: { + // Get point + point: function point(x, y) { + return new Point(x, y).transform(this.screenCTM().inverse()); + } + } + }); - 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 + var Box = + /*#__PURE__*/ + function () { + function Box() { + _classCallCheck(this, Box); - if (Animator.nextDraw === null) { - Animator.nextDraw = window.requestAnimationFrame(Animator._draw); - } // Return the node so we can remove it easily + this.init.apply(this, arguments); + } + _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... - 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 + fullBox(this); + } // Merge rect box with another, return a new instance - if (Animator.nextDraw === null) { - Animator.nextDraw = window.requestAnimationFrame(Animator._draw); + }, { + 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]; + } + }]); - return node; - }, - 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(); - - 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 + return Box; + }(); + function getBox(cb) { + var box; - if (nextTimeout === lastTimeout) break; - } // Run all of the animation frames + try { + box = cb(this.node); + 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) { + console.warn('Getting a bounding box of this element is not possible'); + } + } - var nextFrame = null; - var lastFrame = Animator.frames.last(); + return box; + } - while (nextFrame !== lastFrame && (nextFrame = Animator.frames.shift())) { - nextFrame.run(); + registerMethods({ + Element: { + // Get bounding box + bbox: function bbox() { + return new Box(getBox.call(this, function (node) { + return node.getBBox(); + })); + }, + rbox: function rbox(el) { + var box = new Box(getBox.call(this, function (node) { + return node.getBoundingClientRect(); + })); + if (el) return box.transform(el.screenCTM().inverse()); + return box.addOffset(); } + }, + viewbox: { + viewbox: function viewbox(x, y, width, height) { + // act as getter + if (x == null) return new Box(this.attr('viewBox')); // act as setter - 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; + return this.attr('viewBox', new Box(x, y, width, height)); + } } - }; + }); - var Bare = + var Shape = /*#__PURE__*/ - function (_Container) { - _inherits(Bare, _Container); + function (_Element) { + _inherits(Shape, _Element); - function Bare(node) { - _classCallCheck(this, Bare); + function Shape() { + _classCallCheck(this, Shape); - return _possibleConstructorReturn(this, _getPrototypeOf(Bare).call(this, nodeOrNew(node, typeof node === 'string' ? null : node), Bare)); + return _possibleConstructorReturn(this, _getPrototypeOf(Shape).apply(this, arguments)); } - _createClass(Bare, [{ - key: "words", - value: function words(text) { - // remove contents - while (this.node.hasChildNodes()) { - this.node.removeChild(this.node.lastChild); - } // create text node - - - this.node.appendChild(document.createTextNode(text)); - return this; - } - }]); - - return Bare; - }(Container); - register(Bare); - registerMethods('Container', { - // Create an element that is not described by SVG.js - element: function element(node, inherit) { - return this.put(new Bare(node, inherit)); - } - }); + return Shape; + }(Element); // FIXME: import this to runner @@ -2288,28 +2392,6 @@ var SVG = (function () { }); register(Circle); - // 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 baseFind(query, parent) { return map((parent || document).querySelectorAll(query), function (node) { return adopt(node); @@ -2343,7 +2425,7 @@ var SVG = (function () { el.unclip(); }); // remove clipPath from parent - return _get(_getPrototypeOf(ClipPath.prototype), "remove", this).call(this); // return remove.call(this) + return _get(_getPrototypeOf(ClipPath.prototype), "remove", this).call(this); } }, { key: "targets", @@ -2380,56 +2462,235 @@ var SVG = (function () { }); register(ClipPath); - var A = - /*#__PURE__*/ - function (_Container) { - _inherits(A, _Container); - - function A(node) { - _classCallCheck(this, A); - - return _possibleConstructorReturn(this, _getPrototypeOf(A).call(this, nodeOrNew('a', node), A)); - } // Link url + /*** + Base Class + ========== + The base stepper class that will be + ***/ + function makeSetterGetter(k, f) { + return function (v) { + if (v == null) return this[v]; + this[k] = v; + if (f) f.call(this); + return this; + }; + } - _createClass(A, [{ - key: "to", - value: function to(url) { - return this.attr('href', url, xlink); - } // Link target attribute + 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); + } - }, { - key: "target", - value: function target(_target) { - return this.attr('target', _target); + _createClass(Stepper, [{ + key: "done", + value: function done() { + return false; } }]); - return A; - }(Container); - registerMethods({ - 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(); + return Stepper; + }(); + /*** + Easing Functions + ================ + ***/ - if (typeof url === 'function') { - url.call(link, link); - } else { - link.to(url); + var Ease = + /*#__PURE__*/ + function (_Stepper) { + _inherits(Ease, _Stepper); + + function Ease(fn) { + var _this; + + _classCallCheck(this, Ease); + + _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 this.parent().put(link).put(this); + return from + (to - from) * this.ease(pos); + } + }]); + + return Ease; + }(Stepper); + /*** + Controller Types + ================ + ***/ + + var Controller = + /*#__PURE__*/ + function (_Stepper2) { + _inherits(Controller, _Stepper2); + + function Controller(fn) { + var _this2; + + _classCallCheck(this, Controller); + + _this2 = _possibleConstructorReturn(this, _getPrototypeOf(Controller).call(this)); + _this2.stepper = fn; + return _this2; + } + + _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; } + }]); + + return Controller; + }(Stepper); + + function recalculate() { + // Apply the default parameters + var duration = (this._duration || 500) / 1000; + var overshoot = this._overshoot || 0; // Calculate the PID natural response + + 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 + + this.d = 2 * zeta * wn; + this.k = wn * wn; + } + + var Spring = + /*#__PURE__*/ + function (_Controller) { + _inherits(Spring, _Controller); + + function Spring(duration, overshoot) { + var _this3; + + _classCallCheck(this, Spring); + + _this3 = _possibleConstructorReturn(this, _getPrototypeOf(Spring).call(this)); + + _this3.duration(duration || 500).overshoot(overshoot || 0); + + return _this3; } + + _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 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 + + c.velocity = velocity + acceleration * dt; // Figure out if we have converged, and if so, pass the value + + c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002; + return c.done ? target : newPosition; + } + }]); + + return Spring; + }(Controller); + extend(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; + + _classCallCheck(this, PID); + + _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); + + return _this4; + } + + _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)); + } + + 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 PID; + }(Controller); + extend(PID, { + windup: makeSetterGetter('windup'), + p: makeSetterGetter('P'), + i: makeSetterGetter('I'), + d: makeSetterGetter('D') }); - register(A); var Ellipse = /*#__PURE__*/ @@ -2513,240 +2774,198 @@ var SVG = (function () { to: to }); - 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 - }; - } - - if (!parser.nodes.svg.node.parentNode) { - var b = document.body || document.documentElement; - parser.nodes.svg.addTo(b); - } - - return parser.nodes; - } - - var Point = + var Gradient = /*#__PURE__*/ - function () { - // Initialize - function Point(x, y, base) { - _classCallCheck(this, Point); - - var source; - base = base || { - x: 0, - y: 0 // ensure source as object + function (_Container) { + _inherits(Gradient, _Container); - }; - 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 + function Gradient(type) { + _classCallCheck(this, Gradient); - }; - this.x = source.x == null ? base.x : source.x; - this.y = source.y == null ? base.y : source.y; - } // Clone point + return _possibleConstructorReturn(this, _getPrototypeOf(Gradient).call(this, nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type), Gradient)); + } // Add a color stop - _createClass(Point, [{ - key: "clone", - value: function clone() { - return new Point(this); - } // Convert to native SVGPoint + _createClass(Gradient, [{ + key: "stop", + value: function stop(offset, color, opacity) { + return this.put(new Stop()).update(offset, color, opacity); + } // Update gradient }, { - key: "native", - value: function native() { - // create new point - var point = parser().svg.node.createSVGPoint(); // update with current values + key: "update", + value: function update(block) { + // remove all stops + this.clear(); // invoke passed block - point.x = this.x; - point.y = this.y; - return point; - } // transform point with matrix + if (typeof block === 'function') { + block.call(this, this); + } + + return this; + } // Return the fill id }, { - 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 + key: "url", + value: function url() { + return 'url(#' + this.id() + ')'; + } // Alias string convertion to fill - return new Point(x, y); + }, { + key: "toString", + value: function toString() { + return this.url(); + } // custom attr to handle transform + + }, { + key: "attr", + value: function attr(a, b, c) { + if (a === 'transform') a = 'gradientTransform'; + return _get(_getPrototypeOf(Gradient.prototype), "attr", this).call(this, a, b, c); + } + }, { + key: "targets", + value: function targets() { + return find('svg [fill*="' + this.id() + '"]'); + } + }, { + key: "bbox", + value: function bbox() { + return new Box(); } }]); - return Point; - }(); + return Gradient; + }(Container); + extend(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); + } + } + }); + register(Gradient); + + var G = + /*#__PURE__*/ + function (_Container) { + _inherits(G, _Container); + + function G(node) { + _classCallCheck(this, G); + + return _possibleConstructorReturn(this, _getPrototypeOf(G).call(this, nodeOrNew('g', node), G)); + } + + return G; + }(Container); registerMethods({ Element: { - // Get point - point: function point(x, y) { - return new Point(x, y).transform(this.screenCTM().inverse()); + // Create a group element + group: function group() { + return this.put(new G()); } } }); + register(G); - var Box = + var HtmlNode = /*#__PURE__*/ - function () { - function Box() { - _classCallCheck(this, Box); + function (_Dom) { + _inherits(HtmlNode, _Dom); - this.init.apply(this, arguments); + function HtmlNode(node) { + _classCallCheck(this, HtmlNode); + + return _possibleConstructorReturn(this, _getPrototypeOf(HtmlNode).call(this, node, HtmlNode)); } - _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... + return HtmlNode; + }(Dom); + register(HtmlNode); - fullBox(this); - } // Merge rect box with another, return a new instance + var A = + /*#__PURE__*/ + function (_Container) { + _inherits(A, _Container); - }, { - 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 A(node) { + _classCallCheck(this, A); - return Box; - }(); + return _possibleConstructorReturn(this, _getPrototypeOf(A).call(this, nodeOrNew('a', node), A)); + } // Link url - function getBox(cb) { - var box; - try { - box = cb(this.node); + _createClass(A, [{ + key: "to", + value: function to(url) { + return this.attr('href', url, xlink); + } // Link target attribute - 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) { - console.warn('Getting a bounding box of this element is not possible'); + }, { + key: "target", + value: function target(_target) { + return this.attr('target', _target); } - } - - return box; - } + }]); + return A; + }(Container); registerMethods({ - Element: { - // Get bounding box - bbox: function bbox() { - return new Box(getBox.call(this, function (node) { - return node.getBBox(); - })); - }, - rbox: function rbox(el) { - var box = new Box(getBox.call(this, function (node) { - return node.getBoundingClientRect(); - })); - if (el) return box.transform(el.screenCTM().inverse()); - return box.addOffset(); + Container: { + // Create a hyperlink element + link: function link(url) { + return this.put(new A()).to(url); } }, - viewbox: { - viewbox: function viewbox(x, y, width, height) { - // act as getter - if (x == null) return new Box(this.attr('viewBox')); // act as setter + Element: { + // Create a hyperlink element + linkTo: function linkTo(url) { + var link = new A(); - return this.attr('viewBox', new Box(x, y, width, height)); + if (typeof url === 'function') { + url.call(link, link); + } else { + link.to(url); + } + + return this.parent().put(link).put(this); } } }); + register(A); - var Gradient = + var Pattern = /*#__PURE__*/ function (_Container) { - _inherits(Gradient, _Container); + _inherits(Pattern, _Container); - function Gradient(type) { - _classCallCheck(this, Gradient); + // Initialize node + function Pattern(node) { + _classCallCheck(this, Pattern); - return _possibleConstructorReturn(this, _getPrototypeOf(Gradient).call(this, nodeOrNew(type + 'Gradient', typeof type === 'string' ? null : type), Gradient)); - } // Add a color stop + return _possibleConstructorReturn(this, _getPrototypeOf(Pattern).call(this, nodeOrNew('pattern', node), Pattern)); + } // Return the fill id - _createClass(Gradient, [{ - key: "stop", - value: function stop(offset, color, opacity) { - return this.put(new Stop()).update(offset, color, opacity); - } // Update gradient + _createClass(Pattern, [{ + key: "url", + value: function url() { + return 'url(#' + this.id() + ')'; + } // Update pattern by rebuilding }, { key: "update", value: function update(block) { - // remove all stops + // remove content this.clear(); // invoke passed block if (typeof block === 'function') { @@ -2754,12 +2973,6 @@ var SVG = (function () { } return this; - } // Return the fill id - - }, { - key: "url", - value: function url() { - return 'url(#' + this.id() + ')'; } // Alias string convertion to fill }, { @@ -2771,8 +2984,8 @@ var SVG = (function () { }, { key: "attr", value: function attr(a, b, c) { - if (a === 'transform') a = 'gradientTransform'; - return _get(_getPrototypeOf(Gradient.prototype), "attr", this).call(this, a, b, c); // return attr.call(this, a, b, c) + if (a === 'transform') a = 'patternTransform'; + return _get(_getPrototypeOf(Pattern.prototype), "attr", this).call(this, a, b, c); } }, { key: "targets", @@ -2786,82 +2999,7 @@ var SVG = (function () { } }]); - return Gradient; - }(Container); - extend(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); - } - } - }); - register(Gradient); - - var Pattern = - /*#__PURE__*/ - function (_Container) { - _inherits(Pattern, _Container); - - // Initialize node - function Pattern(node) { - _classCallCheck(this, Pattern); - - return _possibleConstructorReturn(this, _getPrototypeOf(Pattern).call(this, nodeOrNew('pattern', node), Pattern)); - } // 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 - - }, { - key: "attr", - value: function attr(a, b, c) { - if (a === 'transform') a = 'patternTransform'; - return _get(_getPrototypeOf(Pattern.prototype), "attr", this).call(this, a, b, c); // return attr.call(this, a, b, c) - } - }, { - key: "targets", - value: function targets() { - return find('svg [fill*="' + this.id() + '"]'); - } - }, { - key: "bbox", - value: function bbox() { - return new Box(); - } - }]); - - return Pattern; + return Pattern; }(Container); registerMethods({ Container: { @@ -3056,129 +3194,7 @@ var SVG = (function () { height: maxY - minY }; } - }); // export default class PointArray extends SVGArray { - // constructor (array, fallback = [[0, 0]]) { - // super(array, fallback) - // } - // - // // Convert array to string - // toString () { - // // convert to a poly point string - // for (var i = 0, il = this.length, array = []; i < il; i++) { - // array.push(this[i].join(',')) - // } - // - // return array.join(' ') - // } - // - // // toArray () { - // // return this.reduce(function (prev, curr) { - // // return [].concat.call(prev, curr) - // // }, []) - // // } - // - // // Convert array to line object - // toLine () { - // return { - // x1: this[0][0], - // y1: this[0][1], - // x2: this[1][0], - // y2: this[1][1] - // } - // } - // - // // Get morphed array at given position - // at (pos) { - // // make sure a destination is defined - // if (!this.destination) return this - // - // // generate morphed point string - // for (var i = 0, il = this.length, array = []; i < il; i++) { - // array.push([ - // this[i][0] + (this.destination[i][0] - this[i][0]) * pos, - // this[i][1] + (this.destination[i][1] - this[i][1]) * pos - // ]) - // } - // - // return new PointArray(array) - // } - // - // // Parse point string and flat array - // parse (array) { - // var points = [] - // - // array = array.valueOf() - // - // // if it is an array - // 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. - // 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] ]) - // } - // - // return points - // } - // - // // Move point string - // 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.length - 1; i >= 0; i--) { - // this[i] = [this[i][0] + x, this[i][1] + y] - // } - // } - // - // return this - // } - // - // // Resize poly string - // size (width, height) { - // var i - // var box = this.bbox() - // - // // recalculate position of all points according to new size - // for (i = this.length - 1; i >= 0; i--) { - // if (box.width) this[i][0] = ((this[i][0] - box.x) * width) / box.width + box.x - // if (box.height) this[i][1] = ((this[i][1] - box.y) * height) / box.height + box.y - // } - // - // return this - // } - // - // // Get bounding box of points - // bbox () { - // var maxX = -Infinity - // var maxY = -Infinity - // var minX = Infinity - // var minY = Infinity - // this.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 MorphArray = PointArray; // Move by left top corner over x-axis @@ -3382,7 +3398,7 @@ var SVG = (function () { el.unmask(); }); // remove mask from parent - return _get(_getPrototypeOf(Mask.prototype), "remove", this).call(this); // return remove.call(this) + return _get(_getPrototypeOf(Mask.prototype), "remove", this).call(this); } }, { key: "targets", @@ -3418,3409 +3434,2924 @@ var SVG = (function () { }); register(Mask); - var PathArray = subClassArray('PathArray', SVGArray); - 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(''); + var Matrix = + /*#__PURE__*/ + function () { + function Matrix() { + _classCallCheck(this, Matrix); - 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()); - } + this.init.apply(this, arguments); + } // Initialize - extend(PathArray, { - // Convert array to string - toString: function toString() { - return arrayToString(this); - }, - // Move path string - move: function move(x, y) { - // get bounding box of current situation - var box = this.bbox(); // get relative offset - x -= box.x; - y -= box.y; + _createClass(Matrix, [{ + key: "init", + value: function init(source) { + var base = arrayToMatrix([1, 0, 0, 1, 0, 0]); // ensure source as object - if (!isNaN(x) && !isNaN(y)) { - // move every point - for (var l, i = this.length - 1; i >= 0; i--) { - l = this[i][0]; + source = source instanceof 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 - 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; + 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 - if (l === 'C') { - this[i][5] += x; - this[i][6] += y; - } - } else if (l === 'A') { - this[i][6] += x; - this[i][7] += y; - } - } - } + }, { + key: "clone", + value: function clone() { + return new Matrix(this); + } // Transform a matrix into another matrix by manipulating the space - return this; - }, - // Resize path string - size: 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 + }, { + 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 - 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; + var t = Matrix.formatTransforms(o); + var current = this; - 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 + var _transform = new Point(t.ox, t.oy).transform(current), + ox = _transform.x, + oy = _transform.y; // Construct the resulting 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; - } - } - return this; - }, - // Test if the passed path array use the same path data commands as this path array - equalCommands: function equalCommands(pathArray) { - var i, il, equalCommands; - pathArray = new PathArray(pathArray); - equalCommands = this.length === pathArray.length; + 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 - for (i = 0, il = this.length; equalCommands && i < il; i++) { - equalCommands = this[i][0] === pathArray[i][0]; - } - - return equalCommands; - }, - // Make path array morphable - morph: function morph(pathArray) { - pathArray = new PathArray(pathArray); - - if (this.equalCommands(pathArray)) { - this.destination = pathArray; - } else { - this.destination = null; - } - - return this; - }, - // Get morphed path array at given position - at: 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 + if (isFinite(t.px) || isFinite(t.py)) { + var origin = new Point(ox, oy).transform(transformer); // TODO: Replace t.px with isFinite(t.px) - for (i = 0, il = sourceArray.length; i < il; i++) { - array[i] = [sourceArray[i][0]]; + 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 - 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 + transformer.translateO(t.tx, t.ty); + return transformer; + } // Applies a matrix defined by its affine parameters - 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 + }, { + key: "compose", + value: function compose(o) { + if (o.origin) { + o.originX = o.origin[0]; + o.originY = o.origin[1]; + } // Get the parameters - pathArray.value = array; - return pathArray; - }, - // Absolutize and parse path to array - parse: function parse() { - var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [['M', 0, 0]]; - // if it's already a patharray, no need to parse it - if (array instanceof PathArray) return array; // prepare for parsing + 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 - var s; - var paramCnt = { - 'M': 2, - 'L': 2, - 'H': 1, - 'V': 1, - 'C': 6, - 'S': 4, - 'Q': 4, - 'T': 2, - 'A': 7, - 'Z': 0 - }; + 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 - 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' ...] + }, { + 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 + 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 - var result = []; - var p = new Point(); - var p0 = new Point(); - var index = 0; - var len = array.length; + 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 - 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'; - } + var lam = (a * c + b * d) / determinant; + var sy = c * sx / (lam * a - b) || d * sx / (lam * b + a); // Use the translations - result.push(pathHandlers[s].call(null, array.slice(index, index = index + paramCnt[s.toUpperCase()]).map(parseFloat), p, p0)); - } while (len > index); + 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 result; - }, - // Get bounding box of path - bbox: function bbox() { - parser().path.setAttribute('d', this.toString()); - return parser.nodes.path.getBBox(); - } - }); // export default class PathArray extends SVGArray { - // constructor (array, fallback = [['M', 0, 0]]) { - // super(array, fallback) - // } - // - // // Convert array to string - // toString () { - // return arrayToString(this) - // } - // - // toArray () { - // return this.reduce(function (prev, curr) { - // return [].concat.call(prev, curr) - // }, []) - // } - // - // // Move path string - // move (x, y) { - // // get bounding box of current situation - // var box = this.bbox() - // - // // get relative offset - // x -= box.x - // y -= box.y - // - // if (!isNaN(x) && !isNaN(y)) { - // // move every point - // for (var l, i = this.length - 1; i >= 0; i--) { - // l = this[i][0] - // - // 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 - // - // 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 - // 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 - // - // 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[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 this - // } - // - // // Test if the passed path array use the same path data commands as this path array - // equalCommands (pathArray) { - // var i, il, equalCommands - // - // pathArray = new PathArray(pathArray) - // - // equalCommands = this.length === pathArray.value.length - // for (i = 0, il = this.length; equalCommands && i < il; i++) { - // equalCommands = this[i][0] === pathArray.value[i][0] - // } - // - // return equalCommands - // } - // - // // Make path array morphable - // morph (pathArray) { - // pathArray = new PathArray(pathArray) - // - // if (this.equalCommands(pathArray)) { - // this.destination = pathArray - // } else { - // this.destination = null - // } - // - // return this - // } - // - // // Get morphed path array at given position - // 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 - // 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 - // 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 - // 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 - // bbox () { - // parser().path.setAttribute('d', this.toString()) - // return parser.nodes.path.getBBox() - // } - // } + 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 - var Path = - /*#__PURE__*/ - function (_Shape) { - _inherits(Path, _Shape); + }, { + 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 - // Initialize node - function Path(node) { - _classCallCheck(this, Path); + }, { + 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 - return _possibleConstructorReturn(this, _getPrototypeOf(Path).call(this, nodeOrNew('path', node), Path)); - } // Get array + 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 - _createClass(Path, [{ - key: "array", - value: function array() { - return this._array || (this._array = new PathArray(this.attr('d'))); - } // Plot new path + 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: "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: "inverse", + value: function inverse() { + return this.clone().inverseO(); + } // Translate matrix }, { - key: "clear", - value: function clear() { - delete this._array; + 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; - } // Move by left top corner + } // Scale matrix }, { - 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: "scale", + value: function scale(x, y, cx, cy) { + var _this$clone; + return (_this$clone = this.clone()).scaleO.apply(_this$clone, arguments); + } }, { - 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: "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: "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 + // Support uniform scaling + if (arguments.length === 3) { + cy = cx; + cx = y; + y = x; + } - }, { - key: "size", - value: function size(width, height) { - var p = proportionalSize(this, width, height); - return this.attr('d', this.array().size(p.width, p.height)); - } // Set width of element + 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: "width", - value: function width(_width) { - return _width == null ? this.bbox().width : this.size(_width, this.bbox().height); - } // Set height of element + 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: "height", - value: function height(_height) { - return _height == null ? this.bbox().height : this.size(this.bbox().width, _height); + key: "flip", + value: function flip(axis, around) { + return this.clone().flipO(axis, around); } }, { - key: "targets", - value: function targets() { - return baseFind('svg textpath [href*="' + this.id() + '"]'); + 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 + + }, { + 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 - return Path; - }(Shape); // Define morphable array - Path.prototype.MorphArray = PathArray; // Add parent method + }, { + key: "skew", + value: function skew(x, y, cx, cy) { + var _this$clone2; - 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()); + return (_this$clone2 = this.clone()).skewO.apply(_this$clone2, arguments); } - } - }); - register(Path); + }, { + 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; - // Add polygon-specific functions + // support uniformal skew + if (arguments.length === 3) { + cy = cx; + cx = y; + y = x; + } // Convert degrees to radians - function array() { - return this._array || (this._array = new PointArray(this.attr('points'))); - } // Plot new path - function plot(p) { - return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new PointArray(p)); - } // Clear array cache + 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 - function clear() { - delete this._array; - return this; - } // Move by left top corner + }, { + 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 - function move(x, y) { - return this.attr('points', this.array().move(x, y)); - } // Set element size to given width and height + }, { + 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 - function size$1(width, height) { - var p = proportionalSize(this, width, height); - return this.attr('points', this.array().size(p.width, p.height)); - } + }, { + 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 - var poly = /*#__PURE__*/Object.freeze({ - array: array, - plot: plot, - clear: clear, - move: move, - size: size$1 - }); + }, { + key: "native", + value: function native() { + // create new matrix + var matrix = parser().svg.node.createSVGMatrix(); // update with current values - var Polygon = - /*#__PURE__*/ - function (_Shape) { - _inherits(Polygon, _Shape); + for (var i = abcdef.length - 1; i >= 0; i--) { + matrix[abcdef[i]] = this[abcdef[i]]; + } - // Initialize node - function Polygon(node) { - _classCallCheck(this, Polygon); + return matrix; + } // Check if two matrices are equal - return _possibleConstructorReturn(this, _getPrototypeOf(Polygon).call(this, nodeOrNew('polygon', node), Polygon)); - } + }, { + 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 Polygon; - }(Shape); - registerMethods({ - Container: { - // 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()); + }, { + key: "toString", + value: function toString() { + return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'; } - } - }); - extend(Polygon, pointed); - extend(Polygon, poly); - register(Polygon); - - var Polyline = - /*#__PURE__*/ - function (_Shape) { - _inherits(Polyline, _Shape); - - // Initialize node - function Polyline(node) { - _classCallCheck(this, Polyline); - - return _possibleConstructorReturn(this, _getPrototypeOf(Polyline).call(this, nodeOrNew('polyline', node), Polyline)); - } - - return Polyline; - }(Shape); - registerMethods({ - Container: { - // 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()); + }, { + key: "toArray", + value: function toArray() { + return [this.a, this.b, this.c, this.d, this.e, this.f]; } - } - }); - extend(Polyline, pointed); - extend(Polyline, poly); - register(Polyline); - - var Rect = - /*#__PURE__*/ - function (_Shape) { - _inherits(Rect, _Shape); - - // Initialize node - function Rect(node) { - _classCallCheck(this, Rect); - - return _possibleConstructorReturn(this, _getPrototypeOf(Rect).call(this, nodeOrNew('rect', node), Rect)); - } // FIXME: unify with circle - // Radius x value + }, { + 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 - _createClass(Rect, [{ - key: "rx", - value: function rx(_rx) { - return this.attr('rx', _rx); - } // Radius y value + 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: "ry", - value: function ry(_ry) { - return this.attr('ry', _ry); + 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 Rect; - }(Shape); + return Matrix; + }(); registerMethods({ - Container: { - // Create a rect element - rect: function rect(width, height) { - return this.put(new Rect()).size(width, height); + 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 + This is needed because FF does not return the transformation matrix + for the inner coordinate system when getScreenCTM() is called on nested svgs. + However all other Browsers do that */ + if (typeof this.isRoot === 'function' && !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()); } } }); - register(Rect); - - var _Symbol = - /*#__PURE__*/ - function (_Container) { - _inherits(_Symbol, _Container); - - // Initialize node - function _Symbol(node) { - _classCallCheck(this, _Symbol); - return _possibleConstructorReturn(this, _getPrototypeOf(_Symbol).call(this, nodeOrNew('symbol', node), _Symbol)); + var PathArray = subClassArray('PathArray', SVGArray); + 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 _Symbol; - }(Container); - registerMethods({ - Container: { - symbol: function symbol() { - return this.put(new _Symbol()); - } - } - }); - register(_Symbol); + 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()); + } - // Create plain text node - function plain(text) { - // clear if build mode is disabled - if (this._build === false) { - this.clear(); - } // create text node + extend(PathArray, { + // Convert array to string + toString: function toString() { + return arrayToString(this); + }, + // Move path string + move: function move(x, y) { + // get bounding box of current situation + var box = this.bbox(); // get relative offset + x -= box.x; + y -= box.y; - this.node.appendChild(document.createTextNode(text)); - return this; - } // FIXME: Does this also work for textpath? - // Get length of text element + if (!isNaN(x) && !isNaN(y)) { + // move every point + for (var l, i = this.length - 1; i >= 0; i--) { + l = this[i][0]; - function length() { - return this.node.getComputedTextLength(); - } + 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; - var textable = /*#__PURE__*/Object.freeze({ - plain: plain, - length: length - }); + if (l === 'C') { + this[i][5] += x; + this[i][6] += y; + } + } else if (l === 'A') { + this[i][6] += x; + this[i][7] += y; + } + } + } - var Text = - /*#__PURE__*/ - function (_Shape) { - _inherits(Text, _Shape); + return this; + }, + // Resize path string + size: 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 - // Initialize node - function Text(node) { - var _this; + for (i = this.length - 1; i >= 0; i--) { + l = this[i][0]; - _classCallCheck(this, Text); + 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; - _this = _possibleConstructorReturn(this, _getPrototypeOf(Text).call(this, nodeOrNew('text', node), Text)); - _this.dom.leading = new SVGNumber(1.3); // store leading value for rebuilding + 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._rebuild = true; // enable automatic updating of dy values + 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; + } + } - _this._build = false; // disable build mode for adding multiple lines - // set default font + return this; + }, + // Test if the passed path array use the same path data commands as this path array + equalCommands: function equalCommands(pathArray) { + var i, il, equalCommands; + pathArray = new PathArray(pathArray); + equalCommands = this.length === pathArray.length; - _this.attr('font-family', attrs['font-family']); + for (i = 0, il = this.length; equalCommands && i < il; i++) { + equalCommands = this[i][0] === pathArray[i][0]; + } - return _this; - } // Move over x-axis + return equalCommands; + }, + // Make path array morphable + morph: function morph(pathArray) { + pathArray = new PathArray(pathArray); + if (this.equalCommands(pathArray)) { + this.destination = pathArray; + } else { + this.destination = null; + } - _createClass(Text, [{ - key: "x", - value: function x(_x) { - // act as getter - if (_x == null) { - return this.attr('x'); - } + return this; + }, + // Get morphed path array at given position + at: 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 - return this.attr('x', _x); - } // Move over y-axis + for (i = 0, il = sourceArray.length; i < il; i++) { + array[i] = [sourceArray[i][0]]; - }, { - key: "y", - value: function y(_y) { - var oy = this.attr('y'); - var o = typeof oy === 'number' ? oy - this.bbox().y : 0; // act as getter + 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 - if (_y == null) { - return typeof oy === 'number' ? oy - o : oy; - } - return this.attr('y', typeof _y === 'number' ? _y + o : _y); - } // Move center over x-axis + 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 - }, { - 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 + pathArray.value = array; + return pathArray; + }, + // Absolutize and parse path to array + parse: function parse() { + var array = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [['M', 0, 0]]; + // if it's already a patharray, no need to parse it + if (array instanceof PathArray) return array; // prepare for parsing - }, { - key: "text", - value: function text(_text) { - // act as getter - if (_text === undefined) { - // FIXME use children() or each() - var children = this.node.childNodes; - var firstLine = 0; - _text = ''; + var s; + var paramCnt = { + 'M': 2, + 'L': 2, + 'H': 1, + 'V': 1, + 'C': 6, + 'S': 4, + 'Q': 4, + 'T': 2, + 'A': 7, + 'Z': 0 + }; - 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 + 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' ...] - if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) { - _text += '\n'; - } // add content of this node + 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'; + } - _text += children[i].textContent; - } + result.push(pathHandlers[s].call(null, array.slice(index, index = index + paramCnt[s.toUpperCase()]).map(parseFloat), p, p0)); + } while (len > index); - return _text; - } // remove existing content + return result; + }, + // Get bounding box of path + bbox: function bbox() { + parser().path.setAttribute('d', this.toString()); + return parser.nodes.path.getBBox(); + } + }); + var Morphable = + /*#__PURE__*/ + function () { + function Morphable(stepper) { + _classCallCheck(this, Morphable); - this.clear().build(true); + // 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; + } - 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 - - for (var j = 0, jl = _text.length; j < jl; j++) { - this.tspan(_text[j]).newLine(); - } - } // disable build mode and rebuild lines - - - return this.build(false).rebuild(); - } // Set / get leading + _createClass(Morphable, [{ + key: "from", + value: function from(val) { + if (val == null) { + return this._from; + } + this._from = this._set(val); + return this; + } }, { - 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: "to", + value: function to(val) { + if (val == null) { + return this._to; + } + this._to = this._set(val); + return this; + } }, { - key: "rebuild", - value: function rebuild(_rebuild) { - // store new rebuild flag if given - if (typeof _rebuild === 'boolean') { - this._rebuild = _rebuild; - } // define position of all lines + key: "type", + value: function type(_type) { + // getter + if (_type == null) { + return this._type; + } // setter - 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')); + this._type = _type; + return this; + } + }, { + key: "_set", + value: function _set$$1(value) { + if (!this._type) { + var type = _typeof(value); - if (this.text() === '\n') { - blankLineOffset += dy; - } else { - this.attr('dy', dy + blankLineOffset); - blankLineOffset = 0; - } + if (type === 'number') { + this.type(SVGNumber); + } else if (type === 'string') { + if (Color.isColor(value)) { + this.type(Color); + } else if (delimiter.test(value)) { + this.type(pathLetters.test(value) ? PathArray : SVGArray); + } else if (numberAndUnit.test(value)) { + this.type(SVGNumber); + } else { + this.type(NonMorphable); } - }); - this.fire('rebuild'); + } 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(ObjectBag); + } else { + this.type(NonMorphable); + } } - return this; - } // Enable / disable build mode - + 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: "build", - value: function build(_build) { - this._build = !!_build; + key: "stepper", + value: function stepper(_stepper) { + if (_stepper == null) return this._stepper; + this._stepper = _stepper; 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; + key: "done", + value: function done() { + var complete = this._context.map(this._stepper.done).reduce(function (last, curr) { + return last && curr; + }, true); + + return complete; } - }]); + }, { + key: "at", + value: function at(pos) { + var _this = this; - return Text; - }(Shape); - extend(Text, textable); - registerMethods({ - Container: { - // Create text element - text: function text(_text2) { - return this.put(new Text()).text(_text2); - }, - // Create plain text element - plain: function plain$$1(text) { - return this.put(new Text()).plain(text); + return this._morphObj.fromArray(this._from.map(function (i, index) { + return _this._stepper.step(i, _this._to[index], pos, _this._context[index], _this._context); + })); } - } - }); - register(Text); + }]); - var TextPath = + return Morphable; + }(); + var NonMorphable = /*#__PURE__*/ - function (_Text) { - _inherits(TextPath, _Text); - - // Initialize node - function TextPath(node) { - _classCallCheck(this, TextPath); - - return _possibleConstructorReturn(this, _getPrototypeOf(TextPath).call(this, nodeOrNew('textPath', node), TextPath)); - } // return the array of the path track element - + function () { + function NonMorphable() { + _classCallCheck(this, NonMorphable); - _createClass(TextPath, [{ - key: "array", - value: function array() { - var track = this.track(); - return track ? track.array() : null; - } // Plot path if any + this.init.apply(this, arguments); + } + _createClass(NonMorphable, [{ + key: "init", + value: function init(val) { + val = Array.isArray(val) ? val[0] : val; + this.value = val; + } }, { - key: "plot", - value: function plot(d) { - var track = this.track(); - var pathArray = null; - - if (track) { - pathArray = track.plot(d); - } - - return d == null ? pathArray : this; - } // Get the path element - + key: "valueOf", + value: function valueOf() { + return this.value; + } }, { - key: "track", - value: function track() { - return this.reference('href'); + key: "toArray", + value: function toArray() { + return [this.value]; } }]); - return TextPath; - }(Text); - 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 - - if (!(track instanceof Path)) { - // create path element - track = this.doc().defs().path(track); - } // link textPath to path and add content + return NonMorphable; + }(); + var TransformBag = + /*#__PURE__*/ + function () { + function TransformBag() { + _classCallCheck(this, TransformBag); + this.init.apply(this, arguments); + } - path.attr('href', '#' + track, xlink); // add textPath element as child node and return textPath + _createClass(TransformBag, [{ + 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] + }; + } - return this.put(path); - }, - // FIXME: make this plural? - // Get the textPath children - textPath: function textPath() { - return this.find('textPath'); + Object.assign(this, TransformBag.defaults, obj); } - }, - Path: { - // creates a textPath from this path - text: function text(_text) { - if (_text instanceof Text) { - var txt = _text.text(); + }, { + 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]; + } + }]); - return _text.clear().path(this).text(txt); + return TransformBag; + }(); + TransformBag.defaults = { + scaleX: 1, + scaleY: 1, + shear: 0, + rotate: 0, + translateX: 0, + translateY: 0, + originX: 0, + originY: 0 + }; + var ObjectBag = + /*#__PURE__*/ + function () { + function ObjectBag() { + _classCallCheck(this, ObjectBag); + + this.init.apply(this, arguments); + } + + _createClass(ObjectBag, [{ + key: "init", + value: function init(objOrArr) { + this.values = []; + + if (Array.isArray(objOrArr)) { + this.values = objOrArr; + return; } - return this.parent().put(new Text()).path(this).text(_text); - } // FIXME: Maybe add `targets` to get all textPaths associated with this path + 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; - } - }); - TextPath.prototype.MorphArray = PathArray; - register(TextPath); + for (var i = 0, len = arr.length; i < len; i += 2) { + obj[arr[i]] = arr[i + 1]; + } - var Tspan = + return obj; + } + }, { + key: "toArray", + value: function toArray() { + return this.values; + } + }]); + + return ObjectBag; + }(); + var morphableTypes = [NonMorphable, TransformBag, ObjectBag]; + function registerMorphableType() { + var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; + morphableTypes.push.apply(morphableTypes, _toConsumableArray([].concat(type))); + } + function makeMorphable() { + extend(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; + } + }); + } + + var Path = /*#__PURE__*/ - function (_Text) { - _inherits(Tspan, _Text); + function (_Shape) { + _inherits(Path, _Shape); // Initialize node - function Tspan(node) { - _classCallCheck(this, Tspan); + function Path(node) { + _classCallCheck(this, Path); - return _possibleConstructorReturn(this, _getPrototypeOf(Tspan).call(this, nodeOrNew('tspan', node), Tspan)); - } // Set text content + return _possibleConstructorReturn(this, _getPrototypeOf(Path).call(this, nodeOrNew('path', node), Path)); + } // Get array - _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(Path, [{ + key: "array", + value: function array() { + return this._array || (this._array = new PathArray(this.attr('d'))); + } // Plot new path }, { - key: "dx", - value: function dx(_dx) { - return this.attr('dx', _dx); - } // Shortcut dy + 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: "dy", - value: function dy(_dy) { - return this.attr('dy', _dy); - } // Create new line + key: "clear", + value: function clear() { + delete this._array; + return this; + } // Move by left top corner }, { - key: "newLine", - value: function newLine() { - // fetch text parent - var t = this.parent(Text); // mark new line - - this.dom.newLined = true; // apply new position + 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 this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x()); - } - }]); + }, { + 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 - return Tspan; - }(Text); - extend(Tspan, textable); - registerMethods({ - Tspan: { - tspan: function tspan(text) { - var tspan = new Tspan(); // clear if build mode is disabled + }, { + 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 - if (!this._build) { - this.clear(); - } // add new tspan + }, { + key: "size", + value: function size(width, height) { + var p = proportionalSize(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 - this.node.appendChild(tspan.node); - return tspan.text(text); + }, { + key: "height", + value: function height(_height) { + return _height == null ? this.bbox().height : this.size(this.bbox().width, _height); } - } - }); - register(Tspan); - - var Use = - /*#__PURE__*/ - function (_Shape) { - _inherits(Use, _Shape); - - function Use(node) { - _classCallCheck(this, Use); - - 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); + }, { + key: "targets", + value: function targets() { + return baseFind('svg textpath [href*="' + this.id() + '"]'); } }]); - return Use; - }(Shape); + return Path; + }(Shape); // Define morphable array + Path.prototype.MorphArray = PathArray; // Add parent method + registerMethods({ Container: { - // Create a use element - use: function use(element, file) { - return this.put(new Use()).element(element, file); + // 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(Use); - - var Matrix = - /*#__PURE__*/ - function () { - function Matrix() { - _classCallCheck(this, Matrix); + register(Path); - this.init.apply(this, arguments); - } // Initialize + // Add polygon-specific functions + function array() { + return this._array || (this._array = new PointArray(this.attr('points'))); + } // Plot new path - _createClass(Matrix, [{ - key: "init", - value: function init(source) { - var base = arrayToMatrix([1, 0, 0, 1, 0, 0]); // ensure source as object + function plot(p) { + return p == null ? this.array() : this.clear().attr('points', typeof p === 'string' ? p : this._array = new PointArray(p)); + } // Clear array cache - source = source instanceof 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 + function clear() { + delete this._array; + return this; + } // Move by left top corner - 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 + function move(x, y) { + return this.attr('points', this.array().move(x, y)); + } // Set element size to given width and height - }, { - key: "clone", - value: function clone() { - return new Matrix(this); - } // Transform a matrix into another matrix by manipulating the space + function size$1(width, height) { + var p = proportionalSize(this, width, height); + return this.attr('points', this.array().size(p.width, p.height)); + } - }, { - 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 poly = /*#__PURE__*/Object.freeze({ + array: array, + plot: plot, + clear: clear, + move: move, + size: size$1 + }); + var Polygon = + /*#__PURE__*/ + function (_Shape) { + _inherits(Polygon, _Shape); - var t = Matrix.formatTransforms(o); - var current = this; + // Initialize node + function Polygon(node) { + _classCallCheck(this, Polygon); - var _transform = new Point(t.ox, t.oy).transform(current), - ox = _transform.x, - oy = _transform.y; // Construct the resulting matrix + return _possibleConstructorReturn(this, _getPrototypeOf(Polygon).call(this, nodeOrNew('polygon', node), Polygon)); + } + return Polygon; + }(Shape); + registerMethods({ + Container: { + // 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()); + } + } + }); + extend(Polygon, pointed); + extend(Polygon, poly); + register(Polygon); - 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 + var Polyline = + /*#__PURE__*/ + function (_Shape) { + _inherits(Polyline, _Shape); - if (isFinite(t.px) || isFinite(t.py)) { - var origin = new Point(ox, oy).transform(transformer); // TODO: Replace t.px with isFinite(t.px) + // Initialize node + function Polyline(node) { + _classCallCheck(this, Polyline); - 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 + return _possibleConstructorReturn(this, _getPrototypeOf(Polyline).call(this, nodeOrNew('polyline', node), Polyline)); + } + return Polyline; + }(Shape); + registerMethods({ + Container: { + // 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()); + } + } + }); + extend(Polyline, pointed); + extend(Polyline, poly); + register(Polyline); - transformer.translateO(t.tx, t.ty); - return transformer; - } // Applies a matrix defined by its affine parameters + var Rect = + /*#__PURE__*/ + function (_Shape) { + _inherits(Rect, _Shape); - }, { - key: "compose", - value: function compose(o) { - if (o.origin) { - o.originX = o.origin[0]; - o.originY = o.origin[1]; - } // Get the parameters + // Initialize node + function Rect(node) { + _classCallCheck(this, Rect); + return _possibleConstructorReturn(this, _getPrototypeOf(Rect).call(this, nodeOrNew('rect', node), Rect)); + } // FIXME: unify with circle + // Radius x value - 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 - 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(Rect, [{ + key: "rx", + value: function rx(_rx) { + return this.attr('rx', _rx); + } // Radius y value }, { - 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 - - 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: "ry", + value: function ry(_ry) { + return this.attr('ry', _ry); + } + }]); - 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 + return Rect; + }(Shape); + registerMethods({ + Container: { + // Create a rect element + rect: function rect(width, height) { + return this.put(new Rect()).size(width, height); + } + } + }); + register(Rect); - var lam = (a * c + b * d) / determinant; - var sy = c * sx / (lam * a - b) || d * sx / (lam * b + a); // Use the translations + var time = window.performance || Date; - 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 + 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 + }; + }; - 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 + var Timeline = + /*#__PURE__*/ + function () { + // Construct a new timeline on the given element + function Timeline() { + _classCallCheck(this, Timeline); - }, { - 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 + this._timeSource = function () { + return time.now(); + }; - }, { - 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 + this._dispatcher = document.createElement('div'); // Store the timing variables - var det = a * d - b * c; - if (!det) throw new Error('Cannot invert ' + this); // Calculate the top 2x2 matrix + this._startTime = 0; + this._speed = 1.0; // Play control variables control how the animation proceeds - var na = d / det; - var nb = -b / det; - var nc = -c / det; - var nd = a / det; // Apply the inverted matrix to the top right + this._reverse = false; + this._persist = 0; // Keep track of the running animations and their starting parameters - var ne = -(na * e + nc * f); - var nf = -(nb * e + nd * f); // Construct the inverted matrix + this._nextFrame = null; + this._paused = false; + this._runners = []; + this._order = []; + this._time = 0; + this._lastSourceTime = 0; + this._lastStepTime = 0; + } - 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 - - }, { - key: "translate", - value: function translate(x, y) { - return this.clone().translateO(x, y); + _createClass(Timeline, [{ + key: "getEventTarget", + value: function getEventTarget() { + return this._dispatcher; } - }, { - key: "translateO", - value: function translateO(x, y) { - this.e += x || 0; - this.f += y || 0; - return this; - } // Scale matrix + /** + * + */ + // schedules a runner on the timeline }, { - key: "scale", - value: function scale(x, y, cx, cy) { - var _this$clone; + 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; + }); + } - 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; + if (!this.active()) { + this._step(); - // Support uniform scaling - if (arguments.length === 3) { - cy = cx; - cx = y; - y = x; - } + 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 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: "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 + var absoluteStartTime = 0; + delay = delay || 0; // Work out when to start the animation - }, { - 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 (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]; - }, { - 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 + if (runnerInfo) { + absoluteStartTime = runnerInfo.start + delay; + delay = 0; + } + } else { + throw new Error('Invalid value for the "when" parameter'); + } // Manage runner - }, { - 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; + runner.unschedule(); + runner.timeline(this); + runner.time(-delay); // Save startTime for next runner - // support uniformal skew - if (arguments.length === 3) { - cy = cx; - cx = y; - y = x; - } // Convert degrees to radians + this._startTime = absoluteStartTime + runner.duration() + delay; // Save runnerInfo + this._runners[runner.id] = { + persist: this.persist(), + runner: runner, + start: absoluteStartTime // Save order and continue - 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 + }; - }, { - 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 + this._order.push(runner.id); - }, { - 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 + this._continue(); - }, { - 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 + return this; + } // Remove the runner from this timeline }, { - key: "native", - value: function native() { - // create new matrix - var matrix = parser().svg.node.createSVGMatrix(); // update with current values + key: "unschedule", + value: function unschedule(runner) { + var index = this._order.indexOf(runner.id); - for (var i = abcdef.length - 1; i >= 0; i--) { - matrix[abcdef[i]] = this[abcdef[i]]; - } + if (index < 0) return this; + delete this._runners[runner.id]; - return matrix; - } // Check if two matrices are equal + this._order.splice(index, 1); + runner.timeline(null); + return 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 - + key: "play", + value: function play() { + // Now make sure we are not paused and continue the animation + this._paused = false; + return this._continue(); + } }, { - key: "toString", - value: function toString() { - return 'matrix(' + this.a + ',' + this.b + ',' + this.c + ',' + this.d + ',' + this.e + ',' + this.f + ')'; + key: "pause", + value: function pause() { + // Cancel the next animation frame and pause + this._nextFrame = null; + this._paused = true; + return this; } }, { - key: "toArray", - value: function toArray() { - return [this.a, this.b, this.c, this.d, this.e, this.f]; + key: "stop", + value: function stop() { + // Cancel the next animation frame and go to start + this.seek(-this._time); + return this.pause(); } }, { - 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: "finish", + value: function finish() { + this.seek(Infinity); + return this.pause(); + } }, { - 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; + key: "speed", + value: function speed(_speed) { + if (_speed == null) return this._speed; + this._speed = _speed; + return this; } - }]); - - return Matrix; - }(); - registerMethods({ - 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 - This is needed because FF does not return the transformation matrix - for the inner coordinate system when getScreenCTM() is called on nested svgs. - However all other Browsers do that */ - if (typeof this.isRoot === 'function' && !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()); + }, { + 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); } - } - }); - - /*** - Base Class - ========== - The base stepper class that will be - ***/ - - 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); - } - - _createClass(Stepper, [{ - key: "done", - value: function done() { - return false; + }, { + key: "seek", + value: function seek(dt) { + this._time += dt; + return this._continue(); } - }]); - - return Stepper; - }(); - /*** - Easing Functions - ================ - ***/ - - var Ease = - /*#__PURE__*/ - function (_Stepper) { - _inherits(Ease, _Stepper); - - function Ease(fn) { - var _this; - - _classCallCheck(this, Ease); - - _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); + }, { + key: "time", + value: function time(_time) { + if (_time == null) return this._time; + this._time = _time; + return this; } - }]); - - return Ease; - }(Stepper); - /*** - Controller Types - ================ - ***/ - - var Controller = - /*#__PURE__*/ - function (_Stepper2) { - _inherits(Controller, _Stepper2); - - function Controller(fn) { - var _this2; - - _classCallCheck(this, Controller); - - _this2 = _possibleConstructorReturn(this, _getPrototypeOf(Controller).call(this)); - _this2.stepper = fn; - return _this2; - } - - _createClass(Controller, [{ - key: "step", - value: function step(current, target, dt, c) { - return this.stepper(current, target, dt, c); + }, { + key: "persist", + value: function persist(dtOrForever) { + if (dtOrForever == null) return this._persist; + this._persist = dtOrForever; + return this; } }, { - key: "done", - value: function done(c) { - return c.done; + 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 - return Controller; - }(Stepper); + var time = this._timeSource(); - function recalculate() { - // Apply the default parameters - var duration = (this._duration || 500) / 1000; - var overshoot = this._overshoot || 0; // Calculate the PID natural response + var dtSource = time - this._lastSourceTime; + var dtTime = this._speed * dtSource + (this._time - this._lastStepTime); + this._lastSourceTime = time; // Update the time - 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 + this._time += dtTime; + this._lastStepTime = this._time; // this.fire('time', this._time) + // Run all of the runners directly - this.d = 2 * zeta * wn; - this.k = wn * wn; - } + var runnersLeft = false; - var Spring = - /*#__PURE__*/ - function (_Controller) { - _inherits(Spring, _Controller); + 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 - function Spring(duration, overshoot) { - var _this3; + var dtToStart = this._time - runnerInfo.start; // Dont run runner if not started yet - _classCallCheck(this, Spring); + if (dtToStart < 0) { + runnersLeft = true; + continue; + } else if (dtToStart < dt) { + // Adjust dt to make sure that animation is on point + dt = dtToStart; + } - _this3 = _possibleConstructorReturn(this, _getPrototypeOf(Spring).call(this)); + if (!runner.active()) continue; // If this runner is still going, signal that we need another animation + // frame, otherwise, remove the completed runner - _this3.duration(duration || 500).overshoot(overshoot || 0); + var finished = runner.step(dt).done; - return _this3; - } + 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; - _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 + 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 - 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 + if (runnersLeft) { + this._nextFrame = Animator.frame(this._step.bind(this)); + } else { + this._nextFrame = null; + } - c.velocity = velocity + acceleration * dt; // Figure out if we have converged, and if so, pass the value + return this; + } // Checks if we are running and continues the animation - c.done = Math.abs(target - newPosition) + Math.abs(velocity) < 0.002; - return c.done ? target : newPosition; + }, { + 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 Spring; - }(Controller); - extend(Spring, { - duration: makeSetterGetter('_duration', recalculate), - overshoot: makeSetterGetter('_overshoot', recalculate) + return Timeline; + }(); + registerMethods({ + Element: { + timeline: function timeline() { + this._timeline = this._timeline || new Timeline(); + return this._timeline; + } + } }); - var PID = + + // 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 (_Controller2) { - _inherits(PID, _Controller2); + function (_EventTarget) { + _inherits(Runner, _EventTarget); - function PID(p, i, d, windup) { - var _this4; + function Runner(options) { + var _this; - _classCallCheck(this, PID); + _classCallCheck(this, Runner); - _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 = _possibleConstructorReturn(this, _getPrototypeOf(Runner).call(this)); // Store a unique id on the runner, so that we can identify it later - _this4.p(p).i(i).d(d).windup(windup); + _this.id = Runner.id++; // Ensure a default value - return _this4; - } + options = options == null ? timeline.duration : options; // Ensure that we get a controller - _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 + options = typeof options === 'function' ? new Controller(options) : options; // Declare all of the variables - if (windup !== false) { - i = Math.max(-windup, Math.min(i, windup)); - } + _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 - 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); - } - }]); + _this._history = {}; // Store the state of the runner - return PID; - }(Controller); - extend(PID, { - windup: makeSetterGetter('windup'), - p: makeSetterGetter('P'), - i: makeSetterGetter('I'), - d: makeSetterGetter('D') - }); + _this.enabled = true; + _this._time = 0; + _this._last = 0; // Save transforms applied to this runner - var Morphable = - /*#__PURE__*/ - function () { - function Morphable(stepper) { - _classCallCheck(this, Morphable); + _this.transforms = new Matrix(); + _this.transformId = 1; // Looping variables - // 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; + _this._haveReversed = false; + _this._reverse = false; + _this._loopsDone = 0; + _this._swing = false; + _this._wait = 0; + _this._times = 1; + return _this; } + /* + Runner Definitions + ================== + These methods help us define the runtime behaviour of the Runner or they + help us make new runners from the current runner + */ - _createClass(Morphable, [{ - key: "from", - value: function from(val) { - if (val == null) { - return this._from; - } - this._from = this._set(val); + _createClass(Runner, [{ + key: "element", + value: function element(_element) { + if (_element == null) return this._element; + this._element = _element; + + _element._prepareRunner(); + return this; } }, { - key: "to", - value: function to(val) { - if (val == null) { - return this._to; - } - - this._to = this._set(val); + 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: "type", - value: function type(_type) { - // getter - if (_type == null) { - return this._type; - } // setter - - - this._type = _type; - 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: "_set", - value: function _set$$1(value) { - if (!this._type) { - var type = _typeof(value); + 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 (type === 'number') { - this.type(SVGNumber); - } else if (type === 'string') { - if (Color.isColor(value)) { - this.type(Color); - } else if (delimiter.test(value)) { - this.type(pathLetters.test(value) ? PathArray : SVGArray); - } else if (numberAndUnit.test(value)) { - this.type(SVGNumber); - } else { - this.type(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(ObjectBag); - } else { - this.type(NonMorphable); - } - } - 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; + 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: "stepper", - value: function stepper(_stepper) { - if (_stepper == null) return this._stepper; - this._stepper = _stepper; + key: "unschedule", + value: function unschedule() { + var timeline$$1 = this.timeline(); + timeline$$1 && timeline$$1.unschedule(this); return this; } }, { - key: "done", - value: function done() { - var complete = this._context.map(this._stepper.done).reduce(function (last, curr) { - return last && curr; - }, true); + 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 - return complete; + + this._times = times || Infinity; + this._swing = swing || false; + this._wait = wait || 0; + 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); - })); + key: "delay", + value: function delay(_delay) { + return this.animate(0, _delay); } - }]); - - return Morphable; - }(); - var NonMorphable = - /*#__PURE__*/ - function () { - function NonMorphable() { - _classCallCheck(this, NonMorphable); + /* + Basic Functionality + =================== + These methods allow us to attach basic functions to the runner directly + */ - this.init.apply(this, arguments); - } + }, { + key: "queue", + value: function queue(initFn, runFn, isTransform) { + this._queue.push({ + initialiser: initFn || noop, + runner: runFn || noop, + isTransform: isTransform, + initialised: false, + finished: false + }); - _createClass(NonMorphable, [{ - key: "init", - value: function init(val) { - val = Array.isArray(val) ? val[0] : val; - this.value = val; + var timeline$$1 = this.timeline(); + timeline$$1 && this.timeline()._continue(); + return this; } }, { - key: "valueOf", - value: function valueOf() { - return this.value; + key: "during", + value: function during(fn) { + return this.queue(null, fn); } }, { - key: "toArray", - value: function toArray() { - return [this.value]; + key: "after", + value: function after(fn) { + return this.on('finish', fn); } - }]); - - return NonMorphable; - }(); - var TransformBag = - /*#__PURE__*/ - function () { - function TransformBag() { - _classCallCheck(this, TransformBag); + /* + Runner animation methods + ======================== + Control how the animation plays + */ - this.init.apply(this, arguments); - } + }, { + key: "time", + value: function time(_time) { + if (_time == null) { + return this._time; + } - _createClass(TransformBag, [{ - 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] - }; + 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; + + 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); } - Object.assign(this, TransformBag.defaults, obj); + var whole = Math.floor(p); + var partial = p % 1; + var time = loopDuration * whole + this._duration * partial; + return this.time(time); } }, { - 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]; - } - }]); + 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 TransformBag; - }(); - TransformBag.defaults = { - scaleX: 1, - scaleY: 1, - shear: 0, - rotate: 0, - translateX: 0, - translateY: 0, - originX: 0, - originY: 0 - }; - var ObjectBag = - /*#__PURE__*/ - function () { - function ObjectBag() { - _classCallCheck(this, ObjectBag); + if (p == null) { + /* + This function converts a time to a position in the range [0, 1] + The full explanation can be found in this desmos demonstration + https://www.desmos.com/calculator/u4fbavgche + The logic is slightly simplified here because we can use booleans + */ + // 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 - this.init.apply(this, arguments); - } - _createClass(ObjectBag, [{ - key: "init", - value: function init(objOrArr) { - this.values = []; + 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 - if (Array.isArray(objOrArr)) { - this.values = objOrArr; - return; - } - 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); - }, []); + 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: "valueOf", - value: function valueOf() { - var obj = {}; - var arr = this.values; - - for (var i = 0, len = arr.length; i < len; i += 2) { - obj[arr[i]] = arr[i + 1]; + key: "progress", + value: function progress(p) { + if (p == null) { + return Math.min(1, this._time / this.duration()); } - return obj; + return this.time(p * this.duration()); } }, { - key: "toArray", - value: function toArray() { - return this.values; - } - }]); + 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 - return ObjectBag; - }(); - var morphableTypes = [NonMorphable, TransformBag, ObjectBag]; - function registerMorphableType() { - var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; - morphableTypes.push.apply(morphableTypes, _toConsumableArray([].concat(type))); - } - function makeMorphable() { - extend(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; - } - }); - } + dt = dt == null ? 16 : dt; + this._time += dt; + var position = this.position(); // Figure out if we need to run the stepper in this frame - var time = window.performance || Date; + var running = this._lastPosition !== position && this._time >= 0; + this._lastPosition = position; // Figure out if we just started - 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 duration = this.duration(); + var justStarted = this._lastTime < 0 && this._time > 0; + var justFinished = this._lastTime < this._time && this.time > duration; + this._lastTime = this._time; - var Timeline = - /*#__PURE__*/ - function () { - // Construct a new timeline on the given element - function Timeline() { - _classCallCheck(this, Timeline); + if (justStarted) { + this.fire('start', this); + } // 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) - this._timeSource = function () { - return time.now(); - }; - this._dispatcher = document.createElement('div'); // Store the timing variables + var declarative = this._isDeclarative; + this.done = !declarative && !justFinished && this._time >= duration; // Call initialise and the run function - this._startTime = 0; - this._speed = 1.0; // Play control variables control how the animation proceeds + if (running || declarative) { + this._initialise(running); // clear the transforms on this runner so they dont get added again and again - 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; - } + this.transforms = new Matrix(); - _createClass(Timeline, [{ - key: "getEventTarget", - value: function getEventTarget() { - return this._dispatcher; - } - /** - * - */ - // schedules a runner on the timeline + var converged = this._run(declarative ? dt : position); - }, { - 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; - }); + 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); } - if (!this.active()) { - this._step(); + 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; + } + /* + Private Methods + =============== + Methods that shouldn't be used externally + */ + // Save a morpher to the morpher list so that we can retarget it later - 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 + }, { + 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 + }, { + 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 absoluteStartTime = 0; - delay = delay || 0; // Work out when to start the animation + this._queue.splice(index, 1); - 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]; + return false; + } // for the case of transformations, we use the special retarget function + // which has access to the outer scope - if (runnerInfo) { - absoluteStartTime = runnerInfo.start + delay; - delay = 0; - } - } else { - throw new Error('Invalid value for the "when" parameter'); - } // Manage runner + if (this._history[method].caller.isTransform) { + this._history[method].caller.isTransform(target); // for everything else a simple morpher change is sufficient - runner.unschedule(); - runner.timeline(this); - runner.time(-delay); // Save startTime for next runner + } else { + this._history[method].morpher.to(target); + } - this._startTime = absoluteStartTime + runner.duration() + delay; // Save runnerInfo + this._history[method].caller.finished = false; + var timeline$$1 = this.timeline(); + timeline$$1 && timeline$$1._continue(); + return true; + } - this._runners[runner.id] = { - persist: this.persist(), - runner: runner, - start: absoluteStartTime // Save order and continue + return false; + } // Run each initialise function in the runner if required - }; + }, { + 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 - this._order.push(runner.id); + 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 - this._continue(); + var needsIt = this._isDeclarative || !current.initialised && running; + running = !current.finished; // Call the initialiser if we need to - return this; - } // Remove the runner from this timeline + if (needsIt && running) { + current.initialiser.call(this); + current.initialised = true; + } + } + } // Run each run function for the position or dt given }, { - key: "unschedule", - value: function unschedule(runner) { - var index = this._order.indexOf(runner.id); + key: "_run", + value: function _run(positionOrDt) { + // Run all of the _queue directly + var allfinished = true; - if (index < 0) return this; - delete this._runners[runner.id]; + 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 - this._order.splice(index, 1); + 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 - 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(); + + return allfinished; } }, { - key: "pause", - value: function pause() { - // Cancel the next animation frame and pause - this._nextFrame = null; - this._paused = true; + key: "addTransform", + value: function addTransform(transform, index) { + this.transforms.lmultiplyO(transform); 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; + key: "clearTransform", + value: function clearTransform() { + this.transforms = new Matrix(); 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: "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 + }; } - }, { - key: "time", - value: function time(_time) { - if (_time == null) return this._time; - this._time = _time; + }]); + + return Runner; + }(EventTarget); + 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, FakeRunner); + + this.transforms = transforms; + this.id = id; + this.done = done; + }; + + extend([Runner, FakeRunner], { + mergeWith: function mergeWith(runner) { + return new FakeRunner(runner.transforms.lmultiply(this.transforms), runner.id); + } + }); // FakeRunner.emptyRunner = new FakeRunner() + + var lmultiply = function lmultiply(last, curr) { + return last.lmultiplyO(curr); + }; + + var getRunnerTransform = function getRunnerTransform(runner) { + return runner.transforms; + }; + + 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); + + this._transformationRunners.merge(); + + if (this._transformationRunners.length() === 1) { + this._frameId = null; + } + } + + var RunnerArray = + /*#__PURE__*/ + function () { + function RunnerArray() { + _classCallCheck(this, RunnerArray); + + this.runners = []; + this.ids = []; + } + + _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: "persist", - value: function persist(dtOrForever) { - if (dtOrForever == null) return this._persist; - this._persist = dtOrForever; - return this; + key: "getByID", + value: function getByID(id) { + return this.runners[this.ids.indexOf(id + 1)]; } }, { - key: "source", - value: function source(fn) { - if (fn == null) return this._timeSource; - this._timeSource = fn; + 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: "_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; + key: "merge", + value: function merge() { + var _this2 = this; - 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; + var lastRunner = null; + this.runners.forEach(function (runner, i) { + if (lastRunner && runner.done && lastRunner.done) { + _this2.remove(runner.id); - 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); - } + _this2.edit(lastRunner.id, runner.mergeWith(lastRunner)); } - } // Get the next animation frame to keep the simulation going - - - if (runnersLeft) { - this._nextFrame = Animator.frame(this._step.bind(this)); - } else { - this._nextFrame = null; - } + lastRunner = runner; + }); 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)); - } - + 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: "active", - value: function active() { - return !!this._nextFrame; + 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; } }]); - return Timeline; + return RunnerArray; }(); + + var frameId = 0; registerMethods({ Element: { - timeline: function timeline() { - this._timeline = this._timeline || new Timeline(); - return this._timeline; + 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); + + 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++; + } } } }); + extend(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]); + } + } - // 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 (_EventTarget) { - _inherits(Runner, _EventTarget); - - function Runner(options) { - var _this; - - _classCallCheck(this, Runner); - - _this = _possibleConstructorReturn(this, _getPrototypeOf(Runner).call(this)); // 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 + 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; + }, - _this.transforms = new Matrix(); - _this.transformId = 1; // Looping variables + /** + ** absolute transformations + **/ + // + // 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; - _this._haveReversed = false; - _this._reverse = false; - _this._loopsDone = 0; - _this._swing = false; - _this._wait = 0; - _this._times = 1; - return _this; - } - /* - Runner Definitions - ================== - These methods help us define the runtime behaviour of the Runner or they - help us make new runners from the current runner - */ + if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) { + return this; + } // Parse the parameters - _createClass(Runner, [{ - key: "element", - value: function element(_element) { - if (_element == null) return this._element; - this._element = _element; + var isMatrix = isMatrixLike(transforms); + affine = transforms.affine != null ? transforms.affine : affine != null ? affine : !isMatrix; // Create a morepher and set its type - _element._prepareRunner(); + var morpher = new Morphable().type(affine ? TransformBag : Matrix).stepper(this._stepper); + var origin; + var element; + var current; + var currentAngle; + var startTransform; - 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... + 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 + element.addRunner(this); // Deactivate all transforms that have run so far if we are absolute - if (!timeline$$1) { - throw Error('Runner cannot be scheduled without timeline'); - } // Schedule the runner on the timeline provided + if (!relative) { + element._clearTransformRunnersBefore(this); + } + } + 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(); - 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 + var _transform = new Point(origin).transform(element._currentTransform(this)), + x = _transform.x, + y = _transform.y; + var target = new Matrix(_objectSpread({}, transforms, { + origin: [x, y] + })); + var start = this._isDeclarative && current ? current : startTransform; - 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); - } - /* - Basic Functionality - =================== - These methods allow us to attach basic functions to the runner directly - */ + if (affine) { + target = target.decompose(x, y); + start = start.decompose(x, y); // Get the current and target angle as it was set - }, { - key: "queue", - value: function queue(initFn, runFn, isTransform) { - this._queue.push({ - initialiser: initFn || noop, - runner: runFn || noop, - isTransform: isTransform, - initialised: false, - finished: false - }); + var rTarget = target.rotate; + var rCurrent = start.rotate; // Figure out the shortest path to rotate directly - 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); - } - /* - Runner animation methods - ======================== - Control how the animation plays - */ + 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]; + } - }, { - key: "time", - value: function time(_time) { - if (_time == null) { - return this._time; + 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; + } + + if (this._isDeclarative && currentAngle) { + start.rotate = currentAngle; + } } - var dt = _time - this._time; - this.step(dt); - return this; - } - }, { - key: "duration", - value: function duration() { - return this._times * (this._wait + this._duration) - this._wait; + morpher.from(start); + morpher.to(target); + var affineParameters = morpher.at(pos); + currentAngle = affineParameters.rotate; + current = new Matrix(affineParameters); + this.addTransform(current); + return morpher.done(); } - }, { - 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); - } + 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 - var whole = Math.floor(p); - var partial = p % 1; - var time = loopDuration * whole + this._duration * partial; - return this.time(time); + + transforms = _objectSpread({}, newTransforms, { + origin: origin + }); } - }, { - 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) { - /* - This function converts a time to a position in the range [0, 1] - The full explanation can be found in this desmos demonstration - https://www.desmos.com/calculator/u4fbavgche - The logic is slightly simplified here because we can use booleans - */ - // 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 + 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 (this._tryRetargetDelta(method, to)) return this; // Make a morpher and queue the animation - 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 + 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 + this._rememberMorpher(method, morpher); - 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()); - } + 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 - 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 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 - dt = dt == null ? 16 : dt; - this._time += dt; - var position = this.position(); // Figure out if we need to run the stepper in this frame + this._rememberMorpher(method, morpher); - var running = this._lastPosition !== position && this._time >= 0; - this._lastPosition = position; // Figure out if we just started + 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; - 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; + if (!width || !height) { + box = this._element.bbox(); + } - if (justStarted) { - this.fire('start', this); - } // 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) + if (!width) { + width = box.width / box.height * height; + } + if (!height) { + height = box.height / box.width * width; + } - var declarative = this._isDeclarative; - this.done = !declarative && !justFinished && this._time >= duration; // Call initialise and the run function + 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 - if (running || declarative) { - this._initialise(running); // clear the transforms on this runner so they dont get added again and again + return this._queueObject('plot', new this._element.MorphArray(a)); + /* + var morpher = this._element.morphArray().to(a) + this.queue(function () { + morpher.from(this._element.array()) + }, function (pos) { + this._element.plot(morpher.at(pos)) + }) + return this + */ + }, + // 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] + }); + } - this.transforms = new Matrix(); + 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; + } + }); - var converged = this._run(declarative ? dt : position); + var _Symbol = + /*#__PURE__*/ + function (_Container) { + _inherits(_Symbol, _Container); - this.fire('step', this); - } // correct the done flag here - // declaritive animations itself know when they converged + // Initialize node + function _Symbol(node) { + _classCallCheck(this, _Symbol); + return _possibleConstructorReturn(this, _getPrototypeOf(_Symbol).call(this, nodeOrNew('symbol', node), _Symbol)); + } - this.done = this.done || converged && declarative; + return _Symbol; + }(Container); + registerMethods({ + Container: { + symbol: function symbol() { + return this.put(new _Symbol()); + } + } + }); + register(_Symbol); - if (this.done) { - this.fire('finish', this); - } + // Create plain text node + function plain(text) { + // clear if build mode is disabled + if (this._build === false) { + this.clear(); + } // create text node - 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; - } - /* - Private Methods - =============== - Methods that shouldn't be used externally - */ - // 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 + this.node.appendChild(document.createTextNode(text)); + return this; + } // FIXME: Does this also work for textpath? + // Get length of text element - }, { - 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 length() { + return this.node.getComputedTextLength(); + } - this._queue.splice(index, 1); + var textable = /*#__PURE__*/Object.freeze({ + plain: plain, + length: length + }); - return false; - } // for the case of transformations, we use the special retarget function - // which has access to the outer scope + var Text = + /*#__PURE__*/ + function (_Shape) { + _inherits(Text, _Shape); + // Initialize node + function Text(node) { + var _this; - if (this._history[method].caller.isTransform) { - this._history[method].caller.isTransform(target); // for everything else a simple morpher change is sufficient + _classCallCheck(this, Text); - } else { - this._history[method].morpher.to(target); - } + _this = _possibleConstructorReturn(this, _getPrototypeOf(Text).call(this, nodeOrNew('text', node), Text)); + _this.dom.leading = new SVGNumber(1.3); // store leading value for rebuilding - this._history[method].caller.finished = false; - var timeline$$1 = this.timeline(); - timeline$$1 && timeline$$1._continue(); - return true; - } + _this._rebuild = true; // enable automatic updating of dy values - return false; - } // Run each initialise function in the runner if required + _this._build = false; // disable build mode for adding multiple lines + // set default font - }, { - 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 + _this.attr('font-family', attrs['font-family']); - 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 + return _this; + } // Move over x-axis - var needsIt = this._isDeclarative || !current.initialised && running; - running = !current.finished; // Call the initialiser if we need to - if (needsIt && running) { - current.initialiser.call(this); - current.initialised = true; - } + _createClass(Text, [{ + key: "x", + value: function x(_x) { + // act as getter + if (_x == null) { + return this.attr('x'); } - } // Run each run function for the position or dt given + + return this.attr('x', _x); + } // Move over y-axis }, { - key: "_run", - value: function _run(positionOrDt) { - // Run all of the _queue directly - var allfinished = true; + key: "y", + value: function y(_y) { + var oy = this.attr('y'); + var o = typeof oy === 'number' ? oy - this.bbox().y : 0; // act as getter - 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 + if (_y == null) { + return typeof oy === 'number' ? oy - o : oy; + } - 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 this.attr('y', typeof _y === 'number' ? _y + o : _y); + } // Move center over x-axis + }, { + key: "cx", + value: function cx(x) { + return x == null ? this.bbox().cx : this.x(x - this.bbox().width / 2); + } // Move center over y-axis - return allfinished; - } }, { - key: "addTransform", - value: function addTransform(transform, index) { - this.transforms.lmultiplyO(transform); - return this; - } + key: "cy", + value: function cy(y) { + return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2); + } // Set the text content + }, { - 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 + key: "text", + value: function text(_text) { + // act as getter + if (_text === undefined) { + // FIXME use children() or each() + var children = this.node.childNodes; + var firstLine = 0; + _text = ''; - 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; - } + 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 - return { - duration: duration, - delay: delay, - swing: swing, - times: times, - wait: wait, - when: when - }; - } - }]); - return Runner; - }(EventTarget); - Runner.id = 0; + if (i !== firstLine && children[i].nodeType !== 3 && adopt(children[i]).dom.newLined === true) { + _text += '\n'; + } // add content of this node - 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, FakeRunner); + _text += children[i].textContent; + } - this.transforms = transforms; - this.id = id; - this.done = done; - }; + return _text; + } // remove existing content - extend([Runner, FakeRunner], { - mergeWith: function mergeWith(runner) { - return new FakeRunner(runner.transforms.lmultiply(this.transforms), runner.id); - } - }); // FakeRunner.emptyRunner = new FakeRunner() - var lmultiply = function lmultiply(last, curr) { - return last.lmultiplyO(curr); - }; + this.clear().build(true); - var getRunnerTransform = function getRunnerTransform(runner) { - return runner.transforms; - }; + 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 - 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); + for (var j = 0, jl = _text.length; j < jl; j++) { + this.tspan(_text[j]).newLine(); + } + } // disable build mode and rebuild lines - this._transformationRunners.merge(); - if (this._transformationRunners.length() === 1) { - this._frameId = null; - } - } + return this.build(false).rebuild(); + } // Set / get leading - var RunnerArray = - /*#__PURE__*/ - function () { - function RunnerArray() { - _classCallCheck(this, RunnerArray); + }, { + key: "leading", + value: function leading(value) { + // act as getter + if (value == null) { + return this.dom.leading; + } // act as setter - this.runners = []; - this.ids = []; - } - _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; - } + this.dom.leading = new SVGNumber(value); + return this.rebuild(); + } // Rebuild appearance type + }, { - key: "merge", - value: function merge() { - var _this2 = this; + key: "rebuild", + value: function rebuild(_rebuild) { + // store new rebuild flag if given + if (typeof _rebuild === 'boolean') { + this._rebuild = _rebuild; + } // define position of all lines - var lastRunner = null; - this.runners.forEach(function (runner, i) { - if (lastRunner && runner.done && lastRunner.done) { - _this2.remove(runner.id); - _this2.edit(lastRunner.id, runner.mergeWith(lastRunner)); - } + 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'); + } - 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; - } + } // Enable / disable build mode + }, { - key: "length", - value: function length() { - return this.ids.length; - } + key: "build", + value: function build(_build) { + this._build = !!_build; + return this; + } // overwrite method from parent to set data properly + }, { - 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()); + key: "setData", + value: function setData(o) { + this.dom = o; + this.dom.leading = new SVGNumber(o.leading || 1.3); return this; } }]); - return RunnerArray; - }(); - - var frameId = 0; + return Text; + }(Shape); + extend(Text, textable); 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); - - Animator.transform_frame(mergeTransforms.bind(this), this._frameId); + Container: { + // Create text element + text: function text(_text2) { + return this.put(new Text()).text(_text2); }, - _prepareRunner: function _prepareRunner() { - if (this._frameId == null) { - this._transformationRunners = new RunnerArray().add(new FakeRunner(new Matrix(this))); - this._frameId = frameId++; - } + // Create plain text element + plain: function plain$$1(text) { + return this.put(new Text()).plain(text); } } }); - extend(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]); - } - } + register(Text); - 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; - }, + var TextPath = + /*#__PURE__*/ + function (_Text) { + _inherits(TextPath, _Text); - /** - ** absolute transformations - **/ - // - // 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; + // Initialize node + function TextPath(node) { + _classCallCheck(this, TextPath); - if (this._isDeclarative && !relative && this._tryRetarget('transform', transforms)) { - return this; - } // Parse the parameters + return _possibleConstructorReturn(this, _getPrototypeOf(TextPath).call(this, nodeOrNew('textPath', node), TextPath)); + } // return the array of the path track element - var isMatrix = isMatrixLike(transforms); - affine = transforms.affine != null ? transforms.affine : affine != null ? affine : !isMatrix; // Create a morepher and set its type + _createClass(TextPath, [{ + key: "array", + value: function array() { + var track = this.track(); + return track ? track.array() : null; + } // Plot path if any - var morpher = new Morphable().type(affine ? TransformBag : Matrix).stepper(this._stepper); - var origin; - var element; - var current; - var currentAngle; - var startTransform; + }, { + key: "plot", + value: function plot(d) { + var track = this.track(); + var pathArray = null; - 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 + if (track) { + pathArray = track.plot(d); + } - element.addRunner(this); // Deactivate all transforms that have run so far if we are absolute + return d == null ? pathArray : this; + } // Get the path element - if (!relative) { - element._clearTransformRunnersBefore(this); - } + }, { + key: "track", + value: function track() { + return this.reference('href'); } + }]); - 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 TextPath; + }(Text); + 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 - var _transform = new Point(origin).transform(element._currentTransform(this)), - x = _transform.x, - y = _transform.y; + if (!(track instanceof Path)) { + // create path element + track = this.doc().defs().path(track); + } // link textPath to path and add content - var target = new Matrix(_objectSpread({}, transforms, { - origin: [x, y] - })); - var start = this._isDeclarative && current ? current : startTransform; - if (affine) { - target = target.decompose(x, y); - start = start.decompose(x, y); // Get the current and target angle as it was set + path.attr('href', '#' + track, xlink); // add textPath element as child node and return textPath - var rTarget = target.rotate; - var rCurrent = start.rotate; // Figure out the shortest path to rotate directly + return this.put(path); + }, + // FIXME: make this plural? + // Get the textPath children + textPath: function textPath() { + return this.find('textPath'); + } + }, + Path: { + // creates a textPath from this path + text: function text(_text) { + if (_text instanceof Text) { + var txt = _text.text(); - 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]; + return _text.clear().path(this).text(txt); } - 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; - } + return this.parent().put(new Text()).path(this).text(_text); + } // FIXME: Maybe add `targets` to get all textPaths associated with this path - if (this._isDeclarative && currentAngle) { - start.rotate = currentAngle; - } - } + } + }); + TextPath.prototype.MorphArray = PathArray; + register(TextPath); - morpher.from(start); - morpher.to(target); - var affineParameters = morpher.at(pos); - currentAngle = affineParameters.rotate; - current = new Matrix(affineParameters); - this.addTransform(current); - return morpher.done(); - } + var Tspan = + /*#__PURE__*/ + function (_Text) { + _inherits(Tspan, _Text); + + // Initialize node + function Tspan(node) { + _classCallCheck(this, Tspan); - 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 _possibleConstructorReturn(this, _getPrototypeOf(Tspan).call(this, nodeOrNew('tspan', node), Tspan)); + } // Set text content - transforms = _objectSpread({}, newTransforms, { - origin: origin - }); - } + _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 - 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: "dx", + value: function dx(_dx) { + return this.attr('dx', _dx); + } // Shortcut dy - if (this._tryRetargetDelta(method, to)) return this; // Make a morpher and queue the animation + }, { + key: "dy", + value: function dy(_dy) { + return this.attr('dy', _dy); + } // Create new line - 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 + }, { + key: "newLine", + value: function newLine() { + // fetch text parent + var t = this.parent(Text); // mark new line - this._rememberMorpher(method, morpher); + this.dom.newLined = true; // apply new 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 + return this.dy(t.dom.leading * t.attr('font-size')).attr('x', t.x()); + } + }]); - 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 + return Tspan; + }(Text); + extend(Tspan, textable); + registerMethods({ + Tspan: { + tspan: function tspan(text) { + var tspan = new Tspan(); // clear if build mode is disabled - this._rememberMorpher(method, morpher); + if (!this._build) { + this.clear(); + } // add new tspan - 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(); + this.node.appendChild(tspan.node); + return tspan.text(text); } + } + }); + register(Tspan); - if (!width) { - width = box.width / box.height * height; - } + var Use = + /*#__PURE__*/ + function (_Shape) { + _inherits(Use, _Shape); - if (!height) { - height = box.height / box.width * width; - } + function Use(node) { + _classCallCheck(this, Use); - 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 + return _possibleConstructorReturn(this, _getPrototypeOf(Use).call(this, nodeOrNew('use', node), Use)); + } // Use element as a reference - return this._queueObject('plot', new this._element.MorphArray(a)); - /* - var morpher = this._element.morphArray().to(a) - this.queue(function () { - morpher.from(this._element.array()) - }, function (pos) { - this._element.plot(morpher.at(pos)) - }) - return this - */ - }, - // 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] - }); + _createClass(Use, [{ + key: "element", + value: function element(_element, file) { + // Set lined element + return this.attr('href', (file || '') + '#' + _element, xlink); } + }]); - 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 Use; + }(Shape); + registerMethods({ + Container: { + // Create a use element + use: function use(element, file) { + return this.put(new Use()).element(element, file); + } } }); + register(Use); + - // 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 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' var Classes = /*#__PURE__*/Object.freeze({ - EventTarget: EventTarget, - Dom: Dom, - Element: Element, - Shape: Shape, - Container: Container, - HtmlNode: HtmlNode, - Doc: Doc$1, - Defs: Defs, - G: G, Animator: Animator, + SVGArray: SVGArray, Bare: Bare, + Box: Box, Circle: Circle, ClipPath: ClipPath, - A: A, + Color: Color, + Container: Container, + Controller: Controller, + Ease: Ease, + PID: PID, + Spring: Spring, + Defs: Defs, + Doc: Doc$1, + Dom: Dom, + Element: Element, Ellipse: Ellipse, - Stop: Stop, + EventTarget: EventTarget, Gradient: Gradient, + G: G, + HtmlNode: HtmlNode, + A: A, Image: Image, Line: Line, Marker: Marker, Mask: Mask, + Matrix: Matrix, + Morphable: Morphable, + SVGNumber: SVGNumber, Path: Path, + PathArray: PathArray, Pattern: Pattern, + Point: Point, + PointArray: PointArray, Polygon: Polygon, Polyline: Polyline, + Queue: Queue, Rect: Rect, + Runner: Runner, + Shape: Shape, + Stop: Stop, Symbol: _Symbol, Text: Text, TextPath: TextPath, - Tspan: Tspan, - Use: Use, - SVGNumber: SVGNumber, - SVGArray: SVGArray, - PathArray: PathArray, - PointArray: PointArray, - Matrix: Matrix, - Point: Point, - Box: Box, - Color: Color, - Morphable: Morphable, - Queue: Queue, - Runner: Runner, Timeline: Timeline, - Controller: Controller, - Ease: Ease, - PID: PID, - Spring: Spring + Tspan: Tspan, + Use: Use }); // ### This module adds backward / forward functionality to elements. @@ -7125,10 +6656,6 @@ var SVG = (function () { transform: transform }); - // - // export function setup (node) { - // this._memory = {} - // } // Remember arbitrary data function remember(k, v) { @@ -7167,7 +6694,7 @@ var SVG = (function () { remember: remember, forget: forget, memory: memory - }); // registerConstructor('Memory', setup) + }); var sugar = { stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'], diff --git a/dist/svg.min.js b/dist/svg.min.js index 7f3eb18..001199b 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -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 o(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",delay:0},kt={"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"},bt=Object.freeze({noop:gt,timeline:wt,attrs:kt}),xt=function(){function t(){o(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?k.test(t)?(i=p.exec(t.replace(g,"")),this.r=parseInt(i[1]),this.g=parseInt(i[2]),this.b=parseInt(i[3])):w.test(t)&&(i=y.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"#"+z(Math.round(this.r))+z(Math.round(this.g))+z(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+="",w.test(t)||k.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}(),_t=function(){try{return Function("name","baseClass","_constructor",["baseClass = baseClass || Array","return {","[name]: class extends baseClass {","constructor (...args) {","super(...args)","_constructor && _constructor.apply(this, args)","}","}","}[name]"].join("\n"))}catch(t){return function(t){var e=1n.x&&e>n.y&&t=e.time?e.run():Ft.timeouts.push(e),e!==n););for(var i=null,r=Ft.frames.last();i!==r&&(i=Ft.frames.shift());)i.run();Ft.transforms.forEach(function(t){t()}),Ft.nextDraw=Ft.timeouts.first()||Ft.frames.first()?window.requestAnimationFrame(Ft._draw):null}},It=function(t){function e(t){return o(this,e),h(this,u(e).call(this,Q(t,"string"==typeof t?null:t),e))}return r(e,Tt),a(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}();function Xt(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())}function Yt(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())}function Ht(t){return null==t?this.attr("cx"):this.attr("cx",t)}function Gt(t){return null==t?this.attr("cy"):this.attr("cy",t)}function Vt(t){return null==t?2*this.rx():this.rx(new At(t).divide(2))}function Bt(t){return null==t?2*this.ry():this.ry(new At(t).divide(2))}function Qt(t,e){var n=R(this,t,e);return this.rx(new At(n.width).divide(2)).ry(new At(n.height).divide(2))}et(It),Pt("Container",{element:function(t,e){return this.put(new It(t,e))}});var Ut=Object.freeze({rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)},x:Xt,y:Yt,cx:Ht,cy:Gt,width:Vt,height:Bt,size:Qt}),$t=function(t){function e(t){return o(this,e),h(this,u(e).call(this,Q("circle",t),e))}return r(e,St),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 Wt(t,e){return yt((e||document).querySelectorAll(t),function(t){return tt(t)})}function Jt(t){return Wt(t,this.node)}$($t,{x:Xt,y:Yt,cx:Ht,cy:Gt,width:Vt,height:Bt,size:Qt}),Pt({Element:{circle:function(t){return this.put(new $t).radius(new At(t).divide(2)).move(0,0)}}}),et($t),Pt("Dom",{find:Jt});var Zt=function(t){function e(t){return o(this,e),h(this,u(e).call(this,Q("clipPath",t),e))}return r(e,Tt),a(e,[{key:"remove",value:function(){return this.targets().forEach(function(t){t.unclip()}),c(u(e.prototype),"remove",this).call(this)}},{key:"targets",value:function(){return Wt('svg [clip-path*="'+this.id()+'"]')}}]),e}();Pt({Container:{clip:function(){return this.defs().put(new Zt)}},Element:{clipWith:function(t){var e=t instanceof Zt?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")}}}),et(Zt);var Kt=function(t){function e(t){return o(this,e),h(this,u(e).call(this,Q("a",t),e))}return r(e,Tt),a(e,[{key:"to",value:function(t){return this.attr("href",t,G)}},{key:"target",value:function(t){return this.attr("target",t)}}]),e}();Pt({Container:{link:function(t){return this.put(new Kt).to(t)}},Element:{linkTo:function(t){var e=new Kt;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}}),et(Kt);var te=function(t){function e(t){return o(this,e),h(this,u(e).call(this,Q("ellipse",t),e))}return r(e,St),e}();$(te,Ut),Pt("Container",{ellipse:function(t,e){return this.put(new te).size(t,e).move(0,0)}}),et(te);var ee=function(t){function e(t){return o(this,e),h(this,u(e).call(this,Q("stop",t),e))}return r(e,Mt),a(e,[{key:"update",value:function(t){return("number"==typeof t||t instanceof At)&&(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 At(t.offset)),this}}]),e}();et(ee);var ne=Object.freeze({from:function(t,e){return"radialGradient"===(this._element||this).type?this.attr({fx:new At(t),fy:new At(e)}):this.attr({x1:new At(t),y1:new At(e)})},to:function(t,e){return"radialGradient"===(this._element||this).type?this.attr({cx:new At(t),cy:new At(e)}):this.attr({x2:new At(t),y2:new At(e)})}});function ie(){if(!ie.nodes){var t=(new Rt).size(2,0).css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"}),e=t.path().node;ie.nodes={svg:t,path:e}}if(!ie.nodes.svg.node.parentNode){var n=document.body||document.documentElement;ie.nodes.svg.addTo(n)}return ie.nodes}var re=function(){function r(t,e,n){var i;o(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=ie().svg.node.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}();Pt({Element:{point:function(t,e){return new re(t,e).transform(this.screenCTM().inverse())}}});var se=function(){function u(){o(this,u),this.init.apply(this,arguments)}return a(u,[{key:"init",value:function(t){var e;t="string"==typeof t?t.split(C).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 re(this.x,this.y),new re(this.x2,this.y),new re(this.x,this.y2),new re(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(ie().svg).show();n=e(r.node),r.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return n}Pt({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:{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(t){function i(t){return o(this,i),h(this,u(i).call(this,Q(t+"Gradient","string"==typeof t?null:t),i))}return r(i,Tt),a(i,[{key:"stop",value:function(t,e,n){return this.put(new ee).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"),c(u(i.prototype),"attr",this).call(this,t,e,n)}},{key:"targets",value:function(){return Jt('svg [fill*="'+this.id()+'"]')}},{key:"bbox",value:function(){return new se}}]),i}();$(oe,ne),Pt({Container:{gradient:function(t,e){return this.defs().gradient(t,e)}},Defs:{gradient:function(t,e){return this.put(new oe(t)).update(e)}}}),et(oe);var ae=function(t){function i(t){return o(this,i),h(this,u(i).call(this,Q("pattern",t),i))}return r(i,Tt),a(i,[{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"),c(u(i.prototype),"attr",this).call(this,t,e,n)}},{key:"targets",value:function(){return Jt('svg [fill*="'+this.id()+'"]')}},{key:"bbox",value:function(){return new se}}]),i}();Pt({Container:{pattern:function(t,e,n){return this.defs().pattern(t,e,n)}},Defs:{pattern:function(t,e,n){return this.put(new ae).update(n).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}}),et(ae);var he=function(t){function e(t){return o(this,e),h(this,u(e).call(this,Q("image",t),e))}return r(e,St),a(e,[{key:"load",value:function(n,i){if(!n)return this;var r=new window.Image;return lt(r,"load",function(t){var e=this.parent(ae);0===this.width()&&0===this.height()&&this.size(r.width,r.height),e instanceof ae&&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),lt(r,"load error",function(){ct(r)}),this.attr("href",r.src=n,G)}},{key:"attrHook",value:function(t){var e=this;return t.doc().defs().pattern(0,0,function(t){t.add(e)})}}]),e}();Pt({Container:{image:function(t,e){return this.put(new he).size(0,0).load(t,e)}}}),et(he);var le=_t("PointArray",Ot);$(le,{toString:function(){for(var t=0,e=this.length,n=[];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){}}},ze=function(){function t(){o(this,t)}return a(t,[{key:"done",value:function(){return!1}}]),t}(),Re=function(t){function n(t){var e;return o(this,n),(e=h(this,u(n).call(this))).ease=Pe[t||wt.ease]||t,e}return r(n,ze),a(n,[{key:"step",value:function(t,e,n){return"number"!=typeof t?n<1?t:e:t+(e-t)*this.ease(n)}}]),n}(),qe=function(t){function n(t){var e;return o(this,n),(e=h(this,u(n).call(this))).stepper=t,e}return r(n,ze),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 Le(){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 Fe=function(t){function i(t,e){var n;return o(this,i),(n=h(this,u(i).call(this))).duration(t||500).overshoot(e||0),n}return r(i,qe),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;100i;this._lastTime=this._time,r&&this.fire("start",this);var u=this._isDeclarative;if(this.done=!u&&!s&&this._time>=i,n||u){this._initialise(n),this.transforms=new Ne;var o=this._run(u?t:e);this.fire("step",this)}return this.done=this.done||o&&u,this.done&&this.fire("finish",this),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 Re(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=e.time?e.run():d.timeouts.push(e),e!==n););for(var i=null,r=d.frames.last();i!==r&&(i=d.frames.shift());)i.run();d.transforms.forEach(function(t){t()}),d.nextDraw=d.timeouts.first()||d.frames.first()?window.requestAnimationFrame(d._draw):null}},v=/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,y=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,p=/rgb\((\d+),(\d+),(\d+)\)/,m=/(#[a-z0-9\-_]+)/i,e=/\)\s*,?\s*/,g=/\s/g,w=/^#[a-f0-9]{3,6}$/i,k=/^rgb\(/,b=/^(\s+)?$/,x=/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,A=/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,C=/[\s,]+/,j=/([^e])-/gi,M=/[MLHVCSQTAZ]/gi,S=/[MLHVCSQTAZ]/i,T=/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,E=/\./g,N=Object.freeze({numberAndUnit:v,hex:y,rgb:p,reference:m,transforms:e,whitespace:g,isHex:w,isRgb:k,isCss:/[^:]+:[^;]+;?/,isBlank:b,isNumber:x,isPercent:/^-?[\d.]+%$/,isImage:A,delimiter:C,hyphen:j,pathLetters:M,isPathLetter:S,numbersWithDots:T,dots:E}),D=function(){try{return Function("name","baseClass","_constructor",["baseClass = baseClass || Array","return {","[name]: class extends baseClass {","constructor (...args) {","super(...args)","_constructor && _constructor.apply(this, args)","}","}","}[name]"].join("\n"))}catch(t){return function(t){var e=1",delay:0},Mt={"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"},St=Object.freeze({noop:Ct,timeline:jt,attrs:Mt}),Tt=function(){function t(){o(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?k.test(t)?(i=p.exec(t.replace(g,"")),this.r=parseInt(i[1]),this.g=parseInt(i[2]),this.b=parseInt(i[3])):w.test(t)&&(i=y.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"#"+H(Math.round(this.r))+H(Math.round(this.g))+H(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+="",w.test(t)||k.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}();var Et=function(t){function n(t){var e;return o(this,n),(e=h(this,u(n).call(this,t))).node=t,e.type=t.nodeName,e}return r(n,xt),a(n,[{key:"add",value:function(t,e){return t=Z(t),null==e?this.node.appendChild(t.node):t.node!==this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this}},{key:"addTo",value:function(t){return Z(t).put(this)}},{key:"children",value:function(){return _t(this.node.children,function(t){return K(t)})}},{key:"clear",value:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this}},{key:"clone",value:function(t){this.writeDataToDom();var e=rt(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e}},{key:"each",value:function(t,e){var n,i,r=this.children();for(n=0,i=r.length;nn.x&&e>n.y&&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){}}},ie=function(){function t(){o(this,t)}return a(t,[{key:"done",value:function(){return!1}}]),t}(),re=function(t){function n(t){var e;return o(this,n),(e=h(this,u(n).call(this))).ease=ne[t||jt.ease]||t,e}return r(n,ie),a(n,[{key:"step",value:function(t,e,n){return"number"!=typeof t?n<1?t:e:t+(e-t)*this.ease(n)}}]),n}(),se=function(t){function n(t){var e;return o(this,n),(e=h(this,u(n).call(this))).stepper=t,e}return r(n,ie),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 ue(){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 oe=function(t){function i(t,e){var n;return o(this,i),(n=h(this,u(i).call(this))).duration(t||500).overshoot(e||0),n}return r(i,se),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;100i;this._lastTime=this._time,r&&this.fire("start",this);var u=this._isDeclarative;if(this.done=!u&&!s&&this._time>=i,n||u){this._initialise(n),this.transforms=new Oe;var o=this._run(u?t:e);this.fire("step",this)}return this.done=this.done||o&&u,this.done&&this.fire("finish",this),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 re(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= 0; i--) { -// l = this[i][0] -// -// 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 -// -// 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 -// 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 -// -// 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[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 this -// } -// -// // Test if the passed path array use the same path data commands as this path array -// equalCommands (pathArray) { -// var i, il, equalCommands -// -// pathArray = new PathArray(pathArray) -// -// equalCommands = this.length === pathArray.value.length -// for (i = 0, il = this.length; equalCommands && i < il; i++) { -// equalCommands = this[i][0] === pathArray.value[i][0] -// } -// -// return equalCommands -// } -// -// // Make path array morphable -// morph (pathArray) { -// pathArray = new PathArray(pathArray) -// -// if (this.equalCommands(pathArray)) { -// this.destination = pathArray -// } else { -// this.destination = null -// } -// -// return this -// } -// -// // Get morphed path array at given position -// 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 -// 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 -// 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 -// 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 -// bbox () { -// parser().path.setAttribute('d', this.toString()) -// return parser.nodes.path.getBBox() -// } -// } diff --git a/src/Pattern.js b/src/Pattern.js index 6f56e58..4a3e1ad 100644 --- a/src/Pattern.js +++ b/src/Pattern.js @@ -39,7 +39,6 @@ export default class Pattern extends Container { attr (a, b, c) { if (a === 'transform') a = 'patternTransform' return super.attr(a, b, c) - // return attr.call(this, a, b, c) } targets () { diff --git a/src/PointArray.js b/src/PointArray.js index 68aeddc..42299e0 100644 --- a/src/PointArray.js +++ b/src/PointArray.js @@ -118,127 +118,3 @@ extend(PointArray, { return { x: minX, y: minY, width: maxX - minX, height: maxY - minY } } }) - -// export default class PointArray extends SVGArray { -// constructor (array, fallback = [[0, 0]]) { -// super(array, fallback) -// } -// -// // Convert array to string -// toString () { -// // convert to a poly point string -// for (var i = 0, il = this.length, array = []; i < il; i++) { -// array.push(this[i].join(',')) -// } -// -// return array.join(' ') -// } -// -// // toArray () { -// // return this.reduce(function (prev, curr) { -// // return [].concat.call(prev, curr) -// // }, []) -// // } -// -// // Convert array to line object -// toLine () { -// return { -// x1: this[0][0], -// y1: this[0][1], -// x2: this[1][0], -// y2: this[1][1] -// } -// } -// -// // Get morphed array at given position -// at (pos) { -// // make sure a destination is defined -// if (!this.destination) return this -// -// // generate morphed point string -// for (var i = 0, il = this.length, array = []; i < il; i++) { -// array.push([ -// this[i][0] + (this.destination[i][0] - this[i][0]) * pos, -// this[i][1] + (this.destination[i][1] - this[i][1]) * pos -// ]) -// } -// -// return new PointArray(array) -// } -// -// // Parse point string and flat array -// parse (array) { -// var points = [] -// -// array = array.valueOf() -// -// // if it is an array -// 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. -// 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] ]) -// } -// -// return points -// } -// -// // Move point string -// 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.length - 1; i >= 0; i--) { -// this[i] = [this[i][0] + x, this[i][1] + y] -// } -// } -// -// return this -// } -// -// // Resize poly string -// size (width, height) { -// var i -// var box = this.bbox() -// -// // recalculate position of all points according to new size -// for (i = this.length - 1; i >= 0; i--) { -// if (box.width) this[i][0] = ((this[i][0] - box.x) * width) / box.width + box.x -// if (box.height) this[i][1] = ((this[i][1] - box.y) * height) / box.height + box.y -// } -// -// return this -// } -// -// // Get bounding box of points -// bbox () { -// var maxX = -Infinity -// var maxY = -Infinity -// var minX = Infinity -// var minY = Infinity -// this.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} -// } -// } diff --git a/src/SVGArray.js b/src/SVGArray.js index 247f0b2..351e166 100644 --- a/src/SVGArray.js +++ b/src/SVGArray.js @@ -10,15 +10,11 @@ export default SVGArray extend(SVGArray, { init (...args) { - // this.splice(0, this.length) this.length = 0 this.push(...this.parse(...args)) }, toArray () { - // const ret = [] - // ret.push(...this) - // return ret return Array.prototype.concat.apply([], this) }, @@ -31,13 +27,10 @@ extend(SVGArray, { const ret = [] ret.push(...this) return ret - // return this.toArray() }, // Parse whitespace separated string parse (array = []) { - // array = array.valueOf() - // If already is an array, no need to parse it if (array instanceof Array) return array @@ -52,46 +45,3 @@ extend(SVGArray, { return new Set(this) } }) - -// export default class SVGArray extends BaseArray { -// constructor (...args) { -// super() -// this.init(...args) -// } -// -// init (array, fallback = []) { -// //this.splice(0, this.length) -// this.length = 0 -// this.push(...this.parse(array || fallback)) -// } -// -// toArray () { -// return [].concat(this) -// } -// -// toString () { -// return this.join(' ') -// } -// -// valueOf () { -// return this.toArray() -// } -// -// // Parse whitespace separated string -// parse (array) { -// 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) -// } -// -// clone () { -// return new this.constructor(this) -// } -// -// toSet () { -// return new Set(this) -// } -// } diff --git a/src/attr.js b/src/attr.js index cccc340..f3aa230 100644 --- a/src/attr.js +++ b/src/attr.js @@ -79,5 +79,3 @@ export default function attr (attr, val, ns) { return this } - -// registerMethods('Element', {attr}) diff --git a/src/classes.js b/src/classes.js index a4cc758..8e1b866 100644 --- a/src/classes.js +++ b/src/classes.js @@ -1,87 +1,44 @@ -export { default as EventTarget } from './EventTarget.js' -export { default as Dom } from './Dom.js' -export { default as Element } from './Element.js' -export { default as Shape } from './Shape.js' -export { default as Container } from './Container.js' -export { default as HtmlNode } from './HtmlNode.js' -export { default as Doc } from './Doc.js' -export { default as Defs } from './Defs.js' -export { default as G } from './G.js' export { default as Animator } from './Animator.js' +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 A } from './A.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 Dom } from './Dom.js' +export { default as Element } from './Element.js' export { default as Ellipse } from './Ellipse.js' -export { default as Stop } from './Stop.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 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 Tspan } from './Tspan.js' export { default as Use } from './Use.js' -export { default as SVGNumber } from './SVGNumber.js' -export { default as SVGArray } from './SVGArray.js' -export { default as PathArray } from './PathArray.js' -export { default as PointArray } from './PointArray.js' -export { default as Matrix } from './Matrix.js' -export { default as Point } from './Point.js' -export { default as Box } from './Box.js' -export { default as Color } from './Color.js' -export { default as Morphable } from './Morphable.js' -export { default as Queue } from './Queue.js' -export { default as Runner } from './Runner.js' -export { default as Timeline } from './Timeline.js' -export { Controller, Ease, PID, Spring } from './Controller.js' - -// export {default as Animator} from './Animator.js' -// 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 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' diff --git a/src/containers.js b/src/containers.js deleted file mode 100644 index 02869e4..0000000 --- a/src/containers.js +++ /dev/null @@ -1,15 +0,0 @@ -export { default as Bare } from './Bare.js' -export { default as ClipPath } from './ClipPath.js' -export { default as Defs } from './Defs.js' -export { default as Doc } from './Doc.js' -export { default as Gradient } from './Gradient.js' -export { default as G } from './G.js' -export { default as A } from './A.js' -export { default as Marker } from './Marker.js' -export { default as Mask } from './Mask.js' -export { default as Pattern } from './Pattern.js' -export { default as Symbol } from './Symbol.js' - -export { default as Text } from './Text.js' -export { default as Tspan } from './Tspan.js' -export { default as TextPath } from './TextPath.js' diff --git a/src/elements.js b/src/elements.js deleted file mode 100644 index b09d6e8..0000000 --- a/src/elements.js +++ /dev/null @@ -1,25 +0,0 @@ -export { default as Bare } from './Bare.js' -export { default as Circle } from './Circle.js' -export { default as ClipPath } from './ClipPath.js' -export { default as Defs } from './Defs.js' -export { default as Doc } from './Doc.js' -export { default as Ellipse } from './Ellipse.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 Path } from './Path.js' -export { default as Pattern } from './Pattern.js' -export { default as Polygon } from './Polygon.js' -export { default as Polyline } from './Polyline.js' -export { default as Rect } from './Rect.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 Tspan } from './Tspan.js' -export { default as Use } from './Use.js' diff --git a/src/event.js b/src/event.js index 8cd4188..d3cf26d 100644 --- a/src/event.js +++ b/src/event.js @@ -27,12 +27,6 @@ export function on (node, events, listener, binding, options) { // 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 if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++listenerId @@ -59,18 +53,12 @@ export function off (node, events, listener, options) { var bag = getEvents(node) var n = getEventTarget(node) - // we cannot remove an event if its not an svg.js instance - // 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 - // var bag = n.instance.events - // events can be an array of events or a string or undefined events = Array.isArray(events) ? events : (events || '').split(delimiter) diff --git a/src/memory.js b/src/memory.js index 3f81c6f..9c826a2 100644 --- a/src/memory.js +++ b/src/memory.js @@ -1,10 +1,6 @@ import { registerMethods } from './methods.js' -// export const name = 'Memory' -// -// export function setup (node) { -// this._memory = {} -// } +// FIXME: We need a constructor to set this up // Remember arbitrary data export function remember (k, v) { @@ -42,4 +38,3 @@ export function memory () { } registerMethods('Dom', { remember, forget, memory }) -// registerConstructor('Memory', setup) diff --git a/src/methods.js b/src/methods.js index f926598..2373445 100644 --- a/src/methods.js +++ b/src/methods.js @@ -23,11 +23,6 @@ export function getMethodsFor (name) { return methods[name] || {} } -// FIXME: save memory? -// export function cleanMethods () { -// methods = {} -// } - export function registerConstructor (name, setup) { constructors[name] = setup } diff --git a/src/selector.js b/src/selector.js index 6ee1207..7208153 100644 --- a/src/selector.js +++ b/src/selector.js @@ -2,29 +2,6 @@ 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) { -// 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)) -// } - export default function baseFind (query, parent) { return map((parent || document).querySelectorAll(query), function (node) { return adopt(node) -- 2.39.5