diff options
-rw-r--r-- | dist/svg.js | 658 | ||||
-rw-r--r-- | dist/svg.min.js | 4 | ||||
-rw-r--r-- | gulpfile.js | 2 | ||||
-rw-r--r-- | spec/spec/circle.js | 2 | ||||
-rw-r--r-- | spec/spec/queue.js | 111 | ||||
-rw-r--r-- | src/drawLoop.js | 82 | ||||
-rw-r--r-- | src/ellipse.js | 4 | ||||
-rw-r--r-- | src/fx.js | 1918 | ||||
-rw-r--r-- | src/gradient.js | 3 | ||||
-rw-r--r-- | src/matrix.js | 7 | ||||
-rw-r--r-- | src/queue.js | 81 | ||||
-rw-r--r-- | src/sugar.js | 302 | ||||
-rw-r--r-- | src/timeline.js | 171 | ||||
-rw-r--r-- | src/transform.js | 167 |
14 files changed, 2136 insertions, 1376 deletions
diff --git a/dist/svg.js b/dist/svg.js index a66cf21..1c92b34 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -6,7 +6,7 @@ * @copyright Wout Fierens <wout@mick-wout.com> * @license MIT * -* BUILT: Mon Mar 05 2018 02:39:10 GMT+1100 (AEDT) +* BUILT: Tue Apr 17 2018 21:58:30 GMT+1000 (AEST) */; (function(root, factory) { @@ -282,6 +282,171 @@ SVG.defaults = { } } +SVG.Queue = SVG.invent({ + create: function () { + this._first = null + this._last = null + this.length = 0 + this.id = 0 + }, + + extend: { + push: function (value) { + + // An item stores an id and the provided value + var item = { id: this.id++, value: value } + + // Deal with the queue being empty or populated + if (this._last) { + this._last = this._last.next = item + } else { + this._last = this._first = item + } + + this.length++ + }, + + shift: function () { + if (this.length == 0) { + return + } + + var remove = this._first + this._first = remove.next + this._last = --this.length ? this._last : null + return remove.value + }, + + // Shows us the first item in the list + first: function () { + return this._first && this._first.value + }, + + // Shows us the last item in the list + last: function () { + return this._last && this._last.value + }, + + // Removes the first item from the front where matcher returns true + remove: function (matcher) { + // Find the first match + var previous = null + var current = this._first + while (current) { + + // If we have a match, we are done + if (matcher(current)) break + + // Otherwise, advance both of the pointers + previous = current + current = current.next + } + + // If we got the first item, adjust the first pointer + if (current && current === this._first) + this._first = this._first.next + + // If we got the last item, adjust the last pointer + if (current && current === this._last) + this._last = previous + + // If we got an item, fix the list and return the item + if (current) { + --this.length + + if (previous) { + previous.next = current.next + } + + return current.item + } + } + } +}) + + +SVG.Draw = { + nextDraw: null, + frames: new SVG.Queue(), + timeouts: new SVG.Queue(), + frameCount: 0, + timeoutCount: 0, + timer: window.performance || window.Date, + + frame: function (fn) { + SVG.Draw.frames.push({ + id: SVG.Draw.frameCount, + run: fn + }) + + if (SVG.Draw.nextDraw === null) { + SVG.Draw.nextDraw = requestAnimationFrame(SVG.Draw._draw) + } + + return ++SVG.Draw.frameCount + }, + + timeout: function (fn, delay) { + delay = delay || 0 + + // Work out when the event should fire + var time = SVG.Draw.timer.now() + delay + + // Add the timeout to the end of the queue + var thisId = SVG.Draw.timeoutCount++ + SVG.Draw.timeouts.push({ + id: thisId, + run: fn, + time: time + }) + + // Request another animation frame if we need one + if (SVG.Draw.nextDraw === null) { + SVG.Draw.nextDraw = requestAnimationFrame(SVG.Draw._draw) + } + + return thisId + }, + + cancelTimeout: function (id) { + // Find the index of the timeout to cancel and remove it + var index = SVG.Draw.timeouts.remove(function (t) { return t.id == id }) + return index + }, + + _draw: function (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 tracking = true + var nextTimeout = null
+ var lastTimeout = SVG.Draw.timeouts.last() + while ((nextTimeout = SVG.Draw.timeouts.shift())) { + // Run the timeout if its time, or push it to the end + if (now > nextTimeout.time) { + nextTimeout.run() + } else { + SVG.Draw.timeouts.push(nextTimeout) + } + + // If we hit the last item, we should stop shifting out more items + if (nextTimeout === lastTimeout) break + } + + // Run all of the frames available up until this point + var lastFrame = SVG.Draw.frames.last() + var lastFrameId = SVG.Draw.frameCount + while (SVG.Draw.frames.first() && SVG.Draw.frames.first().id < lastFrameId) { + var nextFrame = SVG.Draw.frames.shift() + nextFrame.run(now) + } + + // If we have remaining timeouts or frames, draw until we don't anymore + SVG.Draw.nextDraw = SVG.Draw.timeouts.length > 0 || SVG.Draw.frames.length > 0 + ? requestAnimationFrame(SVG.Draw._draw) + : null + } +} + /* globals fullHex, compToHex */ // Module for color convertions @@ -1386,7 +1551,7 @@ SVG.Situation = SVG.invent({ }) -SVG.FX = SVG.invent({ +SVG.Timeline = SVG.invent({ create: function (element) { this._target = element @@ -2018,10 +2183,10 @@ SVG.FX = SVG.invent({ construct: { // Get fx module or create a new one, then animate with given duration and ease animate: function (o, ease, delay) { - return (this.fx || (this.fx = new SVG.FX(this))).animate(o, ease, delay) + return (this.fx || (this.fx = new SVG.Timeline(this))).animate(o, ease, delay) }, delay: function (delay) { - return (this.fx || (this.fx = new SVG.FX(this))).delay(delay) + return (this.fx || (this.fx = new SVG.Timeline(this))).delay(delay) }, stop: function (jumpToEnd, clearQueue) { if (this.fx) { @@ -2091,7 +2256,7 @@ SVG.MorphObj = SVG.invent({ }) -SVG.extend(SVG.FX, { +SVG.extend(SVG.Timeline, { // Add animatable attributes attr: function (a, v, relative) { // apply attributes individually @@ -2266,6 +2431,13 @@ SVG.Matrix = SVG.invent({ // Transform a matrix into another matrix by manipulating the space transform: function (o) { + // Check if o is a matrix and then left multiply it directly + if (o.a != null) { + var matrix = new SVG.Matrix(o) + var newMatrix = this.lmultiply(matrix) + return newMatrix + } + // Get all of the parameters required to form the matrix var flipX = o.flip && (o.flip === 'x' || o.flip === 'both') ? -1 : 1 var flipY = o.flip && (o.flip === 'y' || o.flip === 'both') ? -1 : 1 @@ -2783,7 +2955,8 @@ SVG.extend(SVG.Element, { SVG.extend(SVG.Element, { // Add transformations - transform: function (o, cyOrRel) { + transform: function (o, relative) { + // Get the bounding box of the element with no transformations applied var bbox = this.bbox() @@ -2792,20 +2965,6 @@ SVG.extend(SVG.Element, { var decomposed = new SVG.Matrix(this).decompose() return decomposed[o] || decomposed - // Let the user pass in a matrix as well - } else if (o.a != null) { - // Construct a matrix from the first parameter - var matrix = new SVG.Matrix(o) - - // If we have a relative matrix, we just apply the old matrix - if (cyOrRel != null) { - var oldMatrix = new SVG.Matrix(this) - matrix = matrix.multiply(oldMatrix) - } - - // Apply the matrix directly - return this.attr('transform', matrix) - // Allow the user to define the origin with a string } else if (typeof o.origin === 'string' || (o.origin == null && o.ox == null && o.oy == null) @@ -2832,13 +2991,14 @@ SVG.extend(SVG.Element, { } // The user can pass a boolean, an SVG.Element or an SVG.Matrix or nothing - var result = new SVG.Matrix(cyOrRel === true ? this : cyOrRel).transform(o) + var cleanRelative = relative === true ? this : (relative || false) + var result = new SVG.Matrix(cleanRelative).transform(o) return this.attr('transform', result) } }) -SVG.extend(SVG.FX, { - transform: function (o, relative) { +SVG.extend(SVG.Timeline, { + transform: function (o, relative, affine) { // // get target in case of the fx module, otherwise reference this // var target = this.target() @@ -2966,149 +3126,6 @@ SVG.extend(SVG.FX, { } }) -// TODO: DESTROY -// ======= -// -// -// SVG.Transformation = SVG.invent({ -// -// create: function(source, inversed){ -// -// if(arguments.length > 1 && typeof inversed != 'boolean'){ -// return this.constructor.call(this, [].slice.call(arguments)) -// } -// -// if(Array.isArray(source)){ -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// this[this.arguments[i]] = source[i] -// } -// } else if(typeof source == 'object'){ -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// this[this.arguments[i]] = source[this.arguments[i]] -// } -// } -// -// this.inversed = false -// -// if(inversed === true){ -// this.inversed = true -// } -// -// } -// -// , extend: { -// -// arguments: [] -// , method: '' -// -// , at: function(pos){ -// -// var params = [] -// -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// params.push(this[this.arguments[i]]) -// } -// -// var m = this._undo || new SVG.Matrix() -// -// m = new SVG.Matrix().morph(SVG.Matrix.prototype[this.method].apply(m, params)).at(pos) -// -// return this.inversed ? m.inverse() : m -// -// } -// -// , undo: function(o){ -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// o[this.arguments[i]] = typeof this[this.arguments[i]] == 'undefined' ? 0 : o[this.arguments[i]] -// } -// -// // The method SVG.Matrix.extract which was used before calling this -// // method to obtain a value for the parameter o doesn't return a cx and -// // a cy so we use the ones that were provided to this object at its creation -// o.cx = this.cx -// o.cy = this.cy -// -// this._undo = new SVG[capitalize(this.method)](o, true).at(1) -// -// return this -// } -// -// } -// -// }) -// -// SVG.Translate = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['transformedX', 'transformedY'] -// , method: 'translate' -// } -// -// }) -// -// SVG.Rotate = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['rotation', 'cx', 'cy'] -// , method: 'rotate' -// , at: function(pos){ -// var m = new SVG.Matrix().rotate(new SVG.Number().morph(this.rotation - (this._undo ? this._undo.rotation : 0)).at(pos), this.cx, this.cy) -// return this.inversed ? m.inverse() : m -// } -// , undo: function(o){ -// this._undo = o -// return this -// } -// } -// -// }) -// -// SVG.Scale = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['scaleX', 'scaleY', 'cx', 'cy'] -// , method: 'scale' -// } -// -// }) -// -// SVG.Skew = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['skewX', 'skewY', 'cx', 'cy'] -// , method: 'skew' -// } -// -// }) - /* global camelCase */ SVG.extend(SVG.Element, { @@ -3721,7 +3738,7 @@ SVG.Gradient = SVG.invent({ }) // Add animatable methods to both gradient and fx module -SVG.extend([SVG.Gradient, SVG.FX], { +SVG.extend([SVG.Gradient, SVG.Timeline], { // From position from: function (x, y) { return (this._target || this).type === 'radialGradient' @@ -3772,7 +3789,6 @@ SVG.Stop = SVG.invent({ return this } } - }) SVG.Pattern = SVG.invent({ @@ -4038,7 +4054,7 @@ SVG.Circle = SVG.invent({ } }) -SVG.extend([SVG.Circle, SVG.FX], { +SVG.extend([SVG.Circle, SVG.Timeline], { // Radius x value rx: function (rx) { return this.attr('r', rx) @@ -4065,7 +4081,7 @@ SVG.Ellipse = SVG.invent({ } }) -SVG.extend([SVG.Ellipse, SVG.Rect, SVG.FX], { +SVG.extend([SVG.Ellipse, SVG.Rect, SVG.Timeline], { // Radius x value rx: function (rx) { return this.attr('rx', rx) @@ -4820,157 +4836,157 @@ SVG.extend([SVG.Line, SVG.Polyline, SVG.Polygon, SVG.Path], { } }) -// Define list of available attributes for stroke and fill -var sugar = { - stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'], - fill: ['color', 'opacity', 'rule'], - prefix: function (t, a) { - return a === 'color' ? t : t + '-' + a - } -} - -// Add sugar for fill and stroke -;['fill', 'stroke'].forEach(function (m) { - var extension = {} - var i - - extension[m] = function (o) { - if (typeof o === 'undefined') { - return this - } - if (typeof o === 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) { - this.attr(m, o) - } else { - // set all attributes from sugar.fill and sugar.stroke list - for (i = sugar[m].length - 1; i >= 0; i--) { - if (o[sugar[m][i]] != null) { - this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]) - } - } - } - - return this - } - - SVG.extend([SVG.Element, SVG.FX], extension) -}) - -SVG.extend([SVG.Element, SVG.FX], { - // Let the user set the matrix directly - matrix: function (mat, b, c, d, e, f) { - // Act as a getter - if (mat == null) { - return new SVG.Matrix(this) - } - - // Act as a setter, the user can pass a matrix or a set of numbers - return this.attr('transform', new SVG.Matrix(mat, b, c, d, e, f)) - }, - - // Map rotation to transform - rotate: function (angle, cx, cy) { - return this.transform({rotate: angle, ox: cx, oy: cy}, true) - }, - - // Map skew to transform - skew: function (x, y, cx, cy) { - return arguments.length === 1 || arguments.length === 3 - ? this.transform({skew: x, ox: y, oy: cx}, true) - : this.transform({skew: [x, y], ox: cx, oy: cy}, true) - }, - - shear: function (lam, cx, cy) { - return this.transform({shear: lam, ox: cx, oy: cy}, true) - }, - - // Map scale to transform - scale: function (x, y, cx, cy) { - return arguments.length === 1 || arguments.length === 3 - ? this.transform({ scale: x, ox: y, oy: cx }, true) - : this.transform({ scale: [x, y], ox: cx, oy: cy }, true) - }, - - // Map translate to transform - translate: function (x, y) { - return this.transform({ translate: [x, y] }, true) - }, - - // Map relative translations to transform - relative: function (x, y) { - return this.transform({ relative: [x, y] }, true) - }, - - // Map flip to transform - flip: function (direction, around) { - var directionString = typeof direction === 'string' ? direction - : isFinite(direction) ? 'both' - : 'both' - var origin = (direction === 'both' && isFinite(around)) ? [around, around] - : (direction === 'x') ? [around, 0] - : (direction === 'y') ? [0, around] - : isFinite(direction) ? [direction, direction] - : [0, 0] - this.transform({flip: directionString, origin: origin}, true) - }, - - // Opacity - opacity: function (value) { - return this.attr('opacity', value) - }, - - // Relative move over x axis - dx: function (x) { - return this.x(new SVG.Number(x).plus(this instanceof SVG.FX ? 0 : this.x()), true) - }, - - // Relative move over y axis - dy: function (y) { - return this.y(new SVG.Number(y).plus(this instanceof SVG.FX ? 0 : this.y()), true) - }, - - // Relative move over x and y axes - dmove: function (x, y) { - return this.dx(x).dy(y) - } -}) - -SVG.extend([SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.FX], { - // Add x and y radius - radius: function (x, y) { - var type = (this._target || this).type - return type === 'radialGradient' || type === 'radialGradient' - ? this.attr('r', new SVG.Number(x)) - : this.rx(x).ry(y == null ? x : y) - } -}) - -SVG.extend(SVG.Path, { - // Get path length - length: function () { - return this.node.getTotalLength() - }, - // Get point at length - pointAt: function (length) { - return new SVG.Point(this.node.getPointAtLength(length)) - } -}) - -SVG.extend([SVG.Parent, SVG.Text, SVG.Tspan, SVG.FX], { - // Set font - font: function (a, v) { - if (typeof a === 'object') { - for (v in a) this.font(v, a[v]) - } - - return a === 'leading' - ? this.leading(v) - : a === 'anchor' - ? this.attr('text-anchor', v) - : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style' - ? this.attr('font-' + a, v) - : this.attr(a, v) - } -}) +// // Define list of available attributes for stroke and fill +// var sugar = { +// stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'], +// fill: ['color', 'opacity', 'rule'], +// prefix: function (t, a) { +// return a === 'color' ? t : t + '-' + a +// } +// } +// +// // Add sugar for fill and stroke +// ;['fill', 'stroke'].forEach(function (m) { +// var extension = {} +// var i +// +// extension[m] = function (o) { +// if (typeof o === 'undefined') { +// return this +// } +// if (typeof o === 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) { +// this.attr(m, o) +// } else { +// // set all attributes from sugar.fill and sugar.stroke list +// for (i = sugar[m].length - 1; i >= 0; i--) { +// if (o[sugar[m][i]] != null) { +// this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]) +// } +// } +// } +// +// return this +// } +// +// SVG.extend([SVG.Element, SVG.Timeline], extension) +// }) +// +// SVG.extend([SVG.Element, SVG.Timeline], { +// // Let the user set the matrix directly +// matrix: function (mat, b, c, d, e, f) { +// // Act as a getter +// if (mat == null) { +// return new SVG.Matrix(this) +// } +// +// // Act as a setter, the user can pass a matrix or a set of numbers +// return this.attr('transform', new SVG.Matrix(mat, b, c, d, e, f)) +// }, +// +// // Map rotation to transform +// rotate: function (angle, cx, cy) { +// return this.transform({rotate: angle, ox: cx, oy: cy}, true) +// }, +// +// // Map skew to transform +// skew: function (x, y, cx, cy) { +// return arguments.length === 1 || arguments.length === 3 +// ? this.transform({skew: x, ox: y, oy: cx}, true) +// : this.transform({skew: [x, y], ox: cx, oy: cy}, true) +// }, +// +// shear: function (lam, cx, cy) { +// return this.transform({shear: lam, ox: cx, oy: cy}, true) +// }, +// +// // Map scale to transform +// scale: function (x, y, cx, cy) { +// return arguments.length === 1 || arguments.length === 3 +// ? this.transform({ scale: x, ox: y, oy: cx }, true) +// : this.transform({ scale: [x, y], ox: cx, oy: cy }, true) +// }, +// +// // Map translate to transform +// translate: function (x, y) { +// return this.transform({ translate: [x, y] }, true) +// }, +// +// // Map relative translations to transform +// relative: function (x, y) { +// return this.transform({ relative: [x, y] }, true) +// }, +// +// // Map flip to transform +// flip: function (direction, around) { +// var directionString = typeof direction === 'string' ? direction +// : isFinite(direction) ? 'both' +// : 'both' +// var origin = (direction === 'both' && isFinite(around)) ? [around, around] +// : (direction === 'x') ? [around, 0] +// : (direction === 'y') ? [0, around] +// : isFinite(direction) ? [direction, direction] +// : [0, 0] +// this.transform({flip: directionString, origin: origin}, true) +// }, +// +// // Opacity +// opacity: function (value) { +// return this.attr('opacity', value) +// }, +// +// // Relative move over x axis +// dx: function (x) { +// return this.x(new SVG.Number(x).plus(this instanceof SVG.Timeline ? 0 : this.x()), true) +// }, +// +// // Relative move over y axis +// dy: function (y) { +// return this.y(new SVG.Number(y).plus(this instanceof SVG.Timeline ? 0 : this.y()), true) +// }, +// +// // Relative move over x and y axes +// dmove: function (x, y) { +// return this.dx(x).dy(y) +// } +// }) +// +// SVG.extend([SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.Timeline], { +// // Add x and y radius +// radius: function (x, y) { +// var type = (this._target || this).type +// return type === 'radialGradient' || type === 'radialGradient' +// ? this.attr('r', new SVG.Number(x)) +// : this.rx(x).ry(y == null ? x : y) +// } +// }) +// +// SVG.extend(SVG.Path, { +// // Get path length +// length: function () { +// return this.node.getTotalLength() +// }, +// // Get point at length +// pointAt: function (length) { +// return new SVG.Point(this.node.getPointAtLength(length)) +// } +// }) +// +// SVG.extend([SVG.Parent, SVG.Text, SVG.Tspan, SVG.Timeline], { +// // Set font +// font: function (a, v) { +// if (typeof a === 'object') { +// for (v in a) this.font(v, a[v]) +// } +// +// return a === 'leading' +// ? this.leading(v) +// : a === 'anchor' +// ? this.attr('text-anchor', v) +// : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style' +// ? this.attr('font-' + a, v) +// : this.attr(a, v) +// } +// }) SVG.extend(SVG.Element, { diff --git a/dist/svg.min.js b/dist/svg.min.js index 0919e6c..c589c44 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1,2 +1,2 @@ -/*! svg.js v3.0.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function n(t,n){if(t instanceof w.Element)return t;if("object"==typeof t)return w.adopt(t);if(null==t)return new w.Doc;if("string"==typeof t&&"<"!==t.charAt(0))return w.adopt(e.querySelector(t));var i=w.create("svg");return i.innerHTML=t,t=w.adopt(i.firstElementChild)}function i(t){return!(t.w||t.h||t.x||t.y)}function r(t){return(e.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t===e}).call(e.documentElement,t)}function s(t,e,n,i){return n+i.replace(w.regex.dots," .")}function o(t){for(var e=t.slice(0),n=e.length;n--;)Array.isArray(e[n])&&(e[n]=o(e[n]));return e}function a(t,e){return t instanceof e}function h(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function u(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function l(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t){return 4===t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function f(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function d(t,e,n){if(null==e||null==n){var i=t.bbox();null==e?e=i.width/i.height*n:null==n&&(n=i.height/i.width*e)}return{width:e,height:n}}function p(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function m(t){for(var e=0,n=t.length,i="";e<n;e++)i+=t[e][0],null!=t[e][1]&&(i+=t[e][1],null!=t[e][2]&&(i+=" ",i+=t[e][2],null!=t[e][3]&&(i+=" ",i+=t[e][3],i+=" ",i+=t[e][4],null!=t[e][5]&&(i+=" ",i+=t[e][5],i+=" ",i+=t[e][6],null!=t[e][7]&&(i+=" ",i+=t[e][7])))));return i+" "}function x(t){for(var e=t.children.length-1;e>=0;e--)x(t.children[e]);return t.id?w.adopt(t).id(w.eid(t.nodeName)):w.adopt(t)}function v(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function y(t){var e=(t||"").toString().match(w.regex.reference);if(e)return e[1]}function g(t,e,n){return Math.abs(e-t)<(n||1e-6)}if(!e.createElementNS||!e.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect)return{supported:!1};var w=this.SVG=function(t){if(w.supported)return t=n(t)};w.supported=!0,w.ns="http://www.w3.org/2000/svg",w.xmlns="http://www.w3.org/2000/xmlns/",w.xlink="http://www.w3.org/1999/xlink",w.svgjs="http://svgjs.com/svgjs",w.did=1e3,w.eid=function(t){return"Svgjs"+l(t)+w.did++},w.create=function(t){return e.createElementNS(this.ns,t)},w.extend=function(t,e){var n,i;for(t=Array.isArray(t)?t:[t],i=t.length-1;i>=0;i--)if(t[i])for(n in e)t[i].prototype[n]=e[n]},w.invent=function(t){var e="function"==typeof t.create?t.create:function(e){this.constructor(e||w.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&w.extend(e,t.extend),t.construct&&w.extend(t.parent||w.Container,t.construct),e},w.adopt=function(e){if(!e)return null;if(e.instance instanceof w.Element)return e.instance;if(!(e instanceof t.SVGElement))return new w.HtmlNode(e);return"svg"===e.nodeName?new w.Doc(e):"linearGradient"===e.nodeName||"radialGradient"===e.nodeName?new w.Gradient(e):w[l(e.nodeName)]?new(w[l(e.nodeName)])(e):new w.Parent(e)},w.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},w.utils={map:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)r.push(e(t[n]));return r},filter:function(t,e){var n,i=t.length,r=[];for(n=0;n<i;n++)e(t[n])&&r.push(t[n]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},w.defaults={attrs:{"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"}},w.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?w.regex.isRgb.test(t)?(e=w.regex.rgb.exec(t.replace(w.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):w.regex.isHex.test(t)&&(e=w.regex.hex.exec(c(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},w.extend(w.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+f(this.r)+f(this.g)+f(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new w.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new w.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),w.Color.test=function(t){return t+="",w.regex.isHex.test(t)||w.regex.isRgb.test(t)},w.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},w.Color.isColor=function(t){return w.Color.isRgb(t)||w.Color.test(t)},w.Array=function(t,e){t=(t||[]).valueOf(),0===t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},w.extend(w.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!==this.destination.length){for(var e=this.value[this.value.length-1],n=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(n);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)-1===n.indexOf(this.value[t])&&n.push(this.value[t]);return this.value=n,n},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new w.Array(i)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(w.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=o(this.value),t}}),w.PointArray=function(t,e){w.Array.call(this,t,e||[[0,0]])},w.PointArray.prototype=new w.Array,w.PointArray.prototype.constructor=w.PointArray,w.extend(w.PointArray,{toString:function(){for(var t=0,e=this.value.length,n=[];t<e;t++)n.push(this.value[t].join(","));return n.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,n=this.value.length,i=[];e<n;e++)i.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new w.PointArray(i)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(w.regex.delimiter).map(parseFloat);t.length%2!=0&&t.pop();for(var n=0,i=t.length;n<i;n+=2)e.push([t[n],t[n+1]]);return e},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i=this.value.length-1;i>=0;i--)this.value[i]=[this.value[i][0]+t,this.value[i][1]+e];return this},size:function(t,e){var n,i=this.bbox();for(n=this.value.length-1;n>=0;n--)i.width&&(this.value[n][0]=(this.value[n][0]-i.x)*t/i.width+i.x),i.height&&(this.value[n][1]=(this.value[n][1]-i.y)*e/i.height+i.y);return this},bbox:function(){var t=-1/0,e=-1/0,n=1/0,i=1/0;return this.value.forEach(function(r){t=Math.max(r[0],t),e=Math.max(r[1],e),n=Math.min(r[0],n),i=Math.min(r[1],i)}),{x:n,y:i,width:t-n,height:e-i}}});for(var b={M:function(t,e,n){return e.x=n.x=t[0],e.y=n.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,n){return e.x=n.x,e.y=n.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},P="mlhvqtcsaz".split(""),A=0,C=P.length;A<C;++A)b[P[A]]=function(t){return function(e,n,i){if("H"===t)e[0]=e[0]+n.x;else if("V"===t)e[0]=e[0]+n.y;else if("A"===t)e[5]=e[5]+n.x,e[6]=e[6]+n.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?n.y:n.x);return b[t](e,n,i)}}(P[A].toUpperCase());w.PathArray=function(t,e){w.Array.call(this,t,e||[["M",0,0]])},w.PathArray.prototype=new w.Array,w.PathArray.prototype.constructor=w.PathArray,w.extend(w.PathArray,{toString:function(){return m(this.value)},move:function(t,e){var n=this.bbox();if(t-=n.x,e-=n.y,!isNaN(t)&&!isNaN(e))for(var i,r=this.value.length-1;r>=0;r--)i=this.value[r][0],"M"===i||"L"===i||"T"===i?(this.value[r][1]+=t,this.value[r][2]+=e):"H"===i?this.value[r][1]+=t:"V"===i?this.value[r][1]+=e:"C"===i||"S"===i||"Q"===i?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"===i&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"===i&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var n,i,r=this.bbox();for(n=this.value.length-1;n>=0;n--)i=this.value[n][0],"M"===i||"L"===i||"T"===i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y):"H"===i?this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x:"V"===i?this.value[n][1]=(this.value[n][1]-r.y)*e/r.height+r.y:"C"===i||"S"===i||"Q"===i?(this.value[n][1]=(this.value[n][1]-r.x)*t/r.width+r.x,this.value[n][2]=(this.value[n][2]-r.y)*e/r.height+r.y,this.value[n][3]=(this.value[n][3]-r.x)*t/r.width+r.x,this.value[n][4]=(this.value[n][4]-r.y)*e/r.height+r.y,"C"===i&&(this.value[n][5]=(this.value[n][5]-r.x)*t/r.width+r.x,this.value[n][6]=(this.value[n][6]-r.y)*e/r.height+r.y)):"A"===i&&(this.value[n][1]=this.value[n][1]*t/r.width,this.value[n][2]=this.value[n][2]*e/r.height,this.value[n][6]=(this.value[n][6]-r.x)*t/r.width+r.x,this.value[n][7]=(this.value[n][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,n,i;for(t=new w.PathArray(t),i=this.value.length===t.value.length,e=0,n=this.value.length;i&&e<n;e++)i=this.value[e][0]===t.value[e][0];return i},morph:function(t){return t=new w.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,n,i,r,s=this.value,o=this.destination.value,a=[],h=new w.PathArray;for(e=0,n=s.length;e<n;e++){for(a[e]=[s[e][0]],i=1,r=s[e].length;i<r;i++)a[e][i]=s[e][i]+(o[e][i]-s[e][i])*t;"A"===a[e][0]&&(a[e][4]=+(0!==a[e][4]),a[e][5]=+(0!==a[e][5]))}return h.value=a,h},parse:function(t){if(t instanceof w.PathArray)return t.valueOf();var e,n={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(w.regex.numbersWithDots,s).replace(w.regex.pathLetters," $& ").replace(w.regex.hyphen,"$1 -").trim().split(w.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var i=[],r=new w.Point,o=new w.Point,a=0,h=t.length;do{w.regex.isPathLetter.test(t[a])?(e=t[a],++a):"M"===e?e="L":"m"===e&&(e="l"),i.push(b[e].call(null,t.slice(a,a+=n[e.toUpperCase()]).map(parseFloat),r,o))}while(h>a);return i},bbox:function(){return w.parser().path.setAttribute("d",this.toString()),w.parser.nodes.path.getBBox()}}),w.Number=w.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(w.regex.numberAndUnit))&&(this.value=parseFloat(e[1]),"%"===e[5]?this.value/=100:"s"===e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof w.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"===this.unit?~~(1e8*this.value)/1e6:"s"===this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new w.Number(t),new w.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new w.Number(t),new w.Number(this-t,this.unit||t.unit)},times:function(t){return t=new w.Number(t),new w.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new w.Number(t),new w.Number(this/t,this.unit||t.unit)},to:function(t){var e=new w.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new w.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new w.Number(this.destination).minus(this).times(t).plus(this):this}}}),w.HtmlNode=w.invent({create:function(t){this.node=t},extend:{add:function(t,e){return t=n(t),t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t}}}),w.Element=w.invent({create:function(t){this.events={},this.dom={},this.node=t,this.node&&(this.type=t.nodeName,this.node.instance=this,this.events=t.events||{},t.hasAttribute("svgjs:data")&&this.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}))},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var n=d(this,t,e);return this.width(new w.Number(n.width)).height(new w.Number(n.height))},clone:function(t){this.writeDataToDom();var e=x(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return n(t).put(this)},putIn:function(t){return n(t).add(this)},id:function(t){return void 0!==t||this.node.id||(this.node.id=w.eid(this.type)),this.attr("id",t)},inside:function(t,e){var n=this.bbox();return t>n.x&&e>n.y&&t<n.x+n.width&&e<n.y+n.height},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!==this.css("display")},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(w.regex.delimiter)},hasClass:function(t){return-1!==this.classes().indexOf(t)},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!==t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return w.get(this.attr(t))},parent:function(e){var n=this;if(!n.node.parentNode)return null;if(n=w.adopt(n.node.parentNode),!e)return n;for(;n&&n.node instanceof t.SVGElement;){if("string"==typeof e?n.matches(e):n instanceof e)return n;n=w.adopt(n.node.parentNode)}},doc:function(){var t=this.parent(w.Doc);return t&&t.doc()},defs:function(){return this.doc().defs()},parents:function(t){var e=[],n=this;do{if(!(n=n.parent(t))||!n.node)break;e.push(n)}while(n.parent);return e},matches:function(t){return h(this.node,t)},native:function(){return this.node},svg:function(t){var n,i;if(!(t&&this instanceof w.Parent))return this.writeDataToDom(),this.node.outerHTML;for(n=e.createElementNS(w.ns,"svg"),n.innerHTML=t,i=n.children.length;i--;)this.node.appendChild(n.firstElementChild);return this},writeDataToDom:function(){return this.is(w.Parent)&&this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return a(this,t)}}}),w.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)}},w.morph=function(t){return function(e,n){return new w.MorphObj(e,n).at(t)}},w.Situation=w.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new w.Number(t.duration).valueOf(),this.delay=new w.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),w.FX=w.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,n){"object"==typeof t&&(e=t.ease,n=t.delay,t=t.duration);var i=new w.Situation({duration:t||1e3,delay:n||0,ease:w.easing[e||"-"]||e});return this.queue(i),this},delay:function(t){var e=new w.Situation({duration:t,delay:0,ease:w.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof w.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof w.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof w.Situation?this.start():this.situation(this)),this},initAnimations:function(){var t,e,n,i=this.situation;if(i.init)return this;for(t in i.animations)for(n=this.target()[t](),Array.isArray(n)||(n=[n]),Array.isArray(i.animations[t])||(i.animations[t]=[i.animations[t]]),e=n.length;e--;)i.animations[t][e]instanceof w.Number&&(n[e]=new w.Number(n[e])),i.animations[t][e]=n[e].morph(i.animations[t][e]);for(t in i.attrs)i.attrs[t]=new w.MorphObj(this.target().attr(t),i.attrs[t]);for(t in i.styles)i.styles[t]=new w.MorphObj(this.target().css(t),i.styles[t]);return i.initialTransformation=this.target().matrixify(),i.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var n=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!n&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return!0===this.situation.loops&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var n=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*n,this.situation.finish=this.situation.start+n,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var n=this.last();return n.loops=null==t||t,n.loop=0,e&&(n.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return e.reversed=void 0===t?!e.reversed:t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){function e(i){i.detail.situation===n&&(t.call(this,n),this.off("finished.fx",e))}var n=this.last();return this.target().on("finished.fx",e),this._callStart()},during:function(t){function e(e){e.detail.situation===n&&t.call(this,e.detail.pos,w.morph(e.detail.pos),e.detail.eased,n)}var n=this.last();return this.target().off("during.fx",e).on("during.fx",e),this.after(function(){this.off("during.fx",e)}),this._callStart()},afterAll:function(t){var e=function e(n){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,w.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,n){return this.last()[n||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),!1!==this.situation.loops){var e,n,i;e=Math.max(this.absPos,0),n=Math.floor(e),!0===this.situation.loops||n<this.situation.loops?(this.pos=e-n,i=this.situation.loop,this.situation.loop=n):(this.absPos=this.situation.loops,this.pos=1,i=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!==Boolean((this.situation.loop-i)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1===this.pos&&!this.situation.reversed||this.situation.reversed&&0===this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.situations.length||(this.target().off(".fx"),this.active=!1)),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,n=this,i=this.target(),r=this.situation;for(t in r.animations)e=[].concat(r.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(n.pos),n.pos):t}),i[t].apply(i,e);for(t in r.attrs)e=[t].concat(r.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(n.pos),n.pos):t}),i.attr.apply(i,e);for(t in r.styles)e=[t].concat(r.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(n.pos),n.pos):t}),i.css.apply(i,e);return r.transforms.length,this},once:function(t,e,n){var i=this.last();return n||(t=i.ease(t)),i.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:w.Element,construct:{animate:function(t,e,n){return(this.fx||(this.fx=new w.FX(this))).animate(t,e,n)},delay:function(t){return(this.fx||(this.fx=new w.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),w.MorphObj=w.invent({create:function(t,e){return w.Color.isColor(e)?new w.Color(t).morph(e):w.regex.delimiter.test(t)?new w.Array(t).morph(e):w.regex.numberAndUnit.test(e)?new w.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),w.extend(w.FX,{attr:function(t,e,n){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.add(t,e,"attrs");return this},css:function(t,e){if("object"==typeof t)for(var n in t)this.css(n,t[n]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof w.G)return this.transform({x:t},e),this;var n=new w.Number(t);return n.relative=e,this.add("x",n)},y:function(t,e){if(this.target()instanceof w.G)return this.transform({y:t},e),this;var n=new w.Number(t);return n.relative=e,this.add("y",n)},cx:function(t){return this.add("cx",new w.Number(t))},cy:function(t){return this.add("cy",new w.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof w.Text)this.attr("font-size",t);else{var n;t&&e||(n=this.target().bbox()),t||(t=n.width/n.height*e),e||(e=n.height/n.width*t),this.add("width",new w.Number(t)).add("height",new w.Number(e))}return this},width:function(t){return this.add("width",new w.Number(t))},height:function(t){return this.add("height",new w.Number(t))},plot:function(t,e,n,i){return 4===arguments.length?this.plot([t,e,n,i]):this.add("plot",new(this.target().MorphArray)(t))},leading:function(t){return this.target().leading?this.add("leading",new w.Number(t)):this},viewbox:function(t,e,n,i){return this.target()instanceof w.Container&&this.add("viewbox",new w.Box(t,e,n,i)),this},update:function(t){if(this.target()instanceof w.Stop){if("number"==typeof t||t instanceof w.Number)return this.update({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",t.offset)}return this}}),w.Matrix=w.invent({create:function(t){var e,n=p([1,0,0,1,0,0]);for(t=t instanceof w.Element?t.matrixify():"string"==typeof t?p(t.split(w.regex.delimiter).map(parseFloat)):Array.isArray(t)?p(t):"object"==typeof t?t:6===arguments.length?p([].slice.call(arguments)):n,e=M.length-1;e>=0;--e)this[M[e]]=null!=t[M[e]]?t[M[e]]:n[M[e]]},extend:{clone:function(){return new w.Matrix(this)},transform:function(t){var e=!t.flip||"x"!==t.flip&&"both"!==t.flip?1:-1,n=!t.flip||"y"!==t.flip&&"both"!==t.flip?1:-1,i=t.skew&&t.skew.length?t.skew[0]:isFinite(t.skew)?t.skew:isFinite(t.skewX)?t.skewX:0,r=t.skew&&t.skew.length?t.skew[1]:isFinite(t.skew)?t.skew:isFinite(t.skewY)?t.skewY:0,s=t.scale&&t.scale.length?t.scale[0]*e:isFinite(t.scale)?t.scale*e:isFinite(t.scaleX)?t.scaleX*e:e,o=t.scale&&t.scale.length?t.scale[1]*n:isFinite(t.scale)?t.scale*n:isFinite(t.scaleY)?t.scaleY*n:n,a=t.shear||0,h=t.rotate||0,u=new w.Point(null==t.ox?t.origin:t.ox,t.oy),l=u.x,c=u.y,f=new w.Point(null==t.px?t.position:t.px,t.py,{x:null,y:null}),d=f.x,p=f.y,m=new w.Point(null==t.tx?t.translate:t.tx,t.ty),x=m.x,v=m.y,y=new w.Point(null==t.rx?t.relative:t.rx,t.ry),g=y.x,b=y.y,P=new w.Matrix(this),A=(new w.Matrix).translate(-l,-c).scale(s,o).skew(i,r).shear(a).rotate(h).translate(l,c).translate(g,b).lmultiply(P);if(isFinite(d)||isFinite(p)){var C=new w.Point(l-g,c-b).transform(A),N=d?d-C.x:0,M=p?p-C.y:0;A=A.translate(N,M)}return A=A.translate(x,v)},compose:function(t){var e=t.scaleX||1,n=t.scaleY||1,i=t.shear||0,r=t.rotate||0,s=t.translateX||0,o=t.translateY||0;return(new w.Matrix).scale(e,n).shear(i).rotate(r).translate(s,o).lmultiply(this)},decompose:function(){var t=this.a,e=this.b,n=this.c,i=this.d,r=this.e,s=this.f,o=t*i-e*n,a=o>0?1:-1,h=a*Math.sqrt(t*t+e*e),u=180/Math.PI*Math.atan2(a*e,a*t),l=(t*n+e*i)/o;return{scaleX:h,scaleY:n*h/(l*t-e)||i*h/(l*e+t),shear:l,rotate:u,translateX:r,translateY:s,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}},morph:function(t){return this.destination=new w.Matrix(t),this},at:function(t){return this.destination?new w.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t}):this},multiply:function(t){var e=this,n=new w.Matrix(t),i=e.a*n.a+e.c*n.b,r=e.b*n.a+e.d*n.b,s=e.a*n.c+e.c*n.d,o=e.b*n.c+e.d*n.d,a=e.e+e.a*n.e+e.c*n.f,h=e.f+e.b*n.e+e.d*n.f;return new w.Matrix(i,r,s,o,a,h)},lmultiply:function(t){return new w.Matrix(t).multiply(this)},inverse:function(){return new w.Matrix(this.native().inverse())},translate:function(t,e){var n=new w.Matrix(this);return n.e+=t||0,n.f+=e||0,n},scale:function(t,e,n,i){1===arguments.length?e=t:3===arguments.length&&(i=n,n=e,e=t);var r=new w.Matrix(t,0,0,e,0,0);return this.around(n,i,r)},rotate:function(t,e,n){t=w.utils.radians(t);var i=new w.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0);return this.around(e,n,i)},flip:function(t,e){return"x"===t?this.scale(-1,1,e,0):"y"===t?this.scale(1,-1,0,e):this.scale(-1,-1,t,e||t)},shear:function(t,e,n){var i=new w.Matrix(1,0,t,1,0,0);return this.around(e,n,i)},skew:function(t,e,n,i){1===arguments.length?e=t:3===arguments.length&&(i=n,n=e,e=t),t=w.utils.radians(t),e=w.utils.radians(e);var r=new w.Matrix(1,Math.tan(e),Math.tan(t),1,0,0);return this.around(n,i,r)},skewX:function(t,e,n){return this.skew(t,0,e,n)},skewY:function(t,e,n){return this.skew(0,t,e,n)},around:function(t,e,n){var i=t||0,r=e||0;return this.translate(-i,-r).lmultiply(n).translate(i,r)},native:function(){for(var t=w.parser.nodes.svg.node.createSVGMatrix(),e=M.length-1;e>=0;e--)t[M[e]]=this[M[e]];return t},equals:function(t){var e=new w.Matrix(t);return g(this.a,e.a)&&g(this.b,e.b)&&g(this.c,e.c)&&g(this.d,e.d)&&g(this.e,e.e)&&g(this.f,e.f)},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:w.Element,construct:{ctm:function(){return new w.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof w.Doc&&!this.isRoot()){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new w.Matrix(e)}return new w.Matrix(this.node.getScreenCTM())}}}),w.Point=w.invent({create:function(t,e,n){var i;n=n||{x:0,y:0},i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof 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},extend:{clone:function(){return new w.Point(this)},morph:function(t,e){return this.destination=new w.Point(t,e),this},at:function(t){return this.destination?new w.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t}):this},native:function(){var t=w.parser.nodes.svg.node.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new w.Point(this.native().matrixTransform(t.native()))}}}),w.extend(w.Element,{point:function(t,e){return new w.Point(t,e).transform(this.screenCTM().inverse())}}),w.extend(w.Element,{attr:function(t,e,n){if(null==t){for(t={}, -e=this.node.attributes,n=e.length-1;n>=0;n--)t[e[n].nodeName]=w.regex.isNumber.test(e[n].nodeValue)?parseFloat(e[n].nodeValue):e[n].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?w.defaults.attrs[t]:w.regex.isNumber.test(e)?parseFloat(e):e;"fill"!==t&&"stroke"!==t||(w.regex.isImage.test(e)&&(e=this.doc().defs().image(e)),e instanceof w.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new w.Number(e):w.Color.isColor(e)?e=new w.Color(e):Array.isArray(e)&&(e=new w.Array(e)),"leading"===t?this.leading&&this.leading(e):"string"==typeof n?this.node.setAttributeNS(n,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!==t&&"x"!==t||this.rebuild(t,e)}return this}}),w.extend(w.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(w.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(w.regex.delimiter).map(function(t){return parseFloat(t)})]}).reverse().reduce(function(t,e){return"matrix"===e[0]?t.lmultiply(p(e[1])):t[e[0]].apply(t,e[1])},new w.Matrix)},toParent:function(t){if(this===t)return this;var e=this.screenCTM(),n=t.screenCTM().inverse();return this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),w.extend(w.Element,{transform:function(t,e){var n=this.bbox();if(null==t||"string"==typeof t){var i=new w.Matrix(this).decompose();return i[t]||i}if(null!=t.a){var r=new w.Matrix(t);if(null!=e){var s=new w.Matrix(this);r=r.multiply(s)}return this.attr("transform",r)}if("string"==typeof t.origin||null==t.origin&&null==t.ox&&null==t.oy){var o="string"==typeof t.origin?t.origin.toLowerCase().trim():"center",a=n.height,h=n.width,u=n.x,l=n.y;t.ox=o.includes("left")?u:o.includes("right")?u+h:u+h/2,t.oy=o.includes("top")?l:o.includes("bottom")?l+a:l+a/2,t.origin=null}var c=new w.Matrix(!0===e?this:e).transform(t);return this.attr("transform",c)}}),w.extend(w.FX,{transform:function(t,e){}}),w.extend(w.Element,{css:function(t,e){var n,i,r={};if(0===arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){n=t.split(/\s*:\s*/),r[n[0]]=n[1]}),r;if(arguments.length<2){if(Array.isArray(t)){for(i=t.length;i--;)r[u(t[i])]=this.node.style[u(t[i])];return r}if("string"==typeof t)return this.node.style[u(t)];if("object"==typeof t)for(i in t)this.node.style[u(i)]=null==t[i]||w.regex.isBlank.test(t[i])?"":t[i]}return 2===arguments.length&&(this.node.style[u(t)]=null==e||w.regex.isBlank.test(e)?"":e),this}}),w.Parent=w.invent({create:function(t){this.constructor(t)},inherit:w.Element,extend:{children:function(){return w.utils.map(this.node.children,function(t){return w.adopt(t)})},add:function(t,e){return t=n(t),t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t.instance||t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.children).indexOf(t.node)},get:function(t){return w.adopt(this.node.children[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.children.length-1)},each:function(t,e){var n,i,r=this.children();for(n=0,i=r.length;n<i;n++)r[n]instanceof w.Element&&t.apply(r[n],[n,r]),e&&r[n]instanceof w.Parent&&r[n].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this}}}),w.extend(w.Parent,{flatten:function(t){return this instanceof w.G||this instanceof w.Doc?(t=t||(this instanceof w.Doc&&this.isRoot()?this:this.parent(w.Parent)),this.each(function(){return this instanceof w.Defs?this:this instanceof w.Parent?this.flatten(t):this.toParent(t)}),this.node.firstElementChild||this.remove(),this):this},ungroup:function(t){return this instanceof w.G||this instanceof w.Doc&&!this.isRoot()?(t=t||this.parent(w.Parent),this.each(function(){return this.toParent(t)}),this.remove(),this):this}}),w.Container=w.invent({create:function(t){this.constructor(t)},inherit:w.Parent}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){w.Element.prototype[t]=function(e){return w.on(this,t,e),this}}),w.listenerId=0,w.on=function(t,e,n,i,r){var s=n.bind(i||t),o=t instanceof w.Element?t.node:t;o.instance=o.instance||{events:{}};var a=o.instance.events;n._svgjsListenerId||(n._svgjsListenerId=++w.listenerId),e.split(w.regex.delimiter).forEach(function(t){var e=t.split(".")[0],i=t.split(".")[1]||"*";a[e]=a[e]||{},a[e][i]=a[e][i]||{},a[e][i][n._svgjsListenerId]=s,o.addEventListener(e,s,r||!1)})},w.off=function(t,e,n,i){var r=t instanceof w.Element?t.node:t;if(r.instance&&("function"!=typeof n||(n=n._svgjsListenerId))){var s=r.instance.events;(e||"").split(w.regex.delimiter).forEach(function(t){var e,o,a=t&&t.split(".")[0],h=t&&t.split(".")[1];if(n)s[a]&&s[a][h||"*"]&&(r.removeEventListener(a,s[a][h||"*"][n],i||!1),delete s[a][h||"*"][n]);else if(a&&h){if(s[a]&&s[a][h]){for(o in s[a][h])w.off(r,[a,h].join("."),o);delete s[a][h]}}else if(h)for(t in s)for(e in s[t])h===e&&w.off(r,[t,h].join("."));else if(a){if(s[a]){for(e in s[a])w.off(r,[a,e].join("."));delete s[a]}}else{for(t in s)w.off(r,t);r.instance.events={}}})}},w.extend(w.Element,{on:function(t,e,n,i){return w.on(this,t,e,n,i),this},off:function(t,e){return w.off(this.node,t,e),this},dispatch:function(e,n){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:n,cancelable:!0})),e},fire:function(t,e){return this.dispatch(t,e),this}}),w.Defs=w.invent({create:"defs",inherit:w.Container}),w.G=w.invent({create:"g",inherit:w.Container,extend:{},construct:{group:function(){return this.put(new w.G)}}}),w.extend(w.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},prev:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof w.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof w.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),w.Mask=w.invent({create:"mask",inherit:w.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unmask()}),w.Element.prototype.remove.call(this)},targets:function(){return w.select('svg [mask*="'+this.id()+'"]')}},construct:{mask:function(){return this.defs().put(new w.Mask)}}}),w.extend(w.Element,{maskWith:function(t){var e=t instanceof w.Mask?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}),w.ClipPath=w.invent({create:"clipPath",inherit:w.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unclip()}),w.Element.prototype.remove.call(this)},targets:function(){return w.select('svg [clip-path*="'+this.id()+'"]')}},construct:{clip:function(){return this.defs().put(new w.ClipPath)}}}),w.extend(w.Element,{clipWith:function(t){var e=t instanceof w.ClipPath?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}),w.Gradient=w.invent({create:function(t){this.constructor("object"==typeof t?t:w.create(t+"Gradient"))},inherit:w.Container,extend:{stop:function(t,e,n){return this.put(new w.Stop).update(t,e,n)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},url:function(){return"url(#"+this.id()+")"},toString:function(){return this.url()},attr:function(t,e,n){return"transform"===t&&(t="gradientTransform"),w.Container.prototype.attr.call(this,t,e,n)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),w.extend([w.Gradient,w.FX],{from:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({fx:new w.Number(t),fy:new w.Number(e)}):this.attr({x1:new w.Number(t),y1:new w.Number(e)})},to:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({cx:new w.Number(t),cy:new w.Number(e)}):this.attr({x2:new w.Number(t),y2:new w.Number(e)})}}),w.extend(w.Defs,{gradient:function(t,e){return this.put(new w.Gradient(t)).update(e)}}),w.Stop=w.invent({create:"stop",inherit:w.Element,extend:{update:function(t){return("number"==typeof t||t instanceof w.Number)&&(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 w.Number(t.offset)),this}}}),w.Pattern=w.invent({create:"pattern",inherit:w.Container,extend:{url:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.url()},attr:function(t,e,n){return"transform"===t&&(t="patternTransform"),w.Container.prototype.attr.call(this,t,e,n)}},construct:{pattern:function(t,e,n){return this.defs().pattern(t,e,n)}}}),w.extend(w.Defs,{pattern:function(t,e,n){return this.put(new w.Pattern).update(n).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),w.Doc=w.invent({create:function(t){this.constructor(t||w.create("svg")),this.namespace()},inherit:w.Container,extend:{isRoot:function(){return!(this.node.parentNode&&this.node.parentNode instanceof t.SVGElement&&"#document"!==this.node.parentNode.nodeName)},doc:function(){return this.isRoot()?this:w.Element.prototype.doc.call(this)},namespace:function(){return this.isRoot()?this.attr({xmlns:w.ns,version:"1.1"}).attr("xmlns:xlink",w.xlink,w.xmlns).attr("xmlns:svgjs",w.svgjs,w.xmlns):this.doc().namespace()},defs:function(){return this.isRoot()?w.adopt(this.node.getElementsByTagName("defs")[0])||this.put(new w.Defs):this.doc().defs()},parent:function(t){return this.isRoot()?"#document"===this.node.parentNode.nodeName?null:this.node.parentNode:w.Element.prototype.parent.call(this,t)},remove:function(){return this.isRoot()?(this.parent()&&this.parent().removeChild(this.node),this):w.Element.prototype.remove.call(this)},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this}},construct:{nested:function(){return this.put(new w.Doc)}}}),w.Shape=w.invent({create:function(t){this.constructor(t)},inherit:w.Element}),w.Bare=w.invent({create:function(t,e){if(this.constructor(w.create(t)),e)for(var n in e.prototype)"function"==typeof e.prototype[n]&&(this[n]=e.prototype[n])},inherit:w.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),w.extend(w.Parent,{element:function(t,e){return this.put(new w.Bare(t,e))}}),w.Symbol=w.invent({create:"symbol",inherit:w.Container,construct:{symbol:function(){return this.put(new w.Symbol)}}}),w.Use=w.invent({create:"use",inherit:w.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,w.xlink)}},construct:{use:function(t,e){return this.put(new w.Use).element(t,e)}}}),w.Rect=w.invent({create:"rect",inherit:w.Shape,construct:{rect:function(t,e){return this.put(new w.Rect).size(t,e)}}}),w.Circle=w.invent({create:"circle",inherit:w.Shape,construct:{circle:function(t){return this.put(new w.Circle).rx(new w.Number(t).divide(2)).move(0,0)}}}),w.extend([w.Circle,w.FX],{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),w.Ellipse=w.invent({create:"ellipse",inherit:w.Shape,construct:{ellipse:function(t,e){return this.put(new w.Ellipse).size(t,e).move(0,0)}}}),w.extend([w.Ellipse,w.Rect,w.FX],{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),w.extend([w.Circle,w.Ellipse],{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new w.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new w.Number(t).divide(2))},size:function(t,e){var n=d(this,t,e);return this.rx(new w.Number(n.width).divide(2)).ry(new w.Number(n.height).divide(2))}}),w.Line=w.invent({create:"line",inherit:w.Shape,extend:{array:function(){return new w.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,n,i){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:n,y2:i}:new w.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var n=d(this,t,e);return this.attr(this.array().size(n.width,n.height).toLine())}},construct:{line:function(t,e,n,i){return w.Line.prototype.plot.apply(this.put(new w.Line),null!=t?[t,e,n,i]:[0,0,0,0])}}}),w.Polyline=w.invent({create:"polyline",inherit:w.Shape,construct:{polyline:function(t){return this.put(new w.Polyline).plot(t||new w.PointArray)}}}),w.Polygon=w.invent({create:"polygon",inherit:w.Shape,construct:{polygon:function(t){return this.put(new w.Polygon).plot(t||new w.PointArray)}}}),w.extend([w.Polyline,w.Polygon],{array:function(){return this._array||(this._array=new w.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new w.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var n=d(this,t,e);return this.attr("points",this.array().size(n.width,n.height))}}),w.extend([w.Line,w.Polyline,w.Polygon],{MorphArray:w.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),w.Path=w.invent({create:"path",inherit:w.Shape,extend:{MorphArray:w.PathArray,array:function(){return this._array||(this._array=new w.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new w.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var n=d(this,t,e);return this.attr("d",this.array().size(n.width,n.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new w.Path).plot(t||new w.PathArray)}}}),w.Image=w.invent({create:"image",inherit:w.Shape,extend:{load:function(e,n){if(!e)return this;var i=new t.Image;return w.on(i,"load",function(t){var r=this.parent(w.Pattern);0===this.width()&&0===this.height()&&this.size(i.width,i.height),r instanceof w.Pattern&&0===r.width()&&0===r.height()&&r.size(this.width(),this.height()),"function"==typeof n&&n.call(this,{width:i.width,height:i.height,ratio:i.width/i.height,url:e})},this),w.on(i,"load error",function(){w.off(i)}),this.attr("href",i.src=e,w.xlink)}},construct:{image:function(t,e){return this.put(new w.Image).size(0,0).load(t,e)}}}),w.Text=w.invent({create:function(t){this.constructor(t||w.create("text")),this.dom.leading=new w.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",w.defaults.attrs["font-family"])},inherit:w.Parent,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),n="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-n:e:this.attr("y","number"==typeof t?t+n:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if(void 0===t){var e=this.node.childNodes,n=0;t="";for(var i=0,r=e.length;i<r;++i)"textPath"!==e[i].nodeName?(i!==n&&3!==e[i].nodeType&&!0===w.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent):0===i&&(n=1);return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var s=0,o=t.length;s<o;s++)this.tspan(t[s]).newLine()}return this.build(!1).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new w.Number(t),this.rebuild())},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,n=0,i=this.dom.leading*new w.Number(this.attr("font-size"));this.each(function(){this.dom.newLined&&(this.attr("x",e.attr("x")),"\n"===this.text()?n+=i:(this.attr("dy",i+n),n=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new w.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new w.Text).text(t)},plain:function(t){return this.put(new w.Text).plain(t)}}}),w.Tspan=w.invent({create:"tspan",inherit:w.Parent,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(w.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),w.extend([w.Text,w.Tspan],{plain:function(t){return!1===this._build&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=new w.Tspan;return this._build||this.clear(),this.node.appendChild(e.node),e.text(t)},length:function(){return this.node.getComputedTextLength()}}),w.TextPath=w.invent({create:"textPath",inherit:w.Text,parent:w.Parent,extend:{MorphArray:w.PathArray,array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),n=null;return e&&(n=e.plot(t)),null==t?n:this},track:function(){return this.reference("href")}},construct:{textPath:function(t,e){return this.defs().path(e).text(t).addTo(this)}}}),w.extend([w.Text],{path:function(t){var e=new w.TextPath;return t instanceof w.Path||(t=this.doc().defs().path(t)),e.attr("href","#"+t,w.xlink),this.put(e)},textPath:function(){return this.select("textPath")}}),w.extend([w.Path],{text:function(t){if(t instanceof w.Text){var e=t.text();return t.clear().path(this).text(e)}return this.parent().put(new w.Text).path(this).text(t)}}),w.A=w.invent({create:"a",inherit:w.Container,extend:{to:function(t){return this.attr("href",t,w.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new w.A).to(t)}}}),w.extend(w.Element,{linkTo:function(t){var e=new w.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),w.Marker=w.invent({create:"marker",inherit:w.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,n){return this.defs().marker(t,e,n)}}}),w.extend(w.Defs,{marker:function(t,e,n){return this.put(new w.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(n)}}),w.extend([w.Line,w.Polyline,w.Polygon,w.Path],{marker:function(t,e,n,i){var r=["marker"];return"all"!==t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof w.Marker?arguments[1]:this.doc().marker(e,n,i),this.attr(r,t)}});var N={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"===e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,n={};n[t]=function(n){if(void 0===n)return this;if("string"==typeof n||w.Color.isRgb(n)||n&&"function"==typeof n.fill)this.attr(t,n);else for(e=N[t].length-1;e>=0;e--)null!=n[N[t][e]]&&this.attr(N.prefix(t,N[t][e]),n[N[t][e]]);return this},w.extend([w.Element,w.FX],n)}),w.extend([w.Element,w.FX],{matrix:function(t,e,n,i,r,s){return null==t?new w.Matrix(this):this.attr("transform",new w.Matrix(t,e,n,i,r,s))},rotate:function(t,e,n){return this.transform({rotate:t,ox:e,oy:n},!0)},skew:function(t,e,n,i){return 1===arguments.length||3===arguments.length?this.transform({skew:t,ox:e,oy:n},!0):this.transform({skew:[t,e],ox:n,oy:i},!0)},shear:function(t,e,n){return this.transform({shear:t,ox:e,oy:n},!0)},scale:function(t,e,n,i){return 1===arguments.length||3===arguments.length?this.transform({scale:t,ox:e,oy:n},!0):this.transform({scale:[t,e],ox:n,oy:i},!0)},translate:function(t,e){return this.transform({translate:[t,e]},!0)},relative:function(t,e){return this.transform({relative:[t,e]},!0)},flip:function(t,e){var n="string"==typeof t?t:(isFinite(t),"both"),i="both"===t&&isFinite(e)?[e,e]:"x"===t?[e,0]:"y"===t?[0,e]:isFinite(t)?[t,t]:[0,0];this.transform({flip:n,origin:i},!0)},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new w.Number(t).plus(this instanceof w.FX?0:this.x()),!0)},dy:function(t){return this.y(new w.Number(t).plus(this instanceof w.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),w.extend([w.Rect,w.Ellipse,w.Circle,w.Gradient,w.FX],{radius:function(t,e){var n=(this._target||this).type;return"radialGradient"===n||"radialGradient"===n?this.attr("r",new w.Number(t)):this.rx(t).ry(null==e?t:e)}}),w.extend(w.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return new w.Point(this.node.getPointAtLength(t))}}),w.extend([w.Parent,w.Text,w.Tspan,w.FX],{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"===t?this.leading(e):"anchor"===t?this.attr("text-anchor",e):"size"===t||"family"===t||"weight"===t||"stretch"===t||"variant"===t||"style"===t?this.attr("font-"+t,e):this.attr(t,e)}}),w.extend(w.Element,{data:function(t,e,n){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:!0===n||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),w.extend(w.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var n in t)this.remember(n,t[n]);else{if(1===arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0===arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),w.get=function(t){var n=e.getElementById(y(t)||t);return w.adopt(n)},w.select=function(t,n){return w.utils.map((n||e).querySelectorAll(t),function(t){return w.adopt(t)})},w.$$=function(t,n){return w.utils.map((n||e).querySelectorAll(t),function(t){return w.adopt(t)})},w.$=function(t,n){return w.adopt((n||e).querySelector(t))},w.extend(w.Parent,{select:function(t){return w.select(t,this.node)}});var M="abcdef".split("");return w.Box=w.invent({create:function(t){var e=[0,0,0,0];t="string"==typeof t?t.split(w.regex.delimiter).map(parseFloat):Array.isArray(t)?t:"object"==typeof 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):e,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],v(this)},extend:{merge:function(t){var e=Math.min(this.x,t.x),n=Math.min(this.y,t.y);return new w.Box(e,n,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-n)},transform:function(t){var e=1/0,n=-1/0,i=1/0,r=-1/0;return[new w.Point(this.x,this.y),new w.Point(this.x2,this.y),new w.Point(this.x,this.y2),new w.Point(this.x2,this.y2)].forEach(function(s){s=s.transform(t),e=Math.min(e,s.x),n=Math.max(n,s.x),i=Math.min(i,s.y),r=Math.max(r,s.y)}),new w.Box(e,i,n-e,r-i)},addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this},toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,n,i){return this.destination=new w.Box(t,e,n,i),this},at:function(t){return this.destination?new w.Box(this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t):this}},parent:w.Element,construct:{bbox:function(){var t;try{if(t=this.node.getBBox(),i(t)&&!r(this.node))throw new Exception("Element not in the dom")}catch(n){try{var e=this.clone(w.parser().svg).show();t=e.node.getBBox(),e.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return new w.Box(t)},rbox:function(t){try{var e=new w.Box(this.node.getBoundingClientRect());return t?e.transform(t.screenCTM().inverse()):e.addOffset()}catch(t){return new w.Box}}}}),w.extend([w.Doc,w.Symbol,w.Image,w.Pattern,w.Marker,w.ForeignObject,w.View],{viewbox:function(t,e,n,i){return null==t?new w.Box(this.attr("viewBox")):this.attr("viewBox",new w.Box(t,e,n,i))}}),w.parser=function(){var t;return w.parser.nodes.svg.node.parentNode||(t=e.body||e.documentElement,w.parser.nodes.svg.addTo(t)),w.parser.nodes},w.parser.nodes={svg:w().size(2,0).css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"})},w.parser.nodes.path=w.parser.nodes.svg.path().node,w});
\ No newline at end of file +/*! svg.js v3.0.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function i(t,i){if(t instanceof w.Element)return t;if("object"==typeof t)return w.adopt(t);if(null==t)return new w.Doc;if("string"==typeof t&&"<"!==t.charAt(0))return w.adopt(e.querySelector(t));var n=w.create("svg");return n.innerHTML=t,t=w.adopt(n.firstElementChild)}function n(t){return!(t.w||t.h||t.x||t.y)}function r(t){return(e.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t===e}).call(e.documentElement,t)}function s(t,e,i,n){return i+n.replace(w.regex.dots," .")}function o(t){for(var e=t.slice(0),i=e.length;i--;)Array.isArray(e[i])&&(e[i]=o(e[i]));return e}function a(t,e){return t instanceof e}function h(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function u(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function l(t){return t.charAt(0).toUpperCase()+t.slice(1)}function c(t){return 4===t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function f(t){var e=t.toString(16);return 1===e.length?"0"+e:e}function d(t,e,i){if(null==e||null==i){var n=t.bbox();null==e?e=n.width/n.height*i:null==i&&(i=n.height/n.width*e)}return{width:e,height:i}}function p(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function m(t){for(var e=0,i=t.length,n="";e<i;e++)n+=t[e][0],null!=t[e][1]&&(n+=t[e][1],null!=t[e][2]&&(n+=" ",n+=t[e][2],null!=t[e][3]&&(n+=" ",n+=t[e][3],n+=" ",n+=t[e][4],null!=t[e][5]&&(n+=" ",n+=t[e][5],n+=" ",n+=t[e][6],null!=t[e][7]&&(n+=" ",n+=t[e][7])))));return n+" "}function v(t){for(var e=t.children.length-1;e>=0;e--)v(t.children[e]);return t.id?w.adopt(t).id(w.eid(t.nodeName)):w.adopt(t)}function x(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function y(t){var e=(t||"").toString().match(w.regex.reference);if(e)return e[1]}function g(t,e,i){return Math.abs(e-t)<(i||1e-6)}if(!e.createElementNS||!e.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect)return{supported:!1};var w=this.SVG=function(t){if(w.supported)return t=i(t)};w.supported=!0,w.ns="http://www.w3.org/2000/svg",w.xmlns="http://www.w3.org/2000/xmlns/",w.xlink="http://www.w3.org/1999/xlink",w.svgjs="http://svgjs.com/svgjs",w.did=1e3,w.eid=function(t){return"Svgjs"+l(t)+w.did++},w.create=function(t){return e.createElementNS(this.ns,t)},w.extend=function(t,e){var i,n;for(t=Array.isArray(t)?t:[t],n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i]},w.invent=function(t){var e="function"==typeof t.create?t.create:function(e){this.constructor(e||w.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&w.extend(e,t.extend),t.construct&&w.extend(t.parent||w.Container,t.construct),e},w.adopt=function(e){if(!e)return null;if(e.instance instanceof w.Element)return e.instance;if(!(e instanceof t.SVGElement))return new w.HtmlNode(e);return"svg"===e.nodeName?new w.Doc(e):"linearGradient"===e.nodeName||"radialGradient"===e.nodeName?new w.Gradient(e):w[l(e.nodeName)]?new(w[l(e.nodeName)])(e):new w.Parent(e)},w.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},w.utils={map:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)r.push(e(t[i]));return r},filter:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)e(t[i])&&r.push(t[i]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},w.defaults={attrs:{"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"}},w.Queue=w.invent({create:function(){this._first=null,this._last=null,this.length=0,this.id=0},extend:{push:function(t){var e={id:this.id++,value:t};this._last?this._last=this._last.next=e:this._last=this._first=e,this.length++},shift:function(){if(0!=this.length){var t=this._first;return this._first=t.next,this._last=--this.length?this._last:null,t.value}},first:function(){return this._first&&this._first.value},last:function(){return this._last&&this._last.value},remove:function(t){for(var e=null,i=this._first;i&&!t(i);)e=i,i=i.next;if(i&&i===this._first&&(this._first=this._first.next),i&&i===this._last&&(this._last=e),i)return--this.length,e&&(e.next=i.next),i.item}}}),w.Draw={nextDraw:null,frames:new w.Queue,timeouts:new w.Queue,frameCount:0,timeoutCount:0,timer:t.performance||t.Date,frame:function(t){return w.Draw.frames.push({id:w.Draw.frameCount,run:t}),null===w.Draw.nextDraw&&(w.Draw.nextDraw=requestAnimationFrame(w.Draw._draw)),++w.Draw.frameCount},timeout:function(t,e){e=e||0;var i=w.Draw.timer.now()+e,n=w.Draw.timeoutCount++;return w.Draw.timeouts.push({id:n,run:t,time:i}),null===w.Draw.nextDraw&&(w.Draw.nextDraw=requestAnimationFrame(w.Draw._draw)),n},cancelTimeout:function(t){return w.Draw.timeouts.remove(function(e){return e.id==t})},_draw:function(t){for(var e=null,i=w.Draw.timeouts.last();(e=w.Draw.timeouts.shift())&&(t>e.time?e.run():w.Draw.timeouts.push(e),e!==i););for(var n=(w.Draw.frames.last(),w.Draw.frameCount);w.Draw.frames.first()&&w.Draw.frames.first().id<n;){w.Draw.frames.shift().run(t)}w.Draw.nextDraw=w.Draw.timeouts.length>0||w.Draw.frames.length>0?requestAnimationFrame(w.Draw._draw):null}},w.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?w.regex.isRgb.test(t)?(e=w.regex.rgb.exec(t.replace(w.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):w.regex.isHex.test(t)&&(e=w.regex.hex.exec(c(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},w.extend(w.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+f(this.r)+f(this.g)+f(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new w.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new w.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),w.Color.test=function(t){return t+="",w.regex.isHex.test(t)||w.regex.isRgb.test(t)},w.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},w.Color.isColor=function(t){return w.Color.isRgb(t)||w.Color.test(t)},w.Array=function(t,e){t=(t||[]).valueOf(),0===t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},w.extend(w.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!==this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)-1===i.indexOf(this.value[t])&&i.push(this.value[t]);return this.value=i,i},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new w.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(w.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=o(this.value),t}}),w.PointArray=function(t,e){w.Array.call(this,t,e||[[0,0]])},w.PointArray.prototype=new w.Array,w.PointArray.prototype.constructor=w.PointArray,w.extend(w.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.push(this.value[t].join(","));return i.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new w.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(w.regex.delimiter).map(parseFloat);t.length%2!=0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([t[i],t[i+1]]);return e},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)n.width&&(this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x),n.height&&(this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y);return this},bbox:function(){var t=-1/0,e=-1/0,i=1/0,n=1/0;return this.value.forEach(function(r){t=Math.max(r[0],t),e=Math.max(r[1],e),i=Math.min(r[0],i),n=Math.min(r[1],n)}),{x:i,y:n,width:t-i,height:e-n}}});for(var b={M:function(t,e,i){return e.x=i.x=t[0],e.y=i.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,i){return e.x=i.x,e.y=i.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},P="mlhvqtcsaz".split(""),A=0,C=P.length;A<C;++A)b[P[A]]=function(t){return function(e,i,n){if("H"===t)e[0]=e[0]+i.x;else if("V"===t)e[0]=e[0]+i.y;else if("A"===t)e[5]=e[5]+i.x,e[6]=e[6]+i.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?i.y:i.x);return b[t](e,i,n)}}(P[A].toUpperCase());w.PathArray=function(t,e){w.Array.call(this,t,e||[["M",0,0]])},w.PathArray.prototype=new w.Array,w.PathArray.prototype.constructor=w.PathArray,w.extend(w.PathArray,{toString:function(){return m(this.value)},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n,r=this.value.length-1;r>=0;r--)n=this.value[r][0],"M"===n||"L"===n||"T"===n?(this.value[r][1]+=t,this.value[r][2]+=e):"H"===n?this.value[r][1]+=t:"V"===n?this.value[r][1]+=e:"C"===n||"S"===n||"Q"===n?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"===n&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"===n&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var i,n,r=this.bbox();for(i=this.value.length-1;i>=0;i--)n=this.value[i][0],"M"===n||"L"===n||"T"===n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y):"H"===n?this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x:"V"===n?this.value[i][1]=(this.value[i][1]-r.y)*e/r.height+r.y:"C"===n||"S"===n||"Q"===n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y,this.value[i][3]=(this.value[i][3]-r.x)*t/r.width+r.x,this.value[i][4]=(this.value[i][4]-r.y)*e/r.height+r.y,"C"===n&&(this.value[i][5]=(this.value[i][5]-r.x)*t/r.width+r.x,this.value[i][6]=(this.value[i][6]-r.y)*e/r.height+r.y)):"A"===n&&(this.value[i][1]=this.value[i][1]*t/r.width,this.value[i][2]=this.value[i][2]*e/r.height,this.value[i][6]=(this.value[i][6]-r.x)*t/r.width+r.x,this.value[i][7]=(this.value[i][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,i,n;for(t=new w.PathArray(t),n=this.value.length===t.value.length,e=0,i=this.value.length;n&&e<i;e++)n=this.value[e][0]===t.value[e][0];return n},morph:function(t){return t=new w.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,i,n,r,s=this.value,o=this.destination.value,a=[],h=new w.PathArray;for(e=0,i=s.length;e<i;e++){for(a[e]=[s[e][0]],n=1,r=s[e].length;n<r;n++)a[e][n]=s[e][n]+(o[e][n]-s[e][n])*t;"A"===a[e][0]&&(a[e][4]=+(0!==a[e][4]),a[e][5]=+(0!==a[e][5]))}return h.value=a,h},parse:function(t){if(t instanceof w.PathArray)return t.valueOf();var e,i={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7,Z:0};t="string"==typeof t?t.replace(w.regex.numbersWithDots,s).replace(w.regex.pathLetters," $& ").replace(w.regex.hyphen,"$1 -").trim().split(w.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var n=[],r=new w.Point,o=new w.Point,a=0,h=t.length;do{w.regex.isPathLetter.test(t[a])?(e=t[a],++a):"M"===e?e="L":"m"===e&&(e="l"),n.push(b[e].call(null,t.slice(a,a+=i[e.toUpperCase()]).map(parseFloat),r,o))}while(h>a);return n},bbox:function(){return w.parser().path.setAttribute("d",this.toString()),w.parser.nodes.path.getBBox()}}),w.Number=w.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(w.regex.numberAndUnit))&&(this.value=parseFloat(e[1]),"%"===e[5]?this.value/=100:"s"===e[5]&&(this.value*=1e3),this.unit=e[5]):t instanceof w.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"===this.unit?~~(1e8*this.value)/1e6:"s"===this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new w.Number(t),new w.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new w.Number(t),new w.Number(this-t,this.unit||t.unit)},times:function(t){return t=new w.Number(t),new w.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new w.Number(t),new w.Number(this/t,this.unit||t.unit)},to:function(t){var e=new w.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new w.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new w.Number(this.destination).minus(this).times(t).plus(this):this}}}),w.HtmlNode=w.invent({create:function(t){this.node=t},extend:{add:function(t,e){return t=i(t),t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t}}}),w.Element=w.invent({create:function(t){this.events={},this.dom={},this.node=t,this.node&&(this.type=t.nodeName,this.node.instance=this,this.events=t.events||{},t.hasAttribute("svgjs:data")&&this.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}))},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=d(this,t,e);return this.width(new w.Number(i.width)).height(new w.Number(i.height))},clone:function(t){this.writeDataToDom();var e=v(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return i(t).put(this)},putIn:function(t){return i(t).add(this)},id:function(t){return void 0!==t||this.node.id||(this.node.id=w.eid(this.type)),this.attr("id",t)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&t<i.x+i.width&&e<i.y+i.height},show:function(){return this.css("display","")},hide:function(){return this.css("display","none")},visible:function(){return"none"!==this.css("display")},toString:function(){return this.id()},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(w.regex.delimiter)},hasClass:function(t){return-1!==this.classes().indexOf(t)},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!==t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return w.get(this.attr(t))},parent:function(e){var i=this;if(!i.node.parentNode)return null;if(i=w.adopt(i.node.parentNode),!e)return i;for(;i&&i.node instanceof t.SVGElement;){if("string"==typeof e?i.matches(e):i instanceof e)return i;i=w.adopt(i.node.parentNode)}},doc:function(){var t=this.parent(w.Doc);return t&&t.doc()},defs:function(){return this.doc().defs()},parents:function(t){var e=[],i=this;do{if(!(i=i.parent(t))||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return h(this.node,t)},native:function(){return this.node},svg:function(t){var i,n;if(!(t&&this instanceof w.Parent))return this.writeDataToDom(),this.node.outerHTML;for(i=e.createElementNS(w.ns,"svg"),i.innerHTML=t,n=i.children.length;n--;)this.node.appendChild(i.firstElementChild);return this},writeDataToDom:function(){return this.is(w.Parent)&&this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return a(this,t)}}}),w.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return 1-Math.cos(t*Math.PI/2)}},w.morph=function(t){return function(e,i){return new w.MorphObj(e,i).at(t)}},w.Situation=w.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new w.Number(t.duration).valueOf(),this.delay=new w.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),w.Timeline=w.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new w.Situation({duration:t||1e3,delay:i||0,ease:w.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var e=new w.Situation({duration:t,delay:0,ease:w.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof w.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof w.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof w.Situation?this.start():this.situation(this)),this},initAnimations:function(){var t,e,i,n=this.situation;if(n.init)return this;for(t in n.animations)for(i=this.target()[t](),Array.isArray(i)||(i=[i]),Array.isArray(n.animations[t])||(n.animations[t]=[n.animations[t]]),e=i.length;e--;)n.animations[t][e]instanceof w.Number&&(i[e]=new w.Number(i[e])),n.animations[t][e]=i[e].morph(n.animations[t][e]);for(t in n.attrs)n.attrs[t]=new w.MorphObj(this.target().attr(t),n.attrs[t]);for(t in n.styles)n.styles[t]=new w.MorphObj(this.target().css(t),n.styles[t]);return n.initialTransformation=this.target().matrixify(),n.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var i=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!i&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return!0===this.situation.loops&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var i=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*i,this.situation.finish=this.situation.start+i,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var i=this.last();return i.loops=null==t||t,i.loop=0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return e.reversed=void 0===t?!e.reversed:t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){function e(n){n.detail.situation===i&&(t.call(this,i),this.off("finished.fx",e))}var i=this.last();return this.target().on("finished.fx",e),this._callStart()},during:function(t){function e(e){e.detail.situation===i&&t.call(this,e.detail.pos,w.morph(e.detail.pos),e.detail.eased,i)}var i=this.last();return this.target().off("during.fx",e).on("during.fx",e),this.after(function(){this.off("during.fx",e)}),this._callStart()},afterAll:function(t){var e=function e(i){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,w.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,i){return this.last()[i||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),!1!==this.situation.loops){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),!0===this.situation.loops||i<this.situation.loops?(this.pos=e-i,n=this.situation.loop,this.situation.loop=i):(this.absPos=this.situation.loops,this.pos=1,n=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!==Boolean((this.situation.loop-n)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1===this.pos&&!this.situation.reversed||this.situation.reversed&&0===this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.situations.length||(this.target().off(".fx"),this.active=!1)),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,i=this,n=this.target(),r=this.situation;for(t in r.animations)e=[].concat(r.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(i.pos),i.pos):t}),n[t].apply(n,e);for(t in r.attrs)e=[t].concat(r.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(i.pos),i.pos):t}),n.attr.apply(n,e);for(t in r.styles)e=[t].concat(r.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(i.pos),i.pos):t}),n.css.apply(n,e);return r.transforms.length,this},once:function(t,e,i){var n=this.last();return i||(t=n.ease(t)),n.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:w.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new w.Timeline(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new w.Timeline(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),w.MorphObj=w.invent({create:function(t,e){return w.Color.isColor(e)?new w.Color(t).morph(e):w.regex.delimiter.test(t)?new w.Array(t).morph(e):w.regex.numberAndUnit.test(e)?new w.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),w.extend(w.Timeline,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,e,"attrs");return this},css:function(t,e){if("object"==typeof t)for(var i in t)this.css(i,t[i]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof w.G)return this.transform({x:t},e),this;var i=new w.Number(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof w.G)return this.transform({y:t},e),this;var i=new w.Number(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",new w.Number(t))},cy:function(t){return this.add("cy",new w.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof w.Text)this.attr("font-size",t);else{var i;t&&e||(i=this.target().bbox()),t||(t=i.width/i.height*e),e||(e=i.height/i.width*t),this.add("width",new w.Number(t)).add("height",new w.Number(e))}return this},width:function(t){return this.add("width",new w.Number(t))},height:function(t){return this.add("height",new w.Number(t))},plot:function(t,e,i,n){return 4===arguments.length?this.plot([t,e,i,n]):this.add("plot",new(this.target().MorphArray)(t))},leading:function(t){return this.target().leading?this.add("leading",new w.Number(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof w.Container&&this.add("viewbox",new w.Box(t,e,i,n)),this},update:function(t){if(this.target()instanceof w.Stop){if("number"==typeof t||t instanceof w.Number)return this.update({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",t.offset)}return this}}),w.Matrix=w.invent({create:function(t){var e,i=p([1,0,0,1,0,0]);for(t=t instanceof w.Element?t.matrixify():"string"==typeof t?p(t.split(w.regex.delimiter).map(parseFloat)):Array.isArray(t)?p(t):"object"==typeof t?t:6===arguments.length?p([].slice.call(arguments)):i,e=N.length-1;e>=0;--e)this[N[e]]=null!=t[N[e]]?t[N[e]]:i[N[e]]},extend:{clone:function(){return new w.Matrix(this)},transform:function(t){if(null!=t.a){var e=new w.Matrix(t);return this.lmultiply(e)}var i=!t.flip||"x"!==t.flip&&"both"!==t.flip?1:-1,n=!t.flip||"y"!==t.flip&&"both"!==t.flip?1:-1,r=t.skew&&t.skew.length?t.skew[0]:isFinite(t.skew)?t.skew:isFinite(t.skewX)?t.skewX:0,s=t.skew&&t.skew.length?t.skew[1]:isFinite(t.skew)?t.skew:isFinite(t.skewY)?t.skewY:0,o=t.scale&&t.scale.length?t.scale[0]*i:isFinite(t.scale)?t.scale*i:isFinite(t.scaleX)?t.scaleX*i:i,a=t.scale&&t.scale.length?t.scale[1]*n:isFinite(t.scale)?t.scale*n:isFinite(t.scaleY)?t.scaleY*n:n,h=t.shear||0,u=t.rotate||0,l=new w.Point(null==t.ox?t.origin:t.ox,t.oy),c=l.x,f=l.y,d=new w.Point(null==t.px?t.position:t.px,t.py,{x:null,y:null}),p=d.x,m=d.y,v=new w.Point(null==t.tx?t.translate:t.tx,t.ty),x=v.x,y=v.y,g=new w.Point(null==t.rx?t.relative:t.rx,t.ry),b=g.x,P=g.y,A=new w.Matrix(this),C=(new w.Matrix).translate(-c,-f).scale(o,a).skew(r,s).shear(h).rotate(u).translate(c,f).translate(b,P).lmultiply(A);if(isFinite(p)||isFinite(m)){var N=new w.Point(c-b,f-P).transform(C),M=p?p-N.x:0,S=m?m-N.y:0;C=C.translate(M,S)}return C=C.translate(x,y)},compose:function(t){var e=t.scaleX||1,i=t.scaleY||1,n=t.shear||0,r=t.rotate||0,s=t.translateX||0,o=t.translateY||0;return(new w.Matrix).scale(e,i).shear(n).rotate(r).translate(s,o).lmultiply(this)},decompose:function(){var t=this.a,e=this.b,i=this.c,n=this.d,r=this.e,s=this.f,o=t*n-e*i,a=o>0?1:-1,h=a*Math.sqrt(t*t+e*e),u=180/Math.PI*Math.atan2(a*e,a*t),l=(t*i+e*n)/o;return{scaleX:h,scaleY:i*h/(l*t-e)||n*h/(l*e+t),shear:l,rotate:u,translateX:r,translateY:s,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f}},morph:function(t){return this.destination=new w.Matrix(t),this},at:function(t){return this.destination?new w.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t}):this},multiply:function(t){var e=this,i=new w.Matrix(t),n=e.a*i.a+e.c*i.b,r=e.b*i.a+e.d*i.b,s=e.a*i.c+e.c*i.d,o=e.b*i.c+e.d*i.d,a=e.e+e.a*i.e+e.c*i.f,h=e.f+e.b*i.e+e.d*i.f;return new w.Matrix(n,r,s,o,a,h)},lmultiply:function(t){return new w.Matrix(t).multiply(this)},inverse:function(){return new w.Matrix(this.native().inverse())},translate:function(t,e){var i=new w.Matrix(this);return i.e+=t||0,i.f+=e||0,i},scale:function(t,e,i,n){1===arguments.length?e=t:3===arguments.length&&(n=i,i=e,e=t);var r=new w.Matrix(t,0,0,e,0,0);return this.around(i,n,r)},rotate:function(t,e,i){t=w.utils.radians(t);var n=new w.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0);return this.around(e,i,n)},flip:function(t,e){return"x"===t?this.scale(-1,1,e,0):"y"===t?this.scale(1,-1,0,e):this.scale(-1,-1,t,e||t)},shear:function(t,e,i){var n=new w.Matrix(1,0,t,1,0,0);return this.around(e,i,n)},skew:function(t,e,i,n){1===arguments.length?e=t:3===arguments.length&&(n=i,i=e,e=t),t=w.utils.radians(t),e=w.utils.radians(e) +;var r=new w.Matrix(1,Math.tan(e),Math.tan(t),1,0,0);return this.around(i,n,r)},skewX:function(t,e,i){return this.skew(t,0,e,i)},skewY:function(t,e,i){return this.skew(0,t,e,i)},around:function(t,e,i){var n=t||0,r=e||0;return this.translate(-n,-r).lmultiply(i).translate(n,r)},native:function(){for(var t=w.parser.nodes.svg.node.createSVGMatrix(),e=N.length-1;e>=0;e--)t[N[e]]=this[N[e]];return t},equals:function(t){var e=new w.Matrix(t);return g(this.a,e.a)&&g(this.b,e.b)&&g(this.c,e.c)&&g(this.d,e.d)&&g(this.e,e.e)&&g(this.f,e.f)},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:w.Element,construct:{ctm:function(){return new w.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof w.Doc&&!this.isRoot()){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new w.Matrix(e)}return new w.Matrix(this.node.getScreenCTM())}}}),w.Point=w.invent({create:function(t,e,i){var n;i=i||{x:0,y:0},n=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:{x:t,y:e},this.x=null==n.x?i.x:n.x,this.y=null==n.y?i.y:n.y},extend:{clone:function(){return new w.Point(this)},morph:function(t,e){return this.destination=new w.Point(t,e),this},at:function(t){return this.destination?new w.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t}):this},native:function(){var t=w.parser.nodes.svg.node.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new w.Point(this.native().matrixTransform(t.native()))}}}),w.extend(w.Element,{point:function(t,e){return new w.Point(t,e).transform(this.screenCTM().inverse())}}),w.extend(w.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=w.regex.isNumber.test(e[i].nodeValue)?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?w.defaults.attrs[t]:w.regex.isNumber.test(e)?parseFloat(e):e;"fill"!==t&&"stroke"!==t||(w.regex.isImage.test(e)&&(e=this.doc().defs().image(e)),e instanceof w.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new w.Number(e):w.Color.isColor(e)?e=new w.Color(e):Array.isArray(e)&&(e=new w.Array(e)),"leading"===t?this.leading&&this.leading(e):"string"==typeof i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!==t&&"x"!==t||this.rebuild(t,e)}return this}}),w.extend(w.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){return(this.attr("transform")||"").split(w.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(w.regex.delimiter).map(function(t){return parseFloat(t)})]}).reverse().reduce(function(t,e){return"matrix"===e[0]?t.lmultiply(p(e[1])):t[e[0]].apply(t,e[1])},new w.Matrix)},toParent:function(t){if(this===t)return this;var e=this.screenCTM(),i=t.screenCTM().inverse();return this.addTo(t).untransform().transform(i.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),w.extend(w.Element,{transform:function(t,e){var i=this.bbox();if(null==t||"string"==typeof t){var n=new w.Matrix(this).decompose();return n[t]||n}if("string"==typeof t.origin||null==t.origin&&null==t.ox&&null==t.oy){var r="string"==typeof t.origin?t.origin.toLowerCase().trim():"center",s=i.height,o=i.width,a=i.x,h=i.y;t.ox=r.includes("left")?a:r.includes("right")?a+o:a+o/2,t.oy=r.includes("top")?h:r.includes("bottom")?h+s:h+s/2,t.origin=null}var u=!0===e?this:e||!1,l=new w.Matrix(u).transform(t);return this.attr("transform",l)}}),w.extend(w.Timeline,{transform:function(t,e,i){}}),w.extend(w.Element,{css:function(t,e){var i,n,r={};if(0===arguments.length)return this.node.style.cssText.split(/\s*;\s*/).filter(function(t){return!!t.length}).forEach(function(t){i=t.split(/\s*:\s*/),r[i[0]]=i[1]}),r;if(arguments.length<2){if(Array.isArray(t)){for(n=t.length;n--;)r[u(t[n])]=this.node.style[u(t[n])];return r}if("string"==typeof t)return this.node.style[u(t)];if("object"==typeof t)for(n in t)this.node.style[u(n)]=null==t[n]||w.regex.isBlank.test(t[n])?"":t[n]}return 2===arguments.length&&(this.node.style[u(t)]=null==e||w.regex.isBlank.test(e)?"":e),this}}),w.Parent=w.invent({create:function(t){this.constructor(t)},inherit:w.Element,extend:{children:function(){return w.utils.map(this.node.children,function(t){return w.adopt(t)})},add:function(t,e){return t=i(t),t.node!==this.node.children[e]&&this.node.insertBefore(t.node,this.node.children[e]||null),this},put:function(t,e){return this.add(t,e),t.instance||t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.children).indexOf(t.node)},get:function(t){return w.adopt(this.node.children[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.children.length-1)},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;i<n;i++)r[i]instanceof w.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof w.Parent&&r[i].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this}}}),w.extend(w.Parent,{flatten:function(t){return this instanceof w.G||this instanceof w.Doc?(t=t||(this instanceof w.Doc&&this.isRoot()?this:this.parent(w.Parent)),this.each(function(){return this instanceof w.Defs?this:this instanceof w.Parent?this.flatten(t):this.toParent(t)}),this.node.firstElementChild||this.remove(),this):this},ungroup:function(t){return this instanceof w.G||this instanceof w.Doc&&!this.isRoot()?(t=t||this.parent(w.Parent),this.each(function(){return this.toParent(t)}),this.remove(),this):this}}),w.Container=w.invent({create:function(t){this.constructor(t)},inherit:w.Parent}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){w.Element.prototype[t]=function(e){return w.on(this,t,e),this}}),w.listenerId=0,w.on=function(t,e,i,n,r){var s=i.bind(n||t),o=t instanceof w.Element?t.node:t;o.instance=o.instance||{events:{}};var a=o.instance.events;i._svgjsListenerId||(i._svgjsListenerId=++w.listenerId),e.split(w.regex.delimiter).forEach(function(t){var e=t.split(".")[0],n=t.split(".")[1]||"*";a[e]=a[e]||{},a[e][n]=a[e][n]||{},a[e][n][i._svgjsListenerId]=s,o.addEventListener(e,s,r||!1)})},w.off=function(t,e,i,n){var r=t instanceof w.Element?t.node:t;if(r.instance&&("function"!=typeof i||(i=i._svgjsListenerId))){var s=r.instance.events;(e||"").split(w.regex.delimiter).forEach(function(t){var e,o,a=t&&t.split(".")[0],h=t&&t.split(".")[1];if(i)s[a]&&s[a][h||"*"]&&(r.removeEventListener(a,s[a][h||"*"][i],n||!1),delete s[a][h||"*"][i]);else if(a&&h){if(s[a]&&s[a][h]){for(o in s[a][h])w.off(r,[a,h].join("."),o);delete s[a][h]}}else if(h)for(t in s)for(e in s[t])h===e&&w.off(r,[t,h].join("."));else if(a){if(s[a]){for(e in s[a])w.off(r,[a,e].join("."));delete s[a]}}else{for(t in s)w.off(r,t);r.instance.events={}}})}},w.extend(w.Element,{on:function(t,e,i,n){return w.on(this,t,e,i,n),this},off:function(t,e){return w.off(this.node,t,e),this},dispatch:function(e,i){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:i,cancelable:!0})),e},fire:function(t,e){return this.dispatch(t,e),this}}),w.Defs=w.invent({create:"defs",inherit:w.Container}),w.G=w.invent({create:"g",inherit:w.Container,extend:{},construct:{group:function(){return this.put(new w.G)}}}),w.extend(w.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},prev:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof w.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof w.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),w.Mask=w.invent({create:"mask",inherit:w.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unmask()}),w.Element.prototype.remove.call(this)},targets:function(){return w.select('svg [mask*="'+this.id()+'"]')}},construct:{mask:function(){return this.defs().put(new w.Mask)}}}),w.extend(w.Element,{maskWith:function(t){var e=t instanceof w.Mask?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.id()+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}),w.ClipPath=w.invent({create:"clipPath",inherit:w.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unclip()}),w.Element.prototype.remove.call(this)},targets:function(){return w.select('svg [clip-path*="'+this.id()+'"]')}},construct:{clip:function(){return this.defs().put(new w.ClipPath)}}}),w.extend(w.Element,{clipWith:function(t){var e=t instanceof w.ClipPath?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.id()+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}),w.Gradient=w.invent({create:function(t){this.constructor("object"==typeof t?t:w.create(t+"Gradient"))},inherit:w.Container,extend:{stop:function(t,e,i){return this.put(new w.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},url:function(){return"url(#"+this.id()+")"},toString:function(){return this.url()},attr:function(t,e,i){return"transform"===t&&(t="gradientTransform"),w.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),w.extend([w.Gradient,w.Timeline],{from:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({fx:new w.Number(t),fy:new w.Number(e)}):this.attr({x1:new w.Number(t),y1:new w.Number(e)})},to:function(t,e){return"radialGradient"===(this._target||this).type?this.attr({cx:new w.Number(t),cy:new w.Number(e)}):this.attr({x2:new w.Number(t),y2:new w.Number(e)})}}),w.extend(w.Defs,{gradient:function(t,e){return this.put(new w.Gradient(t)).update(e)}}),w.Stop=w.invent({create:"stop",inherit:w.Element,extend:{update:function(t){return("number"==typeof t||t instanceof w.Number)&&(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 w.Number(t.offset)),this}}}),w.Pattern=w.invent({create:"pattern",inherit:w.Container,extend:{url:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.url()},attr:function(t,e,i){return"transform"===t&&(t="patternTransform"),w.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),w.extend(w.Defs,{pattern:function(t,e,i){return this.put(new w.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),w.Doc=w.invent({create:function(t){this.constructor(t||w.create("svg")),this.namespace()},inherit:w.Container,extend:{isRoot:function(){return!(this.node.parentNode&&this.node.parentNode instanceof t.SVGElement&&"#document"!==this.node.parentNode.nodeName)},doc:function(){return this.isRoot()?this:w.Element.prototype.doc.call(this)},namespace:function(){return this.isRoot()?this.attr({xmlns:w.ns,version:"1.1"}).attr("xmlns:xlink",w.xlink,w.xmlns).attr("xmlns:svgjs",w.svgjs,w.xmlns):this.doc().namespace()},defs:function(){return this.isRoot()?w.adopt(this.node.getElementsByTagName("defs")[0])||this.put(new w.Defs):this.doc().defs()},parent:function(t){return this.isRoot()?"#document"===this.node.parentNode.nodeName?null:this.node.parentNode:w.Element.prototype.parent.call(this,t)},remove:function(){return this.isRoot()?(this.parent()&&this.parent().removeChild(this.node),this):w.Element.prototype.remove.call(this)},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this}},construct:{nested:function(){return this.put(new w.Doc)}}}),w.Shape=w.invent({create:function(t){this.constructor(t)},inherit:w.Element}),w.Bare=w.invent({create:function(t,e){if(this.constructor(w.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:w.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),w.extend(w.Parent,{element:function(t,e){return this.put(new w.Bare(t,e))}}),w.Symbol=w.invent({create:"symbol",inherit:w.Container,construct:{symbol:function(){return this.put(new w.Symbol)}}}),w.Use=w.invent({create:"use",inherit:w.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,w.xlink)}},construct:{use:function(t,e){return this.put(new w.Use).element(t,e)}}}),w.Rect=w.invent({create:"rect",inherit:w.Shape,construct:{rect:function(t,e){return this.put(new w.Rect).size(t,e)}}}),w.Circle=w.invent({create:"circle",inherit:w.Shape,construct:{circle:function(t){return this.put(new w.Circle).rx(new w.Number(t).divide(2)).move(0,0)}}}),w.extend([w.Circle,w.Timeline],{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),w.Ellipse=w.invent({create:"ellipse",inherit:w.Shape,construct:{ellipse:function(t,e){return this.put(new w.Ellipse).size(t,e).move(0,0)}}}),w.extend([w.Ellipse,w.Rect,w.Timeline],{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),w.extend([w.Circle,w.Ellipse],{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new w.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new w.Number(t).divide(2))},size:function(t,e){var i=d(this,t,e);return this.rx(new w.Number(i.width).divide(2)).ry(new w.Number(i.height).divide(2))}}),w.Line=w.invent({create:"line",inherit:w.Shape,extend:{array:function(){return new w.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return null==t?this.array():(t=void 0!==e?{x1:t,y1:e,x2:i,y2:n}:new w.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var i=d(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return w.Line.prototype.plot.apply(this.put(new w.Line),null!=t?[t,e,i,n]:[0,0,0,0])}}}),w.Polyline=w.invent({create:"polyline",inherit:w.Shape,construct:{polyline:function(t){return this.put(new w.Polyline).plot(t||new w.PointArray)}}}),w.Polygon=w.invent({create:"polygon",inherit:w.Shape,construct:{polygon:function(t){return this.put(new w.Polygon).plot(t||new w.PointArray)}}}),w.extend([w.Polyline,w.Polygon],{array:function(){return this._array||(this._array=new w.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new w.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=d(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),w.extend([w.Line,w.Polyline,w.Polygon],{MorphArray:w.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),w.Path=w.invent({create:"path",inherit:w.Shape,extend:{MorphArray:w.PathArray,array:function(){return this._array||(this._array=new w.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new w.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var i=d(this,t,e);return this.attr("d",this.array().size(i.width,i.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new w.Path).plot(t||new w.PathArray)}}}),w.Image=w.invent({create:"image",inherit:w.Shape,extend:{load:function(e,i){if(!e)return this;var n=new t.Image;return w.on(n,"load",function(t){var r=this.parent(w.Pattern);0===this.width()&&0===this.height()&&this.size(n.width,n.height),r instanceof w.Pattern&&0===r.width()&&0===r.height()&&r.size(this.width(),this.height()),"function"==typeof i&&i.call(this,{width:n.width,height:n.height,ratio:n.width/n.height,url:e})},this),w.on(n,"load error",function(){w.off(n)}),this.attr("href",n.src=e,w.xlink)}},construct:{image:function(t,e){return this.put(new w.Image).size(0,0).load(t,e)}}}),w.Text=w.invent({create:function(t){this.constructor(t||w.create("text")),this.dom.leading=new w.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",w.defaults.attrs["font-family"])},inherit:w.Parent,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),i="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-i:e:this.attr("y","number"==typeof t?t+i:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if(void 0===t){var e=this.node.childNodes,i=0;t="";for(var n=0,r=e.length;n<r;++n)"textPath"!==e[n].nodeName?(n!==i&&3!==e[n].nodeType&&!0===w.adopt(e[n]).dom.newLined&&(t+="\n"),t+=e[n].textContent):0===n&&(i=1);return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var s=0,o=t.length;s<o;s++)this.tspan(t[s]).newLine()}return this.build(!1).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new w.Number(t),this.rebuild())},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new w.Number(this.attr("font-size"));this.each(function(){this.dom.newLined&&(this.attr("x",e.attr("x")),"\n"===this.text()?i+=n:(this.attr("dy",n+i),i=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new w.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new w.Text).text(t)},plain:function(t){return this.put(new w.Text).plain(t)}}}),w.Tspan=w.invent({create:"tspan",inherit:w.Parent,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(w.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),w.extend([w.Text,w.Tspan],{plain:function(t){return!1===this._build&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=new w.Tspan;return this._build||this.clear(),this.node.appendChild(e.node),e.text(t)},length:function(){return this.node.getComputedTextLength()}}),w.TextPath=w.invent({create:"textPath",inherit:w.Text,parent:w.Parent,extend:{MorphArray:w.PathArray,array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),i=null;return e&&(i=e.plot(t)),null==t?i:this},track:function(){return this.reference("href")}},construct:{textPath:function(t,e){return this.defs().path(e).text(t).addTo(this)}}}),w.extend([w.Text],{path:function(t){var e=new w.TextPath;return t instanceof w.Path||(t=this.doc().defs().path(t)),e.attr("href","#"+t,w.xlink),this.put(e)},textPath:function(){return this.select("textPath")}}),w.extend([w.Path],{text:function(t){if(t instanceof w.Text){var e=t.text();return t.clear().path(this).text(e)}return this.parent().put(new w.Text).path(this).text(t)}}),w.A=w.invent({create:"a",inherit:w.Container,extend:{to:function(t){return this.attr("href",t,w.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new w.A).to(t)}}}),w.extend(w.Element,{linkTo:function(t){var e=new w.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),w.Marker=w.invent({create:"marker",inherit:w.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,i){return this.defs().marker(t,e,i)}}}),w.extend(w.Defs,{marker:function(t,e,i){return this.put(new w.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),w.extend([w.Line,w.Polyline,w.Polygon,w.Path],{marker:function(t,e,i,n){var r=["marker"];return"all"!==t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof w.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(r,t)}}),w.extend(w.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:!0===i||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),w.extend(w.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var i in t)this.remember(i,t[i]);else{if(1===arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0===arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),w.get=function(t){var i=e.getElementById(y(t)||t);return w.adopt(i)},w.select=function(t,i){return w.utils.map((i||e).querySelectorAll(t),function(t){return w.adopt(t)})},w.$$=function(t,i){return w.utils.map((i||e).querySelectorAll(t),function(t){return w.adopt(t)})},w.$=function(t,i){return w.adopt((i||e).querySelector(t))},w.extend(w.Parent,{select:function(t){return w.select(t,this.node)}});var N="abcdef".split("");return w.Box=w.invent({create:function(t){var e=[0,0,0,0];t="string"==typeof t?t.split(w.regex.delimiter).map(parseFloat):Array.isArray(t)?t:"object"==typeof 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):e,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],x(this)},extend:{merge:function(t){var e=Math.min(this.x,t.x),i=Math.min(this.y,t.y);return new w.Box(e,i,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-i)},transform:function(t){var e=1/0,i=-1/0,n=1/0,r=-1/0;return[new w.Point(this.x,this.y),new w.Point(this.x2,this.y),new w.Point(this.x,this.y2),new w.Point(this.x2,this.y2)].forEach(function(s){s=s.transform(t),e=Math.min(e,s.x),i=Math.max(i,s.x),n=Math.min(n,s.y),r=Math.max(r,s.y)}),new w.Box(e,n,i-e,r-n)},addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this},toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,i,n){return this.destination=new w.Box(t,e,i,n),this},at:function(t){return this.destination?new w.Box(this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t):this}},parent:w.Element,construct:{bbox:function(){var t;try{if(t=this.node.getBBox(),n(t)&&!r(this.node))throw new Exception("Element not in the dom")}catch(i){try{var e=this.clone(w.parser().svg).show();t=e.node.getBBox(),e.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return new w.Box(t)},rbox:function(t){try{var e=new w.Box(this.node.getBoundingClientRect());return t?e.transform(t.screenCTM().inverse()):e.addOffset()}catch(t){return new w.Box}}}}),w.extend([w.Doc,w.Symbol,w.Image,w.Pattern,w.Marker,w.ForeignObject,w.View],{viewbox:function(t,e,i,n){return null==t?new w.Box(this.attr("viewBox")):this.attr("viewBox",new w.Box(t,e,i,n))}}),w.parser=function(){var t;return w.parser.nodes.svg.node.parentNode||(t=e.body||e.documentElement,w.parser.nodes.svg.addTo(t)),w.parser.nodes},w.parser.nodes={svg:w().size(2,0).css({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"})},w.parser.nodes.path=w.parser.nodes.svg.path().node,w});
\ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 1d7870f..5b511ef 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -31,6 +31,8 @@ var parts = [ 'src/regex.js',
'src/utilities.js',
'src/default.js',
+ 'src/queue.js',
+ 'src/drawLoop.js',
'src/color.js',
'src/array.js',
'src/pointarray.js',
diff --git a/spec/spec/circle.js b/spec/spec/circle.js index c0f0936..0f2c8f4 100644 --- a/spec/spec/circle.js +++ b/spec/spec/circle.js @@ -1,3 +1,4 @@ + describe('Circle', function() { var circle @@ -173,5 +174,4 @@ describe('Circle', function() { expect(window.matrixStringToArray(circle.node.getAttribute('transform'))).toEqual([1,0,0,1,12,12]) }) }) - }) diff --git a/spec/spec/queue.js b/spec/spec/queue.js new file mode 100644 index 0000000..738831c --- /dev/null +++ b/spec/spec/queue.js @@ -0,0 +1,111 @@ + +describe ('SVG.Queue()', function () { + + describe('first ()', function () { + + it('returns null if no item in the queue', function () { + var queue = new SVG.Queue() + expect(queue.first()).toEqual(null) + }) + + it ('returns the first value in the queue', function () { + var queue = new SVG.Queue() + queue.push(1) + expect(queue.first()).toBe(1) + queue.push(2) + expect(queue.first()).toBe(1) + }) + }) + + describe('last ()', function () { + + it ('returns null if no item in the queue', function () { + var queue = new SVG.Queue() + expect(queue.last()).toEqual(null) + }) + + it ('returns the last value added', function () { + var queue = new SVG.Queue() + queue.push(1) + expect(queue.last()).toBe(1) + queue.push(2) + expect(queue.last()).toBe(2) + }) + }) + + describe('push ()', function () { + + it ('adds an element to the end of the queue', function () { + var queue = new SVG.Queue() + queue.push(1) + queue.push(2) + queue.push(3) + + expect(queue.first()).toBe(1) + expect(queue.last()).toBe(3) + }) + + it ('changes the length when you add things', function () { + var queue = new SVG.Queue() + queue.push(1) + expect(queue.length).toBe(1) + queue.push(2) + expect(queue.length).toBe(2) + }) + }) + + describe('remove ()', function () { + it('removes an item from the queue which matches the matcher', function () { + var queue = new SVG.Queue() + queue.push(1) + queue.push(2) + queue.push(3) + + queue.remove(function(item) { + return item.value == 3 + }) + + expect(queue.length).toBe(2) + expect(queue.last()).toBe(2) + expect(queue.first()).toBe(1) + }) + + it('removes no item from the queue if nothing is matched', function () { + var queue = new SVG.Queue() + queue.push(1) + queue.push(2) + queue.push(3) + + queue.remove(function(item) { + return item.value == 4 + }) + + expect(queue.length).toBe(3) + expect(queue.last()).toBe(3) + expect(queue.first()).toBe(1) + }) + }) + + describe('shift ()', function () { + it('returns nothing if queue is empty', function () { + var queue = new SVG.Queue() + var val = queue.shift() + expect(val).toBeFalsy() + }) + + it('returns the first item of the queue and removes it', function () { + var queue = new SVG.Queue() + queue.push(1) + queue.push(2) + queue.push(3) + + var val = queue.shift() + + expect(queue.length).toBe(2) + expect(queue.last()).toBe(3) + expect(queue.first()).toBe(2) + + expect(val).toBe(1) + }) + }) +}) diff --git a/src/drawLoop.js b/src/drawLoop.js new file mode 100644 index 0000000..6b6e6c3 --- /dev/null +++ b/src/drawLoop.js @@ -0,0 +1,82 @@ + +SVG.Animator = { + nextDraw: null, + frames: new SVG.Queue(), + timeouts: new SVG.Queue(), + frameCount: 0, + timeoutCount: 0, + timer: window.performance || window.Date, + + frame: function (fn) { + SVG.Animator.frames.push({ + id: SVG.Animator.frameCount, + run: fn + }) + + if (SVG.Animator.nextDraw === null) { + SVG.Animator.nextDraw = requestAnimationFrame(SVG.Animator._draw) + } + + return ++SVG.Animator.frameCount + }, + + timeout: function (fn, delay) { + delay = delay || 0 + + // Work out when the event should fire + var time = SVG.Animator.timer.now() + delay + + // Add the timeout to the end of the queue + var thisId = SVG.Animator.timeoutCount++ + SVG.Animator.timeouts.push({ + id: thisId, + run: fn, + time: time + }) + + // Request another animation frame if we need one + if (SVG.Animator.nextDraw === null) { + SVG.Animator.nextDraw = requestAnimationFrame(SVG.Animator._draw) + } + + return thisId + }, + + cancelTimeout: function (id) { + // Find the index of the timeout to cancel and remove it + var index = SVG.Animator.timeouts.remove(function (t) { return t.id == id }) + return index + }, + + _draw: function (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 tracking = true + var nextTimeout = null
+ var lastTimeout = SVG.Animator.timeouts.last() + while ((nextTimeout = SVG.Animator.timeouts.shift())) { + // Run the timeout if its time, or push it to the end + if (now > nextTimeout.time) { + nextTimeout.run() + } else { + SVG.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 frames available up until this point + var lastFrame = SVG.Animator.frames.last() + var lastFrameId = SVG.Animator.frameCount + while (SVG.Animator.frames.first() && SVG.Animator.frames.first().id < lastFrameId) { + var nextFrame = SVG.Animator.frames.shift() + nextFrame.run(now) + } + + // If we have remaining timeouts or frames, draw until we don't anymore + SVG.Animator.nextDraw = SVG.Animator.timeouts.length > 0 || SVG.Animator.frames.length > 0 + ? requestAnimationFrame(SVG.Animator._draw) + : null + } +} diff --git a/src/ellipse.js b/src/ellipse.js index eb310f9..8a8f027 100644 --- a/src/ellipse.js +++ b/src/ellipse.js @@ -16,7 +16,7 @@ SVG.Circle = SVG.invent({ } }) -SVG.extend([SVG.Circle, SVG.FX], { +SVG.extend([SVG.Circle, SVG.Timeline], { // Radius x value rx: function (rx) { return this.attr('r', rx) @@ -43,7 +43,7 @@ SVG.Ellipse = SVG.invent({ } }) -SVG.extend([SVG.Ellipse, SVG.Rect, SVG.FX], { +SVG.extend([SVG.Ellipse, SVG.Rect, SVG.Timeline], { // Radius x value rx: function (rx) { return this.attr('rx', rx) @@ -11,895 +11,1341 @@ SVG.morph = function (pos) { } } -SVG.Situation = SVG.invent({ +let time = window.performance || window.Date - create: function (o) { - this.init = false - this.reversed = false - this.reversing = false +SVG.Timeline = SVG.invent ({ - this.duration = new SVG.Number(o.duration).valueOf() - this.delay = new SVG.Number(o.delay).valueOf() + create: function () { - this.start = +new Date() + this.delay - this.finish = this.start + this.duration - this.ease = o.ease + // Store all of the closures to animate + this._closures = [] - // this.loop is incremented from 0 to this.loops - // it is also incremented when in an infinite loop (when this.loops is true) - this.loop = 0 - this.loops = false + this._startTime = time.now() + this._duration = 0 + + this._running = true + + }, + + extend: { + + animate (duration, ease, delay, epoch) { - this.animations = { - // functionToCall: [list of morphable objects] - // e.g. move: [SVG.Number, SVG.Number] } - this.attrs = { - // holds all attributes which are not represented from a function svg.js provides - // e.g. someAttr: SVG.Number + loop (times, reverse) { + } - this.styles = { - // holds all styles which should be animated - // e.g. fill-color: SVG.Color + duration (time) { + this._duration = time } - this.transforms = [ - // holds all transformations as transformation objects - // e.g. [SVG.Rotate, SVG.Translate, SVG.Matrix] - ] + delay (by, epoch) { + if (epoch) { + this._startTime = time.now() + } + this._duration = 0 + this._startTime += by + } + + ease (fn) { - this.once = { - // functions to fire at a specific position - // e.g. "0.5": function foo(){} } - } -}) + play () + pause () + stop () + finish (all=true) + speed (newSpeed) + seek (dt) + persist (dt || forever) // 0 by default + reverse () -SVG.FX = SVG.invent({ - - create: function (element) { - this._target = element - this.situations = [] - this.active = false - this.situation = null - this.paused = false - this.lastPos = 0 - this.pos = 0 - // The absolute position of an animation is its position in the context of its complete duration (including delay and loops) - // When performing a delay, absPos is below 0 and when performing a loop, its value is above 1 - this.absPos = 0 - this._speed = 1 - }, - extend: { - /** - * sets or returns the target of this animation - * @param o object || number In case of Object it holds all parameters. In case of number its the duration of the animation - * @param ease function || string Function which should be used for easing or easing keyword - * @param delay Number indicating the delay before the animation starts - * @return target || this - */ - animate: function (o, ease, delay) { - if (typeof o === 'object') { - ease = o.ease - delay = o.delay - o = o.duration - } - var situation = new SVG.Situation({ - duration: o || 1000, - delay: delay || 0, - ease: SVG.easing[ease || '-'] || ease - }) - this.queue(situation) - return this - }, + // fn is a function that takes a position in range [0, 1] + schedule (fn) { // fn can not take parameters - /** - * sets a delay before the next element of the queue is called - * @param delay Duration of delay in milliseconds - * @return this.target() - */ - delay: function (delay) { - // The delay is performed by an empty situation with its duration - // attribute set to the duration of the delay - var situation = new SVG.Situation({ - duration: delay, - delay: 0, - ease: SVG.easing['-'] - }) - return this.queue(situation) - }, - /** - * sets or returns the target of this animation - * @param null || target SVG.Element which should be set as new target - * @return target || this - */ - target: function (target) { - if (target && target instanceof SVG.Element) { - this._target = target - return this - } - return this._target - }, - // returns the absolute position at a given time - timeToAbsPos: function (timestamp) { - return (timestamp - this.situation.start) / (this.situation.duration / this._speed) - }, - // returns the timestamp from a given absolute positon - absPosToTime: function (absPos) { - return this.situation.duration / this._speed * absPos + this.situation.start - }, +let declarative = rect.animate(300, '>', 200) + .loop().color('blue') + .animate(SVG.Spring(300)) - // starts the animationloop - startAnimFrame: function () { - this.stopAnimFrame() - this.animationFrame = window.requestAnimationFrame(function () { this.step() }.bind(this)) - }, +onmousemove() { + declarative.x(mouseX).y(mouseY) +} - // cancels the animationframe - stopAnimFrame: function () { - window.cancelAnimationFrame(this.animationFrame) - }, + SVG.MorphObj = SVG.invent({ - // kicks off the animation - only does something when the queue is currently not active and at least one situation is set - start: function () { - // dont start if already started - if (!this.active && this.situation) { - this.active = true - this.startCurrent() - } + create: function (from, to) { + // prepare color for morphing + if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to) + // prepare value list for morphing + if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to) + // prepare number for morphing + if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to) - return this - }, + // prepare for plain morphing + this.value = from + this.destination = to + }, - // start the current situation - startCurrent: function () { - this.situation.start = +new Date() + this.situation.delay / this._speed - this.situation.finish = this.situation.start + this.situation.duration / this._speed - return this.initAnimations().step() - }, + extend: { + at: function (pos, real) { + return real < 1 ? this.value : this.destination + }, - /** - * adds a function / Situation to the animation queue - * @param fn function / situation to add - * @return this - */ - queue: function (fn) { - if (typeof fn === 'function' || fn instanceof SVG.Situation) { - this.situations.push(fn) - } + valueOf: function () { + return this.value + } + } - if (!this.situation) this.situation = this.situations.shift() + }) - return this - }, - /** - * pulls next element from the queue and execute it - * @return this - */ - dequeue: function () { - // stop current animation - this.stop() - - // get next animation from queue - this.situation = this.situations.shift() - - if (this.situation) { - if (this.situation instanceof SVG.Situation) { - this.start() - } else { - // If it is not a SVG.Situation, then it is a function, we execute it - this.situation(this) - } - } +add('fill-color', val) - return this - }, +add('x', val, 'animations') - // updates all animations to the current state of the element - // this is important when one property could be changed from another property - initAnimations: function () { - var i, j, source - var s = this.situation +add('x', val, 'styles') - if (s.init) return this +add('line-cap', val, 'attrs') - for (i in s.animations) { - source = this.target()[i]() +.style(name, val) { - if (!Array.isArray(source)) { - source = [source] - } - if (!Array.isArray(s.animations[i])) { - s.animations[i] = [s.animations[i]] - } + styleAttr ('style', name, val) +} - // if(s.animations[i].length > source.length) { - // source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length)) - // } +.animate(spring) - for (j = source.length; j--;) { - // The condition is because some methods return a normal number instead - // of a SVG.Number - if (s.animations[i][j] instanceof SVG.Number) { - source[j] = new SVG.Number(source[j]) - } +onmousemove(() => { + el.animate(SVG.Spring(500)) + .move(event.pointX, event.pointY) + .finish() +}) - s.animations[i][j] = source[j].morph(s.animations[i][j]) - } - } - for (i in s.attrs) { - s.attrs[i] = new SVG.MorphObj(this.target().attr(i), s.attrs[i]) - } - for (i in s.styles) { - s.styles[i] = new SVG.MorphObj(this.target().css(i), s.styles[i]) - } +Morphable () - s.initialTransformation = this.target().matrixify() +Controlable () - s.init = true - return this - }, +new Controller(target, controller) - clearQueue: function () { - this.situations = [] - return this - }, - clearCurrent: function () { - this.situation = null - return this +SVG.Timeline = { + styleAttr (type, name, val) { + let morpher = new Morph(this.controller).to(val) + queue ( + ()=> { + morpher = morpher.from(element[type]('name')) + }, + morpher.at + ) + } +} + +.styleAttr (type, name, val) { + + let morpher = declarative ? new Controller(target) : new Morph().to(val) + queue ( + ()=> { + morpher = morpher.from(element[type]('name')) }, + () => { + this.element[type](name, morpher.at(pos)) + } + ) +} - /** stops the animation immediately - * @param jumpToEnd A Boolean indicating whether to complete the current animation immediately. - * @param clearQueue A Boolean indicating whether to remove queued animation as well. - * @return this - */ - stop: function (jumpToEnd, clearQueue) { - var active = this.active - this.active = false - - if (clearQueue) { - this.clearQueue() - } +viewbox(box) { + new Box + let morpher = new Morph().to(box) // box: {width, heught, x, y} +} - if (jumpToEnd && this.situation) { - // initialize the situation if it was not - !active && this.startCurrent() - this.atEnd() - } - this.stopAnimFrame() +new Morph(from, to) - return this.clearCurrent() - }, - /** resets the element to the state where the current element has started - * @return this - */ - reset: function () { - if (this.situation) { - var temp = this.situation - this.stop() - this.situation = temp - this.atStart() - } - return this - }, +new Morpg(from, to, controller = (from, to, pos) => {from + pos * (to - from)}) - // Stop the currently-running animation, remove all queued animations, and complete all animations for the element. - finish: function () { - this.stop(true, false) - while (this.dequeue().situation && this.stop(true, false)); +// Something line +path = "a, b, c" - this.clearQueue().clearCurrent() +SVG.color { + toArray: [r, g, b] + fromArray: new Color({r, g, b}) +} - return this - }, - // set the internal animation pointer at the start position, before any loops, and updates the visualisation - atStart: function () { - return this.at(0, true) - }, - // set the internal animation pointer at the end position, after all the loops, and updates the visualisation - atEnd: function () { - if (this.situation.loops === true) { - // If in a infinite loop, we end the current iteration - this.situation.loops = this.situation.loop + 1 - } - if (typeof this.situation.loops === 'number') { - // If performing a finite number of loops, we go after all the loops - return this.at(this.situation.loops, true) - } else { - // If no loops, we just go at the end - return this.at(1, true) - } - }, - // set the internal animation pointer to the specified position and updates the visualisation - // if isAbsPos is true, pos is treated as an absolute position - at: function (pos, isAbsPos) { - var durDivSpd = this.situation.duration / this._speed - this.absPos = pos - // If pos is not an absolute position, we convert it into one - if (!isAbsPos) { - if (this.situation.reversed) this.absPos = 1 - this.absPos - this.absPos += this.situation.loop - } +morph: function (pathArray) { + pathArray = new SVG.PathArray(pathArray) - this.situation.start = +new Date() - this.absPos * durDivSpd - this.situation.finish = this.situation.start + durDivSpd + if (this.equalCommands(pathArray)) { + this.destination = pathArray + } else { + this.destination = null + } - return this.step(true) - }, + return this +}, - /** - * sets or returns the speed of the animations - * @param speed null || Number The new speed of the animations - * @return Number || this - */ - speed: function (speed) { - if (speed === 0) return this.pause() - - if (speed) { - this._speed = speed - // We use an absolute position here so that speed can affect the delay before the animation - return this.at(this.absPos, true) - } else return this._speed - }, +[['M', 3, 5], ['L', 5, 6]] - // Make loopable - loop: function (times, reverse) { - var c = this.last() +['M', 3, 4, 'L', ...] - // store total loops - c.loops = (times != null) ? times : true - c.loop = 0 - if (reverse) c.reversing = true - return this - }, - // pauses the animation - pause: function () { - this.paused = true - this.stopAnimFrame() - return this - }, +function detectSomething (item) { + if(from instanceof SVG.Morphable) return from.controller(controller) + // prepare color for morphing + if (SVG.Color.isColor(to)) return new SVG.Color(from, controller) + // prepare value list for morphing + if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to) + // prepare number for morphing + if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to) - // unpause the animation - play: function () { - if (!this.paused) return this - this.paused = false - // We use an absolute position here so that the delay before the animation can be paused - return this.at(this.absPos, true) - }, + return item +} - /** - * toggle or set the direction of the animation - * true sets direction to backwards while false sets it to forwards - * @param reversed Boolean indicating whether to reverse the animation or not (default: toggle the reverse status) - * @return this - */ - reverse: function (reversed) { - var c = this.last() +foo->bar - if (typeof reversed === 'undefined') c.reversed = !c.reversed - else c.reversed = reversed - return this - }, +all of these things implement - /** - * returns a float from 0-1 indicating the progress of the current animation - * @param eased Boolean indicating whether the returned position should be eased or not - * @return number - */ - progress: function (easeIt) { - return easeIt ? this.situation.ease(this.pos) : this.pos - }, +interface Morphable { + from: (thing)=> {} + to: (thing)=> {} + at: (pos)=> {} + controller: (fn (nowOrFrom, target, pos))=> {} +} - /** - * adds a callback function which is called when the current animation is finished - * @param fn Function which should be executed as callback - * @return number - */ - after: function (fn) { - var c = this.last() - function wrapper (e) { - if (e.detail.situation === c) { - fn.call(this, c) - this.off('finished.fx', wrapper) // prevent memory leak - } - } - this.target().on('finished.fx', wrapper) +new SVG.MorphObj(el.attr(name)) - return this._callStart() - }, +animate().attr('line-joint', 5) - // adds a callback which is called whenever one animation step is performed - during: function (fn) { - var c = this.last() - function wrapper (e) { - if (e.detail.situation === c) { - fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, c) - } - } +SVG.MorphObj = SVG.invent({ - // see above - this.target().off('during.fx', wrapper).on('during.fx', wrapper) + create: function (from, to) { + // prepare color for morphing + if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to) + // prepare value list for morphing + if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to) + // prepare number for morphing + if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to) - this.after(function () { - this.off('during.fx', wrapper) - }) + // prepare for plain morphing + this.value = from + this.destination = to + }, - return this._callStart() + extend: { + at: function (pos, real) { + return real < 1 ? this.value : this.destination }, - // calls after ALL animations in the queue are finished - afterAll: function (fn) { - var wrapper = function wrapper (e) { - fn.call(this) - this.off('allfinished.fx', wrapper) - } + valueOf: function () { + return this.value + } + } - // see above - this.target().off('allfinished.fx', wrapper).on('allfinished.fx', wrapper) +}) - return this._callStart() - }, - // calls on every animation step for all animations - duringAll: function (fn) { - var wrapper = function (e) { - fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, e.detail.situation) - } +// Only works with a single number +new MorphObj { - this.target().off('during.fx', wrapper).on('during.fx', wrapper) + constr: (control= (from, to, c)=> {from + pos * (to - from)}) { + } - this.afterAll(function () { - this.off('during.fx', wrapper) - }) + _detect: // Gets the user input and returns the right kind of object - return this._callStart() - }, + from: (from) => { - last: function () { - return this.situations.length ? this.situations[this.situations.length - 1] : this.situation - }, + if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to) + // prepare value list for morphing + if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to) + // prepare number for morphing + if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to) - // adds one property to the animations - add: function (method, args, type) { - this.last()[type || 'animations'][method] = args - return this._callStart() - }, + // prepare for plain morphing + this.value = from + this.destination = to + } - /** perform one step of the animation - * @param ignoreTime Boolean indicating whether to ignore time and use position directly or recalculate position based on time - * @return this - */ - step: function (ignoreTime) { - // convert current time to an absolute position - if (!ignoreTime) this.absPos = this.timeToAbsPos(+new Date()) - - // This part convert an absolute position to a position - if (this.situation.loops !== false) { - var absPos, absPosInt, lastLoop - - // If the absolute position is below 0, we just treat it as if it was 0 - absPos = Math.max(this.absPos, 0) - absPosInt = Math.floor(absPos) - - if (this.situation.loops === true || absPosInt < this.situation.loops) { - this.pos = absPos - absPosInt - lastLoop = this.situation.loop - this.situation.loop = absPosInt - } else { - this.absPos = this.situation.loops - this.pos = 1 - // The -1 here is because we don't want to toggle reversed when all the loops have been completed - lastLoop = this.situation.loop - 1 - this.situation.loop = this.situation.loops - } + to: (val) => { - if (this.situation.reversing) { - // Toggle reversed if an odd number of loops as occured since the last call of step - this.situation.reversed = this.situation.reversed !== Boolean((this.situation.loop - lastLoop) % 2) - } - } else { - // If there are no loop, the absolute position must not be above 1 - this.absPos = Math.min(this.absPos, 1) - this.pos = this.absPos - } + } + at (pos) { - // while the absolute position can be below 0, the position must not be below 0 - if (this.pos < 0) this.pos = 0 + let type = from.type + let from = from.toArray() + let to = to.toArray() + result = [] + for (i) + result[i] = this.controller(from[i], to[i], pos) : to[i] - if (this.situation.reversed) this.pos = 1 - this.pos + type.fromArray(result) + } +} - // apply easing - var eased = this.situation.ease(this.pos) +if(declartive) { + mropher.init() + morpher.at(pos/fn) +} - // call once-callbacks - for (var i in this.situation.once) { - if (i > this.lastPos && i <= eased) { - this.situation.once[i].call(this.target(), this.pos, eased) - delete this.situation.once[i] - } - } - // fire during callback with position, eased position and current situation as parameter - if (this.active) this.target().fire('during', {pos: this.pos, eased: eased, fx: this, situation: this.situation}) - // the user may call stop or finish in the during callback - // so make sure that we still have a valid situation - if (!this.situation) { - return this - } +controller(currentPos, target) - // apply the actual animation to every property - this.eachAt() - // do final code when situation is finished - if ((this.pos === 1 && !this.situation.reversed) || (this.situation.reversed && this.pos === 0)) { - // stop animation callback - this.stopAnimFrame() +morph interface +detect type function - // fire finished callback with current situation as parameter - this.target().fire('finished', {fx: this, situation: this.situation}) - if (!this.situations.length) { - this.target().fire('allfinished') +if (mouse in box) + move box + animate(spring) - // Recheck the length since the user may call animate in the afterAll callback - if (!this.situations.length) { - this.target().off('.fx') // there shouldnt be any binding left, but to make sure... - this.active = false - } - } +zoom(level, point) { + let morpher = SVG.Number(level).controller(this.controller) + this.queue( + () => {morpher = morpher.from(element.zoom())}, + (pos) => {element.zoom(morpher.at(pos), point)} + ) +} - // start next animation - if (this.active) this.dequeue() - else this.clearCurrent() - } else if (!this.paused && this.active) { - // we continue animating when we are not at the end - this.startAnimFrame() - } +x (x) { - // save last eased position for once callback triggering - this.lastPos = eased - return this - }, +} - // calculates the step for every property and calls block with it - eachAt: function () { - var i, at - var self = this - var target = this.target() - var s = this.situation +this.queue(fn, morpher) - // apply animations which can be called trough a method - for (i in s.animations) { - at = [].concat(s.animations[i]).map(function (el) { - return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el - }) +new Morph(x(), xGiven) - target[i].apply(target, at) - } - // apply animation which has to be applied with attr() - for (i in s.attrs) { - at = [i].concat(s.attrs[i]).map(function (el) { - return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el - }) + x: function (x, relative) { + if (this.target() instanceof SVG.G) { + this.transform({x: x}, relative) + return this + } - target.attr.apply(target, at) - } + var num = new SVG.Number(x) + num.relative = relative + return this.add('x', num) + }, - // apply animation which has to be applied with css() - for (i in s.styles) { - at = [i].concat(s.styles[i]).map(function (el) { - return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el - }) - target.css.apply(target, at) + viewbox: function(box) { + var m = SVG.Box(box) } - // animate initialTransformation which has to be chained - if (s.transforms.length) { - - // TODO: ANIMATE THE TRANSFORMS - - // // get initial initialTransformation - // at = s.initialTransformation - // for(i = 0, len = s.transforms.length; i < len; i++){ - // - // // get next transformation in chain - // var a = s.transforms[i] - // - // // multiply matrix directly - // if(a instanceof SVG.Matrix){ - // - // if(a.relative){ - // at = at.multiply(new SVG.Matrix().morph(a).at(s.ease(this.pos))) - // }else{ - // at = at.morph(a).at(s.ease(this.pos)) - // } - // continue - // } - // - // // when transformation is absolute we have to reset the needed transformation first - // if(!a.relative) - // a.undo(at.decompose()) - // - // // and reapply it after - // at = at.multiply(a.at(s.ease(this.pos))) - // - // } - // - // // set new matrix on element - // target.matrix(at) - } - return this - }, + new Runner (function(time) { - // adds an once-callback which is called at a specific position and never again - once: function (pos, fn, isEased) { - var c = this.last() - if (!isEased) pos = c.ease(pos) - c.once[pos] = fn + }) - return this - }, - _callStart: function () { - setTimeout(function () { this.start() }.bind(this), 0) - return this - } + var closure = function (time) { - }, + // If it is time to do something, act now. + var running = start < time && time < end + if (running && this._running) { + closure.position = (time - closure.start) / closure.duration + fn (time) + } - parent: SVG.Element, + // If we are not paused or stopped, request another frame + if (this._running) SVG.Animator.frame(closure, this._startTime) - // Add method to parent elements - construct: { - // Get fx module or create a new one, then animate with given duration and ease - animate: function (o, ease, delay) { - return (this.fx || (this.fx = new SVG.FX(this))).animate(o, ease, delay) - }, - delay: function (delay) { - return (this.fx || (this.fx = new SVG.FX(this))).delay(delay) - }, - stop: function (jumpToEnd, clearQueue) { - if (this.fx) { - this.fx.stop(jumpToEnd, clearQueue) - } + // Tell the caller whether this animation is finished + closure.finished = !running - return this - }, - finish: function () { - if (this.fx) { - this.fx.finish() - } + }.bind(this) - return this - }, - // Pause current animation - pause: function () { - if (this.fx) { - this.fx.pause() - } + closure.stop() // toggles a stop flag + closure.pause() + closure.run(t) // If it was paused, it - return this - }, - // Play paused current animation - play: function () { - if (this.fx) { this.fx.play() } - return this - }, - // Set/Get the speed of the animations - speed: function (speed) { - if (this.fx) { - if (speed == null) { return this.fx.speed() } else { this.fx.speed(speed) } - } + closure.start = this._startTime + closure.end = this._startTime + this._duration + closure.positon = + var forwards = true // Decide if running forward based on looping - return this + + // TODO: Store a list of closures + + SVG.Animator.timeout(closure, this._startTime) + _continue() } - } -}) + _step (dt) { -// MorphObj is used whenever no morphable object is given -SVG.MorphObj = SVG.invent({ + } - create: function (from, to) { - // prepare color for morphing - if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to) - // prepare value list for morphing - if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to) - // prepare number for morphing - if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to) + // Checks if we are running and continues the animation + _continue () { + , continue: function () { + if (this.paused) return + if (!this.nextFrame) + this.step() + return this + } - // prepare for plain morphing - this.value = from - this.destination = to + } }, - extend: { - at: function (pos, real) { - return real < 1 ? this.value : this.destination - }, - valueOf: function () { - return this.value + construct: { + animate: function(o, ease, delay, epoch) { + return (this.timeline = this.timeline || new SVG.Timeline(o, ease, delay, epoch)) } } - }) -SVG.extend(SVG.FX, { - // Add animatable attributes - attr: function (a, v, relative) { - // apply attributes individually - if (typeof a === 'object') { - for (var key in a) { - this.attr(key, a[key]) - } - } else { - this.add(a, v, 'attrs') - } - return this - }, - // Add animatable styles - css: function (s, v) { - if (typeof s === 'object') { - for (var key in s) { - this.css(key, s[key]) - } - } else { - this.add(s, v, 'styles') - } - return this - }, - // Animatable x-axis - x: function (x, relative) { - if (this.target() instanceof SVG.G) { - this.transform({x: x}, relative) - return this - } - var num = new SVG.Number(x) - num.relative = relative - return this.add('x', num) - }, - // Animatable y-axis - y: function (y, relative) { - if (this.target() instanceof SVG.G) { - this.transform({y: y}, relative) - return this - } - var num = new SVG.Number(y) - num.relative = relative - return this.add('y', num) - }, - // Animatable center x-axis - cx: function (x) { - return this.add('cx', new SVG.Number(x)) - }, - // Animatable center y-axis - cy: function (y) { - return this.add('cy', new SVG.Number(y)) - }, - // Add animatable move - move: function (x, y) { - return this.x(x).y(y) - }, - // Add animatable center - center: function (x, y) { - return this.cx(x).cy(y) - }, - // Add animatable size - size: function (width, height) { - if (this.target() instanceof SVG.Text) { - // animate font size for Text elements - this.attr('font-size', width) - } else { - // animate bbox based size for all other elements - var box - - if (!width || !height) { - box = this.target().bbox() - } - if (!width) { - width = box.width / box.height * height - } - if (!height) { - height = box.height / box.width * width - } - this.add('width', new SVG.Number(width)) - .add('height', new SVG.Number(height)) - } - return this - }, - // Add animatable width - width: function (width) { - return this.add('width', new SVG.Number(width)) - }, - // Add animatable height - height: function (height) { - return this.add('height', new SVG.Number(height)) - }, - // Add animatable plot - plot: function (a, b, c, d) { - // Lines can be plotted with 4 arguments - if (arguments.length === 4) { - return this.plot([a, b, c, d]) - } - return this.add('plot', new (this.target().MorphArray)(a)) - }, - // Add leading method - leading: function (value) { - return this.target().leading - ? this.add('leading', new SVG.Number(value)) - : this - }, - // Add animatable viewbox - viewbox: function (x, y, width, height) { - if (this.target() instanceof SVG.Container) { - this.add('viewbox', new SVG.Box(x, y, width, height)) - } - return this - }, - update: function (o) { - if (this.target() instanceof SVG.Stop) { - if (typeof o === 'number' || o instanceof SVG.Number) { - return this.update({ - offset: arguments[0], - color: arguments[1], - opacity: arguments[2] - }) - } - 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 - } -}) + + + + + + + + + + + + + + + + + + + + + + + + +// SVG.Situation = SVG.invent({ +// +// create: function (o) { +// this.init = false +// this.reversed = false +// this.reversing = false +// +// this.duration = new SVG.Number(o.duration).valueOf() +// this.delay = new SVG.Number(o.delay).valueOf() +// +// this.start = +new Date() + this.delay +// this.finish = this.start + this.duration +// this.ease = o.ease +// +// // this.loop is incremented from 0 to this.loops +// // it is also incremented when in an infinite loop (when this.loops is true) +// this.loop = 0 +// this.loops = false +// +// this.animations = { +// // functionToCall: [list of morphable objects] +// // e.g. move: [SVG.Number, SVG.Number] +// } +// +// this.attrs = { +// // holds all attributes which are not represented from a function svg.js provides +// // e.g. someAttr: SVG.Number +// } +// +// this.styles = { +// // holds all styles which should be animated +// // e.g. fill-color: SVG.Color +// } +// +// this.transforms = [ +// // holds all transformations as transformation objects +// // e.g. [SVG.Rotate, SVG.Translate, SVG.Matrix] +// ] +// +// this.once = { +// // functions to fire at a specific position +// // e.g. "0.5": function foo(){} +// } +// } +// +// }) +// +// SVG.Timeline = SVG.invent({ +// +// create: function (element) { +// this._target = element +// this.situations = [] +// this.active = false +// this.situation = null +// this.paused = false +// this.lastPos = 0 +// this.pos = 0 +// // The absolute position of an animation is its position in the context of its complete duration (including delay and loops) +// // When performing a delay, absPos is below 0 and when performing a loop, its value is above 1 +// this.absPos = 0 +// this._speed = 1 +// }, +// +// extend: { +// +// /** +// * sets or returns the target of this animation +// * @param o object || number In case of Object it holds all parameters. In case of number its the duration of the animation +// * @param ease function || string Function which should be used for easing or easing keyword +// * @param delay Number indicating the delay before the animation starts +// * @return target || this +// */ +// animate: function (o, ease, delay) { +// if (typeof o === 'object') { +// ease = o.ease +// delay = o.delay +// o = o.duration +// } +// +// var situation = new SVG.Situation({ +// duration: o || 1000, +// delay: delay || 0, +// ease: SVG.easing[ease || '-'] || ease +// }) +// +// this.queue(situation) +// +// return this +// }, +// +// /** +// * sets a delay before the next element of the queue is called +// * @param delay Duration of delay in milliseconds +// * @return this.target() +// */ +// delay: function (delay) { +// // The delay is performed by an empty situation with its duration +// // attribute set to the duration of the delay +// var situation = new SVG.Situation({ +// duration: delay, +// delay: 0, +// ease: SVG.easing['-'] +// }) +// +// return this.queue(situation) +// }, +// +// /** +// * sets or returns the target of this animation +// * @param null || target SVG.Element which should be set as new target +// * @return target || this +// */ +// target: function (target) { +// if (target && target instanceof SVG.Element) { +// this._target = target +// return this +// } +// +// return this._target +// }, +// +// // returns the absolute position at a given time +// timeToAbsPos: function (timestamp) { +// return (timestamp - this.situation.start) / (this.situation.duration / this._speed) +// }, +// +// // returns the timestamp from a given absolute positon +// absPosToTime: function (absPos) { +// return this.situation.duration / this._speed * absPos + this.situation.start +// }, +// +// // starts the animationloop +// startAnimFrame: function () { +// this.stopAnimFrame() +// this.animationFrame = window.requestAnimationFrame(function () { this.step() }.bind(this)) +// }, +// +// // cancels the animationframe +// stopAnimFrame: function () { +// window.cancelAnimationFrame(this.animationFrame) +// }, +// +// // kicks off the animation - only does something when the queue is currently not active and at least one situation is set +// start: function () { +// // dont start if already started +// if (!this.active && this.situation) { +// this.active = true +// this.startCurrent() +// } +// +// return this +// }, +// +// // start the current situation +// startCurrent: function () { +// this.situation.start = +new Date() + this.situation.delay / this._speed +// this.situation.finish = this.situation.start + this.situation.duration / this._speed +// return this.initAnimations().step() +// }, +// +// /** +// * adds a function / Situation to the animation queue +// * @param fn function / situation to add +// * @return this +// */ +// queue: function (fn) { +// if (typeof fn === 'function' || fn instanceof SVG.Situation) { +// this.situations.push(fn) +// } +// +// if (!this.situation) this.situation = this.situations.shift() +// +// return this +// }, +// +// /** +// * pulls next element from the queue and execute it +// * @return this +// */ +// dequeue: function () { +// // stop current animation +// this.stop() +// +// // get next animation from queue +// this.situation = this.situations.shift() +// +// if (this.situation) { +// if (this.situation instanceof SVG.Situation) { +// this.start() +// } else { +// // If it is not a SVG.Situation, then it is a function, we execute it +// this.situation(this) +// } +// } +// +// return this +// }, +// +// // updates all animations to the current state of the element +// // this is important when one property could be changed from another property +// initAnimations: function () { +// var i, j, source +// var s = this.situation +// +// if (s.init) return this +// +// for (i in s.animations) { +// source = this.target()[i]() +// +// if (!Array.isArray(source)) { +// source = [source] +// } +// +// if (!Array.isArray(s.animations[i])) { +// s.animations[i] = [s.animations[i]] +// } +// +// // if(s.animations[i].length > source.length) { +// // source.concat = source.concat(s.animations[i].slice(source.length, s.animations[i].length)) +// // } +// +// for (j = source.length; j--;) { +// // The condition is because some methods return a normal number instead +// // of a SVG.Number +// if (s.animations[i][j] instanceof SVG.Number) { +// source[j] = new SVG.Number(source[j]) +// } +// +// s.animations[i][j] = source[j].morph(s.animations[i][j]) +// } +// } +// +// for (i in s.attrs) { +// s.attrs[i] = new SVG.MorphObj(this.target().attr(i), s.attrs[i]) +// } +// +// for (i in s.styles) { +// s.styles[i] = new SVG.MorphObj(this.target().css(i), s.styles[i]) +// } +// +// s.initialTransformation = this.target().matrixify() +// +// s.init = true +// return this +// }, +// +// clearQueue: function () { +// this.situations = [] +// return this +// }, +// +// clearCurrent: function () { +// this.situation = null +// return this +// }, +// +// /** stops the animation immediately +// * @param jumpToEnd A Boolean indicating whether to complete the current animation immediately. +// * @param clearQueue A Boolean indicating whether to remove queued animation as well. +// * @return this +// */ +// stop: function (jumpToEnd, clearQueue) { +// var active = this.active +// this.active = false +// +// if (clearQueue) { +// this.clearQueue() +// } +// +// if (jumpToEnd && this.situation) { +// // initialize the situation if it was not +// !active && this.startCurrent() +// this.atEnd() +// } +// +// this.stopAnimFrame() +// +// return this.clearCurrent() +// }, +// +// /** resets the element to the state where the current element has started +// * @return this +// */ +// reset: function () { +// if (this.situation) { +// var temp = this.situation +// this.stop() +// this.situation = temp +// this.atStart() +// } +// return this +// }, +// +// // Stop the currently-running animation, remove all queued animations, and complete all animations for the element. +// finish: function () { +// this.stop(true, false) +// +// while (this.dequeue().situation && this.stop(true, false)); +// +// this.clearQueue().clearCurrent() +// +// return this +// }, +// +// // set the internal animation pointer at the start position, before any loops, and updates the visualisation +// atStart: function () { +// return this.at(0, true) +// }, +// +// // set the internal animation pointer at the end position, after all the loops, and updates the visualisation +// atEnd: function () { +// if (this.situation.loops === true) { +// // If in a infinite loop, we end the current iteration +// this.situation.loops = this.situation.loop + 1 +// } +// +// if (typeof this.situation.loops === 'number') { +// // If performing a finite number of loops, we go after all the loops +// return this.at(this.situation.loops, true) +// } else { +// // If no loops, we just go at the end +// return this.at(1, true) +// } +// }, +// +// // set the internal animation pointer to the specified position and updates the visualisation +// // if isAbsPos is true, pos is treated as an absolute position +// at: function (pos, isAbsPos) { +// var durDivSpd = this.situation.duration / this._speed +// +// this.absPos = pos +// // If pos is not an absolute position, we convert it into one +// if (!isAbsPos) { +// if (this.situation.reversed) this.absPos = 1 - this.absPos +// this.absPos += this.situation.loop +// } +// +// this.situation.start = +new Date() - this.absPos * durDivSpd +// this.situation.finish = this.situation.start + durDivSpd +// +// return this.step(true) +// }, +// +// /** +// * sets or returns the speed of the animations +// * @param speed null || Number The new speed of the animations +// * @return Number || this +// */ +// speed: function (speed) { +// if (speed === 0) return this.pause() +// +// if (speed) { +// this._speed = speed +// // We use an absolute position here so that speed can affect the delay before the animation +// return this.at(this.absPos, true) +// } else return this._speed +// }, +// +// // Make loopable +// loop: function (times, reverse) { +// var c = this.last() +// +// // store total loops +// c.loops = (times != null) ? times : true +// c.loop = 0 +// +// if (reverse) c.reversing = true +// return this +// }, +// +// // pauses the animation +// pause: function () { +// this.paused = true +// this.stopAnimFrame() +// +// return this +// }, +// +// // unpause the animation +// play: function () { +// if (!this.paused) return this +// this.paused = false +// // We use an absolute position here so that the delay before the animation can be paused +// return this.at(this.absPos, true) +// }, +// +// /** +// * toggle or set the direction of the animation +// * true sets direction to backwards while false sets it to forwards +// * @param reversed Boolean indicating whether to reverse the animation or not (default: toggle the reverse status) +// * @return this +// */ +// reverse: function (reversed) { +// var c = this.last() +// +// if (typeof reversed === 'undefined') c.reversed = !c.reversed +// else c.reversed = reversed +// +// return this +// }, +// +// /** +// * returns a float from 0-1 indicating the progress of the current animation +// * @param eased Boolean indicating whether the returned position should be eased or not +// * @return number +// */ +// progress: function (easeIt) { +// return easeIt ? this.situation.ease(this.pos) : this.pos +// }, +// +// /** +// * adds a callback function which is called when the current animation is finished +// * @param fn Function which should be executed as callback +// * @return number +// */ +// after: function (fn) { +// var c = this.last() +// function wrapper (e) { +// if (e.detail.situation === c) { +// fn.call(this, c) +// this.off('finished.fx', wrapper) // prevent memory leak +// } +// } +// +// this.target().on('finished.fx', wrapper) +// +// return this._callStart() +// }, +// +// // adds a callback which is called whenever one animation step is performed +// during: function (fn) { +// var c = this.last() +// function wrapper (e) { +// if (e.detail.situation === c) { +// fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, c) +// } +// } +// +// // see above +// this.target().off('during.fx', wrapper).on('during.fx', wrapper) +// +// this.after(function () { +// this.off('during.fx', wrapper) +// }) +// +// return this._callStart() +// }, +// +// // calls after ALL animations in the queue are finished +// afterAll: function (fn) { +// var wrapper = function wrapper (e) { +// fn.call(this) +// this.off('allfinished.fx', wrapper) +// } +// +// // see above +// this.target().off('allfinished.fx', wrapper).on('allfinished.fx', wrapper) +// +// return this._callStart() +// }, +// +// // calls on every animation step for all animations +// duringAll: function (fn) { +// var wrapper = function (e) { +// fn.call(this, e.detail.pos, SVG.morph(e.detail.pos), e.detail.eased, e.detail.situation) +// } +// +// this.target().off('during.fx', wrapper).on('during.fx', wrapper) +// +// this.afterAll(function () { +// this.off('during.fx', wrapper) +// }) +// +// return this._callStart() +// }, +// +// last: function () { +// return this.situations.length ? this.situations[this.situations.length - 1] : this.situation +// }, +// +// // adds one property to the animations +// add: function (method, args, type) { +// this.last()[type || 'animations'][method] = args +// return this._callStart() +// }, +// +// /** perform one step of the animation +// * @param ignoreTime Boolean indicating whether to ignore time and use position directly or recalculate position based on time +// * @return this +// */ +// step: function (ignoreTime) { +// // convert current time to an absolute position +// if (!ignoreTime) this.absPos = this.timeToAbsPos(+new Date()) +// +// // This part convert an absolute position to a position +// if (this.situation.loops !== false) { +// var absPos, absPosInt, lastLoop +// +// // If the absolute position is below 0, we just treat it as if it was 0 +// absPos = Math.max(this.absPos, 0) +// absPosInt = Math.floor(absPos) +// +// if (this.situation.loops === true || absPosInt < this.situation.loops) { +// this.pos = absPos - absPosInt +// lastLoop = this.situation.loop +// this.situation.loop = absPosInt +// } else { +// this.absPos = this.situation.loops +// this.pos = 1 +// // The -1 here is because we don't want to toggle reversed when all the loops have been completed +// lastLoop = this.situation.loop - 1 +// this.situation.loop = this.situation.loops +// } +// +// if (this.situation.reversing) { +// // Toggle reversed if an odd number of loops as occured since the last call of step +// this.situation.reversed = this.situation.reversed !== Boolean((this.situation.loop - lastLoop) % 2) +// } +// } else { +// // If there are no loop, the absolute position must not be above 1 +// this.absPos = Math.min(this.absPos, 1) +// this.pos = this.absPos +// } +// +// // while the absolute position can be below 0, the position must not be below 0 +// if (this.pos < 0) this.pos = 0 +// +// if (this.situation.reversed) this.pos = 1 - this.pos +// +// // apply easing +// var eased = this.situation.ease(this.pos) +// +// // call once-callbacks +// for (var i in this.situation.once) { +// if (i > this.lastPos && i <= eased) { +// this.situation.once[i].call(this.target(), this.pos, eased) +// delete this.situation.once[i] +// } +// } +// +// // fire during callback with position, eased position and current situation as parameter +// if (this.active) this.target().fire('during', {pos: this.pos, eased: eased, fx: this, situation: this.situation}) +// +// // the user may call stop or finish in the during callback +// // so make sure that we still have a valid situation +// if (!this.situation) { +// return this +// } +// +// // apply the actual animation to every property +// this.eachAt() +// +// // do final code when situation is finished +// if ((this.pos === 1 && !this.situation.reversed) || (this.situation.reversed && this.pos === 0)) { +// // stop animation callback +// this.stopAnimFrame() +// +// // fire finished callback with current situation as parameter +// this.target().fire('finished', {fx: this, situation: this.situation}) +// +// if (!this.situations.length) { +// this.target().fire('allfinished') +// +// // Recheck the length since the user may call animate in the afterAll callback +// if (!this.situations.length) { +// this.target().off('.fx') // there shouldnt be any binding left, but to make sure... +// this.active = false +// } +// } +// +// // start next animation +// if (this.active) this.dequeue() +// else this.clearCurrent() +// } else if (!this.paused && this.active) { +// // we continue animating when we are not at the end +// this.startAnimFrame() +// } +// +// // save last eased position for once callback triggering +// this.lastPos = eased +// return this +// }, +// +// // calculates the step for every property and calls block with it +// eachAt: function () { +// var i, at +// var self = this +// var target = this.target() +// var s = this.situation +// +// // apply animations which can be called trough a method +// for (i in s.animations) { +// at = [].concat(s.animations[i]).map(function (el) { +// return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el +// }) +// +// target[i].apply(target, at) +// } +// +// // apply animation which has to be applied with attr() +// for (i in s.attrs) { +// at = [i].concat(s.attrs[i]).map(function (el) { +// return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el +// }) +// +// target.attr.apply(target, at) +// } +// +// // apply animation which has to be applied with css() +// for (i in s.styles) { +// at = [i].concat(s.styles[i]).map(function (el) { +// return typeof el !== 'string' && el.at ? el.at(s.ease(self.pos), self.pos) : el +// }) +// +// target.css.apply(target, at) +// } +// +// // animate initialTransformation which has to be chained +// if (s.transforms.length) { +// +// // TODO: ANIMATE THE TRANSFORMS +// +// // // get initial initialTransformation +// // at = s.initialTransformation +// // for(i = 0, len = s.transforms.length; i < len; i++){ +// // +// // // get next transformation in chain +// // var a = s.transforms[i] +// // +// // // multiply matrix directly +// // if(a instanceof SVG.Matrix){ +// // +// // if(a.relative){ +// // at = at.multiply(new SVG.Matrix().morph(a).at(s.ease(this.pos))) +// // }else{ +// // at = at.morph(a).at(s.ease(this.pos)) +// // } +// // continue +// // } +// // +// // // when transformation is absolute we have to reset the needed transformation first +// // if(!a.relative) +// // a.undo(at.decompose()) +// // +// // // and reapply it after +// // at = at.multiply(a.at(s.ease(this.pos))) +// // +// // } +// // +// // // set new matrix on element +// // target.matrix(at) +// } +// +// return this +// }, +// +// // adds an once-callback which is called at a specific position and never again +// once: function (pos, fn, isEased) { +// var c = this.last() +// if (!isEased) pos = c.ease(pos) +// +// c.once[pos] = fn +// +// return this +// }, +// +// _callStart: function () { +// setTimeout(function () { this.start() }.bind(this), 0) +// return this +// } +// +// }, +// +// parent: SVG.Element, +// +// // Add method to parent elements +// construct: { +// // Get fx module or create a new one, then animate with given duration and ease +// animate: function (o, ease, delay) { +// return (this.fx || (this.fx = new SVG.Timeline(this))).animate(o, ease, delay) +// }, +// delay: function (delay) { +// return (this.fx || (this.fx = new SVG.Timeline(this))).delay(delay) +// }, +// stop: function (jumpToEnd, clearQueue) { +// if (this.fx) { +// this.fx.stop(jumpToEnd, clearQueue) +// } +// +// return this +// }, +// finish: function () { +// if (this.fx) { +// this.fx.finish() +// } +// +// return this +// }, +// // Pause current animation +// pause: function () { +// if (this.fx) { +// this.fx.pause() +// } +// +// return this +// }, +// // Play paused current animation +// play: function () { +// if (this.fx) { this.fx.play() } +// +// return this +// }, +// // Set/Get the speed of the animations +// speed: function (speed) { +// if (this.fx) { +// if (speed == null) { return this.fx.speed() } else { this.fx.speed(speed) } +// } +// +// return this +// } +// } +// +// }) +// +// // MorphObj is used whenever no morphable object is given +// SVG.MorphObj = SVG.invent({ +// +// create: function (from, to) { +// // prepare color for morphing +// if (SVG.Color.isColor(to)) return new SVG.Color(from).morph(to) +// // prepare value list for morphing +// if (SVG.regex.delimiter.test(from)) return new SVG.Array(from).morph(to) +// // prepare number for morphing +// if (SVG.regex.numberAndUnit.test(to)) return new SVG.Number(from).morph(to) +// +// // prepare for plain morphing +// this.value = from +// this.destination = to +// }, +// +// extend: { +// at: function (pos, real) { +// return real < 1 ? this.value : this.destination +// }, +// +// valueOf: function () { +// return this.value +// } +// } +// +// }) +// +// SVG.extend(SVG.Timeline, { +// // Add animatable attributes +// attr: function (a, v, relative) { +// // apply attributes individually +// if (typeof a === 'object') { +// for (var key in a) { +// this.attr(key, a[key]) +// } +// } else { +// this.add(a, v, 'attrs') +// } +// +// return this +// }, +// // Add animatable styles +// css: function (s, v) { +// if (typeof s === 'object') { +// for (var key in s) { +// this.css(key, s[key]) +// } +// } else { +// this.add(s, v, 'styles') +// } +// +// return this +// }, +// // Animatable x-axis +// x: function (x, relative) { +// if (this.target() instanceof SVG.G) { +// this.transform({x: x}, relative) +// return this +// } +// +// var num = new SVG.Number(x) +// num.relative = relative +// return this.add('x', num) +// }, +// // Animatable y-axis +// y: function (y, relative) { +// if (this.target() instanceof SVG.G) { +// this.transform({y: y}, relative) +// return this +// } +// +// var num = new SVG.Number(y) +// num.relative = relative +// return this.add('y', num) +// }, +// // Animatable center x-axis +// cx: function (x) { +// return this.add('cx', new SVG.Number(x)) +// }, +// // Animatable center y-axis +// cy: function (y) { +// return this.add('cy', new SVG.Number(y)) +// }, +// // Add animatable move +// move: function (x, y) { +// return this.x(x).y(y) +// }, +// // Add animatable center +// center: function (x, y) { +// return this.cx(x).cy(y) +// }, +// // Add animatable size +// size: function (width, height) { +// if (this.target() instanceof SVG.Text) { +// // animate font size for Text elements +// this.attr('font-size', width) +// } else { +// // animate bbox based size for all other elements +// var box +// +// if (!width || !height) { +// box = this.target().bbox() +// } +// +// if (!width) { +// width = box.width / box.height * height +// } +// +// if (!height) { +// height = box.height / box.width * width +// } +// +// this.add('width', new SVG.Number(width)) +// .add('height', new SVG.Number(height)) +// } +// +// return this +// }, +// // Add animatable width +// width: function (width) { +// return this.add('width', new SVG.Number(width)) +// }, +// // Add animatable height +// height: function (height) { +// return this.add('height', new SVG.Number(height)) +// }, +// // Add animatable plot +// plot: function (a, b, c, d) { +// // Lines can be plotted with 4 arguments +// if (arguments.length === 4) { +// return this.plot([a, b, c, d]) +// } +// +// return this.add('plot', new (this.target().MorphArray)(a)) +// }, +// // Add leading method +// leading: function (value) { +// return this.target().leading +// ? this.add('leading', new SVG.Number(value)) +// : this +// }, +// // Add animatable viewbox +// viewbox: function (x, y, width, height) { +// if (this.target() instanceof SVG.Container) { +// this.add('viewbox', new SVG.Box(x, y, width, height)) +// } +// +// return this +// }, +// update: function (o) { +// if (this.target() instanceof SVG.Stop) { +// if (typeof o === 'number' || o instanceof SVG.Number) { +// return this.update({ +// offset: arguments[0], +// color: arguments[1], +// opacity: arguments[2] +// }) +// } +// +// 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 +// } +// }) diff --git a/src/gradient.js b/src/gradient.js index ea2197b..2f2a609 100644 --- a/src/gradient.js +++ b/src/gradient.js @@ -50,7 +50,7 @@ SVG.Gradient = SVG.invent({ }) // Add animatable methods to both gradient and fx module -SVG.extend([SVG.Gradient, SVG.FX], { +SVG.extend([SVG.Gradient, SVG.Timeline], { // From position from: function (x, y) { return (this._target || this).type === 'radialGradient' @@ -101,5 +101,4 @@ SVG.Stop = SVG.invent({ return this } } - }) diff --git a/src/matrix.js b/src/matrix.js index 786d1c1..1649370 100644 --- a/src/matrix.js +++ b/src/matrix.js @@ -32,6 +32,13 @@ SVG.Matrix = SVG.invent({ // Transform a matrix into another matrix by manipulating the space transform: function (o) { + // Check if o is a matrix and then left multiply it directly + if (o.a != null) { + var matrix = new SVG.Matrix(o) + var newMatrix = this.lmultiply(matrix) + return newMatrix + } + // Get all of the parameters required to form the matrix var flipX = o.flip && (o.flip === 'x' || o.flip === 'both') ? -1 : 1 var flipY = o.flip && (o.flip === 'y' || o.flip === 'both') ? -1 : 1 diff --git a/src/queue.js b/src/queue.js new file mode 100644 index 0000000..abcfb84 --- /dev/null +++ b/src/queue.js @@ -0,0 +1,81 @@ +SVG.Queue = SVG.invent({ + create: function () { + this._first = null + this._last = null + this.length = 0 + this.id = 0 + }, + + extend: { + push: function (value) { + + // An item stores an id and the provided value + var item = { id: this.id++, value: value } + + // Deal with the queue being empty or populated + if (this._last) { + this._last = this._last.next = item + } else { + this._last = this._first = item + } + + this.length++ + }, + + shift: function () { + if (this.length == 0) { + return + } + + var remove = this._first + this._first = remove.next + this._last = --this.length ? this._last : null + return remove.value + }, + + // Shows us the first item in the list + first: function () { + return this._first && this._first.value + }, + + // Shows us the last item in the list + last: function () { + return this._last && this._last.value + }, + + // Removes the first item from the front where matcher returns true + remove: function (matcher) { + // Find the first match + var previous = null + var current = this._first + while (current) { + + // If we have a match, we are done + if (matcher(current)) break + + // Otherwise, advance both of the pointers + previous = current + current = current.next + } + + // If we got the first item, adjust the first pointer + if (current && current === this._first) + this._first = this._first.next + + // If we got the last item, adjust the last pointer + if (current && current === this._last) + this._last = previous + + // If we got an item, fix the list and return the item + if (current) { + --this.length + + if (previous) { + previous.next = current.next + } + + return current.item + } + } + } +}) diff --git a/src/sugar.js b/src/sugar.js index e3ed6a5..f7b7183 100644 --- a/src/sugar.js +++ b/src/sugar.js @@ -1,151 +1,151 @@ -// Define list of available attributes for stroke and fill -var sugar = { - stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'], - fill: ['color', 'opacity', 'rule'], - prefix: function (t, a) { - return a === 'color' ? t : t + '-' + a - } -} - -// Add sugar for fill and stroke -;['fill', 'stroke'].forEach(function (m) { - var extension = {} - var i - - extension[m] = function (o) { - if (typeof o === 'undefined') { - return this - } - if (typeof o === 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) { - this.attr(m, o) - } else { - // set all attributes from sugar.fill and sugar.stroke list - for (i = sugar[m].length - 1; i >= 0; i--) { - if (o[sugar[m][i]] != null) { - this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]) - } - } - } - - return this - } - - SVG.extend([SVG.Element, SVG.FX], extension) -}) - -SVG.extend([SVG.Element, SVG.FX], { - // Let the user set the matrix directly - matrix: function (mat, b, c, d, e, f) { - // Act as a getter - if (mat == null) { - return new SVG.Matrix(this) - } - - // Act as a setter, the user can pass a matrix or a set of numbers - return this.attr('transform', new SVG.Matrix(mat, b, c, d, e, f)) - }, - - // Map rotation to transform - rotate: function (angle, cx, cy) { - return this.transform({rotate: angle, ox: cx, oy: cy}, true) - }, - - // Map skew to transform - skew: function (x, y, cx, cy) { - return arguments.length === 1 || arguments.length === 3 - ? this.transform({skew: x, ox: y, oy: cx}, true) - : this.transform({skew: [x, y], ox: cx, oy: cy}, true) - }, - - shear: function (lam, cx, cy) { - return this.transform({shear: lam, ox: cx, oy: cy}, true) - }, - - // Map scale to transform - scale: function (x, y, cx, cy) { - return arguments.length === 1 || arguments.length === 3 - ? this.transform({ scale: x, ox: y, oy: cx }, true) - : this.transform({ scale: [x, y], ox: cx, oy: cy }, true) - }, - - // Map translate to transform - translate: function (x, y) { - return this.transform({ translate: [x, y] }, true) - }, - - // Map relative translations to transform - relative: function (x, y) { - return this.transform({ relative: [x, y] }, true) - }, - - // Map flip to transform - flip: function (direction, around) { - var directionString = typeof direction === 'string' ? direction - : isFinite(direction) ? 'both' - : 'both' - var origin = (direction === 'both' && isFinite(around)) ? [around, around] - : (direction === 'x') ? [around, 0] - : (direction === 'y') ? [0, around] - : isFinite(direction) ? [direction, direction] - : [0, 0] - this.transform({flip: directionString, origin: origin}, true) - }, - - // Opacity - opacity: function (value) { - return this.attr('opacity', value) - }, - - // Relative move over x axis - dx: function (x) { - return this.x(new SVG.Number(x).plus(this instanceof SVG.FX ? 0 : this.x()), true) - }, - - // Relative move over y axis - dy: function (y) { - return this.y(new SVG.Number(y).plus(this instanceof SVG.FX ? 0 : this.y()), true) - }, - - // Relative move over x and y axes - dmove: function (x, y) { - return this.dx(x).dy(y) - } -}) - -SVG.extend([SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.FX], { - // Add x and y radius - radius: function (x, y) { - var type = (this._target || this).type - return type === 'radialGradient' || type === 'radialGradient' - ? this.attr('r', new SVG.Number(x)) - : this.rx(x).ry(y == null ? x : y) - } -}) - -SVG.extend(SVG.Path, { - // Get path length - length: function () { - return this.node.getTotalLength() - }, - // Get point at length - pointAt: function (length) { - return new SVG.Point(this.node.getPointAtLength(length)) - } -}) - -SVG.extend([SVG.Parent, SVG.Text, SVG.Tspan, SVG.FX], { - // Set font - font: function (a, v) { - if (typeof a === 'object') { - for (v in a) this.font(v, a[v]) - } - - return a === 'leading' - ? this.leading(v) - : a === 'anchor' - ? this.attr('text-anchor', v) - : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style' - ? this.attr('font-' + a, v) - : this.attr(a, v) - } -}) +// // Define list of available attributes for stroke and fill +// var sugar = { +// stroke: ['color', 'width', 'opacity', 'linecap', 'linejoin', 'miterlimit', 'dasharray', 'dashoffset'], +// fill: ['color', 'opacity', 'rule'], +// prefix: function (t, a) { +// return a === 'color' ? t : t + '-' + a +// } +// } +// +// // Add sugar for fill and stroke +// ;['fill', 'stroke'].forEach(function (m) { +// var extension = {} +// var i +// +// extension[m] = function (o) { +// if (typeof o === 'undefined') { +// return this +// } +// if (typeof o === 'string' || SVG.Color.isRgb(o) || (o && typeof o.fill === 'function')) { +// this.attr(m, o) +// } else { +// // set all attributes from sugar.fill and sugar.stroke list +// for (i = sugar[m].length - 1; i >= 0; i--) { +// if (o[sugar[m][i]] != null) { +// this.attr(sugar.prefix(m, sugar[m][i]), o[sugar[m][i]]) +// } +// } +// } +// +// return this +// } +// +// SVG.extend([SVG.Element, SVG.Timeline], extension) +// }) +// +// SVG.extend([SVG.Element, SVG.Timeline], { +// // Let the user set the matrix directly +// matrix: function (mat, b, c, d, e, f) { +// // Act as a getter +// if (mat == null) { +// return new SVG.Matrix(this) +// } +// +// // Act as a setter, the user can pass a matrix or a set of numbers +// return this.attr('transform', new SVG.Matrix(mat, b, c, d, e, f)) +// }, +// +// // Map rotation to transform +// rotate: function (angle, cx, cy) { +// return this.transform({rotate: angle, ox: cx, oy: cy}, true) +// }, +// +// // Map skew to transform +// skew: function (x, y, cx, cy) { +// return arguments.length === 1 || arguments.length === 3 +// ? this.transform({skew: x, ox: y, oy: cx}, true) +// : this.transform({skew: [x, y], ox: cx, oy: cy}, true) +// }, +// +// shear: function (lam, cx, cy) { +// return this.transform({shear: lam, ox: cx, oy: cy}, true) +// }, +// +// // Map scale to transform +// scale: function (x, y, cx, cy) { +// return arguments.length === 1 || arguments.length === 3 +// ? this.transform({ scale: x, ox: y, oy: cx }, true) +// : this.transform({ scale: [x, y], ox: cx, oy: cy }, true) +// }, +// +// // Map translate to transform +// translate: function (x, y) { +// return this.transform({ translate: [x, y] }, true) +// }, +// +// // Map relative translations to transform +// relative: function (x, y) { +// return this.transform({ relative: [x, y] }, true) +// }, +// +// // Map flip to transform +// flip: function (direction, around) { +// var directionString = typeof direction === 'string' ? direction +// : isFinite(direction) ? 'both' +// : 'both' +// var origin = (direction === 'both' && isFinite(around)) ? [around, around] +// : (direction === 'x') ? [around, 0] +// : (direction === 'y') ? [0, around] +// : isFinite(direction) ? [direction, direction] +// : [0, 0] +// this.transform({flip: directionString, origin: origin}, true) +// }, +// +// // Opacity +// opacity: function (value) { +// return this.attr('opacity', value) +// }, +// +// // Relative move over x axis +// dx: function (x) { +// return this.x(new SVG.Number(x).plus(this instanceof SVG.Timeline ? 0 : this.x()), true) +// }, +// +// // Relative move over y axis +// dy: function (y) { +// return this.y(new SVG.Number(y).plus(this instanceof SVG.Timeline ? 0 : this.y()), true) +// }, +// +// // Relative move over x and y axes +// dmove: function (x, y) { +// return this.dx(x).dy(y) +// } +// }) +// +// SVG.extend([SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.Timeline], { +// // Add x and y radius +// radius: function (x, y) { +// var type = (this._target || this).type +// return type === 'radialGradient' || type === 'radialGradient' +// ? this.attr('r', new SVG.Number(x)) +// : this.rx(x).ry(y == null ? x : y) +// } +// }) +// +// SVG.extend(SVG.Path, { +// // Get path length +// length: function () { +// return this.node.getTotalLength() +// }, +// // Get point at length +// pointAt: function (length) { +// return new SVG.Point(this.node.getPointAtLength(length)) +// } +// }) +// +// SVG.extend([SVG.Parent, SVG.Text, SVG.Tspan, SVG.Timeline], { +// // Set font +// font: function (a, v) { +// if (typeof a === 'object') { +// for (v in a) this.font(v, a[v]) +// } +// +// return a === 'leading' +// ? this.leading(v) +// : a === 'anchor' +// ? this.attr('text-anchor', v) +// : a === 'size' || a === 'family' || a === 'weight' || a === 'stretch' || a === 'variant' || a === 'style' +// ? this.attr('font-' + a, v) +// : this.attr(a, v) +// } +// }) diff --git a/src/timeline.js b/src/timeline.js new file mode 100644 index 0000000..035c0f7 --- /dev/null +++ b/src/timeline.js @@ -0,0 +1,171 @@ + +// Must Change .... +SVG.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 } +} + + +function Runner (timeline) { + + // We store a reference to the function to run and the timeline to use + this.functions = [] + this.timeline = timeline + this.transforms = [] + this.done = false + + // We copy the current values from the timeline because they can change + this._startTime = timeline._startTime + this._duration = timeline._duration + this._loop = timeline._loop +} + +Runner.prototype = { + + add: function (initFn, runFn) { + this.initialisers.push(initFn) + this.functions.push(fn) + }, + + run: function (time) { + + var line = this.timeline + + // If it is time to do something, act now. + var running = this._start < time && time < end + if (running && this._running) { + var position = (time - this._startTime) / this._duration + var toRun = this.functions + for (var i = 0, len = toRun.length, i < len ; ++i) { + toRun[i](position) + } + } + + // If we are not paused or stopped, request another frame + if (this._running) SVG.Animator.frame(closure, this._startTime) + + // Tell the caller whether this animation is finished + closure.finished = !running + }, + + stop: function () { + + }, + + pause: function () { + + }, +} + + +SVG.Timeline = SVG.invent({ + + create: function (o, easy, delay, epoch) { + + this.baseTransform = [] + this.runners = [] + this.controller = null + + if(o instanceof 'function') { + this.controller = o + + } else if (typeof o === 'object') { + ease = o.ease + delay = o.delay + o = o.duration + } + + this.ease = ease + this.delay = delay + this.duration = o + }, + + extend: { + + animate (duration, ease, delay, epoch) + loop (times, reverse) + duration (time) + delay (by, epoch) + ease (fn) + + play () + pause () + stop () + finish (all=true) + speed (newSpeed) + seek (dt) + persist (dt || forever) // 0 by default + reverse () + + _step (dt) { + + }, + + // Checks if we are running and continues the animation + _continue () { + , continue: function () { + if (this.paused) return + if (!this.nextFrame) + this.step() + return this + } + + } + }, + + + construct: { + animate: function(o, ease, delay, epoch) { + return (this.timeline = this.timeline || new SVG.Timeline(o, ease, delay, epoch)) + } + } + +} + +// Extend the attribute methods separately to avoid cluttering the main +// Timeline class above +SVG.extend(SVG.Timeline, { + + + attr: function (a, v) { + return this.styleAttr('attr', a, v) + }, + + // Add animatable styles + css: function (s, v) { + return this.styleAttr('css', s, v) + }, + + styleAttr (type, name, val) { + // apply attributes individually + if (typeof name === 'object') { + for (var key in val) { + this.styleAttr(type, key, val[key]) + } + } + + var morpher = new Morph(this.controller).to(val) + + this.queue( + function () { + morpher = morpher.from(element[type]('name')) + }, + function () { + this.element[type](name, morpher.at(pos)) + } + ) + + return this + }, + + zoom(level, point) { + let morpher = SVG.Number(level).controller(this.controller) + this.queue( + () => {morpher = morpher.from(element.zoom())}, + (pos) => {element.zoom(morpher.at(pos), point)} + ) + return this + } +}) diff --git a/src/transform.js b/src/transform.js index b173cb2..ecb5fc4 100644 --- a/src/transform.js +++ b/src/transform.js @@ -50,7 +50,8 @@ SVG.extend(SVG.Element, { SVG.extend(SVG.Element, { // Add transformations - transform: function (o, cyOrRel) { + transform: function (o, relative) { + // Get the bounding box of the element with no transformations applied var bbox = this.bbox() @@ -59,20 +60,6 @@ SVG.extend(SVG.Element, { var decomposed = new SVG.Matrix(this).decompose() return decomposed[o] || decomposed - // Let the user pass in a matrix as well - } else if (o.a != null) { - // Construct a matrix from the first parameter - var matrix = new SVG.Matrix(o) - - // If we have a relative matrix, we just apply the old matrix - if (cyOrRel != null) { - var oldMatrix = new SVG.Matrix(this) - matrix = matrix.multiply(oldMatrix) - } - - // Apply the matrix directly - return this.attr('transform', matrix) - // Allow the user to define the origin with a string } else if (typeof o.origin === 'string' || (o.origin == null && o.ox == null && o.oy == null) @@ -99,13 +86,14 @@ SVG.extend(SVG.Element, { } // The user can pass a boolean, an SVG.Element or an SVG.Matrix or nothing - var result = new SVG.Matrix(cyOrRel === true ? this : cyOrRel).transform(o) + var cleanRelative = relative === true ? this : (relative || false) + var result = new SVG.Matrix(cleanRelative).transform(o) return this.attr('transform', result) } }) -SVG.extend(SVG.FX, { - transform: function (o, relative) { +SVG.extend(SVG.Timeline, { + transform: function (o, relative, affine) { // // get target in case of the fx module, otherwise reference this // var target = this.target() @@ -232,146 +220,3 @@ SVG.extend(SVG.FX, { // return this._callStart() } }) - -// TODO: DESTROY -// ======= -// -// -// SVG.Transformation = SVG.invent({ -// -// create: function(source, inversed){ -// -// if(arguments.length > 1 && typeof inversed != 'boolean'){ -// return this.constructor.call(this, [].slice.call(arguments)) -// } -// -// if(Array.isArray(source)){ -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// this[this.arguments[i]] = source[i] -// } -// } else if(typeof source == 'object'){ -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// this[this.arguments[i]] = source[this.arguments[i]] -// } -// } -// -// this.inversed = false -// -// if(inversed === true){ -// this.inversed = true -// } -// -// } -// -// , extend: { -// -// arguments: [] -// , method: '' -// -// , at: function(pos){ -// -// var params = [] -// -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// params.push(this[this.arguments[i]]) -// } -// -// var m = this._undo || new SVG.Matrix() -// -// m = new SVG.Matrix().morph(SVG.Matrix.prototype[this.method].apply(m, params)).at(pos) -// -// return this.inversed ? m.inverse() : m -// -// } -// -// , undo: function(o){ -// for(var i = 0, len = this.arguments.length; i < len; ++i){ -// o[this.arguments[i]] = typeof this[this.arguments[i]] == 'undefined' ? 0 : o[this.arguments[i]] -// } -// -// // The method SVG.Matrix.extract which was used before calling this -// // method to obtain a value for the parameter o doesn't return a cx and -// // a cy so we use the ones that were provided to this object at its creation -// o.cx = this.cx -// o.cy = this.cy -// -// this._undo = new SVG[capitalize(this.method)](o, true).at(1) -// -// return this -// } -// -// } -// -// }) -// -// SVG.Translate = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['transformedX', 'transformedY'] -// , method: 'translate' -// } -// -// }) -// -// SVG.Rotate = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['rotation', 'cx', 'cy'] -// , method: 'rotate' -// , at: function(pos){ -// var m = new SVG.Matrix().rotate(new SVG.Number().morph(this.rotation - (this._undo ? this._undo.rotation : 0)).at(pos), this.cx, this.cy) -// return this.inversed ? m.inverse() : m -// } -// , undo: function(o){ -// this._undo = o -// return this -// } -// } -// -// }) -// -// SVG.Scale = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['scaleX', 'scaleY', 'cx', 'cy'] -// , method: 'scale' -// } -// -// }) -// -// SVG.Skew = SVG.invent({ -// -// parent: SVG.Matrix -// , inherit: SVG.Transformation -// -// , create: function(source, inversed){ -// this.constructor.apply(this, [].slice.call(arguments)) -// } -// -// , extend: { -// arguments: ['skewX', 'skewY', 'cx', 'cy'] -// , method: 'skew' -// } -// -// }) |