diff options
-rw-r--r-- | dist/svg.js | 122 | ||||
-rw-r--r-- | dist/svg.min.js | 4 | ||||
-rw-r--r-- | spec/spec/fx.js | 1316 | ||||
-rw-r--r-- | src/fx.js | 120 |
4 files changed, 1279 insertions, 283 deletions
diff --git a/dist/svg.js b/dist/svg.js index dd5cb64..e94fe38 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -6,7 +6,7 @@ * @copyright Wout Fierens <wout@mick-wout.com.com> * @license MIT * -* BUILT: Tue Nov 01 2016 17:15:59 GMT-0400 (EDT) +* BUILT: Tue Nov 01 2016 20:04:39 GMT-0400 (EDT) */; (function(root, factory) { if (typeof define === 'function' && define.amd) { @@ -1240,7 +1240,9 @@ SVG.Situation = SVG.invent({ this.finish = this.start + this.duration this.ease = o.ease - this.loop = false + // 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 = { @@ -1286,6 +1288,9 @@ SVG.FX = SVG.invent({ 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 } @@ -1342,14 +1347,14 @@ SVG.FX = SVG.invent({ return this._target } - // returns the position at a given time - , timeToPos: function(timestamp){ + // 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 positon - , posToTime: function(pos){ - return this.situation.duration/this._speed * pos + this.situation.start + // returns the timestamp from a given absolute positon + , absPosToTime: function(absPos){ + return this.situation.duration/this._speed * absPos + this.situation.start } // starts the animationloop @@ -1367,7 +1372,7 @@ SVG.FX = SVG.invent({ , start: function(){ // dont start if already started if(!this.active && this.situation){ - this.situation.start = +new Date + this.situation.delay + this.situation.start = +new Date + this.situation.delay/this._speed this.situation.finish = this.situation.start + this.situation.duration/this._speed this.initAnimations() @@ -1407,7 +1412,7 @@ SVG.FX = SVG.invent({ var fn = function(){ if(this.situation instanceof SVG.Situation) - this.initAnimations().at(0) + this.initAnimations().atStart() else if(this.situation instanceof SVG.Delay) this.dequeue() else @@ -1498,15 +1503,7 @@ SVG.FX = SVG.invent({ this.active = false if(jumpToEnd && this.situation){ - - this.situation.loop = false - - if(this.situation.loops % 2 == 0 && this.situation.reversing){ - this.situation.reversed = true - } - - this.at(1) - + this.atEnd() } this.stopAnimFrame() @@ -1523,7 +1520,7 @@ SVG.FX = SVG.invent({ var temp = this.situation this.stop() this.situation = temp - this.at(0) + this.atStart() } return this } @@ -1540,13 +1537,40 @@ SVG.FX = SVG.invent({ 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 + return this.at(this.situation.loop+1, true) + } else 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 - , at: function(pos){ + // if isAbsPos is true, pos is treated as an absolute position + , at: function(pos, isAbsPos){ var durDivSpd = this.situation.duration/this._speed - this.pos = pos - this.situation.start = +new Date - pos * durDivSpd + 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) } @@ -1560,7 +1584,8 @@ SVG.FX = SVG.invent({ if (speed) { this._speed = speed - return this.at(this.situation.reversed ? 1-this.pos : this.pos) + // 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 } @@ -1568,8 +1593,9 @@ SVG.FX = SVG.invent({ , loop: function(times, reverse) { var c = this.last() - // store current loop and total loops - c.loop = c.loops = times || true + // store total loops + c.loops = (times != null) ? times : true + c.loop = 0 if(reverse) c.reversing = true return this @@ -1587,7 +1613,8 @@ SVG.FX = SVG.invent({ , play: function(){ if(!this.paused) return this this.paused = false - return this.at(this.pos) + // We use an absolute position here so that the delay before the animation can be paused + return this.at(this.absPos, true) } /** @@ -1692,22 +1719,45 @@ SVG.FX = SVG.invent({ */ , step: function(ignoreTime){ - // convert current time to position - if(!ignoreTime) this.pos = this.timeToPos(+new Date) - - if(this.pos >= 1 && (this.situation.loop === true || (typeof this.situation.loop == 'number' && --this.situation.loop))){ + // 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){ - this.situation.reversed = !this.situation.reversed + 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) } - return this.at(this.pos-1) + + } 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 - // correct position - if(this.pos > 1)this.pos = 1 - if(this.pos < 0)this.pos = 0 // apply easing var eased = this.situation.ease(this.pos) diff --git a/dist/svg.min.js b/dist/svg.min.js index d6b4ca4..2d15761 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1,2 +1,2 @@ -/*! svg.js v2.3.6 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,e){return t instanceof e}function n(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function r(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function s(t){return t.charAt(0).toUpperCase()+t.slice(1)}function a(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 o(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function h(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 u(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function l(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function c(t){return t instanceof y.Matrix||(t=new y.Matrix(t)),t}function f(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function d(t){return t=t.replace(y.regex.whitespace,"").replace(y.regex.matrix,"").split(y.regex.matrixElements),l(y.utils.map(t,function(t){return parseFloat(t)}))}function p(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 m(t){for(var e=t.childNodes.length-1;e>=0;e--)t.childNodes[e]instanceof SVGElement&&m(t.childNodes[e]);return y.adopt(t).id(y.eid(t.nodeName))}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 v(t){var e=t.toString().match(y.regex.reference);if(e)return e[1]}var y=this.SVG=function(t){if(y.supported)return t=new y.Doc(t),y.parser.draw||y.prepare(),t};if(y.ns="http://www.w3.org/2000/svg",y.xmlns="http://www.w3.org/2000/xmlns/",y.xlink="http://www.w3.org/1999/xlink",y.svgjs="http://svgjs.com/svgjs",y.supported=function(){return!!e.createElementNS&&!!e.createElementNS(y.ns,"svg").createSVGRect}(),!y.supported)return!1;y.did=1e3,y.eid=function(t){return"Svgjs"+s(t)+y.did++},y.create=function(t){var i=e.createElementNS(this.ns,t);return i.setAttribute("id",this.eid(t)),i},y.extend=function(){var t,e,i,n;for(t=[].slice.call(arguments),e=t.pop(),n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i];y.Set&&y.Set.inherit&&y.Set.inherit()},y.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,y.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&y.extend(e,t.extend),t.construct&&y.extend(t.parent||y.Container,t.construct),e},y.adopt=function(t){if(!t)return null;if(t.instance)return t.instance;var e;return e="svg"==t.nodeName?t.parentNode instanceof SVGElement?new y.Nested:new y.Doc:"linearGradient"==t.nodeName?new y.Gradient("linear"):"radialGradient"==t.nodeName?new y.Gradient("radial"):y[s(t.nodeName)]?new(y[s(t.nodeName)]):new y.Element(t),e.type=t.nodeName,e.node=t,t.instance=e,e instanceof y.Doc&&e.namespace().defs(),e.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}),e},y.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new y.Doc(t):new y.Doc(e.documentElement).nested()).size(2,0);y.parser={body:t||e.documentElement,draw:i.style("opacity:0;position:fixed;left:100%;top:100%;overflow:hidden"),poly:i.polyline().node,path:i.path().node,native:y.create("svg")}},y.parser={native:y.create("svg")},e.addEventListener("DOMContentLoaded",function(){y.parser.draw||y.prepare()},!1),y.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,matrix:/matrix\(|\)/g,matrixElements:/,*\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,negExp:/e\-/gi,comma:/,/g,hyphen:/\-/g,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,whitespaces:/\s+/,X:/X/g},y.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(t){return this.filter(t,function(t){return t instanceof SVGElement})}},y.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"}},y.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?y.regex.isRgb.test(t)?(e=y.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):y.regex.isHex.test(t)&&(e=y.regex.hex.exec(a(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))},y.extend(y.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+o(this.r)+o(this.g)+o(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 y.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new y.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}}),y.Color.test=function(t){return t+="",y.regex.isHex.test(t)||y.regex.isRgb.test(t)},y.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},y.Color.isColor=function(t){return y.Color.isRgb(t)||y.Color.test(t)},y.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},y.extend(y.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++)i.indexOf(this.value[t])==-1&&i.push(this.value[t]);return this.value=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 y.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:this.split(t)},split:function(t){return t.trim().split(/\s+/)},reverse:function(){return this.value.reverse(),this}}),y.PointArray=function(t,e){this.constructor.call(this,t,e||[[0,0]])},y.PointArray.prototype=new y.Array,y.extend(y.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 y.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t))return t;t=t.trim().split(/\s+|,/),t.length%2!==0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([parseFloat(t[i]),parseFloat(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--)this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x,this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y;return this},bbox:function(){return y.parser.poly.setAttribute("points",this.toString()),y.parser.poly.getBBox()}}),y.PathArray=function(t,e){this.constructor.call(this,t,e||[["M",0,0]])},y.PathArray.prototype=new y.Array,y.extend(y.PathArray,{toString:function(){return p(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},parse:function(t){if(t instanceof y.PathArray)return t.valueOf();var e,i,n,r,s,a,o=0,h=0,u={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7};if("string"==typeof t){for(t=t.replace(y.regex.negExp,"X").replace(y.regex.pathLetters," $& ").replace(y.regex.hyphen," -").replace(y.regex.comma," ").replace(y.regex.X,"e-").trim().split(y.regex.whitespaces),e=t.length;--e;)if(t[e].indexOf(".")!=t[e].lastIndexOf(".")){var l=t[e].split("."),c=[l.shift(),l.shift()].join(".");t.splice.apply(t,[e,1].concat(c,l.map(function(t){return"."+t})))}}else t=t.reduce(function(t,e){return[].concat.apply(t,e)},[]);var a=[];do{for(y.regex.isPathLetter.test(t[0])?(r=t[0],t.shift()):"M"==r?r="L":"m"==r&&(r="l"),s=[r.toUpperCase()],e=0;e<u[s[0]];++e)s.push(parseFloat(t.shift()));r==s[0]?"M"==r||"L"==r||"C"==r||"Q"==r||"S"==r||"T"==r?(o=s[u[s[0]]-1],h=s[u[s[0]]]):"V"==r?h=s[1]:"H"==r?o=s[1]:"A"==r&&(o=s[6],h=s[7]):"m"==r||"l"==r||"c"==r||"s"==r||"q"==r||"t"==r?(s[1]+=o,s[2]+=h,null!=s[3]&&(s[3]+=o,s[4]+=h),null!=s[5]&&(s[5]+=o,s[6]+=h),o=s[u[s[0]]-1],h=s[u[s[0]]]):"v"==r?(s[1]+=h,h=s[1]):"h"==r?(s[1]+=o,o=s[1]):"a"==r&&(s[6]+=o,s[7]+=h,o=s[6],h=s[7]),"M"==s[0]&&(i=o,n=h),"Z"==s[0]&&(o=i,h=n),a.push(s)}while(t.length);return a},bbox:function(){return y.parser.path.setAttribute("d",this.toString()),y.parser.path.getBBox()}}),y.Number=y.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(y.regex.numberAndUnit),e&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5])):t instanceof y.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 new y.Number(this+new y.Number(t),this.unit)},minus:function(t){return this.plus(-new y.Number(t))},times:function(t){return new y.Number(this*new y.Number(t),this.unit)},divide:function(t){return new y.Number(this/new y.Number(t),this.unit)},to:function(t){var e=new y.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new y.Number(t),this},at:function(t){return this.destination?new y.Number(this.destination).minus(this).times(t).plus(this):this}}}),y.Element=y.invent({create:function(t){this._stroke=y.defaults.attrs.stroke,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this,this._stroke=t.getAttribute("stroke")||this._stroke)},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=h(this,t,e);return this.width(new y.Number(i.width)).height(new y.Number(i.height))},clone:function(t){var e=m(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 t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return 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.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(/\s+/)},hasClass:function(t){return this.classes().indexOf(t)!=-1},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 y.get(this.attr(t))},parent:function(t){var e=this;if(!e.node.parentNode)return null;if(e=y.adopt(e.node.parentNode),!t)return e;for(;e&&e.node instanceof SVGElement;){if("string"==typeof t?e.matches(t):e instanceof t)return e;e=y.adopt(e.node.parentNode)}},doc:function(){return this instanceof y.Doc?this:this.parent(y.Doc)},parents:function(t){var e=[],i=this;do{if(i=i.parent(t),!i||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return n(this.node,t)},native:function(){return this.node},svg:function(t){var i=e.createElement("svg");if(!(t&&this instanceof y.Parent))return i.appendChild(t=e.createElement("svg")),this.writeDataToDom(),t.appendChild(this.node.cloneNode(!0)),i.innerHTML.replace(/^<svg>/,"").replace(/<\/svg>$/,"");i.innerHTML="<svg>"+t.replace(/\n/,"").replace(/<(\w+)([^<]+?)\/>/g,"<$1$2></$1>")+"</svg>";for(var n=0,r=i.firstChild.childNodes.length;n<r;n++)this.node.appendChild(i.firstChild.firstChild);return this},writeDataToDom:function(){if(this.each||this.lines){var t=this.each?this:this.lines();t.each(function(){this.writeDataToDom()})}return this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return i(this,t)}}}),y.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-Math.cos(t*Math.PI/2)+1}},y.morph=function(t){return function(e,i){return new y.MorphObj(e,i).at(t)}},y.Situation=y.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new y.Number(t.duration).valueOf(),this.delay=new y.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=!1,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),y.Delay=function(t){this.delay=new y.Number(t).valueOf()},y.FX=y.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._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new y.Situation({duration:t||1e3,delay:i||0,ease:y.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var t=new y.Delay(t);return this.queue(t)},target:function(t){return t&&t instanceof y.Element?(this._target=t,this):this._target},timeToPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},posToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.situation.start=+new Date+this.situation.delay,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations(),this.active=!0,this.startAnimFrame()),this},queue:function(t){return("function"==typeof t||t instanceof y.Situation||t instanceof y.Delay)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){if(this.situation&&this.situation.stop&&this.situation.stop(),this.situation=this.situations.shift(),this.situation){var t=function(){this.situation instanceof y.Situation?this.initAnimations().at(0):this.situation instanceof y.Delay?this.dequeue():this.situation.call(this)}.bind(this);this.situation.delay?setTimeout(function(){t()},this.situation.delay):t()}return this},initAnimations:function(){var t,e=this.situation;if(e.init)return this;for(t in e.animations)"viewbox"==t?e.animations[t]=this.target().viewbox().morph(e.animations[t]):(e.animations[t].value="plot"==t?this.target().array().value:this.target()[t](),e.animations[t].value.value&&(e.animations[t].value=e.animations[t].value.value),e.animations[t].relative&&(e.animations[t].destination.value=e.animations[t].destination.value+e.animations[t].value));for(t in e.attrs)if(e.attrs[t]instanceof y.Color){var i=new y.Color(this.target().attr(t));e.attrs[t].r=i.r,e.attrs[t].g=i.g,e.attrs[t].b=i.b}else e.attrs[t].value=this.target().attr(t);for(t in e.styles)e.styles[t].value=this.target().style(t);return e.initialTransformation=this.target().matrixify(),e.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){return this.active||this.start(),e&&this.clearQueue(),this.active=!1,t&&this.situation&&(this.situation.loop=!1,this.situation.loops%2==0&&this.situation.reversing&&(this.situation.reversed=!0),this.at(1)),this.stopAnimFrame(),clearTimeout(this.timeout),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.at(0)}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},at:function(t){var e=this.situation.duration/this._speed;return this.pos=t,this.situation.start=+new Date-t*e,this.situation.finish=this.situation.start+e,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.situation.reversed?1-this.pos:this.pos)):this._speed},loop:function(t,e){var i=this.last();return i.loop=i.loops=t||!0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),clearTimeout(this.timeout),this},play:function(){return this.paused?(this.paused=!1,this.at(this.pos)):this},reverse:function(t){var e=this.last();return"undefined"==typeof t?e.reversed=!e.reversed:e.reversed=t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,y.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)})},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},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,y.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)})},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,setTimeout(function(){this.start()}.bind(this),0),this},step:function(t){if(t||(this.pos=this.timeToPos(+new Date)),this.pos>=1&&(this.situation.loop===!0||"number"==typeof this.situation.loop&&--this.situation.loop))return this.situation.reversing&&(this.situation.reversed=!this.situation.reversed),this.at(this.pos-1);this.situation.reversed&&(this.pos=1-this.pos),this.pos>1&&(this.pos=1),this.pos<0&&(this.pos=0);var e=this.situation.ease(this.pos);for(var i in this.situation.once)i>this.lastPos&&i<=e&&(this.situation.once[i].call(this.target(),this.pos,e),delete this.situation.once[i]);return this.active&&this.target().fire("during",{pos:this.pos,eased:e,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.target().off(".fx"),this.active=!1),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=e,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 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 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 t.at?t.at(r.ease(i.pos),i.pos):t}),n.style.apply(n,e);if(r.transforms.length){e=r.initialTransformation;for(t in r.transforms){var s=r.transforms[t];s instanceof y.Matrix?e=s.relative?e.multiply(s.at(r.ease(this.pos))):e.morph(s).at(r.ease(this.pos)):(s.relative||s.undo(e.extract()),e=e.multiply(s.at(r.ease(this.pos))))}n.matrix(e)}return this},once:function(t,e,i){return i||(t=this.situation.ease(t)),this.situation.once[t]=e,this}},parent:y.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new y.FX(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new y.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}}}),y.MorphObj=y.invent({create:function(t,e){return y.Color.isColor(e)?new y.Color(t).morph(e):y.regex.numberAndUnit.test(e)?new y.Number(t).morph(e):(this.value=0,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),y.extend(y.FX,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,new y.MorphObj(null,e),"attrs");return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.add(t,new y.MorphObj(null,e),"styles");return this},x:function(t,e){if(this.target()instanceof y.G)return this.transform({x:t},e),this;var i=(new y.Number).morph(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof y.G)return this.transform({y:t},e),this;var i=(new y.Number).morph(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",(new y.Number).morph(t))},cy:function(t){return this.add("cy",(new y.Number).morph(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 y.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 y.Number).morph(t)).add("height",(new y.Number).morph(e))}return this},plot:function(t){return this.add("plot",this.target().array().morph(t))},leading:function(t){return this.target().leading?this.add("leading",(new y.Number).morph(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof y.Container&&this.add("viewbox",new y.ViewBox(t,e,i,n)),this},update:function(t){if(this.target()instanceof y.Stop){if("number"==typeof t||t instanceof y.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}}),y.BBox=y.invent({create:function(t){if(t){var i;try{if(!e.documentElement.contains(t.node))throw new Exception("Element not in the dom");i=t.node.getBBox()}catch(e){if(t instanceof y.Shape){var n=t.clone(y.parser.draw).show();i=n.bbox(),n.remove()}else i={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=i.x,this.y=i.y,this.width=i.width,this.height=i.height}x(this)},parent:y.Element,construct:{bbox:function(){return new y.BBox(this)}}}),y.TBox=y.invent({create:function(t){if(t){var e=t.ctm().extract(),i=t.bbox();this.width=i.width*e.scaleX,this.height=i.height*e.scaleY,this.x=i.x+e.x,this.y=i.y+e.y}x(this)},parent:y.Element,construct:{tbox:function(){return new y.TBox(this)}}}),y.RBox=y.invent({create:function(e){if(e){var i=e.doc().parent(),n=e.node.getBoundingClientRect(),r=1;for(this.x=n.left,this.y=n.top,this.x-=i.offsetLeft,this.y-=i.offsetTop;i=i.offsetParent;)this.x-=i.offsetLeft,this.y-=i.offsetTop;for(i=e;i.parent&&(i=i.parent());)i.viewbox&&(r*=i.viewbox().zoom,this.x-=i.x()||0,this.y-=i.y()||0);this.width=n.width/=r,this.height=n.height/=r}x(this),this.x+=t.pageXOffset,this.y+=t.pageYOffset},parent:y.Element,construct:{rbox:function(){return new y.RBox(this)}}}),[y.BBox,y.TBox,y.RBox].forEach(function(t){y.extend(t,{merge:function(e){var i=new t;return i.x=Math.min(this.x,e.x),i.y=Math.min(this.y,e.y),i.width=Math.max(this.x+this.width,e.x+e.width)-i.x,i.height=Math.max(this.y+this.height,e.y+e.height)-i.y,x(i)}})}),y.Matrix=y.invent({create:function(t){var e,i=l([1,0,0,1,0,0]);for(t=t instanceof y.Element?t.matrixify():"string"==typeof t?d(t):6==arguments.length?l([].slice.call(arguments)):"object"==typeof t?t:i,e=w.length-1;e>=0;--e)this[w[e]]=t&&"number"==typeof t[w[e]]?t[w[e]]:i[w[e]]},extend:{extract:function(){var t=u(this,0,1),e=u(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new y.Matrix(this)}},clone:function(){return new y.Matrix(this)},morph:function(t){return this.destination=new y.Matrix(t),this},at:function(t){if(!this.destination)return this;var e=new y.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});if(this.param&&this.param.to){var i={rotation:this.param.from.rotation+(this.param.to.rotation-this.param.from.rotation)*t,cx:this.param.from.cx,cy:this.param.from.cy};e=e.rotate((this.param.to.rotation-2*this.param.from.rotation)*t,i.cx,i.cy),e.param=i}return e},multiply:function(t){return new y.Matrix(this.native().multiply(c(t).native()))},inverse:function(){return new y.Matrix(this.native().inverse())},translate:function(t,e){return new y.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1!=arguments.length&&3!=arguments.length||(e=t),3==arguments.length&&(n=i,i=e),this.around(i,n,new y.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=y.utils.radians(t),this.around(e,i,new y.Matrix(Math.cos(t),Math.sin(t),(-Math.sin(t)),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):this.scale(1,-1,0,e)},skew:function(t,e,i,n){return this.around(i,n,this.native().skewX(t||0).skewY(e||0))},skewX:function(t,e,i){return this.around(e,i,this.native().skewX(t||0))},skewY:function(t,e,i){return this.around(e,i,this.native().skewY(t||0))},around:function(t,e,i){return this.multiply(new y.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new y.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=y.parser.native.createSVGMatrix(),e=w.length-1;e>=0;e--)t[w[e]]=this[w[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:y.Element,construct:{ctm:function(){return new y.Matrix(this.node.getCTM())},screenCTM:function(){return new y.Matrix(this.node.getScreenCTM())}}}),y.Point=y.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=e?{x:t,y:e}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new y.Point(this)},morph:function(t){return this.destination=new y.Point(t),this},at:function(t){if(!this.destination)return this;var e=new y.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=y.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new y.Point(this.native().matrixTransform(t.native()))}}}),y.extend(y.Element,{point:function(t,e){return new y.Point(t,e).transform(this.screenCTM().inverse())}}),y.extend(y.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]=y.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?y.defaults.attrs[t]:y.regex.isNumber.test(e)?parseFloat(e):e;"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),"fill"!=t&&"stroke"!=t||(y.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof y.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new y.Number(e):y.Color.isColor(e)?e=new y.Color(e):Array.isArray(e)?e=new y.Array(e):e instanceof y.Matrix&&e.param&&(this.param=e.param),"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}}),y.extend(y.Element,{transform:function(t,e){ -var i,n=this;if("object"!=typeof t)return i=new y.Matrix(n).extract(),"string"==typeof t?i[t]:i;if(i=new y.Matrix(n),e=!!e||!!t.relative,null!=t.a)i=e?i.multiply(new y.Matrix(t)):new y.Matrix(t);else if(null!=t.rotation)f(t,n),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var r=i.extract();t.scaleX=1*t.scaleX/r.scaleX,t.scaleY=1*t.scaleY/r.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skewX||null!=t.skewY){if(f(t,n),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,!e){var r=i.extract();i=i.multiply((new y.Matrix).skew(r.skewX,r.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?i=i.flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),y.extend(y.FX,{transform:function(t,e){var i,n=this.target();return"object"!=typeof t?(i=new y.Matrix(n).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new y.Matrix(t):null!=t.rotation?(f(t,n),i=new y.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new y.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(f(t,n),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new y.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?i=(new y.Matrix).morph((new y.Matrix).flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset)):null==t.x&&null==t.y||(i=new y.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),setTimeout(function(){this.start()}.bind(this),0),this):this)}}),y.extend(y.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){var t=(this.attr("transform")||"").split(/\)\s*,?\s*/).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(y.regex.matrixElements).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(l(e[1])):t[e[0]].apply(t,e[1])},new y.Matrix);return t},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.rect(1,1),n=i.screenCTM().inverse();return i.remove(),this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),y.Transformation=y.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.create([].slice.call(arguments));if("object"==typeof t)for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[this.arguments[i]];if(Array.isArray(t))for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[i];this.inversed=!1,e===!0&&(this.inversed=!0)},extend:{at:function(t){for(var e=[],i=0,n=this.arguments.length;i<n;++i)e.push(this[this.arguments[i]]);var r=this._undo||new y.Matrix;return r=(new y.Matrix).morph(y.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,i=this.arguments.length;e<i;++e)t[this.arguments[e]]="undefined"==typeof this[this.arguments[e]]?0:t[this.arguments[e]];return this._undo=new(y[s(this.method)])(t,(!0)).at(1),this}}}),y.Translate=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),y.Rotate=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new y.Matrix).rotate((new y.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){this._undo=t}}}),y.Scale=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),y.Skew=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),y.extend(y.Element,{style:function(t,e){if(0==arguments.length)return this.node.style.cssText||"";if(arguments.length<2)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!y.regex.isCss.test(t))return this.node.style[r(t)];t=t.split(";");for(var i=0;i<t.length;i++)e=t[i].split(":"),this.style(e[0].replace(/\s+/g,""),e[1])}else this.node.style[r(t)]=null===e||y.regex.isBlank.test(e)?"":e;return this}}),y.Parent=y.invent({create:function(t){this.constructor.call(this,t)},inherit:y.Element,extend:{children:function(){return y.utils.map(y.utils.filterSVGElements(this.node.childNodes),function(t){return y.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return y.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;i<n;i++)r[i]instanceof y.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof y.Container&&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},defs:function(){return this.doc().defs()}}}),y.extend(y.Parent,{ungroup:function(t,e){return 0===e||this instanceof y.Defs?this:(t=t||(this instanceof y.Doc?this:this.parent(y.Parent)),e=e||1/0,this.each(function(){return this instanceof y.Defs?this:this instanceof y.Parent?this.ungroup(t,e-1):this.toParent(t)}),this.node.firstChild||this.remove(),this)},flatten:function(t,e){return this.ungroup(t,e)}}),y.Container=y.invent({create:function(t){this.constructor.call(this,t)},inherit:y.Parent}),y.ViewBox=y.invent({create:function(t){var e,i,n,r,s,a,o,h,u=[0,0,0,0],l=1,c=1,f=/[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi;if(t instanceof y.Element){for(o=t,h=t,a=(t.attr("viewBox")||"").match(f),s=t.bbox,n=new y.Number(t.width()),r=new y.Number(t.height());"%"==n.unit;)l*=n.value,n=new y.Number(o instanceof y.Doc?o.parent().offsetWidth:o.parent().width()),o=o.parent();for(;"%"==r.unit;)c*=r.value,r=new y.Number(h instanceof y.Doc?h.parent().offsetHeight:h.parent().height()),h=h.parent();this.x=0,this.y=0,this.width=n*l,this.height=r*c,this.zoom=1,a&&(e=parseFloat(a[0]),i=parseFloat(a[1]),n=parseFloat(a[2]),r=parseFloat(a[3]),this.zoom=this.width/this.height>n/r?this.height/r:this.width/n,this.x=e,this.y=i,this.width=n,this.height=r)}else t="string"==typeof t?t.match(f).map(function(t){return parseFloat(t)}):Array.isArray(t)?t:"object"==typeof t?[t.x,t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):u,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3]},extend:{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t){var t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments);return this.destination=new y.ViewBox(t),this},at:function(t){return this.destination?new y.ViewBox([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:y.Container,construct:{viewbox:function(t){return 0==arguments.length?new y.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t))}}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){y.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),y.listeners=[],y.handlerMap=[],y.listenerId=0,y.on=function(t,e,i,n){var r=i.bind(n||t.instance||t),s=(y.handlerMap.indexOf(t)+1||y.handlerMap.push(t))-1,a=e.split(".")[0],o=e.split(".")[1]||"*";y.listeners[s]=y.listeners[s]||{},y.listeners[s][a]=y.listeners[s][a]||{},y.listeners[s][a][o]=y.listeners[s][a][o]||{},i._svgjsListenerId||(i._svgjsListenerId=++y.listenerId),y.listeners[s][a][o][i._svgjsListenerId]=r,t.addEventListener(a,r,!1)},y.off=function(t,e,i){var n=y.handlerMap.indexOf(t),r=e&&e.split(".")[0],s=e&&e.split(".")[1];if(n!=-1)if(i){if("function"==typeof i&&(i=i._svgjsListenerId),!i)return;y.listeners[n][r]&&y.listeners[n][r][s||"*"]&&(t.removeEventListener(r,y.listeners[n][r][s||"*"][i],!1),delete y.listeners[n][r][s||"*"][i])}else if(s&&r){if(y.listeners[n][r]&&y.listeners[n][r][s]){for(i in y.listeners[n][r][s])y.off(t,[r,s].join("."),i);delete y.listeners[n][r][s]}}else if(s)for(e in y.listeners[n])for(namespace in y.listeners[n][e])s===namespace&&y.off(t,[e,s].join("."));else if(r){if(y.listeners[n][r]){for(namespace in y.listeners[n][r])y.off(t,[r,namespace].join("."));delete y.listeners[n][r]}}else{for(e in y.listeners[n])y.off(t,e);delete y.listeners[n]}},y.extend(y.Element,{on:function(t,e,i){return y.on(this.node,t,e,i),this},off:function(t,e){return y.off(this.node,t,e),this},fire:function(t,e){return t instanceof Event?this.node.dispatchEvent(t):this.node.dispatchEvent(new b(t,{detail:e})),this}}),y.Defs=y.invent({create:"defs",inherit:y.Container}),y.G=y.invent({create:"g",inherit:y.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new y.G)}}}),y.extend(y.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous: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 y.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 y.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}}),y.Mask=y.invent({create:function(){this.constructor.call(this,y.create("mask")),this.targets=[]},inherit:y.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return this.targets=[],this.parent().removeElement(this),this}},construct:{mask:function(){return this.defs().put(new y.Mask)}}}),y.extend(y.Element,{maskWith:function(t){return this.masker=t instanceof y.Mask?t:this.parent().mask().add(t),this.masker.targets.push(this),this.attr("mask",'url("#'+this.masker.attr("id")+'")')},unmask:function(){return delete this.masker,this.attr("mask",null)}}),y.ClipPath=y.invent({create:function(){this.constructor.call(this,y.create("clipPath")),this.targets=[]},inherit:y.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return this.targets=[],this.parent().removeElement(this),this}},construct:{clip:function(){return this.defs().put(new y.ClipPath)}}}),y.extend(y.Element,{clipWith:function(t){return this.clipper=t instanceof y.ClipPath?t:this.parent().clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),y.Gradient=y.invent({create:function(t){this.constructor.call(this,y.create(t+"Gradient")),this.type=t},inherit:y.Container,extend:{at:function(t,e,i){return this.put(new y.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),y.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),y.extend(y.Gradient,y.FX,{from:function(t,e){return"radial"==(this._target||this).type?this.attr({fx:new y.Number(t),fy:new y.Number(e)}):this.attr({x1:new y.Number(t),y1:new y.Number(e)})},to:function(t,e){return"radial"==(this._target||this).type?this.attr({cx:new y.Number(t),cy:new y.Number(e)}):this.attr({x2:new y.Number(t),y2:new y.Number(e)})}}),y.extend(y.Defs,{gradient:function(t,e){return this.put(new y.Gradient(t)).update(e)}}),y.Stop=y.invent({create:"stop",inherit:y.Element,extend:{update:function(t){return("number"==typeof t||t instanceof y.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 y.Number(t.offset)),this}}}),y.Pattern=y.invent({create:"pattern",inherit:y.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),y.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),y.extend(y.Defs,{pattern:function(t,e,i){return this.put(new y.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),y.Doc=y.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,y.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:y.Container,extend:{namespace:function(){return this.attr({xmlns:y.ns,version:"1.1"}).attr("xmlns:xlink",y.xlink,y.xmlns).attr("xmlns:svgjs",y.svgjs,y.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=y.adopt(t):this._defs=new y.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},spof:function(t){var e=this.node.getScreenCTM();return e&&this.style("left",-e.e%1+"px").style("top",-e.f%1+"px"),this},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this}}}),y.Shape=y.invent({create:function(t){this.constructor.call(this,t)},inherit:y.Element}),y.Bare=y.invent({create:function(t,e){if(this.constructor.call(this,y.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:y.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),y.extend(y.Parent,{element:function(t,e){return this.put(new y.Bare(t,e))},symbol:function(){return this.defs().element("symbol",y.Container)}}),y.Use=y.invent({create:"use",inherit:y.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,y.xlink)}},construct:{use:function(t,e){return this.put(new y.Use).element(t,e)}}}),y.Rect=y.invent({create:"rect",inherit:y.Shape,construct:{rect:function(t,e){return this.put(new y.Rect).size(t,e)}}}),y.Circle=y.invent({create:"circle",inherit:y.Shape,construct:{circle:function(t){return this.put(new y.Circle).rx(new y.Number(t).divide(2)).move(0,0)}}}),y.extend(y.Circle,y.FX,{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),y.Ellipse=y.invent({create:"ellipse",inherit:y.Shape,construct:{ellipse:function(t,e){return this.put(new y.Ellipse).size(t,e).move(0,0)}}}),y.extend(y.Ellipse,y.Rect,y.FX,{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),y.extend(y.Circle,y.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 y.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new y.Number(t).divide(2))},size:function(t,e){var i=h(this,t,e);return this.rx(new y.Number(i.width).divide(2)).ry(new y.Number(i.height).divide(2))}}),y.Line=y.invent({create:"line",inherit:y.Shape,extend:{array:function(){return new y.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return t="undefined"!=typeof e?{x1:t,y1:e,x2:i,y2:n}:new y.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=h(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return this.put(new y.Line).plot(t,e,i,n)}}}),y.Polyline=y.invent({create:"polyline",inherit:y.Shape,construct:{polyline:function(t){return this.put(new y.Polyline).plot(t)}}}),y.Polygon=y.invent({create:"polygon",inherit:y.Shape,construct:{polygon:function(t){return this.put(new y.Polygon).plot(t)}}}),y.extend(y.Polyline,y.Polygon,{array:function(){return this._array||(this._array=new y.PointArray(this.attr("points")))},plot:function(t){return this.attr("points",this._array=new y.PointArray(t))},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=h(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),y.extend(y.Line,y.Polyline,y.Polygon,{morphArray:y.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)}}),y.Path=y.invent({create:"path",inherit:y.Shape,extend:{morphArray:y.PathArray,array:function(){return this._array||(this._array=new y.PathArray(this.attr("d")))},plot:function(t){return this.attr("d",this._array=new y.PathArray(t))},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=h(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 y.Path).plot(t)}}}),y.Image=y.invent({create:"image",inherit:y.Shape,extend:{load:function(t){if(!t)return this;var i=this,n=e.createElement("img");return n.onload=function(){var e=i.parent(y.Pattern);null!==e&&(0==i.width()&&0==i.height()&&i.size(n.width,n.height),e&&0==e.width()&&0==e.height()&&e.size(i.width(),i.height()),"function"==typeof i._loaded&&i._loaded.call(i,{width:n.width,height:n.height,ratio:n.width/n.height,url:t}))},n.onerror=function(t){"function"==typeof i._error&&i._error.call(i,t)},this.attr("href",n.src=this.src=t,y.xlink)},loaded:function(t){return this._loaded=t,this},error:function(t){return this._error=t,this}},construct:{image:function(t,e,i){return this.put(new y.Image).load(t).size(e||0,i||e||0)}}}),y.Text=y.invent({create:function(){this.constructor.call(this,y.create("text")),this.dom.leading=new y.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",y.defaults.attrs["font-family"])},inherit:y.Shape,extend:{x:function(t){return null==t?this.attr("x"):(this.textPath||this.lines().each(function(){this.dom.newLined&&this.x(t)}),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("undefined"==typeof t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i<n;++i)0!=i&&3!=e[i].nodeType&&1==y.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var i=0,r=t.length;i<r;i++)this.tspan(t[i]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new y.Number(t),this.rebuild())},lines:function(){var t=(this.textPath&&this.textPath()||this).node,e=y.utils.map(y.utils.filterSVGElements(t.childNodes),function(t){return y.adopt(t)});return new y.Set(e)},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new y.Number(this.attr("font-size"));this.lines().each(function(){this.dom.newLined&&(this.textPath||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 y.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new y.Text).text(t)},plain:function(t){return this.put(new y.Text).plain(t)}}}),y.Tspan=y.invent({create:"tspan",inherit:y.Shape,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(y.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),y.extend(y.Text,y.Tspan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,i=new y.Tspan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.text(t)},clear:function(){for(var t=(this.textPath&&this.textPath()||this).node;t.hasChildNodes();)t.removeChild(t.lastChild);return this},length:function(){return this.node.getComputedTextLength()}}),y.TextPath=y.invent({create:"textPath",inherit:y.Parent,parent:y.Text,construct:{path:function(t){for(var e=new y.TextPath,i=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+i,y.xlink),this},plot:function(t){var e=this.track();return e&&e.plot(t),this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return y.adopt(this.node.firstChild)}}}),y.Nested=y.invent({create:function(){this.constructor.call(this,y.create("svg")),this.style("overflow","visible")},inherit:y.Container,construct:{nested:function(){return this.put(new y.Nested)}}}),y.A=y.invent({create:"a",inherit:y.Container,extend:{to:function(t){return this.attr("href",t,y.xlink)},show:function(t){return this.attr("show",t,y.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new y.A).to(t)}}}),y.extend(y.Element,{linkTo:function(t){var e=new y.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),y.Marker=y.invent({create:"marker",inherit:y.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)}}}),y.extend(y.Defs,{marker:function(t,e,i){return this.put(new y.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),y.extend(y.Line,y.Polyline,y.Polygon,y.Path,{marker:function(t,e,i,n){var r=["marker"];return"all"!=t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof y.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(r,t)}});var g={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,i={};i[t]=function(i){if("undefined"==typeof i)return this;if("string"==typeof i||y.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=g[t].length-1;e>=0;e--)null!=i[g[t][e]]&&this.attr(g.prefix(t,g[t][e]),i[g[t][e]]);return this},y.extend(y.Element,y.FX,i)}),y.extend(y.Element,y.FX,{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){return this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return this.transform({flip:t,offset:e})},matrix:function(t){return this.attr("transform",new y.Matrix(t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x((this instanceof y.FX?0:this.x())+t,!0)},dy:function(t){return this.y((this instanceof y.FX?0:this.y())+t,!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),y.extend(y.Rect,y.Ellipse,y.Circle,y.Gradient,y.FX,{radius:function(t,e){var i=(this._target||this).type;return"radial"==i||"circle"==i?this.attr("r",new y.Number(t)):this.rx(t).ry(null==e?t:e)}}),y.extend(y.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),y.extend(y.Parent,y.Text,y.FX,{font:function(t){for(var e in t)"leading"==e?this.leading(t[e]):"anchor"==e?this.attr("text-anchor",t[e]):"size"==e||"family"==e||"weight"==e||"stretch"==e||"variant"==e||"style"==e?this.attr("font-"+e,t[e]):this.attr(e,t[e]);return this}}),y.Set=y.invent({create:function(t){Array.isArray(t)?this.members=t:this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;t<e;t++)this.members.push(i[t]);return this},remove:function(t){var e=this.index(t);return e>-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e<i;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},length:function(){return this.members.length},has:function(t){return this.index(t)>=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},first:function(){return this.get(0)},last:function(){return this.get(this.members.length-1)},valueOf:function(){return this.members},bbox:function(){var t=new y.BBox;if(0==this.members.length)return t;var e=this.members[0].rbox();return t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height,this.each(function(){t=t.merge(this.rbox())}),t}},construct:{set:function(t){return new y.Set(t)}}}),y.FX.Set=y.invent({create:function(t){this.set=t}}),y.Set.inherit=function(){var t,e=[];for(var t in y.Shape.prototype)"function"==typeof y.Shape.prototype[t]&&"function"!=typeof y.Set.prototype[t]&&e.push(t);e.forEach(function(t){y.Set.prototype[t]=function(){for(var e=0,i=this.members.length;e<i;e++)this.members[e]&&"function"==typeof this.members[e][t]&&this.members[e][t].apply(this.members[e],arguments);return"animate"==t?this.fx||(this.fx=new y.FX.Set(this)):this}}),e=[];for(var t in y.FX.prototype)"function"==typeof y.FX.prototype[t]&&"function"!=typeof y.FX.Set.prototype[t]&&e.push(t);e.forEach(function(t){y.FX.Set.prototype[t]=function(){for(var e=0,i=this.set.members.length;e<i;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},y.extend(y.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:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),y.extend(y.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var e in t)this.remember(e,t[e]);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={})}}),y.get=function(t){var i=e.getElementById(v(t)||t);return y.adopt(i)},y.select=function(t,i){return new y.Set(y.utils.map((i||e).querySelectorAll(t),function(t){return y.adopt(t)}))},y.extend(y.Parent,{select:function(t){return y.select(t,this.node)}});var w="abcdef".split("");if("function"!=typeof b){var b=function(t,i){i=i||{bubbles:!1,cancelable:!1,detail:void 0};var n=e.createEvent("CustomEvent");return n.initCustomEvent(t,i.bubbles,i.cancelable,i.detail),n};b.prototype=t.Event.prototype,t.CustomEvent=b}return function(e){for(var i=0,n=["moz","webkit"],r=0;r<n.length&&!t.requestAnimationFrame;++r)e.requestAnimationFrame=e[n[r]+"RequestAnimationFrame"],e.cancelAnimationFrame=e[n[r]+"CancelAnimationFrame"]||e[n[r]+"CancelRequestAnimationFrame"];e.requestAnimationFrame=e.requestAnimationFrame||function(t){var n=(new Date).getTime(),r=Math.max(0,16-(n-i)),s=e.setTimeout(function(){t(n+r)},r);return i=n+r,s},e.cancelAnimationFrame=e.cancelAnimationFrame||e.clearTimeout}(t),y});
\ No newline at end of file +/*! svg.js v2.3.6 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,e){return t instanceof e}function n(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function s(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function r(t){return t.charAt(0).toUpperCase()+t.slice(1)}function a(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 o(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function h(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 u(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function l(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function c(t){return t instanceof y.Matrix||(t=new y.Matrix(t)),t}function f(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function d(t){return t=t.replace(y.regex.whitespace,"").replace(y.regex.matrix,"").split(y.regex.matrixElements),l(y.utils.map(t,function(t){return parseFloat(t)}))}function p(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 m(t){for(var e=t.childNodes.length-1;e>=0;e--)t.childNodes[e]instanceof SVGElement&&m(t.childNodes[e]);return y.adopt(t).id(y.eid(t.nodeName))}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 v(t){var e=t.toString().match(y.regex.reference);if(e)return e[1]}var y=this.SVG=function(t){if(y.supported)return t=new y.Doc(t),y.parser.draw||y.prepare(),t};if(y.ns="http://www.w3.org/2000/svg",y.xmlns="http://www.w3.org/2000/xmlns/",y.xlink="http://www.w3.org/1999/xlink",y.svgjs="http://svgjs.com/svgjs",y.supported=function(){return!!e.createElementNS&&!!e.createElementNS(y.ns,"svg").createSVGRect}(),!y.supported)return!1;y.did=1e3,y.eid=function(t){return"Svgjs"+r(t)+y.did++},y.create=function(t){var i=e.createElementNS(this.ns,t);return i.setAttribute("id",this.eid(t)),i},y.extend=function(){var t,e,i,n;for(t=[].slice.call(arguments),e=t.pop(),n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i];y.Set&&y.Set.inherit&&y.Set.inherit()},y.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,y.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&y.extend(e,t.extend),t.construct&&y.extend(t.parent||y.Container,t.construct),e},y.adopt=function(t){if(!t)return null;if(t.instance)return t.instance;var e;return e="svg"==t.nodeName?t.parentNode instanceof SVGElement?new y.Nested:new y.Doc:"linearGradient"==t.nodeName?new y.Gradient("linear"):"radialGradient"==t.nodeName?new y.Gradient("radial"):y[r(t.nodeName)]?new(y[r(t.nodeName)]):new y.Element(t),e.type=t.nodeName,e.node=t,t.instance=e,e instanceof y.Doc&&e.namespace().defs(),e.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}),e},y.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new y.Doc(t):new y.Doc(e.documentElement).nested()).size(2,0);y.parser={body:t||e.documentElement,draw:i.style("opacity:0;position:fixed;left:100%;top:100%;overflow:hidden"),poly:i.polyline().node,path:i.path().node,native:y.create("svg")}},y.parser={native:y.create("svg")},e.addEventListener("DOMContentLoaded",function(){y.parser.draw||y.prepare()},!1),y.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,matrix:/matrix\(|\)/g,matrixElements:/,*\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,negExp:/e\-/gi,comma:/,/g,hyphen:/\-/g,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,whitespaces:/\s+/,X:/X/g},y.utils={map:function(t,e){var i,n=t.length,s=[];for(i=0;i<n;i++)s.push(e(t[i]));return s},filter:function(t,e){var i,n=t.length,s=[];for(i=0;i<n;i++)e(t[i])&&s.push(t[i]);return s},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(t){return this.filter(t,function(t){return t instanceof SVGElement})}},y.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"}},y.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?y.regex.isRgb.test(t)?(e=y.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):y.regex.isHex.test(t)&&(e=y.regex.hex.exec(a(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))},y.extend(y.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+o(this.r)+o(this.g)+o(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 y.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new y.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}}),y.Color.test=function(t){return t+="",y.regex.isHex.test(t)||y.regex.isRgb.test(t)},y.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},y.Color.isColor=function(t){return y.Color.isRgb(t)||y.Color.test(t)},y.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},y.extend(y.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++)i.indexOf(this.value[t])==-1&&i.push(this.value[t]);return this.value=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 y.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:this.split(t)},split:function(t){return t.trim().split(/\s+/)},reverse:function(){return this.value.reverse(),this}}),y.PointArray=function(t,e){this.constructor.call(this,t,e||[[0,0]])},y.PointArray.prototype=new y.Array,y.extend(y.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 y.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t))return t;t=t.trim().split(/\s+|,/),t.length%2!==0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([parseFloat(t[i]),parseFloat(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--)this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x,this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y;return this},bbox:function(){return y.parser.poly.setAttribute("points",this.toString()),y.parser.poly.getBBox()}}),y.PathArray=function(t,e){this.constructor.call(this,t,e||[["M",0,0]])},y.PathArray.prototype=new y.Array,y.extend(y.PathArray,{toString:function(){return p(this.value)},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n,s=this.value.length-1;s>=0;s--)n=this.value[s][0],"M"==n||"L"==n||"T"==n?(this.value[s][1]+=t,this.value[s][2]+=e):"H"==n?this.value[s][1]+=t:"V"==n?this.value[s][1]+=e:"C"==n||"S"==n||"Q"==n?(this.value[s][1]+=t,this.value[s][2]+=e,this.value[s][3]+=t,this.value[s][4]+=e,"C"==n&&(this.value[s][5]+=t,this.value[s][6]+=e)):"A"==n&&(this.value[s][6]+=t,this.value[s][7]+=e);return this},size:function(t,e){var i,n,s=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]-s.x)*t/s.width+s.x,this.value[i][2]=(this.value[i][2]-s.y)*e/s.height+s.y):"H"==n?this.value[i][1]=(this.value[i][1]-s.x)*t/s.width+s.x:"V"==n?this.value[i][1]=(this.value[i][1]-s.y)*e/s.height+s.y:"C"==n||"S"==n||"Q"==n?(this.value[i][1]=(this.value[i][1]-s.x)*t/s.width+s.x,this.value[i][2]=(this.value[i][2]-s.y)*e/s.height+s.y,this.value[i][3]=(this.value[i][3]-s.x)*t/s.width+s.x,this.value[i][4]=(this.value[i][4]-s.y)*e/s.height+s.y,"C"==n&&(this.value[i][5]=(this.value[i][5]-s.x)*t/s.width+s.x,this.value[i][6]=(this.value[i][6]-s.y)*e/s.height+s.y)):"A"==n&&(this.value[i][1]=this.value[i][1]*t/s.width,this.value[i][2]=this.value[i][2]*e/s.height,this.value[i][6]=(this.value[i][6]-s.x)*t/s.width+s.x,this.value[i][7]=(this.value[i][7]-s.y)*e/s.height+s.y);return this},parse:function(t){if(t instanceof y.PathArray)return t.valueOf();var e,i,n,s,r,a,o=0,h=0,u={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7};if("string"==typeof t){for(t=t.replace(y.regex.negExp,"X").replace(y.regex.pathLetters," $& ").replace(y.regex.hyphen," -").replace(y.regex.comma," ").replace(y.regex.X,"e-").trim().split(y.regex.whitespaces),e=t.length;--e;)if(t[e].indexOf(".")!=t[e].lastIndexOf(".")){var l=t[e].split("."),c=[l.shift(),l.shift()].join(".");t.splice.apply(t,[e,1].concat(c,l.map(function(t){return"."+t})))}}else t=t.reduce(function(t,e){return[].concat.apply(t,e)},[]);var a=[];do{for(y.regex.isPathLetter.test(t[0])?(s=t[0],t.shift()):"M"==s?s="L":"m"==s&&(s="l"),r=[s.toUpperCase()],e=0;e<u[r[0]];++e)r.push(parseFloat(t.shift()));s==r[0]?"M"==s||"L"==s||"C"==s||"Q"==s||"S"==s||"T"==s?(o=r[u[r[0]]-1],h=r[u[r[0]]]):"V"==s?h=r[1]:"H"==s?o=r[1]:"A"==s&&(o=r[6],h=r[7]):"m"==s||"l"==s||"c"==s||"s"==s||"q"==s||"t"==s?(r[1]+=o,r[2]+=h,null!=r[3]&&(r[3]+=o,r[4]+=h),null!=r[5]&&(r[5]+=o,r[6]+=h),o=r[u[r[0]]-1],h=r[u[r[0]]]):"v"==s?(r[1]+=h,h=r[1]):"h"==s?(r[1]+=o,o=r[1]):"a"==s&&(r[6]+=o,r[7]+=h,o=r[6],h=r[7]),"M"==r[0]&&(i=o,n=h),"Z"==r[0]&&(o=i,h=n),a.push(r)}while(t.length);return a},bbox:function(){return y.parser.path.setAttribute("d",this.toString()),y.parser.path.getBBox()}}),y.Number=y.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(y.regex.numberAndUnit),e&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5])):t instanceof y.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 new y.Number(this+new y.Number(t),this.unit)},minus:function(t){return this.plus(-new y.Number(t))},times:function(t){return new y.Number(this*new y.Number(t),this.unit)},divide:function(t){return new y.Number(this/new y.Number(t),this.unit)},to:function(t){var e=new y.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new y.Number(t),this},at:function(t){return this.destination?new y.Number(this.destination).minus(this).times(t).plus(this):this}}}),y.Element=y.invent({create:function(t){this._stroke=y.defaults.attrs.stroke,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this,this._stroke=t.getAttribute("stroke")||this._stroke)},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=h(this,t,e);return this.width(new y.Number(i.width)).height(new y.Number(i.height))},clone:function(t){var e=m(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 t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return 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.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(/\s+/)},hasClass:function(t){return this.classes().indexOf(t)!=-1},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 y.get(this.attr(t))},parent:function(t){var e=this;if(!e.node.parentNode)return null;if(e=y.adopt(e.node.parentNode),!t)return e;for(;e&&e.node instanceof SVGElement;){if("string"==typeof t?e.matches(t):e instanceof t)return e;e=y.adopt(e.node.parentNode)}},doc:function(){return this instanceof y.Doc?this:this.parent(y.Doc)},parents:function(t){var e=[],i=this;do{if(i=i.parent(t),!i||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return n(this.node,t)},native:function(){return this.node},svg:function(t){var i=e.createElement("svg");if(!(t&&this instanceof y.Parent))return i.appendChild(t=e.createElement("svg")),this.writeDataToDom(),t.appendChild(this.node.cloneNode(!0)),i.innerHTML.replace(/^<svg>/,"").replace(/<\/svg>$/,"");i.innerHTML="<svg>"+t.replace(/\n/,"").replace(/<(\w+)([^<]+?)\/>/g,"<$1$2></$1>")+"</svg>";for(var n=0,s=i.firstChild.childNodes.length;n<s;n++)this.node.appendChild(i.firstChild.firstChild);return this},writeDataToDom:function(){if(this.each||this.lines){var t=this.each?this:this.lines();t.each(function(){this.writeDataToDom()})}return this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return i(this,t)}}}),y.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-Math.cos(t*Math.PI/2)+1}},y.morph=function(t){return function(e,i){return new y.MorphObj(e,i).at(t)}},y.Situation=y.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new y.Number(t.duration).valueOf(),this.delay=new y.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={}}}),y.Delay=function(t){this.delay=new y.Number(t).valueOf()},y.FX=y.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 y.Situation({duration:t||1e3,delay:i||0,ease:y.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var t=new y.Delay(t);return this.queue(t)},target:function(t){return t&&t instanceof y.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=requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations(),this.active=!0,this.startAnimFrame()),this},queue:function(t){return("function"==typeof t||t instanceof y.Situation||t instanceof y.Delay)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){if(this.situation&&this.situation.stop&&this.situation.stop(),this.situation=this.situations.shift(),this.situation){var t=function(){this.situation instanceof y.Situation?this.initAnimations().atStart():this.situation instanceof y.Delay?this.dequeue():this.situation.call(this)}.bind(this);this.situation.delay?setTimeout(function(){t()},this.situation.delay):t()}return this},initAnimations:function(){var t,e=this.situation;if(e.init)return this;for(t in e.animations)"viewbox"==t?e.animations[t]=this.target().viewbox().morph(e.animations[t]):(e.animations[t].value="plot"==t?this.target().array().value:this.target()[t](),e.animations[t].value.value&&(e.animations[t].value=e.animations[t].value.value),e.animations[t].relative&&(e.animations[t].destination.value=e.animations[t].destination.value+e.animations[t].value));for(t in e.attrs)if(e.attrs[t]instanceof y.Color){var i=new y.Color(this.target().attr(t));e.attrs[t].r=i.r,e.attrs[t].g=i.g,e.attrs[t].b=i.b}else e.attrs[t].value=this.target().attr(t);for(t in e.styles)e.styles[t].value=this.target().style(t);return e.initialTransformation=this.target().matrixify(),e.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){return this.active||this.start(),e&&this.clearQueue(),this.active=!1,t&&this.situation&&this.atEnd(),this.stopAnimFrame(),clearTimeout(this.timeout),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 this.situation.loops===!0?this.at(this.situation.loop+1,!0):"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(),clearTimeout(this.timeout),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return"undefined"==typeof t?e.reversed=!e.reversed:e.reversed=t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,y.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)})},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},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,y.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)})},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,setTimeout(function(){this.start()}.bind(this),0),this},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),this.situation.loops!==!1){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),this.situation.loops===!0||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 s=this.situation.ease(this.pos);for(var r in this.situation.once)r>this.lastPos&&r<=s&&(this.situation.once[r].call(this.target(),this.pos,s),delete this.situation.once[r]);return this.active&&this.target().fire("during",{pos:this.pos,eased:s,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.target().off(".fx"),this.active=!1),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=s,this):this},eachAt:function(){var t,e,i=this,n=this.target(),s=this.situation;for(t in s.animations)e=[].concat(s.animations[t]).map(function(t){return t.at?t.at(s.ease(i.pos),i.pos):t}),n[t].apply(n,e);for(t in s.attrs)e=[t].concat(s.attrs[t]).map(function(t){return t.at?t.at(s.ease(i.pos),i.pos):t}),n.attr.apply(n,e);for(t in s.styles)e=[t].concat(s.styles[t]).map(function(t){return t.at?t.at(s.ease(i.pos),i.pos):t}),n.style.apply(n,e);if(s.transforms.length){e=s.initialTransformation;for(t in s.transforms){var r=s.transforms[t];r instanceof y.Matrix?e=r.relative?e.multiply(r.at(s.ease(this.pos))):e.morph(r).at(s.ease(this.pos)):(r.relative||r.undo(e.extract()),e=e.multiply(r.at(s.ease(this.pos))))}n.matrix(e)}return this},once:function(t,e,i){return i||(t=this.situation.ease(t)),this.situation.once[t]=e,this}},parent:y.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new y.FX(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new y.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}}}),y.MorphObj=y.invent({create:function(t,e){return y.Color.isColor(e)?new y.Color(t).morph(e):y.regex.numberAndUnit.test(e)?new y.Number(t).morph(e):(this.value=0,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),y.extend(y.FX,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,new y.MorphObj(null,e),"attrs");return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.add(t,new y.MorphObj(null,e),"styles");return this},x:function(t,e){if(this.target()instanceof y.G)return this.transform({x:t},e),this;var i=(new y.Number).morph(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof y.G)return this.transform({y:t},e),this;var i=(new y.Number).morph(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",(new y.Number).morph(t))},cy:function(t){return this.add("cy",(new y.Number).morph(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 y.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 y.Number).morph(t)).add("height",(new y.Number).morph(e))}return this},plot:function(t){return this.add("plot",this.target().array().morph(t))},leading:function(t){return this.target().leading?this.add("leading",(new y.Number).morph(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof y.Container&&this.add("viewbox",new y.ViewBox(t,e,i,n)),this},update:function(t){if(this.target()instanceof y.Stop){if("number"==typeof t||t instanceof y.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}}),y.BBox=y.invent({create:function(t){if(t){var i;try{if(!e.documentElement.contains(t.node))throw new Exception("Element not in the dom");i=t.node.getBBox()}catch(e){if(t instanceof y.Shape){var n=t.clone(y.parser.draw).show();i=n.bbox(),n.remove()}else i={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=i.x,this.y=i.y,this.width=i.width,this.height=i.height}x(this)},parent:y.Element,construct:{bbox:function(){return new y.BBox(this)}}}),y.TBox=y.invent({create:function(t){if(t){var e=t.ctm().extract(),i=t.bbox();this.width=i.width*e.scaleX,this.height=i.height*e.scaleY,this.x=i.x+e.x,this.y=i.y+e.y}x(this)},parent:y.Element,construct:{tbox:function(){return new y.TBox(this)}}}),y.RBox=y.invent({create:function(e){if(e){var i=e.doc().parent(),n=e.node.getBoundingClientRect(),s=1;for(this.x=n.left,this.y=n.top,this.x-=i.offsetLeft,this.y-=i.offsetTop;i=i.offsetParent;)this.x-=i.offsetLeft,this.y-=i.offsetTop;for(i=e;i.parent&&(i=i.parent());)i.viewbox&&(s*=i.viewbox().zoom,this.x-=i.x()||0,this.y-=i.y()||0);this.width=n.width/=s,this.height=n.height/=s}x(this),this.x+=t.pageXOffset,this.y+=t.pageYOffset},parent:y.Element,construct:{rbox:function(){return new y.RBox(this)}}}),[y.BBox,y.TBox,y.RBox].forEach(function(t){y.extend(t,{merge:function(e){var i=new t;return i.x=Math.min(this.x,e.x),i.y=Math.min(this.y,e.y),i.width=Math.max(this.x+this.width,e.x+e.width)-i.x,i.height=Math.max(this.y+this.height,e.y+e.height)-i.y,x(i)}})}),y.Matrix=y.invent({create:function(t){var e,i=l([1,0,0,1,0,0]);for(t=t instanceof y.Element?t.matrixify():"string"==typeof t?d(t):6==arguments.length?l([].slice.call(arguments)):"object"==typeof t?t:i,e=w.length-1;e>=0;--e)this[w[e]]=t&&"number"==typeof t[w[e]]?t[w[e]]:i[w[e]]},extend:{extract:function(){var t=u(this,0,1),e=u(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new y.Matrix(this)}},clone:function(){return new y.Matrix(this)},morph:function(t){return this.destination=new y.Matrix(t),this},at:function(t){if(!this.destination)return this;var e=new y.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});if(this.param&&this.param.to){var i={rotation:this.param.from.rotation+(this.param.to.rotation-this.param.from.rotation)*t,cx:this.param.from.cx,cy:this.param.from.cy};e=e.rotate((this.param.to.rotation-2*this.param.from.rotation)*t,i.cx,i.cy),e.param=i}return e},multiply:function(t){return new y.Matrix(this.native().multiply(c(t).native()))},inverse:function(){return new y.Matrix(this.native().inverse())},translate:function(t,e){return new y.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1!=arguments.length&&3!=arguments.length||(e=t),3==arguments.length&&(n=i,i=e),this.around(i,n,new y.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=y.utils.radians(t),this.around(e,i,new y.Matrix(Math.cos(t),Math.sin(t),(-Math.sin(t)),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):this.scale(1,-1,0,e)},skew:function(t,e,i,n){return this.around(i,n,this.native().skewX(t||0).skewY(e||0))},skewX:function(t,e,i){return this.around(e,i,this.native().skewX(t||0))},skewY:function(t,e,i){return this.around(e,i,this.native().skewY(t||0))},around:function(t,e,i){return this.multiply(new y.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new y.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=y.parser.native.createSVGMatrix(),e=w.length-1;e>=0;e--)t[w[e]]=this[w[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:y.Element,construct:{ctm:function(){return new y.Matrix(this.node.getCTM())},screenCTM:function(){return new y.Matrix(this.node.getScreenCTM())}}}),y.Point=y.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=e?{x:t,y:e}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new y.Point(this)},morph:function(t){return this.destination=new y.Point(t),this},at:function(t){if(!this.destination)return this;var e=new y.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=y.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new y.Point(this.native().matrixTransform(t.native()))}}}),y.extend(y.Element,{point:function(t,e){return new y.Point(t,e).transform(this.screenCTM().inverse())}}),y.extend(y.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]=y.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?y.defaults.attrs[t]:y.regex.isNumber.test(e)?parseFloat(e):e;"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),"fill"!=t&&"stroke"!=t||(y.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)), +e instanceof y.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new y.Number(e):y.Color.isColor(e)?e=new y.Color(e):Array.isArray(e)?e=new y.Array(e):e instanceof y.Matrix&&e.param&&(this.param=e.param),"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}}),y.extend(y.Element,{transform:function(t,e){var i,n=this;if("object"!=typeof t)return i=new y.Matrix(n).extract(),"string"==typeof t?i[t]:i;if(i=new y.Matrix(n),e=!!e||!!t.relative,null!=t.a)i=e?i.multiply(new y.Matrix(t)):new y.Matrix(t);else if(null!=t.rotation)f(t,n),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var s=i.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skewX||null!=t.skewY){if(f(t,n),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,!e){var s=i.extract();i=i.multiply((new y.Matrix).skew(s.skewX,s.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?i=i.flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),y.extend(y.FX,{transform:function(t,e){var i,n=this.target();return"object"!=typeof t?(i=new y.Matrix(n).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new y.Matrix(t):null!=t.rotation?(f(t,n),i=new y.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new y.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(f(t,n),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new y.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?i=(new y.Matrix).morph((new y.Matrix).flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset)):null==t.x&&null==t.y||(i=new y.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),setTimeout(function(){this.start()}.bind(this),0),this):this)}}),y.extend(y.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){var t=(this.attr("transform")||"").split(/\)\s*,?\s*/).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(y.regex.matrixElements).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(l(e[1])):t[e[0]].apply(t,e[1])},new y.Matrix);return t},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.rect(1,1),n=i.screenCTM().inverse();return i.remove(),this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),y.Transformation=y.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.create([].slice.call(arguments));if("object"==typeof t)for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[this.arguments[i]];if(Array.isArray(t))for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[i];this.inversed=!1,e===!0&&(this.inversed=!0)},extend:{at:function(t){for(var e=[],i=0,n=this.arguments.length;i<n;++i)e.push(this[this.arguments[i]]);var s=this._undo||new y.Matrix;return s=(new y.Matrix).morph(y.Matrix.prototype[this.method].apply(s,e)).at(t),this.inversed?s.inverse():s},undo:function(t){for(var e=0,i=this.arguments.length;e<i;++e)t[this.arguments[e]]="undefined"==typeof this[this.arguments[e]]?0:t[this.arguments[e]];return this._undo=new(y[r(this.method)])(t,(!0)).at(1),this}}}),y.Translate=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),y.Rotate=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new y.Matrix).rotate((new y.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){this._undo=t}}}),y.Scale=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),y.Skew=y.invent({parent:y.Matrix,inherit:y.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),y.extend(y.Element,{style:function(t,e){if(0==arguments.length)return this.node.style.cssText||"";if(arguments.length<2)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!y.regex.isCss.test(t))return this.node.style[s(t)];t=t.split(";");for(var i=0;i<t.length;i++)e=t[i].split(":"),this.style(e[0].replace(/\s+/g,""),e[1])}else this.node.style[s(t)]=null===e||y.regex.isBlank.test(e)?"":e;return this}}),y.Parent=y.invent({create:function(t){this.constructor.call(this,t)},inherit:y.Element,extend:{children:function(){return y.utils.map(y.utils.filterSVGElements(this.node.childNodes),function(t){return y.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return y.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,s=this.children();for(i=0,n=s.length;i<n;i++)s[i]instanceof y.Element&&t.apply(s[i],[i,s]),e&&s[i]instanceof y.Container&&s[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},defs:function(){return this.doc().defs()}}}),y.extend(y.Parent,{ungroup:function(t,e){return 0===e||this instanceof y.Defs?this:(t=t||(this instanceof y.Doc?this:this.parent(y.Parent)),e=e||1/0,this.each(function(){return this instanceof y.Defs?this:this instanceof y.Parent?this.ungroup(t,e-1):this.toParent(t)}),this.node.firstChild||this.remove(),this)},flatten:function(t,e){return this.ungroup(t,e)}}),y.Container=y.invent({create:function(t){this.constructor.call(this,t)},inherit:y.Parent}),y.ViewBox=y.invent({create:function(t){var e,i,n,s,r,a,o,h,u=[0,0,0,0],l=1,c=1,f=/[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi;if(t instanceof y.Element){for(o=t,h=t,a=(t.attr("viewBox")||"").match(f),r=t.bbox,n=new y.Number(t.width()),s=new y.Number(t.height());"%"==n.unit;)l*=n.value,n=new y.Number(o instanceof y.Doc?o.parent().offsetWidth:o.parent().width()),o=o.parent();for(;"%"==s.unit;)c*=s.value,s=new y.Number(h instanceof y.Doc?h.parent().offsetHeight:h.parent().height()),h=h.parent();this.x=0,this.y=0,this.width=n*l,this.height=s*c,this.zoom=1,a&&(e=parseFloat(a[0]),i=parseFloat(a[1]),n=parseFloat(a[2]),s=parseFloat(a[3]),this.zoom=this.width/this.height>n/s?this.height/s:this.width/n,this.x=e,this.y=i,this.width=n,this.height=s)}else t="string"==typeof t?t.match(f).map(function(t){return parseFloat(t)}):Array.isArray(t)?t:"object"==typeof t?[t.x,t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):u,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3]},extend:{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t){var t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments);return this.destination=new y.ViewBox(t),this},at:function(t){return this.destination?new y.ViewBox([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:y.Container,construct:{viewbox:function(t){return 0==arguments.length?new y.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t))}}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){y.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),y.listeners=[],y.handlerMap=[],y.listenerId=0,y.on=function(t,e,i,n){var s=i.bind(n||t.instance||t),r=(y.handlerMap.indexOf(t)+1||y.handlerMap.push(t))-1,a=e.split(".")[0],o=e.split(".")[1]||"*";y.listeners[r]=y.listeners[r]||{},y.listeners[r][a]=y.listeners[r][a]||{},y.listeners[r][a][o]=y.listeners[r][a][o]||{},i._svgjsListenerId||(i._svgjsListenerId=++y.listenerId),y.listeners[r][a][o][i._svgjsListenerId]=s,t.addEventListener(a,s,!1)},y.off=function(t,e,i){var n=y.handlerMap.indexOf(t),s=e&&e.split(".")[0],r=e&&e.split(".")[1];if(n!=-1)if(i){if("function"==typeof i&&(i=i._svgjsListenerId),!i)return;y.listeners[n][s]&&y.listeners[n][s][r||"*"]&&(t.removeEventListener(s,y.listeners[n][s][r||"*"][i],!1),delete y.listeners[n][s][r||"*"][i])}else if(r&&s){if(y.listeners[n][s]&&y.listeners[n][s][r]){for(i in y.listeners[n][s][r])y.off(t,[s,r].join("."),i);delete y.listeners[n][s][r]}}else if(r)for(e in y.listeners[n])for(namespace in y.listeners[n][e])r===namespace&&y.off(t,[e,r].join("."));else if(s){if(y.listeners[n][s]){for(namespace in y.listeners[n][s])y.off(t,[s,namespace].join("."));delete y.listeners[n][s]}}else{for(e in y.listeners[n])y.off(t,e);delete y.listeners[n]}},y.extend(y.Element,{on:function(t,e,i){return y.on(this.node,t,e,i),this},off:function(t,e){return y.off(this.node,t,e),this},fire:function(t,e){return t instanceof Event?this.node.dispatchEvent(t):this.node.dispatchEvent(new b(t,{detail:e})),this}}),y.Defs=y.invent({create:"defs",inherit:y.Container}),y.G=y.invent({create:"g",inherit:y.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new y.G)}}}),y.extend(y.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous: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 y.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 y.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}}),y.Mask=y.invent({create:function(){this.constructor.call(this,y.create("mask")),this.targets=[]},inherit:y.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return this.targets=[],this.parent().removeElement(this),this}},construct:{mask:function(){return this.defs().put(new y.Mask)}}}),y.extend(y.Element,{maskWith:function(t){return this.masker=t instanceof y.Mask?t:this.parent().mask().add(t),this.masker.targets.push(this),this.attr("mask",'url("#'+this.masker.attr("id")+'")')},unmask:function(){return delete this.masker,this.attr("mask",null)}}),y.ClipPath=y.invent({create:function(){this.constructor.call(this,y.create("clipPath")),this.targets=[]},inherit:y.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return this.targets=[],this.parent().removeElement(this),this}},construct:{clip:function(){return this.defs().put(new y.ClipPath)}}}),y.extend(y.Element,{clipWith:function(t){return this.clipper=t instanceof y.ClipPath?t:this.parent().clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),y.Gradient=y.invent({create:function(t){this.constructor.call(this,y.create(t+"Gradient")),this.type=t},inherit:y.Container,extend:{at:function(t,e,i){return this.put(new y.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),y.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),y.extend(y.Gradient,y.FX,{from:function(t,e){return"radial"==(this._target||this).type?this.attr({fx:new y.Number(t),fy:new y.Number(e)}):this.attr({x1:new y.Number(t),y1:new y.Number(e)})},to:function(t,e){return"radial"==(this._target||this).type?this.attr({cx:new y.Number(t),cy:new y.Number(e)}):this.attr({x2:new y.Number(t),y2:new y.Number(e)})}}),y.extend(y.Defs,{gradient:function(t,e){return this.put(new y.Gradient(t)).update(e)}}),y.Stop=y.invent({create:"stop",inherit:y.Element,extend:{update:function(t){return("number"==typeof t||t instanceof y.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 y.Number(t.offset)),this}}}),y.Pattern=y.invent({create:"pattern",inherit:y.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),y.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),y.extend(y.Defs,{pattern:function(t,e,i){return this.put(new y.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),y.Doc=y.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,y.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:y.Container,extend:{namespace:function(){return this.attr({xmlns:y.ns,version:"1.1"}).attr("xmlns:xlink",y.xlink,y.xmlns).attr("xmlns:svgjs",y.svgjs,y.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=y.adopt(t):this._defs=new y.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},spof:function(t){var e=this.node.getScreenCTM();return e&&this.style("left",-e.e%1+"px").style("top",-e.f%1+"px"),this},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this}}}),y.Shape=y.invent({create:function(t){this.constructor.call(this,t)},inherit:y.Element}),y.Bare=y.invent({create:function(t,e){if(this.constructor.call(this,y.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:y.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),y.extend(y.Parent,{element:function(t,e){return this.put(new y.Bare(t,e))},symbol:function(){return this.defs().element("symbol",y.Container)}}),y.Use=y.invent({create:"use",inherit:y.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,y.xlink)}},construct:{use:function(t,e){return this.put(new y.Use).element(t,e)}}}),y.Rect=y.invent({create:"rect",inherit:y.Shape,construct:{rect:function(t,e){return this.put(new y.Rect).size(t,e)}}}),y.Circle=y.invent({create:"circle",inherit:y.Shape,construct:{circle:function(t){return this.put(new y.Circle).rx(new y.Number(t).divide(2)).move(0,0)}}}),y.extend(y.Circle,y.FX,{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),y.Ellipse=y.invent({create:"ellipse",inherit:y.Shape,construct:{ellipse:function(t,e){return this.put(new y.Ellipse).size(t,e).move(0,0)}}}),y.extend(y.Ellipse,y.Rect,y.FX,{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),y.extend(y.Circle,y.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 y.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new y.Number(t).divide(2))},size:function(t,e){var i=h(this,t,e);return this.rx(new y.Number(i.width).divide(2)).ry(new y.Number(i.height).divide(2))}}),y.Line=y.invent({create:"line",inherit:y.Shape,extend:{array:function(){return new y.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return t="undefined"!=typeof e?{x1:t,y1:e,x2:i,y2:n}:new y.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=h(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return this.put(new y.Line).plot(t,e,i,n)}}}),y.Polyline=y.invent({create:"polyline",inherit:y.Shape,construct:{polyline:function(t){return this.put(new y.Polyline).plot(t)}}}),y.Polygon=y.invent({create:"polygon",inherit:y.Shape,construct:{polygon:function(t){return this.put(new y.Polygon).plot(t)}}}),y.extend(y.Polyline,y.Polygon,{array:function(){return this._array||(this._array=new y.PointArray(this.attr("points")))},plot:function(t){return this.attr("points",this._array=new y.PointArray(t))},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=h(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),y.extend(y.Line,y.Polyline,y.Polygon,{morphArray:y.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)}}),y.Path=y.invent({create:"path",inherit:y.Shape,extend:{morphArray:y.PathArray,array:function(){return this._array||(this._array=new y.PathArray(this.attr("d")))},plot:function(t){return this.attr("d",this._array=new y.PathArray(t))},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=h(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 y.Path).plot(t)}}}),y.Image=y.invent({create:"image",inherit:y.Shape,extend:{load:function(t){if(!t)return this;var i=this,n=e.createElement("img");return n.onload=function(){var e=i.parent(y.Pattern);null!==e&&(0==i.width()&&0==i.height()&&i.size(n.width,n.height),e&&0==e.width()&&0==e.height()&&e.size(i.width(),i.height()),"function"==typeof i._loaded&&i._loaded.call(i,{width:n.width,height:n.height,ratio:n.width/n.height,url:t}))},n.onerror=function(t){"function"==typeof i._error&&i._error.call(i,t)},this.attr("href",n.src=this.src=t,y.xlink)},loaded:function(t){return this._loaded=t,this},error:function(t){return this._error=t,this}},construct:{image:function(t,e,i){return this.put(new y.Image).load(t).size(e||0,i||e||0)}}}),y.Text=y.invent({create:function(){this.constructor.call(this,y.create("text")),this.dom.leading=new y.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",y.defaults.attrs["font-family"])},inherit:y.Shape,extend:{x:function(t){return null==t?this.attr("x"):(this.textPath||this.lines().each(function(){this.dom.newLined&&this.x(t)}),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("undefined"==typeof t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i<n;++i)0!=i&&3!=e[i].nodeType&&1==y.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var i=0,s=t.length;i<s;i++)this.tspan(t[i]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new y.Number(t),this.rebuild())},lines:function(){var t=(this.textPath&&this.textPath()||this).node,e=y.utils.map(y.utils.filterSVGElements(t.childNodes),function(t){return y.adopt(t)});return new y.Set(e)},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new y.Number(this.attr("font-size"));this.lines().each(function(){this.dom.newLined&&(this.textPath||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 y.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new y.Text).text(t)},plain:function(t){return this.put(new y.Text).plain(t)}}}),y.Tspan=y.invent({create:"tspan",inherit:y.Shape,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(y.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),y.extend(y.Text,y.Tspan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,i=new y.Tspan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.text(t)},clear:function(){for(var t=(this.textPath&&this.textPath()||this).node;t.hasChildNodes();)t.removeChild(t.lastChild);return this},length:function(){return this.node.getComputedTextLength()}}),y.TextPath=y.invent({create:"textPath",inherit:y.Parent,parent:y.Text,construct:{path:function(t){for(var e=new y.TextPath,i=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+i,y.xlink),this},plot:function(t){var e=this.track();return e&&e.plot(t),this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return y.adopt(this.node.firstChild)}}}),y.Nested=y.invent({create:function(){this.constructor.call(this,y.create("svg")),this.style("overflow","visible")},inherit:y.Container,construct:{nested:function(){return this.put(new y.Nested)}}}),y.A=y.invent({create:"a",inherit:y.Container,extend:{to:function(t){return this.attr("href",t,y.xlink)},show:function(t){return this.attr("show",t,y.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new y.A).to(t)}}}),y.extend(y.Element,{linkTo:function(t){var e=new y.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),y.Marker=y.invent({create:"marker",inherit:y.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)}}}),y.extend(y.Defs,{marker:function(t,e,i){return this.put(new y.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),y.extend(y.Line,y.Polyline,y.Polygon,y.Path,{marker:function(t,e,i,n){var s=["marker"];return"all"!=t&&s.push(t),s=s.join("-"),t=arguments[1]instanceof y.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(s,t)}});var g={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,i={};i[t]=function(i){if("undefined"==typeof i)return this;if("string"==typeof i||y.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=g[t].length-1;e>=0;e--)null!=i[g[t][e]]&&this.attr(g.prefix(t,g[t][e]),i[g[t][e]]);return this},y.extend(y.Element,y.FX,i)}),y.extend(y.Element,y.FX,{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){return this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return this.transform({flip:t,offset:e})},matrix:function(t){return this.attr("transform",new y.Matrix(t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x((this instanceof y.FX?0:this.x())+t,!0)},dy:function(t){return this.y((this instanceof y.FX?0:this.y())+t,!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),y.extend(y.Rect,y.Ellipse,y.Circle,y.Gradient,y.FX,{radius:function(t,e){var i=(this._target||this).type;return"radial"==i||"circle"==i?this.attr("r",new y.Number(t)):this.rx(t).ry(null==e?t:e)}}),y.extend(y.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),y.extend(y.Parent,y.Text,y.FX,{font:function(t){for(var e in t)"leading"==e?this.leading(t[e]):"anchor"==e?this.attr("text-anchor",t[e]):"size"==e||"family"==e||"weight"==e||"stretch"==e||"variant"==e||"style"==e?this.attr("font-"+e,t[e]):this.attr(e,t[e]);return this}}),y.Set=y.invent({create:function(t){Array.isArray(t)?this.members=t:this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;t<e;t++)this.members.push(i[t]);return this},remove:function(t){var e=this.index(t);return e>-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e<i;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},length:function(){return this.members.length},has:function(t){return this.index(t)>=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},first:function(){return this.get(0)},last:function(){return this.get(this.members.length-1)},valueOf:function(){return this.members},bbox:function(){var t=new y.BBox;if(0==this.members.length)return t;var e=this.members[0].rbox();return t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height,this.each(function(){t=t.merge(this.rbox())}),t}},construct:{set:function(t){return new y.Set(t)}}}),y.FX.Set=y.invent({create:function(t){this.set=t}}),y.Set.inherit=function(){var t,e=[];for(var t in y.Shape.prototype)"function"==typeof y.Shape.prototype[t]&&"function"!=typeof y.Set.prototype[t]&&e.push(t);e.forEach(function(t){y.Set.prototype[t]=function(){for(var e=0,i=this.members.length;e<i;e++)this.members[e]&&"function"==typeof this.members[e][t]&&this.members[e][t].apply(this.members[e],arguments);return"animate"==t?this.fx||(this.fx=new y.FX.Set(this)):this}}),e=[];for(var t in y.FX.prototype)"function"==typeof y.FX.prototype[t]&&"function"!=typeof y.FX.Set.prototype[t]&&e.push(t);e.forEach(function(t){y.FX.Set.prototype[t]=function(){for(var e=0,i=this.set.members.length;e<i;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},y.extend(y.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:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),y.extend(y.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var e in t)this.remember(e,t[e]);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={})}}),y.get=function(t){var i=e.getElementById(v(t)||t);return y.adopt(i)},y.select=function(t,i){return new y.Set(y.utils.map((i||e).querySelectorAll(t),function(t){return y.adopt(t)}))},y.extend(y.Parent,{select:function(t){return y.select(t,this.node)}});var w="abcdef".split("");if("function"!=typeof b){var b=function(t,i){i=i||{bubbles:!1,cancelable:!1,detail:void 0};var n=e.createEvent("CustomEvent");return n.initCustomEvent(t,i.bubbles,i.cancelable,i.detail),n};b.prototype=t.Event.prototype,t.CustomEvent=b}return function(e){for(var i=0,n=["moz","webkit"],s=0;s<n.length&&!t.requestAnimationFrame;++s)e.requestAnimationFrame=e[n[s]+"RequestAnimationFrame"],e.cancelAnimationFrame=e[n[s]+"CancelAnimationFrame"]||e[n[s]+"CancelRequestAnimationFrame"];e.requestAnimationFrame=e.requestAnimationFrame||function(t){var n=(new Date).getTime(),s=Math.max(0,16-(n-i)),r=e.setTimeout(function(){t(n+s)},s);return i=n+s,r},e.cancelAnimationFrame=e.cancelAnimationFrame||e.clearTimeout}(t),y});
\ No newline at end of file diff --git a/spec/spec/fx.js b/spec/spec/fx.js index a0c7fd7..0bd014e 100644 --- a/spec/spec/fx.js +++ b/spec/spec/fx.js @@ -4,21 +4,32 @@ describe('FX', function() { beforeEach(function() { rect = draw.rect(100,100).move(100,100) fx = rect.animate(500) + + jasmine.clock().install() + jasmine.clock().mockDate() // This freeze the Date + }) + + afterEach(function() { + jasmine.clock().uninstall() }) + it('creates an instance of SVG.FX and sets parameter', function() { expect(fx instanceof SVG.FX).toBe(true) expect(fx._target).toBe(rect) + expect(fx.absPos).toBe(0) expect(fx.pos).toBe(0) expect(fx.lastPos).toBe(0) - expect(fx.paused).toBeFalsy() - expect(fx.active).toBeFalsy() + expect(fx.paused).toBe(false) + expect(fx.active).toBe(false) expect(fx._speed).toBe(1) expect(fx.situations).toEqual([]) - expect(fx.situation.init).toBeFalsy() - expect(fx.situation.reversed).toBeFalsy() + expect(fx.situation.init).toBe(false) + expect(fx.situation.reversed).toBe(false) expect(fx.situation.duration).toBe(500) expect(fx.situation.delay).toBe(0) + expect(fx.situation.loops).toBe(false) + expect(fx.situation.loop).toBe(0) expect(fx.situation.animations).toEqual({}) expect(fx.situation.attrs).toEqual({}) expect(fx.situation.styles).toEqual({}) @@ -37,9 +48,10 @@ describe('FX', function() { }) }) - describe('timeToPos()', function() { - it('converts a timestamp to a progress', function() { - expect(fx.timeToPos( fx.situation.start + fx.situation.duration*0.5 )).toBe(0.5) + + describe('timeToAbsPos()', function() { + it('converts a timestamp to an absolute progress', function() { + expect(fx.timeToAbsPos( fx.situation.start + fx.situation.duration*0.5 )).toBe(0.5) }) it('should take speed into consideration', function() { @@ -47,17 +59,18 @@ describe('FX', function() { spd = 4 fx.speed(spd) - expect(fx.timeToPos( fx.situation.start + (fx.situation.duration/spd)*0.5 )).toBe(0.5) + expect(fx.timeToAbsPos( fx.situation.start + (fx.situation.duration/spd)*0.5 )).toBe(0.5) spd = 0.5 fx.speed(spd) - expect(fx.timeToPos( fx.situation.start + (fx.situation.duration/spd)*0.25 )).toBe(0.25) + expect(fx.timeToAbsPos( fx.situation.start + (fx.situation.duration/spd)*0.25 )).toBe(0.25) }) }) - describe('posToTime()', function() { - it('converts a progress to a timestamp', function() { - expect(fx.posToTime(0.5)).toBe( fx.situation.start + fx.situation.duration*0.5 ) + + describe('absPosToTime()', function() { + it('converts an absolute progress to a timestamp', function() { + expect(fx.absPosToTime(0.5)).toBe( fx.situation.start + fx.situation.duration*0.5 ) }) it('should take speed into consideration', function() { @@ -65,21 +78,367 @@ describe('FX', function() { spd = 4 fx.speed(spd) - expect(fx.posToTime(0.5)).toBe( fx.situation.start + (fx.situation.duration/spd)*0.5 ) + expect(fx.absPosToTime(0.5)).toBe( fx.situation.start + (fx.situation.duration/spd)*0.5 ) spd = 0.5 fx.speed(spd) - expect(fx.posToTime(0.25)).toBe( fx.situation.start + (fx.situation.duration/spd)*0.25 ) + expect(fx.absPosToTime(0.25)).toBe( fx.situation.start + (fx.situation.duration/spd)*0.25 ) + }) + }) + + + describe('atStart()', function () { + it('sets the animation at the start', function() { + // When the animation is running forward, the start position is 0 + this.pos = 0.5 + expect(fx.atStart().pos).toBe(0) + + // When the animation is running backward, the start position is 1 + this.pos = 0.5 + expect(fx.reverse(true).atStart().pos).toBe(1) + }) + + it('sets the animation at the start, before any loops', function() { + fx.loop(true) + + // When the animation is running forward, the start position is 0 + fx.at(3.7, true) + expect(fx.absPos).toBe(3.7) + expect(fx.pos).toBeCloseTo(0.7) + expect(fx.situation.loop).toBe(3) + + fx.atStart() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(0) + expect(fx.situation.loop).toBe(0) + + // When the animation is running backward, the start position is 1 + fx.reverse(true).at(2.14, true) + expect(fx.absPos).toBe(2.14) + expect(fx.pos).toBeCloseTo(1 - 0.14) + expect(fx.situation.loop).toBe(2) + expect(fx.situation.reversed).toBe(true) + + fx.atStart() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(1) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.reversed).toBe(true) + }) + + it('sets the animation at the start, before any loops when reversing is true', function() { + fx.loop(true, true) // Set reversing to true + + // When the animation is running forward, the start position is 0 + fx.at(11.21, true) + expect(fx.absPos).toBe(11.21) + expect(fx.pos).toBeCloseTo(1 - 0.21) + expect(fx.situation.loop).toBe(11) + expect(fx.situation.reversed).toBe(true) + + fx.atStart() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(0) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.reversed).toBe(false) + + // When the animation is running backward, the start position is 1 + fx.reverse(true).at(14.10, true) + expect(fx.absPos).toBe(14.10) + expect(fx.pos).toBeCloseTo(1 - 0.10) + expect(fx.situation.loop).toBe(14) + expect(fx.situation.reversed).toBe(true) + + fx.atStart() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(1) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.reversed).toBe(true) + }) + }) + + + describe('atEnd()', function () { + it('sets the animation at the end', function() { + // When the animation is running forward, the end position is 1 + this.pos = 0.5 + expect(fx.atEnd().pos).toBe(1) + expect(fx.situation).toBeNull() + + // Recreate an animation since the other one was ended + fx.animate() + + // When the animation is running backward, the end position is 0 + this.pos = 0.5 + expect(fx.reverse(true).atEnd().pos).toBe(0) + expect(fx.situation).toBeNull() + }) + + it('sets the animation at the end, after all loops', function() { + var loops + + // When the animation is running forward, the end position is 1 + loops = 12 + fx.loop(loops).start().step() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(0) + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.loops).toBe(loops) + + fx.atEnd() + expect(fx.absPos).toBe(loops) + expect(fx.pos).toBe(1) + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + + // Recreate an animation since the other one was ended + fx.animate() + + + // When the animation is running backward, the end position is 0 + loops = 21 + fx.reverse(true).loop(loops).start().step() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(1) + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.loops).toBe(loops) + expect(fx.situation.reversed).toBe(true) + + fx.atEnd() + expect(fx.absPos).toBe(loops) + expect(fx.pos).toBe(0) + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + }) + + it('sets the animation at the end, after all loops when reversing is true', function() { + var loops + + // When reversing is true, the end position equal the start position when + // loops is even + + // The animation is running forward + loops = 6 + fx.loop(loops, true).start().step() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(0) + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.loops).toBe(loops) + expect(fx.situation.reversed).toBe(false) + + fx.atEnd() + expect(fx.absPos).toBe(loops) + expect(fx.pos).toBe(0) // Equal start position because loops is even + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + + // Recreate an animation since the other one was ended + fx.animate() + + + // The animation is running backward + loops = 3 + fx.reverse(true).loop(loops, true).start().step() + expect(fx.absPos).toBe(0) + expect(fx.pos).toBe(1) + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.loops).toBe(loops) + expect(fx.situation.reversed).toBe(true) + + fx.atEnd() + expect(fx.absPos).toBe(loops) + expect(fx.pos).toBe(0) // Not equal to the start position because loops is odd + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() }) }) + describe('at()', function() { it('sets the progress to the specified position', function() { - var start = fx.situation.start - expect(fx.at(0.5).pos).toBe(0.5) - // time is running so we cant compare it directly - expect(fx.situation.start).toBeLessThan(start - fx.situation.duration * 0.5 + 1, 0.0001) - expect(fx.situation.start).toBeGreaterThan(start - fx.situation.duration * 0.5 - 10) + var pos + + // Animation running forward + pos = 0.5 + expect(fx.at(pos).pos).toBe(pos) + expect(fx.situation.start).toBe(+new Date - fx.situation.duration * pos) + + // Animation running backward + pos = 0.4 + expect(fx.reverse(true).at(pos).pos).toBe(pos) + expect(fx.situation.start).toBe(+new Date - fx.situation.duration * (1-pos)) + }) + + it('should convert a position to an absolute position', function () { + var pos, loop, absPos + + fx.loop(true) + + // Animation running forward + pos = 0.7 + loop = 4 + absPos = pos+loop + fx.situation.loop = loop + expect(fx.at(pos).absPos).toBe(absPos) + expect(fx.situation.start).toBe(+new Date - fx.situation.duration * absPos) + + // Animation running backward + pos = 0.23 + loop = 9 + absPos = (1-pos)+loop + fx.situation.loop = loop + fx.situation.reversed = true + expect(fx.at(pos).absPos).toBe(absPos) + expect(fx.situation.start).toBe(+new Date - fx.situation.duration * absPos) + + }) + + it('should end the animation when the end position is passed', function() { + var pos + + fx.start() + expect(fx.active).toBe(true) + expect(fx.situation).not.toBeNull() + + // When running forward, the end position is 1 + pos = 1 + expect(fx.at(pos).pos).toBe(pos) + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + + // Recreate an animation since the other one was ended + fx.animate().start() + expect(fx.active).toBe(true) + expect(fx.situation).not.toBeNull() + + // When running backward, the end position is 0 + pos = 0 + expect(fx.reverse(true).at(pos).pos).toBe(pos) + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + }) + + it('correct the passed position when it is out of [0,1] and the animation is not looping', function () { + var pos + + pos = -0.7 + expect(fx.at(pos).pos).toBe(0) + + pos = 1.3 + expect(fx.at(pos).pos).toBe(1) + + // Recreate an animation since the other one was ended + fx.animate() + + // Should work even when animation is running backward + pos = 1.3 + expect(fx.reverse(true).at(pos).pos).toBe(1) + + pos = -0.7 + expect(fx.reverse(true).at(pos).pos).toBe(0) + }) + + it('should, when the animation is looping and the passed position is out of [0,1], use the integer part of postion to update the loop counter and set position to its fractional part', function(){ + var loop, pos, posFrac, posInt + + // Without the reverse flag + fx.loop(10) + expect(fx.situation.loops).toBe(10) + expect(fx.situation.loop).toBe(loop = 0) + + pos = 1.3 + posFrac = pos % 1 + posInt = pos - posFrac + expect(fx.at(pos).pos).toBeCloseTo(posFrac) + expect(fx.situation.loop).toBe(loop += posInt) + + pos = 7.723 + posFrac = pos % 1 + posInt = pos - posFrac + expect(fx.at(pos).pos).toBeCloseTo(posFrac) + expect(fx.situation.loop).toBe(loop += posInt) + + // In this case, pos is above the remaining number of loops, so we expect + // the position to be set to 1 and the animation to be ended + pos = 4.3 + posFrac = pos % 1 + posInt = pos - posFrac + expect(fx.at(pos).pos).toBe(1) + expect(fx.situation).toBeNull() + + // Recreate an animation since the other one was ended + fx.animate() + + // With the reverse flag, the position is reversed each time loop is odd + fx.loop(10, true) + expect(fx.situation.loops).toBe(10) + expect(fx.situation.loop).toBe(loop = 0) + expect(fx.situation.reversed).toBe(false) + + pos = 3.3 + posFrac = pos % 1 + posInt = pos - posFrac + expect(fx.at(pos).pos).toBeCloseTo(1-posFrac) // Animation is reversed because 0+3 is odd + expect(fx.situation.loop).toBe(loop += posInt) + expect(fx.situation.reversed).toBe(true) + + // When the passed position is below 0, the integer part of position is + // substracted from 1, so, in this case, -0.6 has 1 as is integer part + // This is necessary so we can add something to the loop counter + pos = -0.645 + posFrac = (1-pos) % 1 + posInt = (1-pos) - posFrac + expect(fx.at(pos).pos).toBeCloseTo(posFrac) + expect(fx.situation.loop).toBe(loop += posInt) + expect(fx.situation.reversed).toBe(false) + + // In this case, pos is above the remaining number of loop, so we expect + // the position to be set to 0 (since we end reversed) and the animation to + // be ended + pos = 7.2 + posFrac = pos % 1 + posInt = pos - posFrac + expect(fx.at(pos).pos).toBe(0) + expect(fx.situation).toBeNull() + }) + + it('should, when the animation is in a infinite loop and the passed position is out of [0,1], use the integer part of postion to update the loop counter and set position to its fractional part', function(){ + var loop, pos, posFrac, posInt + + // Without the reverse flag + fx.loop(true) + expect(fx.situation.loops).toBe(true) + expect(fx.situation.loop).toBe(loop = 0) + + pos = 10.34 + posFrac = pos % 1 + posInt = pos - posFrac + expect(fx.at(pos).pos).toBeCloseTo(posFrac) + expect(fx.situation.loop).toBe(loop += posInt) + + // With the reverse flag, the position is reversed each time loop is odd + fx.loop(true, true) + expect(fx.situation.loops).toBe(true) + expect(fx.situation.loop).toBe(loop = 0) + expect(fx.situation.reversed).toBe(false) + + pos = 3.3 + posFrac = pos % 1 + posInt = pos - posFrac + expect(fx.at(pos).pos).toBeCloseTo(1-posFrac) // Animation is reversed because 3+0 is odd + expect(fx.situation.loop).toBe(loop += posInt) + expect(fx.situation.reversed).toBe(true) + + pos = -8.41 + posFrac = (1-pos) % 1 + posInt = (1-pos) - posFrac + expect(fx.at(pos).pos).toBeCloseTo(posFrac) + expect(fx.situation.loop).toBe(loop += posInt) + expect(fx.situation.reversed).toBe(false) }) it('should take speed into consideration', function() { @@ -103,28 +462,68 @@ describe('FX', function() { fx.speed(spd).at(0.83) expect(fx.situation.finish-fx.situation.start).toBe(dur/spd) }) + + it('should consider the first parameter as an absolute position when the second parameter is true', function() { + var absPos + + fx.loop(true) + + absPos = 3.2 + expect(fx.at(absPos, true).absPos).toBe(absPos) + + absPos = -4.27 + expect(fx.at(absPos, true).absPos).toBe(absPos) + + absPos = 0 + expect(fx.at(absPos, true).absPos).toBe(absPos) + + absPos = 1 + expect(fx.at(absPos, true).absPos).toBe(absPos) + }) }) + describe('start()', function(){ - it('starts the animation', function(done) { + it('starts the animation', function() { fx.start() expect(fx.active).toBe(true) expect(fx.timeout).not.toBe(0) - setTimeout(function(){ - expect(fx.pos).toBeGreaterThan(0) - done() - }, 200) + + jasmine.clock().tick(201) + fx.step() // Call step to update the animation + + expect(fx.pos).toBeGreaterThan(0) }) it('should take speed into consideration', function() { - var dur = fx.situation.duration + var dur = 500 + , delay = 300 , spd = 4 - fx.speed(spd).start() - expect(fx.situation.finish-fx.situation.start).toBe(dur/spd) + + fx.stop().animate(dur, '-', delay).speed(spd).start() + expect(fx.situation.finish - new Date).toBe(delay/spd + dur/spd) + }) + + it('should do the delay', function() { + fx.situation.delay = 1000 + expect(fx.start().active).toBe(true) + + jasmine.clock().tick(501) + fx.step() // Call step to update the animation + expect(fx.active).toBe(true) + + jasmine.clock().tick(501) + fx.step() // Call step to update the animation + expect(fx.active).toBe(true) + + jasmine.clock().tick(501) + fx.step() // Call step to update the animation + expect(fx.active).toBe(false) }) }) + describe('pause()', function() { it('pause the animation', function() { expect(fx.pause().paused).toBe(true) @@ -132,16 +531,64 @@ describe('FX', function() { }) describe('play()', function() { - it('unpause the animation', function(done) { + it('unpause the animation', function() { var start = fx.start().pause().situation.start - setTimeout(function(){ - expect(fx.play().paused).toBe(false) - expect(fx.situation.start).not.toBe(start) - done() - }, 200) + + jasmine.clock().tick(200) + + expect(fx.situation.start).toBe(start) + expect(fx.play().paused).toBe(false) + expect(fx.situation.start).not.toBe(start) + }) + + it('should not change the position when the animation is unpaused while it is set to run backward', function(){ + var pos = 0.4 + + expect(fx.reverse(true).at(pos).pause().play().pos).toBe(pos) + }) + + it('should be able to unpause the delay', function () { + fx.stop().animate(500, '-', 300).start().step() + expect(fx.pos).toBe(0) + expect(fx.absPos).toBeCloseTo(-0.6) + + // At this point, we should have an animation of 500 ms with a delay of + // 300 ms that should be running. + + jasmine.clock().tick(150) + + // Should be halfway through the delay + fx.step() + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(-0.3) + + expect(fx.pause().paused).toBe(true) // Pause the delay + + jasmine.clock().tick(150) + + // Unpause, should still be halfway through the delay + expect(fx.play().paused).toBe(false) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(-0.3) + + jasmine.clock().tick(150) + + // Delay should be done + fx.step() + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(0) + + jasmine.clock().tick(500) + + // Animation and delay should be done + fx.step() + expect(fx.active).toBe(false) + expect(fx.pos).toBe(1) + expect(fx.absPos).toBe(1) }) }) + describe('speed()', function() { it('set the speed of the animation', function(){ var dur, spd @@ -172,7 +619,7 @@ describe('FX', function() { it('should not change the position when the animation is run backward', function(){ var pos = 0.4 - expect(fx.at(pos).reverse(true).speed(2).pos).toBe(pos) + expect(fx.reverse(true).at(pos).speed(2).pos).toBe(pos) }) it('return the current speed with no argument given', function(){ @@ -199,7 +646,7 @@ describe('FX', function() { expect(fx.paused).toBe(true) }) - it('should affect all animations in the queue', function(done){ + it('should affect all animations in the queue', function(){ fx.speed(2).animate(300) expect(fx.situations.length).not.toBe(0) expect(fx.pos).not.toBe(1) @@ -209,25 +656,64 @@ describe('FX', function() { // we just added. Normally, it would take 800ms before both of these // animations are done, but because we set the speed to 2, it should // only take 400ms to do both animations. - fx.start() + fx.start().step() - // We expect this timeout to happen while the second animation is running - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situations.length).toBe(0) - expect(fx.pos).not.toBe(1) - }, 300) + jasmine.clock().tick(250) - // Here, we expect that all the animations are done - setTimeout(function(){ - expect(fx.active).toBe(false) - expect(fx.situations.length).toBe(0) - expect(fx.pos).toBe(1) - done() - }, 450) + // Should be playing the second animation + fx.step() + expect(fx.active).toBe(true) + expect(fx.situations.length).toBe(0) + expect(fx.pos).not.toBe(1) + + jasmine.clock().tick(150) // 400ms have passed + + // All animations should be done + fx.step() + expect(fx.active).toBe(false) + expect(fx.situations.length).toBe(0) + expect(fx.pos).toBe(1) + }) + + it('should affect the delay', function() { + fx.stop().animate(500, '-', 300).start().step() + expect(fx.pos).toBe(0) + expect(fx.absPos).toBeCloseTo(-0.6) + + fx.speed(2) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBeCloseTo(-0.6) + + // At this point, we should have an animation of 500 ms with a delay of + // 300 ms that should be running. Normally, it would take 800 ms for the + // animation and its delay to complete, but because the speed is set to 2 + // , it should only take 400ms + + jasmine.clock().tick(75) + + // Should be halfway through the delay + fx.step() + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(-0.3) + + jasmine.clock().tick(75) + + // Delay should be done + fx.step() + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(0) + + jasmine.clock().tick(250) + + // Animation and delay should be done + fx.step() + expect(fx.active).toBe(false) + expect(fx.pos).toBe(1) + expect(fx.absPos).toBe(1) }) }) + describe('reverse()', function() { it('toggles the direction of the animation without a parameter', function() { expect(fx.reverse().situation.reversed).toBe(true) @@ -246,20 +732,36 @@ describe('FX', function() { }) }) + + describe('dequeue()', function() { + it('initialize the animation pulled from the queue to its start position', function() { + // When the animation is forward, the start position is 0 + fx.animate() + fx.pos = 0.5 + expect(fx.dequeue().pos).toBe(0) + + // When the animation backward, the start position is 1 + fx.animate().reverse(true) + fx.pos = 0.5 + expect(fx.dequeue().pos).toBe(1) + }) + }) + + describe('stop()', function() { it('stops the animation immediately without a parameter', function() { - fx.animate(500) + fx.animate(500).start() expect(fx.stop().situation).toBeNull() - expect(fx.active).toBeFalsy() + expect(fx.active).toBe(false) expect(fx.situations.length).toBe(1) }) }) describe('stop()', function() { it('stops the animation immediately and fullfill it if first parameter true', function() { - fx.animate(500) + fx.animate(500).start() expect(fx.stop(true).situation).toBeNull() - expect(fx.active).toBeFalsy() + expect(fx.active).toBe(false) expect(fx.pos).toBe(1) expect(fx.situations.length).toBe(1) }) @@ -267,13 +769,38 @@ describe('FX', function() { describe('stop()', function() { it('stops the animation immediately and remove all items from queue when second parameter true', function() { - fx.animate(500) + fx.animate(500).start() expect(fx.stop(false, true).situation).toBeNull() - expect(fx.active).toBeFalsy() + expect(fx.active).toBe(false) expect(fx.situations.length).toBe(0) }) }) + + describe('reset()', function() { + it('resets the element to the state it was when the current animation was started', function() { + var loops = 4 + , situation = fx.situation + + // These settings make the animations run backward + fx.situation.loop = 2 + fx.situation.loops = loops + fx.situation.reversed = true + fx.pos = 0.5 + fx.absPos = 2.5 + + fx.reset() + + expect(fx.situation).toBe(situation) + expect(fx.situation.loops).toBe(loops) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.reversed).toBe(true) // True because the animation is backward + expect(fx.pos).toBe(1) + expect(fx.absPos).toBe(0) + }) + }) + + describe('finish()', function() { it('finish the whole animation by fullfilling every single one', function() { fx.animate(500) @@ -283,6 +810,7 @@ describe('FX', function() { }) }) + describe('progress()', function() { it('returns the current position', function() { expect(fx.progress()).toBe(0) @@ -290,46 +818,108 @@ describe('FX', function() { }) }) + describe('after()', function() { - it('adds a callback which is called when the current animation is finished', function(done) { + it('adds a callback which is called when the current animation is finished', function() { + var called = false + fx.start().after(function(situation){ expect(fx.situation).toBe(situation) expect(fx.pos).toBe(1) - done() + called = true }) + + jasmine.clock().tick(500) + fx.step() + expect(called).toBe(true) }) }) + describe('afterAll()', function() { - it('adds a callback which is called when all animations are finished', function(done) { + it('adds a callback which is called when all animations are finished', function() { + var called = false + fx.animate(150).animate(125).start().afterAll(function(){ expect(fx.pos).toBe(1) expect(fx.situations.length).toBe(0) - done() + called = true }) + + expect(fx.situations.length).toBe(2) + + // End of the first animation + jasmine.clock().tick(500) + fx.step() + expect(fx.situations.length).toBe(1) + expect(called).toBe(false) + + // End of the second animation + jasmine.clock().tick(150) + fx.step() + expect(fx.situations.length).toBe(0) + expect(called).toBe(false) + + // End of the third and last animation + jasmine.clock().tick(125) + fx.step() + expect(fx.situation).toBeNull() + expect(called).toBe(true) }) }) + describe('during()', function() { - it('adds a callback which is called on every animation step', function(done) { + it('adds a callback which is called on every animation step', function() { + var called = 0 fx.start().during(function(pos, morph, eased, situation){ expect(fx.situation).toBe(situation) - expect(morph(0, 100)).toBeCloseTo(pos*100) - if(fx.pos > 0.9){ - rect.off('.fx') - fx.stop() + switch(++called) { + case 1: + expect(pos).toBeCloseTo(0.25) + break + + case 2: + expect(pos).toBeCloseTo(0.5) + break + + case 3: + expect(pos).toBeCloseTo(0.65) + break - done() + case 4: + expect(pos).toBe(1) + break } + + expect(morph(0, 100)).toBeCloseTo(pos*100) + }) + + jasmine.clock().tick(125) + fx.step() + expect(called).toBe(1) + + jasmine.clock().tick(125) // 250 ms have passed + fx.step() + expect(called).toBe(2) + + jasmine.clock().tick(75) // 325 ms have passed + fx.step() + expect(called).toBe(3) + + jasmine.clock().tick(175) // 500 ms have passed + fx.step() + expect(called).toBe(4) }) }) + describe('duringAll()', function() { - it('adds a callback which is called on every animation step for the whole chain', function(done) { + it('adds a callback which is called on every animation step for the whole chain', function() { fx.finish() rect.off('.fx') @@ -341,218 +931,523 @@ describe('FX', function() { var pos1 = false var pos2 = false - setTimeout(function(){ - pos1 = true - }, 300) - - setTimeout(function(){ - pos2 = true - }, 800) - fx.duringAll(function(pos, morph, eased, situation){ if(pos1){ pos1 = false sit = situation - expect(this.fx.pos).toBeGreaterThan(0.5) + expect(this.fx.pos).toBeCloseTo(0.6) } if(pos2){ pos2 = null expect(situation).not.toBe(sit) - expect(this.fx.pos).toBeGreaterThan(0.5) - done() + expect(this.fx.pos).toBeCloseTo(0.75) } }) - setTimeout(function(){ - if(pos2 === null) return + pos1 = true + jasmine.clock().tick(300) + fx.step() + + jasmine.clock().tick(200) // End of the first animation + fx.step() + + pos2 = true + jasmine.clock().tick(375) + fx.step() + + if(pos1 || pos2) { fail('Not enough situations called') - done() - }, 1200) + } }) }) + describe('once()', function() { - it('adds a callback which is called once at the specified position', function(done) { + it('adds a callback which is called once at the specified position', function() { + var called = false fx.start().once(0.5, function(pos, eased){ - expect(pos).toBeGreaterThan(0.49) - done() + called = true + expect(pos).toBeCloseTo(0.5) }) + + jasmine.clock().tick(125) + fx.step() + expect(called).toBe(false) + + jasmine.clock().tick(125) // 250 ms have passed + fx.step() + expect(called).toBe(true) }) }) + describe('loop()', function() { - it('should create an eternal loop when no arguments are given', function(done) { + it('should create an eternal loop when no arguments are given', function() { + var time = 10523, dur = fx.situation.duration + fx.loop() - expect(fx.situation.loop).toBe(true) + expect(fx.situation.loop).toBe(0) expect(fx.situation.loops).toBe(true) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(0) - fx.start() - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(true) - expect(fx.situation.loops).toBe(true) - expect(fx.pos).toBeCloseTo(0.6, 1) - done() - }, 800) + fx.start().step() + jasmine.clock().tick(time) + fx.step() + + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe( Math.floor(time/dur) ) + expect(fx.situation.loops).toBe(true) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) }) - it('should create an eternal loop when the first argument is true', function(done) { + it('should create an eternal loop when the first argument is true', function() { + var time = 850452, dur = fx.situation.duration + fx.loop(true) - expect(fx.situation.loop).toBe(true) + expect(fx.situation.loop).toBe(0) expect(fx.situation.loops).toBe(true) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(0) - fx.start() - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(true) - expect(fx.situation.loops).toBe(true) - expect(fx.pos).toBeCloseTo(0.3, 1) - done() - }, 650) + fx.start().step() + jasmine.clock().tick(time) + fx.step() + + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe( Math.floor(time/dur) ) + expect(fx.situation.loops).toBe(true) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) }) - it('should loop for the specified number of times', function(done) { + it('should loop for the specified number of times', function() { + var time = 0, dur = fx.situation.duration + fx.loop(3) - expect(fx.situation.loop).toBe(3) + expect(fx.situation.loop).toBe(0) expect(fx.situation.loops).toBe(3) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(0) - fx.start() - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(3) - expect(fx.situation.loops).toBe(3) - expect(fx.pos).toBeCloseTo(0.4, 1) - }, 200) - - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(2) - expect(fx.situation.loops).toBe(3) - expect(fx.pos).toBeCloseTo(0.5, 1) - }, 750) - - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(1) - expect(fx.situation.loops).toBe(3) - expect(fx.pos).toBeCloseTo(0.64, 1) - }, 1320) - - setTimeout(function(){ - expect(fx.active).toBe(false) - expect(fx.situation).toBeNull() - expect(fx.pos).toBe(1) - done() - }, 1600) + fx.start().step() + jasmine.clock().tick(200) + time = 200 + + fx.step() + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.loops).toBe(3) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) + + jasmine.clock().tick(550) + time += 550 // time at 750 + + fx.step() + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(1) + expect(fx.situation.loops).toBe(3) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) + + jasmine.clock().tick(570) + time += 570 // time at 1320 + + fx.step() + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(2) + expect(fx.situation.loops).toBe(3) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) + + jasmine.clock().tick(180) + time += 180 // time at 1500 + + fx.step() + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + expect(fx.pos).toBe(1) + expect(fx.absPos).toBe(3) }) - it('should go from beginning to end and start over again (0->1.0->1.0->1.) by default', function(done) { + it('should go from beginning to end and start over again (0->1.0->1.0->1.) by default', function() { + var time = 0, dur = fx.situation.duration + fx.loop(2) - expect(fx.situation.loop).toBe(2) + expect(fx.situation.loop).toBe(0) expect(fx.situation.loops).toBe(2) expect(fx.situation.reversing).toBe(false) expect(fx.situation.reversed).toBe(false) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(0) - fx.start() - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(2) - expect(fx.situation.loops).toBe(2) - expect(fx.situation.reversing).toBe(false) - expect(fx.situation.reversed).toBe(false) - expect(fx.pos).toBeCloseTo(0.65, 1) - }, 325) - - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(1) - expect(fx.situation.loops).toBe(2) - expect(fx.situation.reversing).toBe(false) - expect(fx.situation.reversed).toBe(false) - expect(fx.pos).toBeCloseTo(0.8, 1) - }, 900) + fx.start().step() + jasmine.clock().tick(325) + time = 325 - setTimeout(function(){ - expect(fx.active).toBe(false) - expect(fx.situation).toBeNull() - expect(fx.pos).toBe(1) - done() - }, 1100) + fx.step() + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.loops).toBe(2) + expect(fx.situation.reversing).toBe(false) + expect(fx.situation.reversed).toBe(false) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) + + jasmine.clock().tick(575) + time += 575 // time at 900 + + fx.step() + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(1) + expect(fx.situation.loops).toBe(2) + expect(fx.situation.reversing).toBe(false) + expect(fx.situation.reversed).toBe(false) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) + + jasmine.clock().tick(200) + time += 200 // time at 1100 + + fx.step() + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + expect(fx.pos).toBe(1) + expect(fx.absPos).toBe(2) }) - it('should be completely reversed before starting over (0->1->0->1->0->1.) when the reverse flag is passed', function(done) { + it('should be completely reversed before starting over (0->1->0->1->0->1.) when the reverse flag is passed', function() { + var time = 0, dur = fx.situation.duration + fx.loop(2, true) - expect(fx.situation.loop).toBe(2) + expect(fx.situation.loop).toBe(0) expect(fx.situation.loops).toBe(2) expect(fx.situation.reversing).toBe(true) expect(fx.situation.reversed).toBe(false) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(0) - fx.start() - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(2) - expect(fx.situation.loops).toBe(2) - expect(fx.situation.reversing).toBe(true) - expect(fx.situation.reversed).toBe(false) - expect(fx.pos).toBeCloseTo(0.65, 1) - }, 325) - - setTimeout(function(){ - expect(fx.active).toBe(true) - expect(fx.situation.loop).toBe(1) - expect(fx.situation.loops).toBe(2) - expect(fx.situation.reversing).toBe(true) - expect(fx.situation.reversed).toBe(true) - expect(fx.pos).toBeCloseTo(0.2, 1) - }, 900) + fx.start().step() + jasmine.clock().tick(325) + time = 325 - setTimeout(function(){ - expect(fx.active).toBe(false) - expect(fx.situation).toBeNull() - expect(fx.pos).toBe(0) - done() - }, 1100) + fx.step() + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(0) + expect(fx.situation.loops).toBe(2) + expect(fx.situation.reversing).toBe(true) + expect(fx.situation.reversed).toBe(false) + expect(fx.pos).toBeCloseTo((time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) + + jasmine.clock().tick(575) + time += 575 // time at 900 + + fx.step() + expect(fx.active).toBe(true) + expect(fx.situation.loop).toBe(1) + expect(fx.situation.loops).toBe(2) + expect(fx.situation.reversing).toBe(true) + expect(fx.situation.reversed).toBe(true) + expect(fx.pos).toBeCloseTo(1 - (time/dur) % 1) + expect(fx.absPos).toBeCloseTo(time/dur) + + jasmine.clock().tick(200) + time += 200 // time at 1100 + + fx.step() + expect(fx.active).toBe(false) + expect(fx.situation).toBeNull() + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(2) }) it('should be applied on the last situation', function() { fx.loop(5) - expect(fx.situation.loop).toBe(5) + expect(fx.situation.loop).toBe(0) expect(fx.situation.loops).toBe(5) expect(fx.situation.reversing).toBe(false) fx.animate().loop(3, true) - expect(fx.situation.loop).toBe(5) + expect(fx.situation.loop).toBe(0) expect(fx.situation.loops).toBe(5) expect(fx.situation.reversing).toBe(false) var c = fx.last() - expect(c.loop).toBe(3) + expect(c.loop).toBe(0) expect(c.loops).toBe(3) expect(c.reversing).toBe(true) }) + + it('should be possible to call it with false as the first argument', function() { + fx.situation.loops = true + fx.loop(false) + expect(fx.situation.loops).toBe(false) + }) }) - it('animates the x/y-attr', function(done) { + + describe('step()', function() { + it('should not recalculate the absolute position if the first parameter is true', function() { + var absPos + + // We shift start to help us see if the absolute position get recalculated + // If it get recalculated, the result would be 0.5 + fx.situation.start -= 250 + + absPos = 0.4 + fx.absPos = absPos + expect(fx.step(true).absPos).toBe(absPos) + + absPos = 0 + fx.absPos = absPos + expect(fx.step(true).absPos).toBe(absPos) + + absPos = -3.7 + fx.absPos = absPos + expect(fx.step(true).absPos).toBe(absPos) + + absPos = 1 + fx.absPos = absPos + expect(fx.step(true).absPos).toBe(absPos) + }) + + it('should not allow an absolute position to be above the end', function() { + var absPos, loops + + // With no loops, absolute position should not go above 1 + absPos = 4.26 + fx.absPos = absPos + expect(fx.step(true).absPos).toBe(1) + expect(fx.situation).toBeNull() + + fx.animate() // Recreate an animation since the other one was ended + + // With loops, absolute position should not go above loops + loops = 4 + absPos = 7.42 + fx.absPos = absPos + expect(fx.loop(loops).step(true).absPos).toBe(loops) + expect(fx.situation).toBeNull() + }) + + describe('when converting an absolute position to a position', function() { + it('should, when the absolute position is below the maximum number of loops, use the integer part of the absolute position to set the loop counter and use its fractional part to set the position', function(){ + var absPos, absPosFrac, absPosInt, loops + + // Without the reverse flag + loops = 12 + absPos = 4.52 + absPosInt = Math.floor(absPos) + absPosFrac = absPos - absPosInt + fx.absPos = absPos + fx.loop(loops).step(true) + expect(fx.pos).toBe(absPosFrac) + expect(fx.situation.loop).toBe(absPosInt) + + fx.stop().animate() + + loops = true + absPos = 2.57 + absPosInt = Math.floor(absPos) + absPosFrac = absPos - absPosInt + fx.absPos = absPos + fx.loop(loops).step(true) + expect(fx.pos).toBe(absPosFrac) + expect(fx.situation.loop).toBe(absPosInt) + + fx.stop().animate() + + // With the reverse flag, the position is reversed at each odd loop + loops = 412 + absPos = 6.14 + absPosInt = Math.floor(absPos) + absPosFrac = absPos - absPosInt + fx.absPos = absPos + fx.loop(loops, true).step(true) + expect(fx.pos).toBe(absPosFrac) + expect(fx.situation.loop).toBe(absPosInt) + expect(fx.situation.reversed).toBe(false) + + fx.stop().animate() + + loops = true + absPos = 5.12 + absPosInt = Math.floor(absPos) + absPosFrac = absPos - absPosInt + fx.absPos = absPos + fx.loop(loops, true).step(true) + expect(fx.pos).toBe(1-absPosFrac) // Odd loop, so it is reversed + expect(fx.situation.loop).toBe(absPosInt) + expect(fx.situation.reversed).toBe(true) + + fx.stop().animate() + + // When the animation is set to run backward, it is the opposite, the position is reversed at each even loop + loops = 14 + absPos = 8.46 + absPosInt = Math.floor(absPos) + absPosFrac = absPos - absPosInt + fx.absPos = absPos + fx.reverse(true).loop(loops, true).step(true) + expect(fx.pos).toBe(1-absPosFrac) // Even loop, so it is reversed + expect(fx.situation.loop).toBe(absPosInt) + expect(fx.situation.reversed).toBe(true) + + fx.stop().animate() + + loops = true + absPos = 3.12 + absPosInt = Math.floor(absPos) + absPosFrac = absPos - absPosInt + fx.absPos = absPos + fx.reverse(true).loop(loops, true).step(true) + expect(fx.pos).toBe(absPosFrac) + expect(fx.situation.loop).toBe(absPosInt) + expect(fx.situation.reversed).toBe(false) + }) + + it('should, when the absolute position is above or equal to the the maximum number of loops, set the position to its end value and end the animation', function() { + var absPos, loops + + // Without the reverse flag, the end value of position is 1 + loops = 6 + absPos = 13.52 + fx.absPos = absPos + fx.loop(loops).step(true) + expect(fx.pos).toBe(1) + expect(fx.situation).toBeNull() + + fx.animate() // Recreate an animation since the other one was ended + + loops = false + absPos = 146.22 + fx.absPos = absPos + fx.loop(loops).step(true) + expect(fx.pos).toBe(1) + expect(fx.situation).toBeNull() + + fx.animate() // Recreate an animation since the other one was ended + + // With the reverse flag, the end value of position is 0 when loops is even and 1 when loops is an odd number or false + loops = 6 + absPos = 6 + fx.absPos = absPos + fx.loop(loops, true).step(true) + expect(fx.pos).toBe(0) // Even loops + expect(fx.situation).toBeNull() + + fx.animate() // Recreate an animation since the other one was ended + + loops = false + absPos = 4.47 + fx.absPos = absPos + fx.loop(loops, true).step(true) + expect(fx.pos).toBe(1) // 1 since loops is false + expect(fx.situation).toBeNull() + + fx.animate() // Recreate an animation since the other one was ended + + // When the animation is set to run backward, it is the opposite, the end value of position is 1 when loops is even and 0 when loops is an odd number or false + loops = 8 + absPos = 12.65 + fx.absPos = absPos + fx.reverse(true).loop(loops, true).step(true) + expect(fx.pos).toBe(1) // Even loops + expect(fx.situation).toBeNull() + + fx.animate() // Recreate an animation since the other one was ended + + loops = 11 + absPos = 12.41 + fx.absPos = absPos + fx.reverse(true).loop(loops, true).step(true) + expect(fx.pos).toBe(0) // Odd loops + expect(fx.situation).toBeNull() + }) + + it('should set the position to its start value when the absolute position is below 0', function() { + var absPos + + // When the animation is not set to run backward the start value is 0 + absPos = -2.27 + fx.loop(7) + fx.situation.loop = 3 + fx.absPos = absPos + fx.step(true) + expect(fx.pos).toBe(0) + expect(fx.absPos).toBe(absPos) + expect(fx.situation.loop).toBe(0) + + fx.stop().animate() + + // When the animation is set to run backward the start value is 1 + absPos = -4.12 + fx.absPos = absPos + fx.reverse(true).step(true) + expect(fx.pos).toBe(1) + expect(fx.absPos).toBe(absPos) + }) + + it('should, when looping with the reverse flag, toggle reversed only when the difference between the new value of loop counter and its old value is odd', function() { + // The new value of the loop counter is the integer part of absPos + + fx.loop(9, true) + expect(fx.situation.loop).toBe(0) + expect(fx.pos).toBe(0) + expect(fx.situation.reversed).toBe(false) + + fx.absPos = 3 + fx.step(true) + expect(fx.situation.reversed).toBe(true) // (3-0) is odd + + fx.absPos = 1 + fx.step(true) + expect(fx.situation.reversed).toBe(true) // (1-3) is even + + fx.absPos = 6 + fx.step(true) + expect(fx.situation.reversed).toBe(false) // (6-1) is odd + + fx.absPos = 9 + fx.step(true) + expect(fx.situation).toBeNull() + expect(fx.pos).toBe(1) // It should end not reversed, which mean the position is expected to be 1 + // ((9-1)-6) is even, the -1 is because we do not want reversed to be toggled after the last loop + }) + }) + }) + + + it('animates the x/y-attr', function() { + var called = false fx.move(200,200).after(function(){ expect(rect.x()).toBe(200) expect(rect.y()).toBe(200) - done() + called = true - }); + }) - setTimeout(function(){ - expect(rect.x()).toBeGreaterThan(100) - expect(rect.y()).toBeGreaterThan(100) - }, 250) + jasmine.clock().tick(250) + fx.step() + expect(rect.x()).toBeGreaterThan(100) + expect(rect.y()).toBeGreaterThan(100) + jasmine.clock().tick(250) + fx.step() + expect(called).toBe(true) }) - it('animates matrix', function(done) { + + it('animates matrix', function() { + var ctm, called = false fx.transform({a:0.8, b:0.4, c:-0.15, d:0.7, e: 90.3, f: 27.07}).after(function(){ @@ -563,22 +1458,23 @@ describe('FX', function() { expect(ctm.d).toBeCloseTo(0.7) expect(ctm.e).toBeCloseTo(90.3) expect(ctm.f).toBeCloseTo(27.07) - - done() + called = true }) - setTimeout(function(){ - - var ctm = rect.ctm(); - expect(ctm.a).toBeLessThan(1) - expect(ctm.b).toBeGreaterThan(0) - expect(ctm.c).toBeLessThan(0) - expect(ctm.d).toBeGreaterThan(0) - expect(ctm.e).toBeGreaterThan(0) - expect(ctm.f).toBeGreaterThan(0) - }, 250) - + jasmine.clock().tick(250) + fx.step() + ctm = rect.ctm() + expect(ctm.a).toBeLessThan(1) + expect(ctm.b).toBeGreaterThan(0) + expect(ctm.c).toBeLessThan(0) + expect(ctm.d).toBeGreaterThan(0) + expect(ctm.e).toBeGreaterThan(0) + expect(ctm.f).toBeGreaterThan(0) + + jasmine.clock().tick(250) + fx.step() + expect(called).toBe(true) }) }) @@ -25,7 +25,9 @@ SVG.Situation = SVG.invent({ this.finish = this.start + this.duration this.ease = o.ease - this.loop = false + // 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 = { @@ -71,6 +73,9 @@ SVG.FX = SVG.invent({ 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 } @@ -127,14 +132,14 @@ SVG.FX = SVG.invent({ return this._target } - // returns the position at a given time - , timeToPos: function(timestamp){ + // 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 positon - , posToTime: function(pos){ - return this.situation.duration/this._speed * pos + this.situation.start + // returns the timestamp from a given absolute positon + , absPosToTime: function(absPos){ + return this.situation.duration/this._speed * absPos + this.situation.start } // starts the animationloop @@ -152,7 +157,7 @@ SVG.FX = SVG.invent({ , start: function(){ // dont start if already started if(!this.active && this.situation){ - this.situation.start = +new Date + this.situation.delay + this.situation.start = +new Date + this.situation.delay/this._speed this.situation.finish = this.situation.start + this.situation.duration/this._speed this.initAnimations() @@ -192,7 +197,7 @@ SVG.FX = SVG.invent({ var fn = function(){ if(this.situation instanceof SVG.Situation) - this.initAnimations().at(0) + this.initAnimations().atStart() else if(this.situation instanceof SVG.Delay) this.dequeue() else @@ -283,15 +288,7 @@ SVG.FX = SVG.invent({ this.active = false if(jumpToEnd && this.situation){ - - this.situation.loop = false - - if(this.situation.loops % 2 == 0 && this.situation.reversing){ - this.situation.reversed = true - } - - this.at(1) - + this.atEnd() } this.stopAnimFrame() @@ -308,7 +305,7 @@ SVG.FX = SVG.invent({ var temp = this.situation this.stop() this.situation = temp - this.at(0) + this.atStart() } return this } @@ -325,13 +322,40 @@ SVG.FX = SVG.invent({ 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 + return this.at(this.situation.loop+1, true) + } else 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 - , at: function(pos){ + // if isAbsPos is true, pos is treated as an absolute position + , at: function(pos, isAbsPos){ var durDivSpd = this.situation.duration/this._speed - this.pos = pos - this.situation.start = +new Date - pos * durDivSpd + 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) } @@ -345,7 +369,8 @@ SVG.FX = SVG.invent({ if (speed) { this._speed = speed - return this.at(this.situation.reversed ? 1-this.pos : this.pos) + // 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 } @@ -353,8 +378,9 @@ SVG.FX = SVG.invent({ , loop: function(times, reverse) { var c = this.last() - // store current loop and total loops - c.loop = c.loops = times || true + // store total loops + c.loops = (times != null) ? times : true + c.loop = 0 if(reverse) c.reversing = true return this @@ -372,7 +398,8 @@ SVG.FX = SVG.invent({ , play: function(){ if(!this.paused) return this this.paused = false - return this.at(this.pos) + // We use an absolute position here so that the delay before the animation can be paused + return this.at(this.absPos, true) } /** @@ -477,22 +504,45 @@ SVG.FX = SVG.invent({ */ , step: function(ignoreTime){ - // convert current time to position - if(!ignoreTime) this.pos = this.timeToPos(+new Date) - - if(this.pos >= 1 && (this.situation.loop === true || (typeof this.situation.loop == 'number' && --this.situation.loop))){ + // 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){ - this.situation.reversed = !this.situation.reversed + 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) } - return this.at(this.pos-1) + + } 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 - // correct position - if(this.pos > 1)this.pos = 1 - if(this.pos < 0)this.pos = 0 // apply easing var eased = this.situation.ease(this.pos) |