diff options
author | wout <wout@impinc.co.uk> | 2013-06-23 14:59:46 +0100 |
---|---|---|
committer | wout <wout@impinc.co.uk> | 2013-06-23 14:59:46 +0100 |
commit | a72b8a7afb609b9a76c494d9123d78e5c40962bf (patch) | |
tree | fdaacf9d56a3cc9e935ab1a5dcb4ad0458f929e4 | |
parent | 5e52bd4f9f309b20bc848d5d45e5e620b17c1ad7 (diff) | |
download | svg.js-a72b8a7afb609b9a76c494d9123d78e5c40962bf.tar.gz svg.js-a72b8a7afb609b9a76c494d9123d78e5c40962bf.zip |
Added SVG.Number, reworked gradient system
-rw-r--r-- | README.md | 34 | ||||
-rw-r--r-- | Rakefile | 4 | ||||
-rw-r--r-- | dist/svg.js | 203 | ||||
-rw-r--r-- | dist/svg.min.js | 2 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | spec/index.html | 1 | ||||
-rw-r--r-- | spec/spec/ellipse.js | 4 | ||||
-rw-r--r-- | spec/spec/gradient.js | 68 | ||||
-rw-r--r-- | spec/spec/number.js | 177 | ||||
-rw-r--r-- | src/default.js | 34 | ||||
-rw-r--r-- | src/element.js | 14 | ||||
-rw-r--r-- | src/ellipse.js | 10 | ||||
-rw-r--r-- | src/fx.js | 28 | ||||
-rw-r--r-- | src/gradient.js | 35 | ||||
-rw-r--r-- | src/number.js | 75 | ||||
-rw-r--r-- | src/regex.js | 5 |
16 files changed, 558 insertions, 138 deletions
@@ -771,7 +771,7 @@ If you want the masked object to be rendered at 100% you need to set the fill co ```javascript var gradient = draw.gradient('linear', function(stop) { stop.at({ offset: 0, color: '#000' }) - stop.at({ offset: 100, color: '#fff' }) + stop.at({ offset: 1, color: '#fff' }) }) var ellipse = draw.ellipse(80, 40).move(10, 10).fill({ color: gradient }) @@ -881,14 +881,14 @@ There are linear and radial gradients. The linear gradient can be created like t ```javascript var gradient = draw.gradient('linear', function(stop) { stop.at({ offset: 0, color: '#333', opacity: 1 }) - stop.at({ offset: 100, color: '#fff', opacity: 1 }) + stop.at({ offset: 1, color: '#fff', opacity: 1 }) }) ``` -The `offset` and `color` parameters are required for stops, `opacity` is optional. Offset is an integer expressed in percentage. To define the direction you can set from `x`, `y` and to `x`, `y`: +The `offset` and `color` parameters are required for stops, `opacity` is optional. Offset is float between 0 and 1, or a percentage value (e.g. `33%`). To define the direction you can set from `x`, `y` and to `x`, `y`: ```javascript -gradient.from(0, 0).to(0, 100) +gradient.from(0, 0).to(0, 1) ``` The from and to values are also expressed in percent. @@ -903,18 +903,18 @@ Radial gradients have a `radius()` method to define the outermost radius to wher ```javascript var gradient = draw.gradient('radial', function(stop) { stop.at({ offset: 0, color: '#333', opacity: 1 }) - stop.at({ offset: 100, color: '#fff', opacity: 1 }) + stop.at({ offset: 1, color: '#fff', opacity: 1 }) }) -gradient.from(50, 50).to(50, 50).radius(50) +gradient.from(0.5, 0.5).to(0.5, 0.5).radius(0.5) ``` A gradient can also be updated afterwards: ```javascript gradient.update(function(stop) { - stop.at({ offset: 10, color: '#333', opacity: 0.2 }) - stop.at({ offset: 90, color: '#f03', opacity: 1 }) + stop.at({ offset: 0.1, color: '#333', opacity: 0.2 }) + stop.at({ offset: 0.9, color: '#f03', opacity: 1 }) }) ``` @@ -925,11 +925,23 @@ var s1, s2, s3 draw.gradient('radial', function(stop) { s1 = stop.at({ offset: 0, color: '#000', opacity: 1 }) - s2 = stop.at({ offset: 50, color: '#f03', opacity: 1 }) - s3 = stop.at({ offset: 100, color: '#066', opacity: 1 }) + s2 = stop.at({ offset: 0.5, color: '#f03', opacity: 1 }) + s3 = stop.at({ offset: 1, color: '#066', opacity: 1 }) }) -s1.update({ offset: 10, color: '#0f0', opacity: 1 }) +s1.update({ offset: 0.1, color: '#0f0', opacity: 1 }) +``` + +The `get()` method makes it even easier to get a stop from an existing gradient: + +```javascript +var gradient = draw.gradient('radial', function(stop) { + stop.at({ offset: 0, color: '#000', opacity: 1 }) // -> first + stop.at({ offset: 0.5, color: '#f03', opacity: 1 }) // -> second + stop.at({ offset: 1, color: '#066', opacity: 1 }) // -> third +}) + +var s1 = gradient.get(0) // -> returns "first" stop ``` [W3Schools](http://www.w3schools.com/svg/svg_grad_linear.asp) has a great example page on how @@ -1,7 +1,7 @@ -SVGJS_VERSION = '0.19' +SVGJS_VERSION = '0.20' # all available modules in the correct loading order -MODULES = %w[ svg regex default color viewbox bbox rbox element container fx event group arrange defs mask clip pattern gradient doc shape rect ellipse line poly path plotable image text nested sugar ] +MODULES = %w[ svg regex default color number viewbox bbox rbox element container fx event group arrange defs mask clip pattern gradient doc shape rect ellipse line poly path plotable image text nested sugar ] # how many bytes in a "kilobyte" KILO = 1024 diff --git a/dist/svg.js b/dist/svg.js index cac039e..a046985 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -1,4 +1,4 @@ -/* svg.js v0.19 - svg regex default color viewbox bbox rbox element container fx event group arrange defs mask clip pattern gradient doc shape rect ellipse line poly path plotable image text nested sugar - svgjs.com/license */ +/* svg.js v0.20 - svg regex default color number viewbox bbox rbox element container fx event group arrange defs mask clip pattern gradient doc shape rect ellipse line poly path plotable image text nested sugar - svgjs.com/license */ ;(function() { this.SVG = function(element) { @@ -79,7 +79,7 @@ /* parse rgb value */ , rgb: /rgb\((\d+),(\d+),(\d+)\)/ - + /* test hex value */ , isHex: /^#[a-f0-9]{3,6}$/i @@ -97,6 +97,9 @@ /* test for numeric string */ , isNumber: /^-?[\d\.]+$/ + + /* test for percent value */ + , isPercent: /^-?[\d\.]+%$/ } @@ -110,23 +113,25 @@ 'fill-opacity': 1 , 'stroke-opacity': 1 , 'stroke-width': 0 - , fill: '#000' - , stroke: '#000' - , opacity: 1 + , fill: '#000' + , stroke: '#000' + , opacity: 1 /* position */ - , x: 0 - , y: 0 - , cx: 0 - , cy: 0 - /* size */ - , width: 0 - , height: 0 - /* radius */ - , r: 0 - , rx: 0 - , ry: 0 - /* gradient */ - , offset: 0 + , x: 0 + , y: 0 + , cx: 0 + , cy: 0 + /* size */ + , width: 0 + , height: 0 + /* radius */ + , r: 0 + , rx: 0 + , ry: 0 + /* gradient */ + , offset: 0 + , 'stop-opacity': 1 + , 'stop-color': '#000' } // Default transformation values @@ -246,6 +251,81 @@ return color && typeof color.r == 'number' } + SVG.Number = function(value) { + + /* initialize defaults */ + this.value = 0 + this.unit = '' + + /* parse value */ + switch(typeof value) { + case 'number': + this.value = value + break + case 'string': + var match = value.match(SVG.regex.unit) + + /* make valu numeric */ + this.value = parseFloat(match[1]) + + /* normalize percent value */ + if (match[2] == '%') + this.value /= 100 + + /* store unit */ + this.unit = match[2] + + break + default: + if (value instanceof SVG.Number) { + this.value = value.value + this.unit = value.unit + } + break + } + } + + SVG.extend(SVG.Number, { + // Stringalize + toString: function() { + return (this.unit == '%' ? ~~(this.value * 100) : this.value) + this.unit + } + , // Convert to primitive + valueOf: function() { + return this.value + } + // Convert to different unit + , to: function(unit) { + if (typeof unit === 'string') + this.unit = unit + + return this + } + // Add number + , plus: function(number) { + this.value = this + new SVG.Number(number) + + return this + } + // Subtract number + , minus: function(number) { + return this.plus(-new SVG.Number(number)) + } + // Multiply number + , times: function(number) { + this.value = this * new SVG.Number(number) + + return this + } + // Divide number + , divide: function(number) { + this.value = this / new SVG.Number(number) + + return this + } + + }) + SVG.ViewBox = function(element) { var x, y, width, height , box = element.bbox() @@ -428,12 +508,18 @@ SVG.extend(SVG.Element, { // Move over x-axis x: function(x) { - if (x) x /= this.trans.scaleX + if (x) { + x = new SVG.Number(x) + x.value /= this.trans.scaleX + } return this.attr('x', x) } // Move over y-axis , y: function(y) { - if (y) y /= this.trans.scaleY + if (y) { + y = new SVG.Number(y) + y.value /= this.trans.scaleY + } return this.attr('y', y) } // Move by center over x-axis @@ -455,8 +541,8 @@ // Set element size to given width and height , size: function(width, height) { return this.attr({ - width: width - , height: height + width: new SVG.Number(width) + , height: new SVG.Number(height) }) } // Clone element @@ -1162,6 +1248,16 @@ return this } + // Add animateable gradient update + , update: function(o) { + if (this.target instanceof SVG.Stop) { + if (o.opacity != null) this.attr('stop-opacity', o.opacity) + if (o.color != null) this.attr('stop-color', o.color) + if (o.offset != null) this.attr('offset', new SVG.Number(o.offset)) + } + + return this + } // Add callback for each keyframe , during: function(during) { this._during = during @@ -1203,7 +1299,10 @@ /* unit recalculation */ SVG.regex.unit.test(o.to) ? - this._unit(o, pos) : + new SVG.Number(o.to) + .minus(new SVG.Number(o.from)) + .times(pos) + .plus(new SVG.Number(o.from)) : /* color recalculation */ o.to && (o.to.r || SVG.Color.test(o.to)) ? @@ -1212,19 +1311,6 @@ /* for all other values wait until pos has reached 1 to return the final value */ pos < 1 ? o.from : o.to } - // Private: tween unit - , _unit: function(o, pos) { - var match, from - - /* convert FROM unit */ - match = SVG.regex.unit.exec(o.from.toString()) - from = parseFloat(match ? match[1] : 0) - - /* convert TO unit */ - match = SVG.regex.unit.exec(o.to) - - return (from + (parseFloat(match[1]) - from) * pos) + match[2] - } // Private: tween color , _color: function(o, pos) { var from, to @@ -1532,19 +1618,19 @@ // From position from: function(x, y) { return this.type == 'radial' ? - this.attr({ fx: x + '%', fy: y + '%' }) : - this.attr({ x1: x + '%', y1: y + '%' }) + this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) }) : + this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) }) } // To position , to: function(x, y) { return this.type == 'radial' ? - this.attr({ cx: x + '%', cy: y + '%' }) : - this.attr({ x2: x + '%', y2: y + '%' }) + this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) }) : + this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) }) } // Radius for radial gradient - , radius: function(radius) { + , radius: function(r) { return this.type == 'radial' ? - this.attr({ r: radius + '%' }) : + this.attr({ r: new SVG.Number(r) }) : this } // Add a color stop @@ -1554,8 +1640,7 @@ // Update gradient , update: function(block) { /* remove all stops */ - while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild) + this.clear() /* invoke passed block */ block(this) @@ -1566,6 +1651,10 @@ , fill: function() { return 'url(#' + this.attr('id') + ')' } + // Get a stop at the given index + , get: function(i) { + return this.children()[i] + } }) @@ -1601,22 +1690,18 @@ } // Inherit from SVG.Element - SVG.Stop.prototype = new SVG.Element() + SVG.Stop.prototype = new SVG.Element // SVG.extend(SVG.Stop, { // add color stops update: function(o) { - var index - , attr = ['opacity', 'color'] - - /* build style attribute */ - for (index = attr.length - 1; index >= 0; index--) - if (o[attr[index]] != null) - this.style('stop-' + attr[index], o[attr[index]]) - /* set attributes */ - return this.attr('offset', (o.offset != null ? o.offset : this.attr('offset')) + '%') + if (o.opacity != null) this.attr('stop-opacity', o.opacity) + if (o.color != null) this.attr('stop-color', o.color) + if (o.offset != null) this.attr('offset', new SVG.Number(o.offset)) + + return this } }) @@ -1753,17 +1838,17 @@ } // Move by center over x-axis , cx: function(x) { - return x == null ? this.attr('cx') : this.attr('cx', x / this.trans.scaleX) + return x == null ? this.attr('cx') : this.attr('cx', new SVG.Number(x).divide(this.trans.scaleX)) } // Move by center over y-axis , cy: function(y) { - return y == null ? this.attr('cy') : this.attr('cy', y / this.trans.scaleY) + return y == null ? this.attr('cy') : this.attr('cy', new SVG.Number(y).divide(this.trans.scaleY)) } // Custom size function , size: function(width, height) { return this.attr({ - rx: width / 2, - ry: height / 2 + rx: new SVG.Number(width).divide(2) + , ry: new SVG.Number(height).divide(2) }) } @@ -1777,7 +1862,7 @@ } // Create an ellipse , ellipse: function(width, height) { - return this.put(new SVG.Ellipse().size(width, height).move(0, 0)) + return this.put(new SVG.Ellipse).size(width, height).move(0, 0) } }) diff --git a/dist/svg.min.js b/dist/svg.min.js index d4ad94a..f41495b 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1 +1 @@ -(function(){if(this.SVG=function(t){return SVG.supported?new SVG.Doc(t):void 0},this.svg=function(t){return console.warn("WARNING: svg() is deprecated, please use SVG() instead."),SVG(t)},SVG.ns="http://www.w3.org/2000/svg",SVG.xlink="http://www.w3.org/1999/xlink",SVG.did=1e3,SVG.eid=function(t){return"Svgjs"+t.charAt(0).toUpperCase()+t.slice(1)+SVG.did++},SVG.create=function(t){var e=document.createElementNS(this.ns,t);return e.setAttribute("id",this.eid(t)),e},SVG.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]},SVG.get=function(t){var e=document.getElementById(t);return e?e.instance:void 0},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}(),!SVG.supported)return!1;SVG.regex={test:function(t,e){return this[e].test(t)},unit:/^([\d\.]+)([a-z%]{0,2})$/,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isStyle:/^font|text|leading|cursor/,isBlank:/^(\s+)?$/,isNumber:/^-?[\d\.]+$/},SVG.defaults={matrix:"1,0,0,1,0,0",attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,fill:"#000",stroke:"#000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0},trans:function(){return{x:0,y:0,scaleX:1,scaleY:1,rotation:0,skewX:0,skewY:0,matrix:this.matrix,a:1,b:0,c:0,d:1,e:0,f:0}}},SVG.Color=function(t){var e;this.r=0,this.g=0,this.b=0,"string"==typeof t?SVG.regex.isRgb.test(t)?(e=SVG.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):SVG.regex.isHex.test(t)&&(e=SVG.regex.hex.exec(this._fullHex(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)},SVG.extend(SVG.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+this._compToHex(this.r)+this._compToHex(this.g)+this._compToHex(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return.3*(this.r/255)+.59*(this.g/255)+.11*(this.b/255)},_fullHex:function(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},_compToHex:function(t){var e=t.toString(16);return 1==e.length?"0"+e:e}}),SVG.Color.test=function(t){return t+="",SVG.regex.isHex.test(t)||SVG.regex.isRgb.test(t)},SVG.Color.isRgb=function(t){return t&&"number"==typeof t.r},SVG.ViewBox=function(t){var e,i,n,s,r=t.bbox(),o=(t.attr("viewBox")||"").match(/-?[\d\.]+/g);this.x=r.x,this.y=r.y,this.width=t.node.offsetWidth||t.attr("width"),this.height=t.node.offsetHeight||t.attr("height"),o&&(e=parseFloat(o[0]),i=parseFloat(o[1]),n=parseFloat(o[2]),s=parseFloat(o[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),this.zoom=this.zoom||1},SVG.extend(SVG.ViewBox,{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height}}),SVG.BBox=function(t){var e;if(this.x=0,this.y=0,this.width=0,this.height=0,t){try{e=t.node.getBBox()}catch(i){e={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=e.x+t.trans.x,this.y=e.y+t.trans.y,this.width=e.width*t.trans.scaleX,this.height=e.height*t.trans.scaleY}this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.extend(SVG.BBox,{merge:function(t){var e=new SVG.BBox;return e.x=Math.min(this.x,t.x),e.y=Math.min(this.y,t.y),e.width=Math.max(this.x+this.width,t.x+t.width)-e.x,e.height=Math.max(this.y+this.height,t.y+t.height)-e.y,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2,e}}),SVG.RBox=function(t){var e,i,n={};if(this.x=0,this.y=0,this.width=0,this.height=0,t){for(e=t.doc().parent,i=t.doc().viewbox().zoom,n=t.node.getBoundingClientRect(),this.x=n.left,this.y=n.top,this.x-=e.offsetLeft,this.y-=e.offsetTop;e=e.offsetParent;)this.x-=e.offsetLeft,this.y-=e.offsetTop;for(e=t;e=e.parent;)"svg"==e.type&&e.viewbox&&(i*=e.viewbox().zoom,this.x-=e.x()||0,this.y-=e.y()||0)}this.x/=i,this.y/=i,this.width=n.width/=i,this.height=n.height/=i,this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.Element=function(t){this._stroke=SVG.defaults.attrs.stroke,this.styles={},this.trans=SVG.defaults.trans(),(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},SVG.extend(SVG.Element,{x:function(t){return t&&(t/=this.trans.scaleX),this.attr("x",t)},y:function(t){return t&&(t/=this.trans.scaleY),this.attr("y",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)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){return this.attr({width:t,height:e})},clone:function(){var t,e,i=this.type;return t="rect"==i||"ellipse"==i?this.parent[i](0,0):"line"==i?this.parent[i](0,0,0,0):"image"==i?this.parent[i](this.src):"text"==i?this.parent[i](this.content):"path"==i?this.parent[i](this.attr("d")):"polyline"==i||"polygon"==i?this.parent[i](this.attr("points")):"g"==i?this.parent.group():this.parent[i](),e=this.attr(),delete e.id,t.attr(e),t.trans=this.trans,t.transform({})},remove:function(){return this.parent&&this.parent.removeElement(this),this},doc:function(t){return this._parent(t||SVG.Doc)},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]=SVG.regex.test(e[i].nodeValue,"isNumber")?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 this._isStyle(t)?"text"==t?this.content:"leading"==t&&this.leading?this.leading():this.style(t):(e=this.node.getAttribute(t),null==e?SVG.defaults.attrs[t]:SVG.regex.test(e,"isNumber")?parseFloat(e):e);if("style"==t)return this.style(e);if("function"==typeof e.fill&&(e=e.fill()),"x"==t&&Array.isArray(this.lines))for(i=this.lines.length-1;i>=0;i--)this.lines[i].attr(t,e);"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),(SVG.Color.test(e)||SVG.Color.isRgb(e))&&(e=new SVG.Color(e).toHex()),null!=i?this.node.setAttributeNS(i,t,e):this.node.setAttribute(t,e),this._isStyle(t)&&("text"==t?this.text(e):"leading"==t&&this.leading?this.leading(e):this.style(t,e),this.rebuild&&this.rebuild(t,e))}return this},transform:function(t,e){if(0==arguments.length)return this.trans;if("string"==typeof t){if(2>arguments.length)return this.trans[t];var i={};return i[t]=e,this.transform(i)}var i=[];t=this._parseMatrix(t);for(e in t)null!=t[e]&&(this.trans[e]=t[e]);return this.trans.matrix=this.trans.a+","+this.trans.b+","+this.trans.c+","+this.trans.d+","+this.trans.e+","+this.trans.f,t=this.trans,t.matrix!=SVG.defaults.matrix&&i.push("matrix("+t.matrix+")"),0!=t.rotation&&i.push("rotate("+t.rotation+","+(t.cx||this.bbox().cx)+","+(t.cy||this.bbox().cy)+")"),(1!=t.scaleX||1!=t.scaleY)&&i.push("scale("+t.scaleX+","+t.scaleY+")"),0!=t.skewX&&i.push("skewX("+t.skewX+")"),0!=t.skewY&&i.push("skewY("+t.skewY+")"),(0!=t.x||0!=t.y)&&i.push("translate("+t.x/t.scaleX+","+t.y/t.scaleY+")"),this._offset&&i.push("translate("+-this._offset.x+","+-this._offset.y+")"),0==i.length?this.node.removeAttribute("transform"):this.node.setAttribute("transform",i.join(" ")),this},style:function(t,e){if(0==arguments.length)return this.attr("style")||"";if(2>arguments.length)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!SVG.regex.isCss.test(t))return this.styles[t];t=t.split(";");for(var i=0;t.length>i;i++)e=t[i].split(":"),2==e.length&&this.style(e[0].replace(/\s+/g,""),e[1].replace(/^\s+/,"").replace(/\s+$/,""))}else null===e||SVG.regex.test(e,"isBlank")?delete this.styles[t]:this.styles[t]=e;t="";for(e in this.styles)t+=e+":"+this.styles[e]+";";return""==t?this.node.removeAttribute("style"):this.node.setAttribute("style",t),this},data:function(t,e,i){if(2>arguments.length)try{return JSON.parse(this.attr("data-"+t))}catch(n){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},bbox:function(){return new SVG.BBox(this)},rbox:function(){return new SVG.RBox(this)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&i.x+i.width>t&&i.y+i.height>e},show:function(){return this.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},_parent:function(t){for(var e=this;null!=e&&!(e instanceof t);)e=e.parent;return e},_isStyle:function(t){return"string"==typeof t?SVG.regex.test(t,"isStyle"):!1},_parseMatrix:function(t){if(t.matrix){var e=t.matrix.replace(/\s/g,"").split(",");6==e.length&&(t.a=parseFloat(e[0]),t.b=parseFloat(e[1]),t.c=parseFloat(e[2]),t.d=parseFloat(e[3]),t.e=parseFloat(e[4]),t.f=parseFloat(e[5]))}return t}}),SVG.Container=function(t){this.constructor.call(this,t)},SVG.Container.prototype=new SVG.Element,SVG.extend(SVG.Container,{children:function(){return this._children||(this._children=[])},add:function(t,e){if(!this.has(t)){if(e=null==e?this.children().length:e,t.parent){var i=t.parent.children().indexOf(t);t.parent.children().splice(i,1)}this.children().splice(e,0,t),this.node.insertBefore(t.node,this.node.childNodes[e]||null),t.parent=this}return this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.children().indexOf(t)>=0},each:function(t,e){var i,n,s=this.children();for(i=0,n=s.length;n>i;i++)s[i]instanceof SVG.Shape&&t.apply(s[i],[i,s]),e&&s[i]instanceof SVG.Container&&s[i].each(t,e);return this},removeElement:function(t){var e=this.children().indexOf(t);return this.children().splice(e,1),this.node.removeChild(t.node),t.parent=null,this},defs:function(){return this._defs||(this._defs=this.put(new SVG.Defs,0))},level:function(){return this.removeElement(this.defs()).put(this.defs(),0)},first:function(){return this.children()[0]instanceof SVG.Defs?this.children()[1]:this.children()[0]},last:function(){return this.children()[this.children().length-1]},viewbox:function(t){return 0==arguments.length?new SVG.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t.join(" ")))},clear:function(){for(var t=this.children().length-1;t>=0;t--)this.removeElement(this.children()[t]);return this._defs&&(this._defs.remove(),delete this._defs),this}}),SVG.FX=function(t){this.target=t},SVG.extend(SVG.FX,{animate:function(t,e,i){var n,s,r,o,h=this.target,a=this;return"object"==typeof t&&(i=t.delay,e=t.ease,t=t.duration),t=null==t?1e3:t,e=e||"<>",a.to=function(t){var i;if(t=0>t?0:t>1?1:t,null==n){n=[];for(o in a.attrs)n.push(o)}if(null==s){s=[];for(o in a.trans)s.push(o)}if(null==r){r=[];for(o in a.styles)r.push(o)}for(t="<>"==e?-Math.cos(t*Math.PI)/2+.5:">"==e?Math.sin(t*Math.PI/2):"<"==e?-Math.cos(t*Math.PI/2)+1:"-"==e?t:"function"==typeof e?e(t):t,a._x?h.x(a._at(a._x,t)):a._cx&&h.cx(a._at(a._cx,t)),a._y?h.y(a._at(a._y,t)):a._cy&&h.cy(a._at(a._cy,t)),a._size&&h.size(a._at(a._size.width,t),a._at(a._size.height,t)),a._viewbox&&h.viewbox(a._at(a._viewbox.x,t),a._at(a._viewbox.y,t),a._at(a._viewbox.width,t),a._at(a._viewbox.height,t)),i=n.length-1;i>=0;i--)h.attr(n[i],a._at(a.attrs[n[i]],t));for(i=s.length-1;i>=0;i--)h.transform(s[i],a._at(a.trans[s[i]],t));for(i=r.length-1;i>=0;i--)h.style(r[i],a._at(a.styles[r[i]],t));a._during&&a._during.call(h,t,function(e,i){return a._at({from:e,to:i},t)})},"number"==typeof t&&(this.timeout=setTimeout(function(){var e=1e3/60,i=(new Date).getTime(),n=i+t;a.interval=setInterval(function(){var e=(new Date).getTime(),s=e>n?1:(e-i)/t;a.to(s),e>n&&(clearInterval(a.interval),a._after?a._after.apply(h,[a]):a.stop())},t>e?e:t)},i||0)),this},bbox:function(){return this.target.bbox()},attr:function(t,e){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.attrs[t]={from:this.target.attr(t),to:e};return this},transform:function(t,e){if(1==arguments.length){t=this.target._parseMatrix(t),delete t.matrix;for(e in t)this.trans[e]={from:this.target.trans[e],to:t[e]}}else{var i={};i[t]=e,this.transform(i)}return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.styles[t]={from:this.target.style(t),to:e};return this},x:function(t){return this._x={from:this.target.x(),to:t},this},y:function(t){return this._y={from:this.target.y(),to:t},this},cx:function(t){return this._cx={from:this.target.cx(),to:t},this},cy:function(t){return this._cy={from:this.target.cy(),to:t},this},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 SVG.Text)this.attr("font-size",t);else{var i=this.target.bbox();this._size={width:{from:i.width,to:t},height:{from:i.height,to:e}}}return this},viewbox:function(t,e,i,n){if(this.target instanceof SVG.Container){var s=this.target.viewbox();this._viewbox={x:{from:s.x,to:t},y:{from:s.y,to:e},width:{from:s.width,to:i},height:{from:s.height,to:n}}}return this},during:function(t){return this._during=t,this},after:function(t){return this._after=t,this},stop:function(){return clearTimeout(this.timeout),clearInterval(this.interval),this.attrs={},this.trans={},this.styles={},delete this._x,delete this._y,delete this._cx,delete this._cy,delete this._size,delete this._after,delete this._during,delete this._viewbox,this},_at:function(t,e){return"number"==typeof t.from?t.from+(t.to-t.from)*e:SVG.regex.unit.test(t.to)?this._unit(t,e):t.to&&(t.to.r||SVG.Color.test(t.to))?this._color(t,e):1>e?t.from:t.to},_unit:function(t,e){var i,n;return i=SVG.regex.unit.exec(t.from.toString()),n=parseFloat(i?i[1]:0),i=SVG.regex.unit.exec(t.to),n+(parseFloat(i[1])-n)*e+i[2]},_color:function(t,e){var i,n;return e=0>e?0:e>1?1:e,i=new SVG.Color(t.from),n=new SVG.Color(t.to),new SVG.Color({r:~~(i.r+(n.r-i.r)*e),g:~~(i.g+(n.g-i.g)*e),b:~~(i.b+(n.b-i.b)*e)}).toHex()}}),SVG.extend(SVG.Element,{animate:function(t,e,i){return(this.fx||(this.fx=new SVG.FX(this))).stop().animate(t,e,i)},stop:function(){return this.fx&&this.fx.stop(),this}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchend","touchmove","touchcancel"].forEach(function(t){SVG.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),SVG.on=function(t,e,i){t.addEventListener?t.addEventListener(e,i,!1):t.attachEvent("on"+e,i)},SVG.off=function(t,e,i){t.removeEventListener?t.removeEventListener(e,i,!1):t.detachEvent("on"+e,i)},SVG.extend(SVG.Element,{on:function(t,e){return SVG.on(this.node,t,e),this},off:function(t,e){return SVG.off(this.node,t,e),this}}),SVG.G=function(){this.constructor.call(this,SVG.create("g"))},SVG.G.prototype=new SVG.Container,SVG.extend(SVG.G,{x:function(t){return null==t?this.trans.x:this.transform("x",t)},y:function(t){return null==t?this.trans.y:this.transform("y",t)},defs:function(){return this.doc().defs()}}),SVG.extend(SVG.Container,{group:function(){return this.put(new SVG.G)}}),SVG.extend(SVG.Element,{siblings:function(){return this.parent.children()},position:function(){return this.siblings().indexOf(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){return this.parent.removeElement(this).put(this,this.position()+1)},backward:function(){this.parent.level();var t=this.position();return t>1&&this.parent.removeElement(this).add(this,t-1),this},front:function(){return this.parent.removeElement(this).put(this)},back:function(){return this.parent.level(),this.position()>1&&this.parent.removeElement(this).add(this,0),this}}),SVG.Defs=function(){this.constructor.call(this,SVG.create("defs"))},SVG.Defs.prototype=new SVG.Container,SVG.Mask=function(){this.constructor.call(this,SVG.create("mask"))},SVG.Mask.prototype=new SVG.Container,SVG.extend(SVG.Element,{maskWith:function(t){return this.mask=t instanceof SVG.Mask?t:this.parent.mask().add(t),this.attr("mask","url(#"+this.mask.attr("id")+")")}}),SVG.extend(SVG.Container,{mask:function(){return this.defs().put(new SVG.Mask)}}),SVG.Clip=function(){this.constructor.call(this,SVG.create("clipPath"))},SVG.Clip.prototype=new SVG.Container,SVG.extend(SVG.Element,{clipWith:function(t){return this.clip=t instanceof SVG.Clip?t:this.parent.clip().add(t),this.attr("clip-path","url(#"+this.clip.attr("id")+")")}}),SVG.extend(SVG.Container,{clip:function(){return this.defs().put(new SVG.Clip)}}),SVG.Pattern=function(){this.constructor.call(this,SVG.create("pattern"))},SVG.Pattern.prototype=new SVG.Container,SVG.extend(SVG.Pattern,{fill:function(){return"url(#"+this.attr("id")+")"}}),SVG.extend(SVG.Defs,{pattern:function(t,e,i){var n=this.put(new SVG.Pattern);return i(n),n.attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),SVG.extend(SVG.Container,{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}),SVG.Gradient=function(t){this.constructor.call(this,SVG.create(t+"Gradient")),this.type=t},SVG.Gradient.prototype=new SVG.Container,SVG.extend(SVG.Gradient,{from:function(t,e){return"radial"==this.type?this.attr({fx:t+"%",fy:e+"%"}):this.attr({x1:t+"%",y1:e+"%"})},to:function(t,e){return"radial"==this.type?this.attr({cx:t+"%",cy:e+"%"}):this.attr({x2:t+"%",y2:e+"%"})},radius:function(t){return"radial"==this.type?this.attr({r:t+"%"}):this},at:function(t){return this.put(new SVG.Stop(t))},update:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return t(this),this},fill:function(){return"url(#"+this.attr("id")+")"}}),SVG.extend(SVG.Defs,{gradient:function(t,e){var i=this.put(new SVG.Gradient(t));return e(i),i}}),SVG.extend(SVG.Container,{gradient:function(t,e){return this.defs().gradient(t,e)}}),SVG.Stop=function(t){this.constructor.call(this,SVG.create("stop")),this.update(t)},SVG.Stop.prototype=new SVG.Element,SVG.extend(SVG.Stop,{update:function(t){var e,i=["opacity","color"];for(e=i.length-1;e>=0;e--)null!=t[i[e]]&&this.style("stop-"+i[e],t[i[e]]);return this.attr("offset",(null!=t.offset?t.offset:this.attr("offset"))+"%")}}),SVG.Doc=function(t){this.parent="string"==typeof t?document.getElementById(t):t,this.constructor.call(this,"svg"==this.parent.nodeName?this.parent:SVG.create("svg")),this.attr({xmlns:SVG.ns,version:"1.1",width:"100%",height:"100%"}).attr("xlink",SVG.xlink,SVG.ns).defs(),"svg"!=this.parent.nodeName&&this.stage()},SVG.Doc.prototype=new SVG.Container,SVG.extend(SVG.Doc,{stage:function(){var t,e=this,i=document.createElement("div");return i.style.cssText="position:relative;height:100%;",e.parent.appendChild(i),i.appendChild(e.node),t=function(){"complete"===document.readyState?(e.style("position:absolute;"),setTimeout(function(){e.style("position:relative;"),e.parent.removeChild(e.node.parentNode),e.node.parentNode.removeChild(e.node),e.parent.appendChild(e.node),e.fixSubPixelOffset(),SVG.on(window,"resize",function(){e.fixSubPixelOffset()})},5)):setTimeout(t,10)},t(),this},fixSubPixelOffset:function(){var t=this.node.getScreenCTM();this.style("left",-t.e%1+"px").style("top",-t.f%1+"px")}}),SVG.Shape=function(t){this.constructor.call(this,t)},SVG.Shape.prototype=new SVG.Element,SVG.Rect=function(){this.constructor.call(this,SVG.create("rect"))},SVG.Rect.prototype=new SVG.Shape,SVG.extend(SVG.Container,{rect:function(t,e){return this.put((new SVG.Rect).size(t,e))}}),SVG.Ellipse=function(){this.constructor.call(this,SVG.create("ellipse"))},SVG.Ellipse.prototype=new SVG.Shape,SVG.extend(SVG.Ellipse,{x:function(t){return null==t?this.cx()-this.attr("rx"):this.cx(t+this.attr("rx"))},y:function(t){return null==t?this.cy()-this.attr("ry"):this.cy(t+this.attr("ry"))},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t/this.trans.scaleX)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t/this.trans.scaleY)},size:function(t,e){return this.attr({rx:t/2,ry:e/2})}}),SVG.extend(SVG.Container,{circle:function(t){return this.ellipse(t,t)},ellipse:function(t,e){return this.put((new SVG.Ellipse).size(t,e).move(0,0))}}),SVG.Line=function(){this.constructor.call(this,SVG.create("line"))},SVG.Line.prototype=new SVG.Shape,SVG.extend(SVG.Line,{x:function(t){var e=this.bbox();return null==t?e.x:this.attr({x1:this.attr("x1")-e.x+t,x2:this.attr("x2")-e.x+t})},y:function(t){var e=this.bbox();return null==t?e.y:this.attr({y1:this.attr("y1")-e.y+t,y2:this.attr("y2")-e.y+t})},cx:function(t){var e=this.bbox().width/2;return null==t?this.x()+e:this.x(t-e)},cy:function(t){var e=this.bbox().height/2;return null==t?this.y()+e:this.y(t-e)},size:function(t,e){var i=this.bbox();return this.attr(this.attr("x1")<this.attr("x2")?"x2":"x1",i.x+t).attr(this.attr("y1")<this.attr("y2")?"y2":"y1",i.y+e)},plot:function(t,e,i,n){return this.attr({x1:t,y1:e,x2:i,y2:n})}}),SVG.extend(SVG.Container,{line:function(t,e,i,n){return this.put((new SVG.Line).plot(t,e,i,n))}}),SVG.Polyline=function(t){this.constructor.call(this,SVG.create("polyline")),this.unbiased=t},SVG.Polyline.prototype=new SVG.Shape,SVG.Polygon=function(t){this.constructor.call(this,SVG.create("polygon")),this.unbiased=t},SVG.Polygon.prototype=new SVG.Shape,SVG.extend(SVG.Polyline,SVG.Polygon,{_plot:function(t){if(Array.isArray(t)){var e,i,n=[];for(e=0,i=t.length;i>e;e++)n.push(t[e].join(","));t=n.length>0?n.join(" "):"0,0"}return this.attr("points",t||"0,0")}}),SVG.extend(SVG.Container,{polyline:function(t,e){return this.put(new SVG.Polyline(e)).plot(t)},polygon:function(t,e){return this.put(new SVG.Polygon(e)).plot(t)}}),SVG.Path=function(t){this.constructor.call(this,SVG.create("path")),this.unbiased=t},SVG.Path.prototype=new SVG.Shape,SVG.extend(SVG.Path,{_plot:function(t){return this.attr("d",t||"M0,0")}}),SVG.extend(SVG.Container,{path:function(t,e){return this.put(new SVG.Path(e)).plot(t)}}),SVG.extend(SVG.Polyline,SVG.Polygon,SVG.Path,{x:function(t){return null==t?this.bbox().x:this.transform("x",t)},y:function(t){return null==t?this.bbox().y:this.transform("y",t)},size:function(t,e){var i=t/this._offset.width;return this.transform({scaleX:i,scaleY:null!=e?e/this._offset.height:i})},plot:function(t){var e=this.trans.scaleX,i=this.trans.scaleY;return this._plot(t),this._offset=this.transform({scaleX:1,scaleY:1}).bbox(),this.unbiased?this._offset.x=this._offset.y=0:(this._offset.x-=this.trans.x,this._offset.y-=this.trans.y),this.transform({scaleX:e,scaleY:i})}}),SVG.Image=function(){this.constructor.call(this,SVG.create("image"))},SVG.Image.prototype=new SVG.Shape,SVG.extend(SVG.Image,{load:function(t){return t?this.attr("xlink:href",this.src=t,SVG.xlink):this}}),SVG.extend(SVG.Container,{image:function(t,e,i){return e=null!=e?e:100,this.put((new SVG.Image).load(t).size(e,null!=i?i:e))}});var t="size family weight stretch variant style".split(" ");SVG.Text=function(){this.constructor.call(this,SVG.create("text")),this.styles={"font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"},this._leading=1.2,this._base=.276666666},SVG.Text.prototype=new SVG.Shape,SVG.extend(SVG.Text,{x:function(t,e){return null==t?e?this.attr("x"):this.bbox().x:(e||(e=this.style("text-anchor"),t="start"==e?t:"end"==e?t+this.bbox().width:t+this.bbox().width/2),this.attr("x",t))},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t,e){return null==t?this.bbox().cy:this.y(e?t:t-this.bbox().height/2)},move:function(t,e,i){return this.x(t,i).y(e)},center:function(t,e,i){return this.cx(t,i).cy(e,i)},text:function(t){if(null==t)return this.content;this.clear(),this.content=SVG.regex.isBlank.test(t)?"text":t;var e,i,n=t.split("\n");for(e=0,i=n.length;i>e;e++)this.tspan(n[e]);return this.attr("textLength",1).attr("textLength",null)},tspan:function(t){var e=(new SVG.TSpan).text(t);return this.node.appendChild(e.node),this.lines.push(e),e.attr("style",this.style())},size:function(t){return this.attr("font-size",t)},leading:function(t){return null==t?this._leading:(this._leading=t,this.rebuild("leading",t))},rebuild:function(){var t,e,i=this.styles["font-size"];for(t=0,e=this.lines.length;e>t;t++)this.lines[t].attr({dy:i*this._leading-(0==t?i*this._base:0),x:this.attr("x")||0,style:this.style()});return this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.lines=[],this}}),SVG.extend(SVG.Container,{text:function(t){return this.put((new SVG.Text).text(t))}}),SVG.TSpan=function(){this.constructor.call(this,SVG.create("tspan"))},SVG.TSpan.prototype=new SVG.Shape,SVG.extend(SVG.TSpan,{text:function(t){return this.node.appendChild(document.createTextNode(t)),this}}),SVG.Nested=function(){this.constructor.call(this,SVG.create("svg")),this.style("overflow","visible")},SVG.Nested.prototype=new SVG.Container,SVG.extend(SVG.Container,{nested:function(){return this.put(new SVG.Nested)}}),SVG._stroke=["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],SVG._fill=["color","opacity","rule"];var e=function(t,e){return"color"==e?t:t+"-"+e};["fill","stroke"].forEach(function(t){var i={};i[t]=function(i){if("string"==typeof i||SVG.Color.isRgb(i))this.attr(t,i);else for(index=SVG["_"+t].length-1;index>=0;index--)null!=i[SVG["_"+t][index]]&&this.attr(e(t,SVG["_"+t][index]),i[SVG["_"+t][index]]);return this},SVG.extend(SVG.Shape,SVG.FX,i)}),SVG.extend(SVG.Element,SVG.FX,{rotate:function(t,e,i){return this.transform({rotation:t||0,cx:e,cy:i})},skew:function(t,e){return this.transform({skewX:t||0,skewY:e||0})},scale:function(t,e){return this.transform({scaleX:t,scaleY:null==e?t:e})},translate:function(t,e){return this.transform({x:t,y:e})},matrix:function(t){return this.transform({matrix:t})},opacity:function(t){return this.attr("opacity",t)}}),SVG.Text&&SVG.extend(SVG.Text,SVG.FX,{font:function(e){for(var i in e)"anchor"==i?this.attr("text-anchor",e[i]):t.indexOf(i)>-1?this.attr("font-"+i,e[i]):this.attr(i,e[i]);return this}})}).call(this);
\ No newline at end of file +!function(){if(this.SVG=function(t){return SVG.supported?new SVG.Doc(t):void 0},this.svg=function(t){return console.warn("WARNING: svg() is deprecated, please use SVG() instead."),SVG(t)},SVG.ns="http://www.w3.org/2000/svg",SVG.xlink="http://www.w3.org/1999/xlink",SVG.did=1e3,SVG.eid=function(t){return"Svgjs"+t.charAt(0).toUpperCase()+t.slice(1)+SVG.did++},SVG.create=function(t){var e=document.createElementNS(this.ns,t);return e.setAttribute("id",this.eid(t)),e},SVG.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]},SVG.get=function(t){var e=document.getElementById(t);return e?e.instance:void 0},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}(),!SVG.supported)return!1;SVG.regex={test:function(t,e){return this[e].test(t)},unit:/^([\d\.]+)([a-z%]{0,2})$/,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isStyle:/^font|text|leading|cursor/,isBlank:/^(\s+)?$/,isNumber:/^-?[\d\.]+$/,isPercent:/^-?[\d\.]+%$/},SVG.defaults={matrix:"1,0,0,1,0,0",attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,fill:"#000",stroke:"#000",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":"#000"},trans:function(){return{x:0,y:0,scaleX:1,scaleY:1,rotation:0,skewX:0,skewY:0,matrix:this.matrix,a:1,b:0,c:0,d:1,e:0,f:0}}},SVG.Color=function(t){var e;this.r=0,this.g=0,this.b=0,"string"==typeof t?SVG.regex.isRgb.test(t)?(e=SVG.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):SVG.regex.isHex.test(t)&&(e=SVG.regex.hex.exec(this._fullHex(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)},SVG.extend(SVG.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+this._compToHex(this.r)+this._compToHex(this.g)+this._compToHex(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return.3*(this.r/255)+.59*(this.g/255)+.11*(this.b/255)},_fullHex:function(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},_compToHex:function(t){var e=t.toString(16);return 1==e.length?"0"+e:e}}),SVG.Color.test=function(t){return t+="",SVG.regex.isHex.test(t)||SVG.regex.isRgb.test(t)},SVG.Color.isRgb=function(t){return t&&"number"==typeof t.r},SVG.Number=function(t){switch(this.value=0,this.unit="",typeof t){case"number":this.value=t;break;case"string":var e=t.match(SVG.regex.unit);this.value=parseFloat(e[1]),"%"==e[2]&&(this.value/=100),this.unit=e[2];break;default:t instanceof SVG.Number&&(this.value=t.value,this.unit=t.unit)}},SVG.extend(SVG.Number,{toString:function(){return("%"==this.unit?~~(100*this.value):this.value)+this.unit},valueOf:function(){return this.value},to:function(t){return"string"==typeof t&&(this.unit=t),this},plus:function(t){return this.value=this+new SVG.Number(t),this},minus:function(t){return this.plus(-new SVG.Number(t))},times:function(t){return this.value=this*new SVG.Number(t),this},divide:function(t){return this.value=this/new SVG.Number(t),this}}),SVG.ViewBox=function(t){var e,i,n,s,r=t.bbox(),o=(t.attr("viewBox")||"").match(/-?[\d\.]+/g);this.x=r.x,this.y=r.y,this.width=t.node.offsetWidth||t.attr("width"),this.height=t.node.offsetHeight||t.attr("height"),o&&(e=parseFloat(o[0]),i=parseFloat(o[1]),n=parseFloat(o[2]),s=parseFloat(o[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),this.zoom=this.zoom||1},SVG.extend(SVG.ViewBox,{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height}}),SVG.BBox=function(t){var e;if(this.x=0,this.y=0,this.width=0,this.height=0,t){try{e=t.node.getBBox()}catch(i){e={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=e.x+t.trans.x,this.y=e.y+t.trans.y,this.width=e.width*t.trans.scaleX,this.height=e.height*t.trans.scaleY}this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.extend(SVG.BBox,{merge:function(t){var e=new SVG.BBox;return e.x=Math.min(this.x,t.x),e.y=Math.min(this.y,t.y),e.width=Math.max(this.x+this.width,t.x+t.width)-e.x,e.height=Math.max(this.y+this.height,t.y+t.height)-e.y,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2,e}}),SVG.RBox=function(t){var e,i,n={};if(this.x=0,this.y=0,this.width=0,this.height=0,t){for(e=t.doc().parent,i=t.doc().viewbox().zoom,n=t.node.getBoundingClientRect(),this.x=n.left,this.y=n.top,this.x-=e.offsetLeft,this.y-=e.offsetTop;e=e.offsetParent;)this.x-=e.offsetLeft,this.y-=e.offsetTop;for(e=t;e=e.parent;)"svg"==e.type&&e.viewbox&&(i*=e.viewbox().zoom,this.x-=e.x()||0,this.y-=e.y()||0)}this.x/=i,this.y/=i,this.width=n.width/=i,this.height=n.height/=i,this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.Element=function(t){this._stroke=SVG.defaults.attrs.stroke,this.styles={},this.trans=SVG.defaults.trans(),(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},SVG.extend(SVG.Element,{x:function(t){return t&&(t=new SVG.Number(t),t.value/=this.trans.scaleX),this.attr("x",t)},y:function(t){return t&&(t=new SVG.Number(t),t.value/=this.trans.scaleY),this.attr("y",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)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){return this.attr({width:new SVG.Number(t),height:new SVG.Number(e)})},clone:function(){var t,e,i=this.type;return t="rect"==i||"ellipse"==i?this.parent[i](0,0):"line"==i?this.parent[i](0,0,0,0):"image"==i?this.parent[i](this.src):"text"==i?this.parent[i](this.content):"path"==i?this.parent[i](this.attr("d")):"polyline"==i||"polygon"==i?this.parent[i](this.attr("points")):"g"==i?this.parent.group():this.parent[i](),e=this.attr(),delete e.id,t.attr(e),t.trans=this.trans,t.transform({})},remove:function(){return this.parent&&this.parent.removeElement(this),this},doc:function(t){return this._parent(t||SVG.Doc)},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]=SVG.regex.test(e[i].nodeValue,"isNumber")?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 this._isStyle(t)?"text"==t?this.content:"leading"==t&&this.leading?this.leading():this.style(t):(e=this.node.getAttribute(t),null==e?SVG.defaults.attrs[t]:SVG.regex.test(e,"isNumber")?parseFloat(e):e);if("style"==t)return this.style(e);if("function"==typeof e.fill&&(e=e.fill()),"x"==t&&Array.isArray(this.lines))for(i=this.lines.length-1;i>=0;i--)this.lines[i].attr(t,e);"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),(SVG.Color.test(e)||SVG.Color.isRgb(e))&&(e=new SVG.Color(e).toHex()),null!=i?this.node.setAttributeNS(i,t,e):this.node.setAttribute(t,e),this._isStyle(t)&&("text"==t?this.text(e):"leading"==t&&this.leading?this.leading(e):this.style(t,e),this.rebuild&&this.rebuild(t,e))}return this},transform:function(t,e){if(0==arguments.length)return this.trans;if("string"==typeof t){if(arguments.length<2)return this.trans[t];var i={};return i[t]=e,this.transform(i)}var i=[];t=this._parseMatrix(t);for(e in t)null!=t[e]&&(this.trans[e]=t[e]);return this.trans.matrix=this.trans.a+","+this.trans.b+","+this.trans.c+","+this.trans.d+","+this.trans.e+","+this.trans.f,t=this.trans,t.matrix!=SVG.defaults.matrix&&i.push("matrix("+t.matrix+")"),0!=t.rotation&&i.push("rotate("+t.rotation+","+(t.cx||this.bbox().cx)+","+(t.cy||this.bbox().cy)+")"),(1!=t.scaleX||1!=t.scaleY)&&i.push("scale("+t.scaleX+","+t.scaleY+")"),0!=t.skewX&&i.push("skewX("+t.skewX+")"),0!=t.skewY&&i.push("skewY("+t.skewY+")"),(0!=t.x||0!=t.y)&&i.push("translate("+t.x/t.scaleX+","+t.y/t.scaleY+")"),this._offset&&i.push("translate("+-this._offset.x+","+-this._offset.y+")"),0==i.length?this.node.removeAttribute("transform"):this.node.setAttribute("transform",i.join(" ")),this},style:function(t,e){if(0==arguments.length)return this.attr("style")||"";if(arguments.length<2)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!SVG.regex.isCss.test(t))return this.styles[t];t=t.split(";");for(var i=0;i<t.length;i++)e=t[i].split(":"),2==e.length&&this.style(e[0].replace(/\s+/g,""),e[1].replace(/^\s+/,"").replace(/\s+$/,""))}else null===e||SVG.regex.test(e,"isBlank")?delete this.styles[t]:this.styles[t]=e;t="";for(e in this.styles)t+=e+":"+this.styles[e]+";";return""==t?this.node.removeAttribute("style"):this.node.setAttribute("style",t),this},data:function(t,e,i){if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(n){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},bbox:function(){return new SVG.BBox(this)},rbox:function(){return new SVG.RBox(this)},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")},_parent:function(t){for(var e=this;null!=e&&!(e instanceof t);)e=e.parent;return e},_isStyle:function(t){return"string"==typeof t?SVG.regex.test(t,"isStyle"):!1},_parseMatrix:function(t){if(t.matrix){var e=t.matrix.replace(/\s/g,"").split(",");6==e.length&&(t.a=parseFloat(e[0]),t.b=parseFloat(e[1]),t.c=parseFloat(e[2]),t.d=parseFloat(e[3]),t.e=parseFloat(e[4]),t.f=parseFloat(e[5]))}return t}}),SVG.Container=function(t){this.constructor.call(this,t)},SVG.Container.prototype=new SVG.Element,SVG.extend(SVG.Container,{children:function(){return this._children||(this._children=[])},add:function(t,e){if(!this.has(t)){if(e=null==e?this.children().length:e,t.parent){var i=t.parent.children().indexOf(t);t.parent.children().splice(i,1)}this.children().splice(e,0,t),this.node.insertBefore(t.node,this.node.childNodes[e]||null),t.parent=this}return this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.children().indexOf(t)>=0},each:function(t,e){var i,n,s=this.children();for(i=0,n=s.length;n>i;i++)s[i]instanceof SVG.Shape&&t.apply(s[i],[i,s]),e&&s[i]instanceof SVG.Container&&s[i].each(t,e);return this},removeElement:function(t){var e=this.children().indexOf(t);return this.children().splice(e,1),this.node.removeChild(t.node),t.parent=null,this},defs:function(){return this._defs||(this._defs=this.put(new SVG.Defs,0))},level:function(){return this.removeElement(this.defs()).put(this.defs(),0)},first:function(){return this.children()[0]instanceof SVG.Defs?this.children()[1]:this.children()[0]},last:function(){return this.children()[this.children().length-1]},viewbox:function(t){return 0==arguments.length?new SVG.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t.join(" ")))},clear:function(){for(var t=this.children().length-1;t>=0;t--)this.removeElement(this.children()[t]);return this._defs&&(this._defs.remove(),delete this._defs),this}}),SVG.FX=function(t){this.target=t},SVG.extend(SVG.FX,{animate:function(t,e,i){var n,s,r,o,h=this.target,a=this;return"object"==typeof t&&(i=t.delay,e=t.ease,t=t.duration),t=null==t?1e3:t,e=e||"<>",a.to=function(t){var i;if(t=0>t?0:t>1?1:t,null==n){n=[];for(o in a.attrs)n.push(o)}if(null==s){s=[];for(o in a.trans)s.push(o)}if(null==r){r=[];for(o in a.styles)r.push(o)}for(t="<>"==e?-Math.cos(t*Math.PI)/2+.5:">"==e?Math.sin(t*Math.PI/2):"<"==e?-Math.cos(t*Math.PI/2)+1:"-"==e?t:"function"==typeof e?e(t):t,a._x?h.x(a._at(a._x,t)):a._cx&&h.cx(a._at(a._cx,t)),a._y?h.y(a._at(a._y,t)):a._cy&&h.cy(a._at(a._cy,t)),a._size&&h.size(a._at(a._size.width,t),a._at(a._size.height,t)),a._viewbox&&h.viewbox(a._at(a._viewbox.x,t),a._at(a._viewbox.y,t),a._at(a._viewbox.width,t),a._at(a._viewbox.height,t)),i=n.length-1;i>=0;i--)h.attr(n[i],a._at(a.attrs[n[i]],t));for(i=s.length-1;i>=0;i--)h.transform(s[i],a._at(a.trans[s[i]],t));for(i=r.length-1;i>=0;i--)h.style(r[i],a._at(a.styles[r[i]],t));a._during&&a._during.call(h,t,function(e,i){return a._at({from:e,to:i},t)})},"number"==typeof t&&(this.timeout=setTimeout(function(){var e=1e3/60,i=(new Date).getTime(),n=i+t;a.interval=setInterval(function(){var e=(new Date).getTime(),s=e>n?1:(e-i)/t;a.to(s),e>n&&(clearInterval(a.interval),a._after?a._after.apply(h,[a]):a.stop())},t>e?e:t)},i||0)),this},bbox:function(){return this.target.bbox()},attr:function(t,e){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.attrs[t]={from:this.target.attr(t),to:e};return this},transform:function(t,e){if(1==arguments.length){t=this.target._parseMatrix(t),delete t.matrix;for(e in t)this.trans[e]={from:this.target.trans[e],to:t[e]}}else{var i={};i[t]=e,this.transform(i)}return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.styles[t]={from:this.target.style(t),to:e};return this},x:function(t){return this._x={from:this.target.x(),to:t},this},y:function(t){return this._y={from:this.target.y(),to:t},this},cx:function(t){return this._cx={from:this.target.cx(),to:t},this},cy:function(t){return this._cy={from:this.target.cy(),to:t},this},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 SVG.Text)this.attr("font-size",t);else{var i=this.target.bbox();this._size={width:{from:i.width,to:t},height:{from:i.height,to:e}}}return this},viewbox:function(t,e,i,n){if(this.target instanceof SVG.Container){var s=this.target.viewbox();this._viewbox={x:{from:s.x,to:t},y:{from:s.y,to:e},width:{from:s.width,to:i},height:{from:s.height,to:n}}}return this},update:function(t){return this.target instanceof SVG.Stop&&(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 SVG.Number(t.offset))),this},during:function(t){return this._during=t,this},after:function(t){return this._after=t,this},stop:function(){return clearTimeout(this.timeout),clearInterval(this.interval),this.attrs={},this.trans={},this.styles={},delete this._x,delete this._y,delete this._cx,delete this._cy,delete this._size,delete this._after,delete this._during,delete this._viewbox,this},_at:function(t,e){return"number"==typeof t.from?t.from+(t.to-t.from)*e:SVG.regex.unit.test(t.to)?new SVG.Number(t.to).minus(new SVG.Number(t.from)).times(e).plus(new SVG.Number(t.from)):t.to&&(t.to.r||SVG.Color.test(t.to))?this._color(t,e):1>e?t.from:t.to},_color:function(t,e){var i,n;return e=0>e?0:e>1?1:e,i=new SVG.Color(t.from),n=new SVG.Color(t.to),new SVG.Color({r:~~(i.r+(n.r-i.r)*e),g:~~(i.g+(n.g-i.g)*e),b:~~(i.b+(n.b-i.b)*e)}).toHex()}}),SVG.extend(SVG.Element,{animate:function(t,e,i){return(this.fx||(this.fx=new SVG.FX(this))).stop().animate(t,e,i)},stop:function(){return this.fx&&this.fx.stop(),this}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchend","touchmove","touchcancel"].forEach(function(t){SVG.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),SVG.on=function(t,e,i){t.addEventListener?t.addEventListener(e,i,!1):t.attachEvent("on"+e,i)},SVG.off=function(t,e,i){t.removeEventListener?t.removeEventListener(e,i,!1):t.detachEvent("on"+e,i)},SVG.extend(SVG.Element,{on:function(t,e){return SVG.on(this.node,t,e),this},off:function(t,e){return SVG.off(this.node,t,e),this}}),SVG.G=function(){this.constructor.call(this,SVG.create("g"))},SVG.G.prototype=new SVG.Container,SVG.extend(SVG.G,{x:function(t){return null==t?this.trans.x:this.transform("x",t)},y:function(t){return null==t?this.trans.y:this.transform("y",t)},defs:function(){return this.doc().defs()}}),SVG.extend(SVG.Container,{group:function(){return this.put(new SVG.G)}}),SVG.extend(SVG.Element,{siblings:function(){return this.parent.children()},position:function(){return this.siblings().indexOf(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){return this.parent.removeElement(this).put(this,this.position()+1)},backward:function(){this.parent.level();var t=this.position();return t>1&&this.parent.removeElement(this).add(this,t-1),this},front:function(){return this.parent.removeElement(this).put(this)},back:function(){return this.parent.level(),this.position()>1&&this.parent.removeElement(this).add(this,0),this}}),SVG.Defs=function(){this.constructor.call(this,SVG.create("defs"))},SVG.Defs.prototype=new SVG.Container,SVG.Mask=function(){this.constructor.call(this,SVG.create("mask"))},SVG.Mask.prototype=new SVG.Container,SVG.extend(SVG.Element,{maskWith:function(t){return this.mask=t instanceof SVG.Mask?t:this.parent.mask().add(t),this.attr("mask","url(#"+this.mask.attr("id")+")")}}),SVG.extend(SVG.Container,{mask:function(){return this.defs().put(new SVG.Mask)}}),SVG.Clip=function(){this.constructor.call(this,SVG.create("clipPath"))},SVG.Clip.prototype=new SVG.Container,SVG.extend(SVG.Element,{clipWith:function(t){return this.clip=t instanceof SVG.Clip?t:this.parent.clip().add(t),this.attr("clip-path","url(#"+this.clip.attr("id")+")")}}),SVG.extend(SVG.Container,{clip:function(){return this.defs().put(new SVG.Clip)}}),SVG.Pattern=function(){this.constructor.call(this,SVG.create("pattern"))},SVG.Pattern.prototype=new SVG.Container,SVG.extend(SVG.Pattern,{fill:function(){return"url(#"+this.attr("id")+")"}}),SVG.extend(SVG.Defs,{pattern:function(t,e,i){var n=this.put(new SVG.Pattern);return i(n),n.attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),SVG.extend(SVG.Container,{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}),SVG.Gradient=function(t){this.constructor.call(this,SVG.create(t+"Gradient")),this.type=t},SVG.Gradient.prototype=new SVG.Container,SVG.extend(SVG.Gradient,{from:function(t,e){return"radial"==this.type?this.attr({fx:new SVG.Number(t),fy:new SVG.Number(e)}):this.attr({x1:new SVG.Number(t),y1:new SVG.Number(e)})},to:function(t,e){return"radial"==this.type?this.attr({cx:new SVG.Number(t),cy:new SVG.Number(e)}):this.attr({x2:new SVG.Number(t),y2:new SVG.Number(e)})},radius:function(t){return"radial"==this.type?this.attr({r:new SVG.Number(t)}):this},at:function(t){return this.put(new SVG.Stop(t))},update:function(t){return this.clear(),t(this),this},fill:function(){return"url(#"+this.attr("id")+")"},get:function(t){return this.children()[t]}}),SVG.extend(SVG.Defs,{gradient:function(t,e){var i=this.put(new SVG.Gradient(t));return e(i),i}}),SVG.extend(SVG.Container,{gradient:function(t,e){return this.defs().gradient(t,e)}}),SVG.Stop=function(t){this.constructor.call(this,SVG.create("stop")),this.update(t)},SVG.Stop.prototype=new SVG.Element,SVG.extend(SVG.Stop,{update:function(t){return 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 SVG.Number(t.offset)),this}}),SVG.Doc=function(t){this.parent="string"==typeof t?document.getElementById(t):t,this.constructor.call(this,"svg"==this.parent.nodeName?this.parent:SVG.create("svg")),this.attr({xmlns:SVG.ns,version:"1.1",width:"100%",height:"100%"}).attr("xlink",SVG.xlink,SVG.ns).defs(),"svg"!=this.parent.nodeName&&this.stage()},SVG.Doc.prototype=new SVG.Container,SVG.extend(SVG.Doc,{stage:function(){var t,e=this,i=document.createElement("div");return i.style.cssText="position:relative;height:100%;",e.parent.appendChild(i),i.appendChild(e.node),t=function(){"complete"===document.readyState?(e.style("position:absolute;"),setTimeout(function(){e.style("position:relative;"),e.parent.removeChild(e.node.parentNode),e.node.parentNode.removeChild(e.node),e.parent.appendChild(e.node),e.fixSubPixelOffset(),SVG.on(window,"resize",function(){e.fixSubPixelOffset()})},5)):setTimeout(t,10)},t(),this},fixSubPixelOffset:function(){var t=this.node.getScreenCTM();this.style("left",-t.e%1+"px").style("top",-t.f%1+"px")}}),SVG.Shape=function(t){this.constructor.call(this,t)},SVG.Shape.prototype=new SVG.Element,SVG.Rect=function(){this.constructor.call(this,SVG.create("rect"))},SVG.Rect.prototype=new SVG.Shape,SVG.extend(SVG.Container,{rect:function(t,e){return this.put((new SVG.Rect).size(t,e))}}),SVG.Ellipse=function(){this.constructor.call(this,SVG.create("ellipse"))},SVG.Ellipse.prototype=new SVG.Shape,SVG.extend(SVG.Ellipse,{x:function(t){return null==t?this.cx()-this.attr("rx"):this.cx(t+this.attr("rx"))},y:function(t){return null==t?this.cy()-this.attr("ry"):this.cy(t+this.attr("ry"))},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",new SVG.Number(t).divide(this.trans.scaleX))},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",new SVG.Number(t).divide(this.trans.scaleY))},size:function(t,e){return this.attr({rx:new SVG.Number(t).divide(2),ry:new SVG.Number(e).divide(2)})}}),SVG.extend(SVG.Container,{circle:function(t){return this.ellipse(t,t)},ellipse:function(t,e){return this.put(new SVG.Ellipse).size(t,e).move(0,0)}}),SVG.Line=function(){this.constructor.call(this,SVG.create("line"))},SVG.Line.prototype=new SVG.Shape,SVG.extend(SVG.Line,{x:function(t){var e=this.bbox();return null==t?e.x:this.attr({x1:this.attr("x1")-e.x+t,x2:this.attr("x2")-e.x+t})},y:function(t){var e=this.bbox();return null==t?e.y:this.attr({y1:this.attr("y1")-e.y+t,y2:this.attr("y2")-e.y+t})},cx:function(t){var e=this.bbox().width/2;return null==t?this.x()+e:this.x(t-e)},cy:function(t){var e=this.bbox().height/2;return null==t?this.y()+e:this.y(t-e)},size:function(t,e){var i=this.bbox();return this.attr(this.attr("x1")<this.attr("x2")?"x2":"x1",i.x+t).attr(this.attr("y1")<this.attr("y2")?"y2":"y1",i.y+e)},plot:function(t,e,i,n){return this.attr({x1:t,y1:e,x2:i,y2:n})}}),SVG.extend(SVG.Container,{line:function(t,e,i,n){return this.put((new SVG.Line).plot(t,e,i,n))}}),SVG.Polyline=function(t){this.constructor.call(this,SVG.create("polyline")),this.unbiased=t},SVG.Polyline.prototype=new SVG.Shape,SVG.Polygon=function(t){this.constructor.call(this,SVG.create("polygon")),this.unbiased=t},SVG.Polygon.prototype=new SVG.Shape,SVG.extend(SVG.Polyline,SVG.Polygon,{_plot:function(t){if(Array.isArray(t)){var e,i,n=[];for(e=0,i=t.length;i>e;e++)n.push(t[e].join(","));t=n.length>0?n.join(" "):"0,0"}return this.attr("points",t||"0,0")}}),SVG.extend(SVG.Container,{polyline:function(t,e){return this.put(new SVG.Polyline(e)).plot(t)},polygon:function(t,e){return this.put(new SVG.Polygon(e)).plot(t)}}),SVG.Path=function(t){this.constructor.call(this,SVG.create("path")),this.unbiased=t},SVG.Path.prototype=new SVG.Shape,SVG.extend(SVG.Path,{_plot:function(t){return this.attr("d",t||"M0,0")}}),SVG.extend(SVG.Container,{path:function(t,e){return this.put(new SVG.Path(e)).plot(t)}}),SVG.extend(SVG.Polyline,SVG.Polygon,SVG.Path,{x:function(t){return null==t?this.bbox().x:this.transform("x",t)},y:function(t){return null==t?this.bbox().y:this.transform("y",t)},size:function(t,e){var i=t/this._offset.width;return this.transform({scaleX:i,scaleY:null!=e?e/this._offset.height:i})},plot:function(t){var e=this.trans.scaleX,i=this.trans.scaleY;return this._plot(t),this._offset=this.transform({scaleX:1,scaleY:1}).bbox(),this.unbiased?this._offset.x=this._offset.y=0:(this._offset.x-=this.trans.x,this._offset.y-=this.trans.y),this.transform({scaleX:e,scaleY:i})}}),SVG.Image=function(){this.constructor.call(this,SVG.create("image"))},SVG.Image.prototype=new SVG.Shape,SVG.extend(SVG.Image,{load:function(t){return t?this.attr("xlink:href",this.src=t,SVG.xlink):this}}),SVG.extend(SVG.Container,{image:function(t,e,i){return e=null!=e?e:100,this.put((new SVG.Image).load(t).size(e,null!=i?i:e))}});var t="size family weight stretch variant style".split(" ");SVG.Text=function(){this.constructor.call(this,SVG.create("text")),this.styles={"font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"},this._leading=1.2,this._base=.276666666},SVG.Text.prototype=new SVG.Shape,SVG.extend(SVG.Text,{x:function(t,e){return null==t?e?this.attr("x"):this.bbox().x:(e||(e=this.style("text-anchor"),t="start"==e?t:"end"==e?t+this.bbox().width:t+this.bbox().width/2),this.attr("x",t))},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t,e){return null==t?this.bbox().cy:this.y(e?t:t-this.bbox().height/2)},move:function(t,e,i){return this.x(t,i).y(e)},center:function(t,e,i){return this.cx(t,i).cy(e,i)},text:function(t){if(null==t)return this.content;this.clear(),this.content=SVG.regex.isBlank.test(t)?"text":t;var e,i,n=t.split("\n");for(e=0,i=n.length;i>e;e++)this.tspan(n[e]);return this.attr("textLength",1).attr("textLength",null)},tspan:function(t){var e=(new SVG.TSpan).text(t);return this.node.appendChild(e.node),this.lines.push(e),e.attr("style",this.style())},size:function(t){return this.attr("font-size",t)},leading:function(t){return null==t?this._leading:(this._leading=t,this.rebuild("leading",t))},rebuild:function(){var t,e,i=this.styles["font-size"];for(t=0,e=this.lines.length;e>t;t++)this.lines[t].attr({dy:i*this._leading-(0==t?i*this._base:0),x:this.attr("x")||0,style:this.style()});return this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.lines=[],this}}),SVG.extend(SVG.Container,{text:function(t){return this.put((new SVG.Text).text(t))}}),SVG.TSpan=function(){this.constructor.call(this,SVG.create("tspan"))},SVG.TSpan.prototype=new SVG.Shape,SVG.extend(SVG.TSpan,{text:function(t){return this.node.appendChild(document.createTextNode(t)),this}}),SVG.Nested=function(){this.constructor.call(this,SVG.create("svg")),this.style("overflow","visible")},SVG.Nested.prototype=new SVG.Container,SVG.extend(SVG.Container,{nested:function(){return this.put(new SVG.Nested)}}),SVG._stroke=["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],SVG._fill=["color","opacity","rule"];var e=function(t,e){return"color"==e?t:t+"-"+e};["fill","stroke"].forEach(function(t){var i={};i[t]=function(i){if("string"==typeof i||SVG.Color.isRgb(i))this.attr(t,i);else for(index=SVG["_"+t].length-1;index>=0;index--)null!=i[SVG["_"+t][index]]&&this.attr(e(t,SVG["_"+t][index]),i[SVG["_"+t][index]]);return this},SVG.extend(SVG.Shape,SVG.FX,i)}),SVG.extend(SVG.Element,SVG.FX,{rotate:function(t,e,i){return this.transform({rotation:t||0,cx:e,cy:i})},skew:function(t,e){return this.transform({skewX:t||0,skewY:e||0})},scale:function(t,e){return this.transform({scaleX:t,scaleY:null==e?t:e})},translate:function(t,e){return this.transform({x:t,y:e})},matrix:function(t){return this.transform({matrix:t})},opacity:function(t){return this.attr("opacity",t)}}),SVG.Text&&SVG.extend(SVG.Text,SVG.FX,{font:function(e){for(var i in e)"anchor"==i?this.attr("text-anchor",e[i]):t.indexOf(i)>-1?this.attr("font-"+i,e[i]):this.attr(i,e[i]);return this}})}.call(this);
\ No newline at end of file diff --git a/package.json b/package.json index 601fd14..bfb80d9 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ , "keywords": ["svg", "vector", "graphics", "animation"] , "author": "Wout Fierens <wout@impinc.co.uk>" , "main": "dist/svg.js" -, "version": "v0.19" +, "version": "v0.20" , "jam": { "include": [ "dist/svg.js" diff --git a/spec/index.html b/spec/index.html index 38150a9..d4cf605 100644 --- a/spec/index.html +++ b/spec/index.html @@ -43,6 +43,7 @@ <script type="text/javascript" src="spec/doc.js"></script> <script type="text/javascript" src="spec/gradient.js"></script> <script type="text/javascript" src="spec/color.js"></script> +<script type="text/javascript" src="spec/number.js"></script> <script type="text/javascript"> (function() { diff --git a/spec/spec/ellipse.js b/spec/spec/ellipse.js index b19aa57..cd3e0e5 100644 --- a/spec/spec/ellipse.js +++ b/spec/spec/ellipse.js @@ -63,7 +63,7 @@ describe('Ellipse', function() { }) describe('center()', function() { - it('should set the cx and cy position', function() { + it('sets the cx and cy position', function() { ellipse.center(321,567) var box = ellipse.bbox() expect(box.cx).toBe(321) @@ -72,7 +72,7 @@ describe('Ellipse', function() { }) describe('size()', function() { - it('should define the rx and ry of the element', function() { + it('defines the rx and ry of the element', function() { ellipse.size(987,654) expect(ellipse.node.getAttribute('rx')).toBe((987 / 2).toString()) expect(ellipse.node.getAttribute('ry')).toBe((654 / 2).toString()) diff --git a/spec/spec/gradient.js b/spec/spec/gradient.js index f07a7e8..8aef33e 100644 --- a/spec/spec/gradient.js +++ b/spec/spec/gradient.js @@ -2,21 +2,81 @@ describe('Gradient', function() { var rect = draw.rect(100,100) , gradient = draw.gradient('linear', function(stop) { stop.at({ offset: 0, color: '#333', opacity: 1 }) - stop.at({ offset: 100, color: '#fff', opacity: 1 }) + stop.at({ offset: 1, color: '#fff', opacity: 1 }) }) - it('should be an instance of SVG.Gradient', function() { + it('is an instance of SVG.Gradient', function() { expect(gradient instanceof SVG.Gradient).toBe(true) }) describe('fill()', function() { - it('should return the id of the gradient wrapped in url()', function() { + it('returns the id of the gradient wrapped in url()', function() { expect(gradient.fill()).toBe('url(#' + gradient.attr('id') + ')') }) - it('should be called when instance is passed as an attribute value', function() { + it('is called when instance is passed as an attribute value', function() { rect.attr('fill', gradient) expect(rect.attr('fill')).toBe('url(#' + gradient.attr('id') + ')') }) }) + + describe('input values', function() { + var s1, s2 + + it('accepts floats', function() { + gradient = draw.gradient('linear', function(stop) { + s1 = stop.at({ offset: 0.12, color: '#333', opacity: 1 }) + s2 = stop.at({ offset: 0.93, color: '#fff', opacity: 1 }) + }) + expect(s1.attr('offset')).toBe(0.12) + expect(s2.attr('offset')).toBe(0.93) + }) + it('accepts string floats', function() { + gradient = draw.gradient('linear', function(stop) { + s1 = stop.at({ offset: '0.13', color: '#333', opacity: 1 }) + s2 = stop.at({ offset: '0.92', color: '#fff', opacity: 1 }) + }) + expect(s1.attr('offset')).toBe(0.13) + expect(s2.attr('offset')).toBe(0.92) + }) + it('accept percentages', function() { + gradient = draw.gradient('linear', function(stop) { + s1 = stop.at({ offset: '14%', color: '#333', opacity: 1 }) + s2 = stop.at({ offset: '91%', color: '#fff', opacity: 1 }) + }) + expect(s1.attr('offset')).toBe('14%') + expect(s2.attr('offset')).toBe('91%') + }) + }) + + describe('update()', function() { + + it('removes all existing children first', function() { + gradient = draw.gradient('linear', function(stop) { + s1 = stop.at({ offset: 0.12, color: '#333', opacity: 1 }) + s2 = stop.at({ offset: 0.93, color: '#fff', opacity: 1 }) + }) + expect(gradient.children().length).toBe(2) + gradient.update(function(stop) { + s1 = stop.at({ offset: 0.33, color: '#666', opacity: 1 }) + s2 = stop.at({ offset: 1, color: '#000', opacity: 1 }) + }) + expect(gradient.children().length).toBe(2) + }) + + }) + + describe('get()', function() { + + it('returns the stop at a given index', function() { + gradient = draw.gradient('linear', function(stop) { + s1 = stop.at({ offset: 0.12, color: '#333', opacity: 1 }) + s2 = stop.at({ offset: 0.93, color: '#fff', opacity: 1 }) + }) + expect(gradient.get(0)).toBe(s1) + expect(gradient.get(1)).toBe(s2) + expect(gradient.get(2)).toBe(undefined) + }) + + }) })
\ No newline at end of file diff --git a/spec/spec/number.js b/spec/spec/number.js new file mode 100644 index 0000000..62e51a2 --- /dev/null +++ b/spec/spec/number.js @@ -0,0 +1,177 @@ +describe('Number', function() { + var number + + beforeEach(function() { + number = new SVG.Number + }) + + describe('new', function() { + + it('is zero', function() { + expect(number.value).toBe(0) + }) + it('has a blank unit', function() { + expect(number.unit).toBe('') + }) + it('parses a pixel value', function() { + number = new SVG.Number('20px') + expect(number.value).toBe(20) + expect(number.unit).toBe('px') + }) + it('parses a percent value', function() { + number = new SVG.Number('99%') + expect(number.value).toBe(0.99) + expect(number.unit).toBe('%') + }) + + }) + + describe('toString()', function() { + + it('converts the number to a string', function() { + expect(number.toString()).toBe('0') + }) + it('appends the unit', function() { + number.value = 1.21 + number.unit = 'px' + expect(number.toString()).toBe('1.21px') + }) + it('converts percent values properly', function() { + number.value = 1.36 + number.unit = '%' + expect(number.toString()).toBe('136%') + }) + + }) + + describe('valueOf()', function() { + + it('returns a numeric value for default units', function() { + expect(typeof number.valueOf()).toBe('number') + number = new SVG.Number('12') + expect(typeof number.valueOf()).toBe('number') + number = new SVG.Number(13) + expect(typeof number.valueOf()).toBe('number') + }) + it('returns a numeric value for pixel units', function() { + number = new SVG.Number('10px') + expect(typeof number.valueOf()).toBe('number') + }) + it('returns a numeric value for percent units', function() { + number = new SVG.Number('20%') + expect(typeof number.valueOf()).toBe('number') + }) + it('converts to a primitive when multiplying', function() { + number.value = 80 + expect(number * 4).toBe(320) + }) + + }) + + describe('to()', function() { + + beforeEach(function() { + number.plus(4) + }) + + it('changes the unit value', function() { + number.to('%') + expect(number.unit).toBe('%') + }) + it('changes the output value', function() { + var oldNumber = number.valueOf() + number.to('%') + expect(number.toString()).toBe('400%') + }) + + }) + + describe('plus()', function() { + + it('adds a given number', function() { + number.plus(3.5) + expect(number.valueOf()).toBe(3.5) + }) + it('adds a given percentage value', function() { + number.plus('225%') + expect(number.valueOf()).toBe(2.25) + }) + it('adds a given pixel value', function() { + number.plus('83px') + expect(number.valueOf()).toBe(83) + }) + + }) + + describe('minus()', function() { + + it('subtracts a given number', function() { + number.minus(3.7) + expect(number.valueOf()).toBe(-3.7) + }) + it('subtracts a given percentage value', function() { + number.minus('223%') + expect(number.valueOf()).toBe(-2.23) + }) + it('subtracts a given pixel value', function() { + number.minus('85px') + expect(number.valueOf()).toBe(-85) + }) + + }) + + describe('times()', function() { + + beforeEach(function() { + number.plus(4) + }) + + it('multiplies with a given number', function() { + number.times(3) + expect(number.valueOf()).toBe(12) + }) + it('multiplies with a given percentage value', function() { + number.times('110%') + expect(number.valueOf()).toBe(4.4) + }) + it('multiplies with a given pixel value', function() { + number.times('85px') + expect(number.valueOf()).toBe(340) + }) + + }) + + describe('divide()', function() { + + beforeEach(function() { + number.plus(90) + }) + + it('divides by a given number', function() { + number.divide(3) + expect(number.valueOf()).toBe(30) + }) + it('divides by a given percentage value', function() { + number.divide('3000%') + expect(number.valueOf()).toBe(3) + }) + it('divides by a given pixel value', function() { + number.divide('45px') + expect(number.valueOf()).toBe(2) + }) + + }) + +}) + + + + + + + + + + + + diff --git a/src/default.js b/src/default.js index 314961d..fd85228 100644 --- a/src/default.js +++ b/src/default.js @@ -9,23 +9,25 @@ SVG.defaults = { 'fill-opacity': 1 , 'stroke-opacity': 1 , 'stroke-width': 0 - , fill: '#000' - , stroke: '#000' - , opacity: 1 + , fill: '#000' + , stroke: '#000' + , opacity: 1 /* position */ - , x: 0 - , y: 0 - , cx: 0 - , cy: 0 - /* size */ - , width: 0 - , height: 0 - /* radius */ - , r: 0 - , rx: 0 - , ry: 0 - /* gradient */ - , offset: 0 + , x: 0 + , y: 0 + , cx: 0 + , cy: 0 + /* size */ + , width: 0 + , height: 0 + /* radius */ + , r: 0 + , rx: 0 + , ry: 0 + /* gradient */ + , offset: 0 + , 'stop-opacity': 1 + , 'stop-color': '#000' } // Default transformation values diff --git a/src/element.js b/src/element.js index 3fa456f..d40108d 100644 --- a/src/element.js +++ b/src/element.js @@ -23,12 +23,18 @@ SVG.Element = function(node) { SVG.extend(SVG.Element, { // Move over x-axis x: function(x) { - if (x) x /= this.trans.scaleX + if (x) { + x = new SVG.Number(x) + x.value /= this.trans.scaleX + } return this.attr('x', x) } // Move over y-axis , y: function(y) { - if (y) y /= this.trans.scaleY + if (y) { + y = new SVG.Number(y) + y.value /= this.trans.scaleY + } return this.attr('y', y) } // Move by center over x-axis @@ -50,8 +56,8 @@ SVG.extend(SVG.Element, { // Set element size to given width and height , size: function(width, height) { return this.attr({ - width: width - , height: height + width: new SVG.Number(width) + , height: new SVG.Number(height) }) } // Clone element diff --git a/src/ellipse.js b/src/ellipse.js index 2ff0c86..ea019e0 100644 --- a/src/ellipse.js +++ b/src/ellipse.js @@ -18,17 +18,17 @@ SVG.extend(SVG.Ellipse, { } // Move by center over x-axis , cx: function(x) { - return x == null ? this.attr('cx') : this.attr('cx', x / this.trans.scaleX) + return x == null ? this.attr('cx') : this.attr('cx', new SVG.Number(x).divide(this.trans.scaleX)) } // Move by center over y-axis , cy: function(y) { - return y == null ? this.attr('cy') : this.attr('cy', y / this.trans.scaleY) + return y == null ? this.attr('cy') : this.attr('cy', new SVG.Number(y).divide(this.trans.scaleY)) } // Custom size function , size: function(width, height) { return this.attr({ - rx: width / 2, - ry: height / 2 + rx: new SVG.Number(width).divide(2) + , ry: new SVG.Number(height).divide(2) }) } @@ -42,7 +42,7 @@ SVG.extend(SVG.Container, { } // Create an ellipse , ellipse: function(width, height) { - return this.put(new SVG.Ellipse().size(width, height).move(0, 0)) + return this.put(new SVG.Ellipse).size(width, height).move(0, 0) } }) @@ -250,6 +250,16 @@ SVG.extend(SVG.FX, { return this } + // Add animateable gradient update +, update: function(o) { + if (this.target instanceof SVG.Stop) { + if (o.opacity != null) this.attr('stop-opacity', o.opacity) + if (o.color != null) this.attr('stop-color', o.color) + if (o.offset != null) this.attr('offset', new SVG.Number(o.offset)) + } + + return this + } // Add callback for each keyframe , during: function(during) { this._during = during @@ -291,7 +301,10 @@ SVG.extend(SVG.FX, { /* unit recalculation */ SVG.regex.unit.test(o.to) ? - this._unit(o, pos) : + new SVG.Number(o.to) + .minus(new SVG.Number(o.from)) + .times(pos) + .plus(new SVG.Number(o.from)) : /* color recalculation */ o.to && (o.to.r || SVG.Color.test(o.to)) ? @@ -300,19 +313,6 @@ SVG.extend(SVG.FX, { /* for all other values wait until pos has reached 1 to return the final value */ pos < 1 ? o.from : o.to } - // Private: tween unit -, _unit: function(o, pos) { - var match, from - - /* convert FROM unit */ - match = SVG.regex.unit.exec(o.from.toString()) - from = parseFloat(match ? match[1] : 0) - - /* convert TO unit */ - match = SVG.regex.unit.exec(o.to) - - return (from + (parseFloat(match[1]) - from) * pos) + match[2] - } // Private: tween color , _color: function(o, pos) { var from, to diff --git a/src/gradient.js b/src/gradient.js index f98a0b0..71da7d1 100644 --- a/src/gradient.js +++ b/src/gradient.js @@ -13,19 +13,19 @@ SVG.extend(SVG.Gradient, { // From position from: function(x, y) { return this.type == 'radial' ? - this.attr({ fx: x + '%', fy: y + '%' }) : - this.attr({ x1: x + '%', y1: y + '%' }) + this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) }) : + this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) }) } // To position , to: function(x, y) { return this.type == 'radial' ? - this.attr({ cx: x + '%', cy: y + '%' }) : - this.attr({ x2: x + '%', y2: y + '%' }) + this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) }) : + this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) }) } // Radius for radial gradient -, radius: function(radius) { +, radius: function(r) { return this.type == 'radial' ? - this.attr({ r: radius + '%' }) : + this.attr({ r: new SVG.Number(r) }) : this } // Add a color stop @@ -35,8 +35,7 @@ SVG.extend(SVG.Gradient, { // Update gradient , update: function(block) { /* remove all stops */ - while (this.node.hasChildNodes()) - this.node.removeChild(this.node.lastChild) + this.clear() /* invoke passed block */ block(this) @@ -47,6 +46,10 @@ SVG.extend(SVG.Gradient, { , fill: function() { return 'url(#' + this.attr('id') + ')' } + // Get a stop at the given index +, get: function(i) { + return this.children()[i] + } }) @@ -82,22 +85,18 @@ SVG.Stop = function(stop) { } // Inherit from SVG.Element -SVG.Stop.prototype = new SVG.Element() +SVG.Stop.prototype = new SVG.Element // SVG.extend(SVG.Stop, { // add color stops update: function(o) { - var index - , attr = ['opacity', 'color'] - - /* build style attribute */ - for (index = attr.length - 1; index >= 0; index--) - if (o[attr[index]] != null) - this.style('stop-' + attr[index], o[attr[index]]) - /* set attributes */ - return this.attr('offset', (o.offset != null ? o.offset : this.attr('offset')) + '%') + if (o.opacity != null) this.attr('stop-opacity', o.opacity) + if (o.color != null) this.attr('stop-color', o.color) + if (o.offset != null) this.attr('offset', new SVG.Number(o.offset)) + + return this } }) diff --git a/src/number.js b/src/number.js new file mode 100644 index 0000000..28e260e --- /dev/null +++ b/src/number.js @@ -0,0 +1,75 @@ +// Module for unit convertions +SVG.Number = function(value) { + + /* initialize defaults */ + this.value = 0 + this.unit = '' + + /* parse value */ + switch(typeof value) { + case 'number': + this.value = value + break + case 'string': + var match = value.match(SVG.regex.unit) + + /* make valu numeric */ + this.value = parseFloat(match[1]) + + /* normalize percent value */ + if (match[2] == '%') + this.value /= 100 + + /* store unit */ + this.unit = match[2] + + break + default: + if (value instanceof SVG.Number) { + this.value = value.value + this.unit = value.unit + } + break + } +} + +SVG.extend(SVG.Number, { + // Stringalize + toString: function() { + return (this.unit == '%' ? ~~(this.value * 100) : this.value) + this.unit + } +, // Convert to primitive + valueOf: function() { + return this.value + } + // Convert to different unit +, to: function(unit) { + if (typeof unit === 'string') + this.unit = unit + + return this + } + // Add number +, plus: function(number) { + this.value = this + new SVG.Number(number) + + return this + } + // Subtract number +, minus: function(number) { + return this.plus(-new SVG.Number(number)) + } + // Multiply number +, times: function(number) { + this.value = this * new SVG.Number(number) + + return this + } + // Divide number +, divide: function(number) { + this.value = this / new SVG.Number(number) + + return this + } + +})
\ No newline at end of file diff --git a/src/regex.js b/src/regex.js index 4cd74ae..4286d8a 100644 --- a/src/regex.js +++ b/src/regex.js @@ -13,7 +13,7 @@ SVG.regex = { /* parse rgb value */ , rgb: /rgb\((\d+),(\d+),(\d+)\)/ - + /* test hex value */ , isHex: /^#[a-f0-9]{3,6}$/i @@ -31,5 +31,8 @@ SVG.regex = { /* test for numeric string */ , isNumber: /^-?[\d\.]+$/ + + /* test for percent value */ +, isPercent: /^-?[\d\.]+%$/ }
\ No newline at end of file |