From 1286e3de26baa3d75ec6a6eafbb2eaa11305c2e1 Mon Sep 17 00:00:00 2001 From: wout Date: Tue, 4 Mar 2014 22:19:01 +0100 Subject: [PATCH] Bumped to 1.0.0-rc.6 --- CHANGELOG.md | 13 + README.md | 25 +- Rakefile | 4 +- bower.json | 2 +- component.json | 2 +- dist/svg.js | 548 ++++++++++++++++++++++--------------------- dist/svg.min.js | 4 +- package.json | 6 +- spec/spec/array.js | 20 +- spec/spec/element.js | 9 +- spec/spec/text.js | 28 +-- src/array.js | 6 + src/bbox.js | 14 +- src/color.js | 28 +-- src/element.js | 101 ++------ src/ellipse.js | 2 +- src/fx.js | 130 +++++----- src/helpers.js | 124 ++++++++++ src/image.js | 3 +- src/line.js | 2 +- src/nested.js | 2 +- src/number.js | 52 ++-- src/path.js | 2 +- src/patharray.js | 39 +-- src/poly.js | 2 +- src/rbox.js | 10 +- src/regex.js | 7 +- src/relative.js | 4 +- src/sugar.js | 2 +- src/text.js | 20 +- 30 files changed, 631 insertions(+), 580 deletions(-) create mode 100644 src/helpers.js diff --git a/CHANGELOG.md b/CHANGELOG.md index f0307b7..3bb4bed 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +# 1.0.0-rc.6 (03/03/2014) + +- fine-tuned text element positioning +- fixed a bug in text `dy()` method +- added `leading()` method to `SVG.FX` +- removed internal representation for `style` +- added `reverse()` method to `SVG.Array` (and thereby also to `SVG.PointArray` and `SVG.PathArray`) +- added `fulfill` option to `stop()` method in `SVG.FX` to finalise animations +- calling `at()` method directly on morphable svg.js instances in `SVG.FX` module +- moved most `_private` methods to local named functions +- moved helpers to a separate file +- added more output values to `bbox()` and `rbox()` methods + # 1.0.0-rc.5 (14/02/2014) - added `plain()` method to `SVG.Text` element to add plain text content, without tspans diff --git a/README.md b/README.md index 100e237..43b2d0e 100755 --- a/README.md +++ b/README.md @@ -529,6 +529,10 @@ text.clear() __`returns`: `itself`__ +### lines +All added tspans are stored in the `lines` reference, which is an instance of `SVG.Set`. + + ## TSpan The tspan elements are only available inside text elements or inside other tspan elements. In svg.js they have a class of their own: @@ -1330,7 +1334,7 @@ path.bbox() This will return an instance of `SVG.BBox` containing the following values: ```javascript -{ width: 20, height: 20, x: 10, y: 20, cx: 30, cy: 20 } +{ width: 20, height: 20, x: 10, y: 20, cx: 20, cy: 30, x2: 30, y2: 40 } ``` As opposed to the native `getBBox()` method any translations used with the `transform()` method will be taken into account. @@ -1498,6 +1502,14 @@ rect.animate().move(200, 200) rect.animate().center(200, 200) ``` +By calling `stop()`, the transition is left at its current position. By passing `true` as the first argument to `stop()`, the animation will be fulfilled instantly: + +```javascript +rect.animate().move(200, 200) + +rect.stop(true) +``` + Stopping an animation is irreversable. __`returns`: `itself`__ @@ -2712,6 +2724,17 @@ Note that this method is only available on `SVG.PointArray` and `SVG.PathArray` __`returns`: `itself`__ +### reverse() +Reverses the order of the array: + +```javascript +var array = new SVG.PointArray([[0, 0], [100, 100]]) +array.reverse() +array.toString() //-> returns '100,100 0,0' +``` + +__`returns`: `itself`__ + ### bbox() Gets the bounding box of the geometry of the array: diff --git a/Rakefile b/Rakefile index 932c317..8ff1eac 100755 --- a/Rakefile +++ b/Rakefile @@ -1,7 +1,7 @@ -SVGJS_VERSION = '1.0.0-rc.5' +SVGJS_VERSION = '1.0.0-rc.6' # all available modules in the correct loading order -MODULES = %w[ svg inventor regex default color array pointarray patharray number viewbox bbox rbox element parent container fx relative event defs group arrange mask clip gradient pattern doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set data memory loader ] +MODULES = %w[ svg inventor regex default color array pointarray patharray number viewbox bbox rbox element parent container fx relative event defs group arrange mask clip gradient pattern doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set data memory loader helpers ] # how many bytes in a "kilobyte" KILO = 1024 diff --git a/bower.json b/bower.json index 7be85f2..62ff0d8 100755 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "svg.js", - "version": "1.0.0-rc.5", + "version": "1.0.0-rc.6", "homepage": "http://svgjs.com/", "authors": [ "Wout Fierens " diff --git a/component.json b/component.json index 5bc99c1..82a55df 100755 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "svg.js", "repo": "wout/svg.js", "description": "A lightweight library for manipulating and animating SVG", - "version": "1.0.0-rc.5", + "version": "1.0.0-rc.6", "keywords": ["svg"], "author": "Wout Fierens ", "main": "dist/svg.js", diff --git a/dist/svg.js b/dist/svg.js index 0fdd667..4de3979 100755 --- a/dist/svg.js +++ b/dist/svg.js @@ -1,4 +1,4 @@ -/* svg.js 1.0.0-rc.5-6-g2a986d0 - svg inventor regex default color array pointarray patharray number viewbox bbox rbox element parent container fx relative event defs group arrange mask clip gradient pattern doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set data memory loader - svgjs.com/license */ +/* svg.js 1.0.0-rc.6 - svg inventor regex default color array pointarray patharray number viewbox bbox rbox element parent container fx relative event defs group arrange mask clip gradient pattern doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set data memory loader helpers - svgjs.com/license */ ;(function() { this.SVG = function(element) { @@ -113,13 +113,8 @@ } SVG.regex = { - /* test a given value */ - test: function(value, test) { - return this[test].test(value) - } - /* parse unit value */ - , unit: /^(-?[\d\.]+)([a-z%]{0,2})$/ + unit: /^(-?[\d\.]+)([a-z%]{0,2})$/ /* parse hex value */ , hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i @@ -223,7 +218,7 @@ this.b = 0 /* parse color */ - if (typeof color == 'string') { + if (typeof color === 'string') { if (SVG.regex.isRgb.test(color)) { /* get rgb values */ match = SVG.regex.rgb.exec(color.replace(/\s/g,'')) @@ -235,7 +230,7 @@ } else if (SVG.regex.isHex.test(color)) { /* get hex values */ - match = SVG.regex.hex.exec(this._fullHex(color)) + match = SVG.regex.hex.exec(fullHex(color)) /* parse numeric values */ this.r = parseInt(match[1], 16) @@ -244,7 +239,7 @@ } - } else if (typeof color == 'object') { + } else if (typeof color === 'object') { this.r = color.r this.g = color.g this.b = color.b @@ -261,9 +256,9 @@ // Build hex value , toHex: function() { return '#' - + this._compToHex(this.r) - + this._compToHex(this.g) - + this._compToHex(this.b) + + compToHex(this.r) + + compToHex(this.g) + + compToHex(this.b) } // Build rgb value , toRgb: function() { @@ -296,23 +291,11 @@ , b: ~~(this.b + (this.destination.b - this.b) * pos) }) } - // Private: ensure to six-based hex - , _fullHex: function(hex) { - return hex.length == 4 ? - [ '#', - hex.substring(1, 2), hex.substring(1, 2) - , hex.substring(2, 3), hex.substring(2, 3) - , hex.substring(3, 4), hex.substring(3, 4) - ].join('') : hex - } - // Private: component to hex value - , _compToHex: function(comp) { - var hex = comp.toString(16) - return hex.length == 1 ? '0' + hex : hex - } }) + // Testers + // Test if given value is a color string SVG.Color.test = function(color) { color += '' @@ -403,6 +386,12 @@ , split: function(string) { return string.replace(/\s+/g, ' ').replace(/^\s+|\s+$/g,'').split(' ') } + // Reverse array + , reverse: function() { + this.value.reverse() + + return this + } }) @@ -695,43 +684,6 @@ } }) - - // PathArray Helpers - function arrayToString(a) { - for (var i = 0, il = a.length, s = ''; i < il; i++) { - s += a[i][0] - - if (a[i][1] != null) { - s += a[i][1] - - if (a[i][2] != null) { - s += ' ' - s += a[i][2] - - if (a[i][3] != null) { - s += ' ' - s += a[i][3] - s += ' ' - s += a[i][4] - - if (a[i][5] != null) { - s += ' ' - s += a[i][5] - s += ' ' - s += a[i][6] - - if (a[i][7] != null) { - s += ' ' - s += a[i][7] - } - } - } - } - } - } - - return s + ' ' - } SVG.Number = function(value) { @@ -740,36 +692,34 @@ this.unit = '' /* parse value */ - switch(typeof value) { - case 'number': - /* ensure a valid numeric value */ - this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value - break - case 'string': - var match = value.match(SVG.regex.unit) - - if (match) { - /* make value numeric */ - this.value = parseFloat(match[1]) + if (typeof value === 'number') { + /* ensure a valid numeric value */ + this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value + + } else if (typeof value === 'string') { + var match = value.match(SVG.regex.unit) + + if (match) { + /* make value numeric */ + this.value = parseFloat(match[1]) - /* normalize percent value */ - if (match[2] == '%') - this.value /= 100 - else if (match[2] == 's') - this.value *= 1000 + /* normalize percent value */ + if (match[2] == '%') + this.value /= 100 + else if (match[2] == 's') + this.value *= 1000 - /* store unit */ - this.unit = match[2] - } - - break - default: - if (value instanceof SVG.Number) { - this.value = value.value - this.unit = value.unit - } - break + /* store unit */ + this.unit = match[2] + } + + } else { + if (value instanceof SVG.Number) { + this.value = value.value + this.unit = value.unit + } } + } SVG.extend(SVG.Number, { @@ -827,7 +777,7 @@ /* make sure a destination is defined */ if (!this.destination) return this - /* generate morphed number */ + /* generate new morphed number */ return new SVG.Number(this.destination) .minus(this) .times(pos) @@ -927,10 +877,9 @@ this.width = box.width * element.trans.scaleX this.height = box.height * element.trans.scaleY } - - /* add the center */ - this.cx = this.x + this.width / 2 - this.cy = this.y + this.height / 2 + + /* add center, right and bottom */ + boxProperties(this) } @@ -946,9 +895,8 @@ b.width = Math.max(this.x + this.width, box.x + box.width) - b.x b.height = Math.max(this.y + this.height, box.y + box.height) - b.y - /* add the center */ - b.cx = b.x + b.width / 2 - b.cy = b.y + b.height / 2 + /* add center, right and bottom */ + boxProperties(b) return b } @@ -1002,9 +950,8 @@ this.width = box.width /= zoom this.height = box.height /= zoom - /* add the center */ - this.cx = this.x + this.width / 2 - this.cy = this.y + this.height / 2 + /* add center, right and bottom */ + boxProperties(this) } @@ -1020,9 +967,8 @@ b.width = Math.max(this.x + this.width, box.x + box.width) - b.x b.height = Math.max(this.y + this.height, box.y + box.height) - b.y - /* add the center */ - b.cx = b.x + b.width / 2 - b.cy = b.y + b.height / 2 + /* add center, right and bottom */ + boxProperties(b) return b } @@ -1034,14 +980,11 @@ create: function(node) { /* make stroke value accessible dynamically */ this._stroke = SVG.defaults.attrs.stroke - - /* initialize style store */ - this.styles = {} - + /* initialize transformation store with defaults */ this.trans = SVG.defaults.trans() - /* keep reference to the element node */ + /* create circular reference */ if (this.node = node) { this.type = node.nodeName this.node.instance = this @@ -1052,7 +995,7 @@ , extend: { // Move over x-axis x: function(x) { - if (x) { + if (x != null) { x = new SVG.Number(x) x.value /= this.trans.scaleX } @@ -1060,7 +1003,7 @@ } // Move over y-axis , y: function(y) { - if (y) { + if (y != null) { y = new SVG.Number(y) y.value /= this.trans.scaleY } @@ -1092,7 +1035,7 @@ } // Set element size to given width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr({ width: new SVG.Number(p.width) @@ -1164,7 +1107,7 @@ a = {} v = this.node.attributes for (n = v.length - 1; n >= 0; n--) - a[v[n].nodeName] = SVG.regex.test(v[n].nodeValue, 'isNumber') ? parseFloat(v[n].nodeValue) : v[n].nodeValue + a[v[n].nodeName] = SVG.regex.isNumber.test(v[n].nodeValue) ? parseFloat(v[n].nodeValue) : v[n].nodeValue return a @@ -1181,7 +1124,7 @@ v = this.node.getAttribute(a) return v == null ? SVG.defaults.attrs[a] : - SVG.regex.test(v, 'isNumber') ? + SVG.regex.isNumber.test(v) ? parseFloat(v) : v } else if (a == 'style') { @@ -1206,14 +1149,14 @@ }) } - /* ensure full hex color */ - if (SVG.Color.isColor(v)) - v = new SVG.Color(v) - - /* ensure correct numeric values */ - else if (typeof v === 'number') + /* ensure correct numeric values (also accepts NaN and Infinity) */ + if (typeof v === 'number') v = new SVG.Number(v) + /* ensure full hex color */ + else if (SVG.Color.isColor(v)) + v = new SVG.Color(v) + /* parse array values */ else if (Array.isArray(v)) v = new SVG.Array(v) @@ -1224,8 +1167,8 @@ if (this.leading) this.leading(v) } else { - /* set give attribute on node */ - n != null ? + /* set given attribute on node */ + typeof n === 'string' ? this.node.setAttributeNS(n, a, v.toString()) : this.node.setAttribute(a, v.toString()) } @@ -1260,7 +1203,7 @@ var transform = [] /* parse matrix */ - o = this._parseMatrix(o) + o = parseMatrix(o) /* merge values */ for (v in o) @@ -1314,7 +1257,7 @@ , style: function(s, v) { if (arguments.length == 0) { /* get full style */ - return this.attr('style') || '' + return this.node.style.cssText || '' } else if (arguments.length < 2) { /* apply every style individually if an object is passed */ @@ -1326,37 +1269,19 @@ s = s.split(';') /* apply every definition individually */ - for (var i = 0; i < s.length; i++) { - v = s[i].split(':') - - if (v.length == 2) - this.style(v[0].replace(/\s+/g, ''), v[1].replace(/^\s+/,'').replace(/\s+$/,'')) + for (v = 0; v < s.length; v++) { + v = s[v].split(':') + this.style(v[0].replace(/\s+/g, ''), v[1]) } } else { /* act as a getter if the first and only argument is not an object */ - return this.styles[s] + return this.node.style[camelCase(s)] } - } else if (v === null || SVG.regex.test(v, 'isBlank')) { - /* remove value */ - delete this.styles[s] - } else { - /* store value */ - this.styles[s] = v + this.node.style[camelCase(s)] = v === null || SVG.regex.isBlank.test(v) ? null : v } - /* rebuild style string */ - s = '' - for (v in this.styles) - s += v + ':' + this.styles[v] + ';' - - /* apply style */ - if (s == '') - this.node.removeAttribute('style') - else - this.node.setAttribute('style', s) - return this } // Get bounding box @@ -1401,43 +1326,7 @@ return element } - // Private: parse a matrix string - , _parseMatrix: function(o) { - if (o.matrix) { - /* split matrix string */ - var m = o.matrix.replace(/\s/g, '').split(',') - - /* pasrse values */ - if (m.length == 6) { - o.a = parseFloat(m[0]) - o.b = parseFloat(m[1]) - o.c = parseFloat(m[2]) - o.d = parseFloat(m[3]) - o.e = parseFloat(m[4]) - o.f = parseFloat(m[5]) - } - } - - return o - } - // Private: calculate proportional width and height values when necessary - , _proportionalSize: function(width, height) { - if (width == null || height == null) { - var box = this.bbox() - - if (height == null) - height = box.height / box.width * width - else if (width == null) - width = box.width / box.height * height - } - - return { - width: width - , height: height - } - } } - }) SVG.Parent = SVG.invent({ @@ -1678,30 +1567,34 @@ } else { /* run all x-position properties */ if (fx._x) - element.x(at(fx._x, pos)) + element.x(fx._x.at(pos)) else if (fx._cx) - element.cx(at(fx._cx, pos)) + element.cx(fx._cx.at(pos)) /* run all y-position properties */ if (fx._y) - element.y(at(fx._y, pos)) + element.y(fx._y.at(pos)) else if (fx._cy) - element.cy(at(fx._cy, pos)) + element.cy(fx._cy.at(pos)) /* run all size properties */ if (fx._size) - element.size(at(fx._size.width, pos), at(fx._size.height, pos)) + element.size(fx._size.width.at(pos), fx._size.height.at(pos)) } /* run all viewbox properties */ if (fx._viewbox) element.viewbox( - at(fx._viewbox.x, pos) - , at(fx._viewbox.y, pos) - , at(fx._viewbox.width, pos) - , at(fx._viewbox.height, pos) + fx._viewbox.x.at(pos) + , fx._viewbox.y.at(pos) + , fx._viewbox.width.at(pos) + , fx._viewbox.height.at(pos) ) + /* run leading property */ + if (fx._leading) + element.leading(fx._leading.at(pos)) + /* animate attributes */ for (i = akeys.length - 1; i >= 0; i--) element.attr(akeys[i], at(fx.attrs[akeys[i]], pos)) @@ -1736,7 +1629,7 @@ } /* render function */ - fx.render = function(){ + fx.render = function() { if (fx.situation.play === true) { // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby. @@ -1802,7 +1695,7 @@ , transform: function(o, v) { if (arguments.length == 1) { /* parse matrix string */ - o = this.target._parseMatrix(o) + o = parseMatrix(o) /* dlete matrixstring from object */ delete o.matrix @@ -1834,25 +1727,25 @@ } // Animatable x-axis , x: function(x) { - this._x = { from: this.target.x(), to: x } + this._x = new SVG.Number(this.target.x()).morph(x) return this } // Animatable y-axis , y: function(y) { - this._y = { from: this.target.y(), to: y } + this._y = new SVG.Number(this.target.y()).morph(y) return this } // Animatable center x-axis , cx: function(x) { - this._cx = { from: this.target.cx(), to: x } + this._cx = new SVG.Number(this.target.cx()).morph(x) return this } // Animatable center y-axis , cy: function(y) { - this._cy = { from: this.target.cy(), to: y } + this._cy = new SVG.Number(this.target.cy()).morph(y) return this } @@ -1875,8 +1768,8 @@ var box = this.target.bbox() this._size = { - width: { from: box.width, to: width } - , height: { from: box.height, to: height } + width: new SVG.Number(box.width).morph(width) + , height: new SVG.Number(box.height).morph(height) } } @@ -1888,16 +1781,23 @@ return this } + // Add leading method + , leading: function(value) { + if (this.target._leading) + this._leading = new SVG.Number(this.target._leading).morph(value) + + return this + } // Add animatable viewbox , viewbox: function(x, y, width, height) { if (this.target instanceof SVG.Container) { var box = this.target.viewbox() this._viewbox = { - x: { from: box.x, to: x } - , y: { from: box.y, to: y } - , width: { from: box.width, to: width } - , height: { from: box.height, to: height } + x: new SVG.Number(box.x).morph(x) + , y: new SVG.Number(box.y).morph(y) + , width: new SVG.Number(box.width).morph(width) + , height: new SVG.Number(box.height).morph(height) } } @@ -1932,28 +1832,35 @@ return this } // Stop running animation - , stop: function() { - /* stop current animation */ - clearTimeout(this.timeout) - clearInterval(this.interval) - - /* reset storage for properties that need animation */ - this.attrs = {} - this.trans = {} - this.styles = {} - this.situation = {} - - delete this._x - delete this._y - delete this._cx - delete this._cy - delete this._size - delete this._plot - delete this._loop - delete this._after - delete this._during - delete this._viewbox + , stop: function(fulfill) { + /* fulfill animation */ + if (fulfill === true) { + this.animate(0) + } else { + /* stop current animation */ + clearTimeout(this.timeout) + + /* reset storage for properties that need animation */ + this.attrs = {} + this.trans = {} + this.styles = {} + this.situation = {} + + /* delete destinations */ + delete this._x + delete this._y + delete this._cx + delete this._cy + delete this._size + delete this._plot + delete this._loop + delete this._after + delete this._during + delete this._leading + delete this._viewbox + } + return this } // Pause running animation @@ -1990,9 +1897,9 @@ return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(d, ease, delay) } // Stop current animation; this is an alias to the fx instance - , stop: function() { + , stop: function(fulfill) { if (this.fx) - this.fx.stop() + this.fx.stop(fulfill) return this } @@ -2013,37 +1920,15 @@ } }) - - // Calculate position according to from and to - function at(o, pos) { - /* number recalculation (don't bother converting to SVG.Number for performance reasons) */ - return typeof o.from == 'number' ? - o.from + (o.to - o.from) * pos : - - /* instance recalculation */ - o instanceof SVG.Color || o instanceof SVG.Number ? o.at(pos) : - - /* for all other values wait until pos has reached 1 to return the final value */ - pos < 1 ? o.from : o.to - } - - // Shim layer with setTimeout fallback by Paul Irish - window.requestAnimFrame = (function(){ - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.msRequestAnimationFrame || - function (c) { window.setTimeout(c, 1000 / 60) } - })() SVG.extend(SVG.Element, SVG.FX, { // Relative move over x axis dx: function(x) { - return this.x(this.x() + x) + return this.x((this.target || this).x() + x) } // Relative move over y axis , dy: function(y) { - return this.y(this.y() + y) + return this.y((this.target || this).y() + y) } // Relative move over x and y axes , dmove: function(x, y) { @@ -2675,7 +2560,7 @@ } // Custom size function , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr({ rx: new SVG.Number(p.width).divide(2) @@ -2751,7 +2636,7 @@ } // Set line size by width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.width(p.width).height(p.height) } @@ -2842,7 +2727,7 @@ } // Set element size to given width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr('points', this.array.size(p.width, p.height)) } @@ -2876,7 +2761,7 @@ } // Set element size to given width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr('d', this.array.size(p.width, p.height)) } @@ -2929,7 +2814,7 @@ p.size(self.width(), self.height()) /* callback */ - if (typeof self._loaded == 'function') + if (typeof self._loaded === 'function') self._loaded.call(self, { width: img.width , height: img.height @@ -2954,6 +2839,7 @@ return this.put(new SVG.Image).load(source).size(width || 0, height || width || 0) } } + }) SVG.Text = SVG.invent({ @@ -2961,9 +2847,9 @@ create: function() { this.constructor.call(this, SVG.create('text')) - this._leading = new SVG.Number(1.3) /* store leading value for rebuilding */ - this._rebuild = true /* enable automatic updating of dy values */ - this._build = false /* disable build mode for adding multiple lines */ + this._leading = new SVG.Number(1.3) /* store leading value for rebuilding */ + this._rebuild = true /* enable automatic updating of dy values */ + this._build = false /* disable build mode for adding multiple lines */ /* set default font */ this.attr('font-family', SVG.defaults.attrs['font-family']) @@ -2988,11 +2874,13 @@ } // Move over y-axis , y: function(y) { + var o = this.attr('y') - this.bbox().y + /* act as getter */ if (y == null) - return this.attr('y') + return this.attr('y') - o - return this.attr('y', y + this.attr('y') - this.bbox().y) + return this.attr('y', y + o) } // Move center over x-axis , cx: function(x) { @@ -3002,14 +2890,6 @@ , cy: function(y) { return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2) } - // Move element to given x and y values - , move: function(x, y) { - return this.x(x).y(y) - } - // Move element by its center - , center: function(x, y) { - return this.cx(x).cy(y) - } // Set the text content , text: function(text) { /* act as getter */ @@ -3238,7 +3118,7 @@ // Add parent method , construct: { // Create nested svg document - nested: function() { + nested: function() { return this.put(new SVG.Nested) } } @@ -3381,7 +3261,7 @@ }) - SVG.extend(SVG.Text, SVG.FX, { + SVG.extend(SVG.Parent, SVG.Text, SVG.FX, { // Set font font: function(o) { for (var k in o) @@ -3614,4 +3494,128 @@ else if (typeof exports !== 'undefined') exports.SVG = SVG + function camelCase(s) { + return s.toLowerCase().replace(/-(.)/g, function(m, g) { + return g.toUpperCase() + }) + } + + // Ensure to six-based hex + function fullHex(hex) { + return hex.length == 4 ? + [ '#', + hex.substring(1, 2), hex.substring(1, 2) + , hex.substring(2, 3), hex.substring(2, 3) + , hex.substring(3, 4), hex.substring(3, 4) + ].join('') : hex + } + + // Component to hex value + function compToHex(comp) { + var hex = comp.toString(16) + return hex.length == 1 ? '0' + hex : hex + } + + // Calculate proportional width and height values when necessary + function proportionalSize(box, width, height) { + if (width == null || height == null) { + if (height == null) + height = box.height / box.width * width + else if (width == null) + width = box.width / box.height * height + } + + return { + width: width + , height: height + } + } + + // Calculate position according to from and to + function at(o, pos) { + /* number recalculation (don't bother converting to SVG.Number for performance reasons) */ + return typeof o.from == 'number' ? + o.from + (o.to - o.from) * pos : + + /* instance recalculation */ + o instanceof SVG.Color || o instanceof SVG.Number ? o.at(pos) : + + /* for all other values wait until pos has reached 1 to return the final value */ + pos < 1 ? o.from : o.to + } + + // PathArray Helpers + function arrayToString(a) { + for (var i = 0, il = a.length, s = ''; i < il; i++) { + s += a[i][0] + + if (a[i][1] != null) { + s += a[i][1] + + if (a[i][2] != null) { + s += ' ' + s += a[i][2] + + if (a[i][3] != null) { + s += ' ' + s += a[i][3] + s += ' ' + s += a[i][4] + + if (a[i][5] != null) { + s += ' ' + s += a[i][5] + s += ' ' + s += a[i][6] + + if (a[i][7] != null) { + s += ' ' + s += a[i][7] + } + } + } + } + } + } + + return s + ' ' + } + + // Add more bounding box properties + function boxProperties(b) { + b.x2 = b.x + b.width + b.y2 = b.y + b.height + b.cx = b.x + b.width / 2 + b.cy = b.y + b.height / 2 + } + + // Parse a matrix string + function parseMatrix(o) { + if (o.matrix) { + /* split matrix string */ + var m = o.matrix.replace(/\s/g, '').split(',') + + /* pasrse values */ + if (m.length == 6) { + o.a = parseFloat(m[0]) + o.b = parseFloat(m[1]) + o.c = parseFloat(m[2]) + o.d = parseFloat(m[3]) + o.e = parseFloat(m[4]) + o.f = parseFloat(m[5]) + } + } + + return o + } + + // Shim layer with setTimeout fallback by Paul Irish + window.requestAnimFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.msRequestAnimationFrame || + function (c) { window.setTimeout(c, 1000 / 60) } + })() + }).call(this); diff --git a/dist/svg.min.js b/dist/svg.min.js index 4f4f0f5..76b553c 100755 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1,2 +1,2 @@ -(function(){function t(t){for(var e=0,i=t.length,n="";i>e;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 e(t,e){return"number"==typeof t.from?t.from+(t.to-t.from)*e:t instanceof SVG.Color||t instanceof SVG.Number?t.at(e):1>e?t.from:t.to}if(this.SVG=function(t){return SVG.supported?(t=new SVG.Doc(t),SVG.parser||SVG.prepare(t),t):void 0},SVG.ns="http://www.w3.org/2000/svg",SVG.xmlns="http://www.w3.org/2000/xmlns/",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.Set&&SVG.Set.inherit&&SVG.Set.inherit()},SVG.get=function(t){var e=document.getElementById(t);return e?e.instance:void 0},SVG.prepare=function(t){var e=document.getElementsByTagName("body")[0],i=(e?new SVG.Doc(e):t.nested()).size(2,2),n=SVG.create("path");i.node.appendChild(n),SVG.parser={body:e||t.parent,draw:i.style("opacity:0;position:fixed;left:100%;top:100%;overflow:hidden"),poly:i.polyline().node,path:n}},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}(),!SVG.supported)return!1;SVG.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,SVG.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&SVG.extend(e,t.extend),t.construct&&SVG.extend(t.parent||SVG.Container,t.construct),e},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:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^-?[\d\.]+$/,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif)(\?[^=]+.*)?/i},SVG.defaults={matrix:"1 0 0 1 0 0",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"},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)},morph:function(t){return this.destination=new SVG.Color(t),this},at:function(t){return this.destination?(t=0>t?0:t>1?1:t,new SVG.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},_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&&"number"==typeof t.g&&"number"==typeof t.b},SVG.Color.isColor=function(t){return SVG.Color.isRgb(t)||SVG.Color.test(t)},SVG.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},SVG.extend(SVG.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.lengtht;t++)-1==i.indexOf(this.value[t])&&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=[];i>e;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new SVG.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.replace(/\s+/g," ").replace(/^\s+|\s+$/g,"").split(" ")}}),SVG.PointArray=function(){this.constructor.apply(this,arguments)},SVG.PointArray.prototype=new SVG.Array,SVG.extend(SVG.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];e>t;t++)i.push(this.value[t].join(","));return i.join(" ")},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];i>e;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 SVG.PointArray(n)},parse:function(t){if(t=t.valueOf(),Array.isArray(t))return t;t=this.split(t);for(var e,i=0,n=t.length,r=[];n>i;i++)e=t[i].split(","),r.push([parseFloat(e[0]),parseFloat(e[1])]);return r},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.x;return this},bbox:function(){return SVG.parser.poly.setAttribute("points",this.toString()),SVG.parser.poly.getBBox()}}),SVG.PathArray=function(t,e){this.constructor.call(this,t,e)},SVG.PathArray.prototype=new SVG.Array,SVG.extend(SVG.PathArray,{toString:function(){return t(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(e){if(e instanceof SVG.PathArray)return e.valueOf();var i,n,r,s,h,o,a,u,l,c,f,p=0,d=0;for(SVG.parser.path.setAttribute("d","string"==typeof e?e:t(e)),f=SVG.parser.path.pathSegList,i=0,n=f.numberOfItems;n>i;++i)c=f.getItem(i),l=c.pathSegTypeAsLetter,"M"==l||"L"==l||"H"==l||"V"==l||"C"==l||"S"==l||"Q"==l||"T"==l||"A"==l?("x"in c&&(p=c.x),"y"in c&&(d=c.y)):("x1"in c&&(h=p+c.x1),"x2"in c&&(a=p+c.x2),"y1"in c&&(o=d+c.y1),"y2"in c&&(u=d+c.y2),"x"in c&&(p+=c.x),"y"in c&&(d+=c.y),"m"==l?f.replaceItem(SVG.parser.path.createSVGPathSegMovetoAbs(p,d),i):"l"==l?f.replaceItem(SVG.parser.path.createSVGPathSegLinetoAbs(p,d),i):"h"==l?f.replaceItem(SVG.parser.path.createSVGPathSegLinetoHorizontalAbs(p),i):"v"==l?f.replaceItem(SVG.parser.path.createSVGPathSegLinetoVerticalAbs(d),i):"c"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicAbs(p,d,h,o,a,u),i):"s"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicSmoothAbs(p,d,a,u),i):"q"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticAbs(p,d,h,o),i):"t"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticSmoothAbs(p,d),i):"a"==l?f.replaceItem(SVG.parser.path.createSVGPathSegArcAbs(p,d,c.r1,c.r2,c.angle,c.largeArcFlag,c.sweepFlag),i):("z"==l||"Z"==l)&&(p=r,d=s)),("M"==l||"m"==l)&&(r=p,s=d);for(e=[],f=SVG.parser.path.pathSegList,i=0,n=f.numberOfItems;n>i;++i)c=f.getItem(i),l=c.pathSegTypeAsLetter,p=[l],"M"==l||"L"==l||"T"==l?p.push(c.x,c.y):"H"==l?p.push(c.x):"V"==l?p.push(c.y):"C"==l?p.push(c.x1,c.y1,c.x2,c.y2,c.x,c.y):"S"==l?p.push(c.x2,c.y2,c.x,c.y):"Q"==l?p.push(c.x1,c.y1,c.x,c.y):"A"==l&&p.push(c.r1,c.r2,c.angle,0|c.largeArcFlag,0|c.sweepFlag,c.x,c.y),e.push(p);return e},bbox:function(){return SVG.parser.path.setAttribute("d",this.toString()),SVG.parser.path.getBBox()}}),SVG.Number=function(t){switch(this.value=0,this.unit="",typeof t){case"number":this.value=isNaN(t)?0:isFinite(t)?t:0>t?-3.4e38:3.4e38;break;case"string":var e=t.match(SVG.regex.unit);e&&(this.value=parseFloat(e[1]),"%"==e[2]?this.value/=100:"s"==e[2]&&(this.value*=1e3),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?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},valueOf:function(){return this.value},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},to:function(t){return"string"==typeof t&&(this.unit=t),this},morph:function(t){return this.destination=new SVG.Number(t),this},at:function(t){return this.destination?new SVG.Number(this.destination).minus(this).times(t).plus(this):this}}),SVG.ViewBox=function(t){var e,i,n,r,s=1,h=1,o=t.bbox(),a=(t.attr("viewBox")||"").match(/-?[\d\.]+/g);for(n=new SVG.Number(t.width()),r=new SVG.Number(t.height());"%"==n.unit;)s*=n.value,n=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetWidth:t.width());for(;"%"==r.unit;)h*=r.value,r=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetHeight:t.height());this.x=o.x,this.y=o.y,this.width=n*s,this.height=r*h,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)},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.extend(SVG.RBox,{merge:function(t){var e=new SVG.RBox;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.Element=SVG.invent({create: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)},extend:{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.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=this._proportionalSize(t,e);return this.attr({width:new SVG.Number(i.width),height:new SVG.Number(i.height)})},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},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(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 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);"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),("fill"==t||"stroke"==t)&&(SVG.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof SVG.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),SVG.Color.isColor(e)?e=new SVG.Color(e):"number"==typeof e?e=new SVG.Number(e):Array.isArray(e)&&(e=new SVG.Array(e)),"leading"==t?this.leading&&this.leading(e):null!=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},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+" "+(null==t.cx?this.bbox().cx:t.cx)+" "+(null==t.cy?this.bbox().cy:t.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("+new SVG.Number(t.x/t.scaleX)+" "+new SVG.Number(t.y/t.scaleY)+")"),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},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")},toString:function(){return this.attr("id")},_parent:function(t){for(var e=this;null!=e&&!(e instanceof t);)e=e.parent;return e},_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},_proportionalSize:function(t,e){if(null==t||null==e){var i=this.bbox();null==e?e=i.height/i.width*t:null==t&&(t=i.width/i.height*e)}return{width:t,height:e}}}}),SVG.Parent=SVG.invent({create:function(t){this.constructor.call(this,t)},inherit:SVG.Element,extend:{children:function(){return this._children||(this._children=[])},add:function(t,e){return this.has(t)||(e=null==e?this.children().length:e,t.parent&&t.parent.children().splice(t.parent.index(t),1),this.children().splice(e,0,t),this.node.insertBefore(t.node,this.node.childNodes[e]||null),t.parent=this),this._defs&&(this.node.removeChild(this._defs.node),this.node.appendChild(this._defs.node)),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return this.children().indexOf(t)},get:function(t){return this.children()[t]},first:function(){return this.children()[0]},last:function(){return this.children()[this.children().length-1]},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;n>i;i++)r[i]instanceof SVG.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof SVG.Container&&r[i].each(t,e);return this},removeElement:function(t){return this.children().splice(this.index(t),1),this.node.removeChild(t.node),t.parent=null,this},clear:function(){for(var t=this.children().length-1;t>=0;t--)this.removeElement(this.children()[t]);return this._defs&&this._defs.clear(),this},defs:function(){return this.doc().defs()}}}),SVG.Container=SVG.invent({create:function(t){this.constructor.call(this,t)},inherit:SVG.Parent,extend:{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))}}}),SVG.FX=SVG.invent({create:function(t){this.target=t},extend:{animate:function(t,i,n){var r,s,h,o,a=this.target,u=this;return"object"==typeof t&&(n=t.delay,i=t.ease,t=t.duration),t="="==t?t:null==t?1e3:new SVG.Number(t).valueOf(),i=i||"<>",u.to=function(t){var n;if(t=0>t?0:t>1?1:t,null==r){r=[];for(o in u.attrs)r.push(o);if(a.morphArray&&(u._plot||r.indexOf("points")>-1)){var l,c=new a.morphArray(u._plot||u.attrs.points||a.array);u._size&&c.size(u._size.width.to,u._size.height.to),l=c.bbox(),u._x?c.move(u._x.to,l.y):u._cx&&c.move(u._cx.to-l.width/2,l.y),l=c.bbox(),u._y?c.move(l.x,u._y.to):u._cy&&c.move(l.x,u._cy.to-l.height/2),delete u._x,delete u._y,delete u._cx,delete u._cy,delete u._size,u._plot=a.array.morph(c)}}if(null==s){s=[];for(o in u.trans)s.push(o)}if(null==h){h=[];for(o in u.styles)h.push(o)}for(t="<>"==i?-Math.cos(t*Math.PI)/2+.5:">"==i?Math.sin(t*Math.PI/2):"<"==i?-Math.cos(t*Math.PI/2)+1:"-"==i?t:"function"==typeof i?i(t):t,u._plot?a.plot(u._plot.at(t)):(u._x?a.x(e(u._x,t)):u._cx&&a.cx(e(u._cx,t)),u._y?a.y(e(u._y,t)):u._cy&&a.cy(e(u._cy,t)),u._size&&a.size(e(u._size.width,t),e(u._size.height,t))),u._viewbox&&a.viewbox(e(u._viewbox.x,t),e(u._viewbox.y,t),e(u._viewbox.width,t),e(u._viewbox.height,t)),n=r.length-1;n>=0;n--)a.attr(r[n],e(u.attrs[r[n]],t));for(n=s.length-1;n>=0;n--)a.transform(s[n],e(u.trans[s[n]],t));for(n=h.length-1;n>=0;n--)a.style(h[n],e(u.styles[h[n]],t));u._during&&u._during.call(a,t,function(i,n){return e({from:i,to:n},t)})},"number"==typeof t&&(this.timeout=setTimeout(function(){var e=(new Date).getTime();u.situation={interval:1e3/60,start:e,play:!0,finish:e+t,duration:t},u.render=function(){if(u.situation.play===!0){var e=(new Date).getTime(),r=e>u.situation.finish?1:(e-u.situation.start)/t;u.to(r),e>u.situation.finish?(u._plot&&a.plot(new SVG.PointArray(u._plot.destination).settle()),u._loop===!0||"number"==typeof u._loop&&u._loop>1?("number"==typeof u._loop&&--u._loop,u.animate(t,i,n)):u._after?u._after.apply(a,[u]):u.stop()):requestAnimFrame(u.render)}else requestAnimFrame(u.render)},u.render()},new SVG.Number(n).valueOf())),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{var n=this.target.attr(t);this.attrs[t]=SVG.Color.isColor(n)?new SVG.Color(n).morph(e):SVG.regex.unit.test(n)?new SVG.Number(n).morph(e):{from:n,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},plot:function(t){return this._plot=t,this},viewbox:function(t,e,i,n){if(this.target instanceof SVG.Container){var r=this.target.viewbox();this._viewbox={x:{from:r.x,to:t},y:{from:r.y,to:e},width:{from:r.width,to:i},height:{from:r.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},loop:function(t){return this._loop=t||!0,this},stop:function(){return clearTimeout(this.timeout),clearInterval(this.interval),this.attrs={},this.trans={},this.styles={},this.situation={},delete this._x,delete this._y,delete this._cx,delete this._cy,delete this._size,delete this._plot,delete this._loop,delete this._after,delete this._during,delete this._viewbox,this},pause:function(){return this.situation.play===!0&&(this.situation.play=!1,this.situation.pause=(new Date).getTime()),this},play:function(){if(this.situation.play===!1){var t=(new Date).getTime()-this.situation.pause;this.situation.finish+=t,this.situation.start+=t,this.situation.play=!0}return this}},parent:SVG.Element,construct:{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},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this}}}),window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}(),SVG.extend(SVG.Element,SVG.FX,{dx:function(t){return this.x(this.x()+t)},dy:function(t){return this.y(this.y()+t)},dmove:function(t,e){return this.dx(t).dy(e)}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchmove","touchleave","touchend","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.Defs=SVG.invent({create:"defs",inherit:SVG.Container}),SVG.G=SVG.invent({create:"g",inherit:SVG.Container,extend:{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)},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)}},construct:{group:function(){return this.put(new SVG.G)}}}),SVG.extend(SVG.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();return this.parent.removeElement(this).put(this,t+1)},backward:function(){var t=this.position();return t>0&&this.parent.removeElement(this).add(this,t-1),this},front:function(){return this.parent.removeElement(this).put(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}}),SVG.Mask=SVG.invent({create:function(){this.constructor.call(this,SVG.create("mask")),this.targets=[]},inherit:SVG.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return delete this.targets,this.parent.removeElement(this),this}},construct:{mask:function(){return this.defs().put(new SVG.Mask)}}}),SVG.extend(SVG.Element,{maskWith:function(t){return this.masker=t instanceof SVG.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)}}),SVG.Clip=SVG.invent({create:function(){this.constructor.call(this,SVG.create("clipPath")),this.targets=[]},inherit:SVG.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return delete this.targets,this.parent.removeElement(this),this}},construct:{clip:function(){return this.defs().put(new SVG.Clip)}}}),SVG.extend(SVG.Element,{clipWith:function(t){return this.clipper=t instanceof SVG.Clip?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)}}),SVG.Gradient=SVG.invent({create:function(t){this.constructor.call(this,SVG.create(t+"Gradient")),this.type=t},inherit:SVG.Container,extend:{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,e,i){return this.put(new SVG.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.attr("id")+")"},toString:function(){return this.fill()}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),SVG.extend(SVG.Defs,{gradient:function(t,e){return this.put(new SVG.Gradient(t)).update(e)}}),SVG.Stop=SVG.invent({create:"stop",inherit:SVG.Element,extend:{update:function(t){return("number"==typeof t||t instanceof SVG.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 SVG.Number(t.offset)),this}}}),SVG.Pattern=SVG.invent({create:"pattern",inherit:SVG.Container,extend:{fill:function(){return"url(#"+this.attr("id")+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),SVG.extend(SVG.Defs,{pattern:function(t,e,i){return this.put(new SVG.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),SVG.Doc=SVG.invent({create: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("xmlns:xlink",SVG.xlink,SVG.xmlns),this._defs=new SVG.Defs,this._defs.parent=this,this.node.appendChild(this._defs.node),this.doSpof=!1,this.parent!=this.node&&this.stage()},inherit:SVG.Container,extend:{stage:function(){var t=this;return this.parent.appendChild(this.node),t.spof(),SVG.on(window,"resize",function(){t.spof()}),this},defs:function(){return this._defs},spof:function(){if(this.doSpof){var t=this.node.getScreenCTM();t&&this.style("left",-t.e%1+"px").style("top",-t.f%1+"px")}return this},fixSubPixelOffset:function(){return this.doSpof=!0,this}}}),SVG.Shape=SVG.invent({create:function(t){this.constructor.call(this,t)},inherit:SVG.Element}),SVG.Use=SVG.invent({create:"use",inherit:SVG.Shape,extend:{element:function(t){return this.target=t,this.attr("href","#"+t,SVG.xlink)}},construct:{use:function(t){return this.put(new SVG.Use).element(t)}}}),SVG.Rect=SVG.invent({create:"rect",inherit:SVG.Shape,construct:{rect:function(t,e){return this.put((new SVG.Rect).size(t,e))}}}),SVG.Ellipse=SVG.invent({create:"ellipse",inherit:SVG.Shape,extend:{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))},width:function(t){return null==t?2*this.attr("rx"):this.attr("rx",new SVG.Number(t).divide(2))},height:function(t){return null==t?2*this.attr("ry"):this.attr("ry",new SVG.Number(t).divide(2))},size:function(t,e){var i=this._proportionalSize(t,e);return this.attr({rx:new SVG.Number(i.width).divide(2),ry:new SVG.Number(i.height).divide(2)})}},construct:{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=SVG.invent({create:"line",inherit:SVG.Shape,extend:{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)},width:function(t){var e=this.bbox();return null==t?e.width:this.attr(this.attr("x1")e;e++)this.tspan(t[e]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this._leading:(this._leading=new SVG.Number(t),this.rebuild())},rebuild:function(t){var e=this;return"boolean"==typeof t&&(this._rebuild=t),this._rebuild&&this.lines.each(function(){this.newLined&&(this.textPath||this.attr("x",e.attr("x")),this.attr("dy",e._leading*new SVG.Number(e.attr("font-size"))))}),this},build:function(t){return this._build=!!t,this}},construct:{text:function(t){return this.put(new SVG.Text).text(t)},plain:function(t){return this.put(new SVG.Text).plain(t)}}}),SVG.TSpan=SVG.invent({create:"tspan",inherit:SVG.Shape,extend:{text:function(t){return"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.doc(SVG.Text);return this.newLined=!0,this.dy(t._leading*t.attr("font-size")).attr("x",t.x())}}}),SVG.extend(SVG.Text,SVG.TSpan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(document.createTextNode(this.content=t)),this},tspan:function(t){var e=(this.textPath||this).node,i=new SVG.TSpan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.parent=this,this instanceof SVG.Text&&this.lines.add(i),i.text(t)},clear:function(){for(var t=(this.textPath||this).node;t.hasChildNodes();)t.removeChild(t.lastChild);return this instanceof SVG.Text&&(delete this.lines,this.lines=new SVG.Set,this.content=""),this}}),SVG.TextPath=SVG.invent({create:"textPath",inherit:SVG.Element,parent:SVG.Text,construct:{path:function(t){for(this.textPath=new SVG.TextPath;this.node.hasChildNodes();)this.textPath.node.appendChild(this.node.firstChild);return this.node.appendChild(this.textPath.node),this.track=this.doc().defs().path(t),this.textPath.parent=this,this.textPath.attr("href","#"+this.track,SVG.xlink),this},plot:function(t){return this.track&&this.track.plot(t),this}}}),SVG.Nested=SVG.invent({create:function(){this.constructor.call(this,SVG.create("svg")),this.style("overflow","visible")},inherit:SVG.Container,construct:{nested:function(){return this.put(new SVG.Nested)}}}),SVG.A=SVG.invent({create:"a",inherit:SVG.Container,extend:{to:function(t){return this.attr("href",t,SVG.xlink)},show:function(t){return this.attr("show",t,SVG.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new SVG.A).to(t)}}}),SVG.extend(SVG.Element,{linkTo:function(t){var e=new SVG.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent.put(e).put(this)}});var i={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"==e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,n={};n[t]=function(n){if("string"==typeof n||SVG.Color.isRgb(n)||n&&"function"==typeof n.fill)this.attr(t,n);else for(e=i[t].length-1;e>=0;e--)null!=n[i[t][e]]&&this.attr(i.prefix(t,i[t][e]),n[i[t][e]]);return this},SVG.extend(SVG.Element,SVG.FX,n)}),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.extend(SVG.Rect,SVG.Ellipse,SVG.FX,{radius:function(t,e){return this.attr({rx:t,ry:e||t})}}),SVG.extend(SVG.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),SVG.extend(SVG.Text,SVG.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}}),SVG.Set=SVG.invent({create:function(){this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;e>t;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;i>e;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},has:function(t){return this.index(t)>=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},valueOf:function(){return this.members},bbox:function(){var t=new SVG.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(){return new SVG.Set}}}),SVG.SetFX=SVG.invent({create:function(t){this.set=t}}),SVG.Set.inherit=function(){var t,e=[];for(var t in SVG.Shape.prototype)"function"==typeof SVG.Shape.prototype[t]&&"function"!=typeof SVG.Set.prototype[t]&&e.push(t);e.forEach(function(t){SVG.Set.prototype[t]=function(){for(var e=0,i=this.members.length;i>e;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 SVG.SetFX(this)):this}}),e=[];for(var t in SVG.FX.prototype)"function"==typeof SVG.FX.prototype[t]&&"function"!=typeof SVG.SetFX.prototype[t]&&e.push(t);e.forEach(function(t){SVG.SetFX.prototype[t]=function(){for(var e=0,i=this.set.members.length;i>e;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},SVG.extend(SVG.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else 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}}),SVG.extend(SVG.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={})}}),"function"==typeof define&&define.amd?define(function(){return SVG}):"undefined"!=typeof exports&&(exports.SVG=SVG)}).call(this); \ No newline at end of file +(function(){function t(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function e(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 i(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function n(t,e,i){return(null==e||null==i)&&(null==i?i=t.height/t.width*e:null==e&&(e=t.width/t.height*i)),{width:e,height:i}}function r(t,e){return"number"==typeof t.from?t.from+(t.to-t.from)*e:t instanceof SVG.Color||t instanceof SVG.Number?t.at(e):1>e?t.from:t.to}function s(t){for(var e=0,i=t.length,n="";i>e;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 h(t){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}function o(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}if(this.SVG=function(t){return SVG.supported?(t=new SVG.Doc(t),SVG.parser||SVG.prepare(t),t):void 0},SVG.ns="http://www.w3.org/2000/svg",SVG.xmlns="http://www.w3.org/2000/xmlns/",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.Set&&SVG.Set.inherit&&SVG.Set.inherit()},SVG.get=function(t){var e=document.getElementById(t);return e?e.instance:void 0},SVG.prepare=function(t){var e=document.getElementsByTagName("body")[0],i=(e?new SVG.Doc(e):t.nested()).size(2,2),n=SVG.create("path");i.node.appendChild(n),SVG.parser={body:e||t.parent,draw:i.style("opacity:0;position:fixed;left:100%;top:100%;overflow:hidden"),poly:i.polyline().node,path:n}},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}(),!SVG.supported)return!1;SVG.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,SVG.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&SVG.extend(e,t.extend),t.construct&&SVG.extend(t.parent||SVG.Container,t.construct),e},SVG.regex={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:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^-?[\d\.]+$/,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif)(\?[^=]+.*)?/i},SVG.defaults={matrix:"1 0 0 1 0 0",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"},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 i;this.r=0,this.g=0,this.b=0,"string"==typeof t?SVG.regex.isRgb.test(t)?(i=SVG.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(i[1]),this.g=parseInt(i[2]),this.b=parseInt(i[3])):SVG.regex.isHex.test(t)&&(i=SVG.regex.hex.exec(e(t)),this.r=parseInt(i[1],16),this.g=parseInt(i[2],16),this.b=parseInt(i[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"#"+i(this.r)+i(this.g)+i(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)},morph:function(t){return this.destination=new SVG.Color(t),this},at:function(t){return this.destination?(t=0>t?0:t>1?1:t,new SVG.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}}),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&&"number"==typeof t.g&&"number"==typeof t.b},SVG.Color.isColor=function(t){return SVG.Color.isRgb(t)||SVG.Color.test(t)},SVG.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},SVG.extend(SVG.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.lengtht;t++)-1==i.indexOf(this.value[t])&&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=[];i>e;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new SVG.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.replace(/\s+/g," ").replace(/^\s+|\s+$/g,"").split(" ")},reverse:function(){return this.value.reverse(),this}}),SVG.PointArray=function(){this.constructor.apply(this,arguments)},SVG.PointArray.prototype=new SVG.Array,SVG.extend(SVG.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];e>t;t++)i.push(this.value[t].join(","));return i.join(" ")},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];i>e;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 SVG.PointArray(n)},parse:function(t){if(t=t.valueOf(),Array.isArray(t))return t;t=this.split(t);for(var e,i=0,n=t.length,r=[];n>i;i++)e=t[i].split(","),r.push([parseFloat(e[0]),parseFloat(e[1])]);return r},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.x;return this},bbox:function(){return SVG.parser.poly.setAttribute("points",this.toString()),SVG.parser.poly.getBBox()}}),SVG.PathArray=function(t,e){this.constructor.call(this,t,e)},SVG.PathArray.prototype=new SVG.Array,SVG.extend(SVG.PathArray,{toString:function(){return s(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 SVG.PathArray)return t.valueOf();var e,i,n,r,h,o,a,u,l,c,f,p=0,d=0;for(SVG.parser.path.setAttribute("d","string"==typeof t?t:s(t)),f=SVG.parser.path.pathSegList,e=0,i=f.numberOfItems;i>e;++e)c=f.getItem(e),l=c.pathSegTypeAsLetter,"M"==l||"L"==l||"H"==l||"V"==l||"C"==l||"S"==l||"Q"==l||"T"==l||"A"==l?("x"in c&&(p=c.x),"y"in c&&(d=c.y)):("x1"in c&&(h=p+c.x1),"x2"in c&&(a=p+c.x2),"y1"in c&&(o=d+c.y1),"y2"in c&&(u=d+c.y2),"x"in c&&(p+=c.x),"y"in c&&(d+=c.y),"m"==l?f.replaceItem(SVG.parser.path.createSVGPathSegMovetoAbs(p,d),e):"l"==l?f.replaceItem(SVG.parser.path.createSVGPathSegLinetoAbs(p,d),e):"h"==l?f.replaceItem(SVG.parser.path.createSVGPathSegLinetoHorizontalAbs(p),e):"v"==l?f.replaceItem(SVG.parser.path.createSVGPathSegLinetoVerticalAbs(d),e):"c"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicAbs(p,d,h,o,a,u),e):"s"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicSmoothAbs(p,d,a,u),e):"q"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticAbs(p,d,h,o),e):"t"==l?f.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticSmoothAbs(p,d),e):"a"==l?f.replaceItem(SVG.parser.path.createSVGPathSegArcAbs(p,d,c.r1,c.r2,c.angle,c.largeArcFlag,c.sweepFlag),e):("z"==l||"Z"==l)&&(p=n,d=r)),("M"==l||"m"==l)&&(n=p,r=d);for(t=[],f=SVG.parser.path.pathSegList,e=0,i=f.numberOfItems;i>e;++e)c=f.getItem(e),l=c.pathSegTypeAsLetter,p=[l],"M"==l||"L"==l||"T"==l?p.push(c.x,c.y):"H"==l?p.push(c.x):"V"==l?p.push(c.y):"C"==l?p.push(c.x1,c.y1,c.x2,c.y2,c.x,c.y):"S"==l?p.push(c.x2,c.y2,c.x,c.y):"Q"==l?p.push(c.x1,c.y1,c.x,c.y):"A"==l&&p.push(c.r1,c.r2,c.angle,0|c.largeArcFlag,0|c.sweepFlag,c.x,c.y),t.push(p);return t},bbox:function(){return SVG.parser.path.setAttribute("d",this.toString()),SVG.parser.path.getBBox()}}),SVG.Number=function(t){if(this.value=0,this.unit="","number"==typeof t)this.value=isNaN(t)?0:isFinite(t)?t:0>t?-3.4e38:3.4e38;else if("string"==typeof t){var e=t.match(SVG.regex.unit);e&&(this.value=parseFloat(e[1]),"%"==e[2]?this.value/=100:"s"==e[2]&&(this.value*=1e3),this.unit=e[2])}else t instanceof SVG.Number&&(this.value=t.value,this.unit=t.unit)},SVG.extend(SVG.Number,{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},valueOf:function(){return this.value},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},to:function(t){return"string"==typeof t&&(this.unit=t),this},morph:function(t){return this.destination=new SVG.Number(t),this},at:function(t){return this.destination?new SVG.Number(this.destination).minus(this).times(t).plus(this):this}}),SVG.ViewBox=function(t){var e,i,n,r,s=1,h=1,o=t.bbox(),a=(t.attr("viewBox")||"").match(/-?[\d\.]+/g);for(n=new SVG.Number(t.width()),r=new SVG.Number(t.height());"%"==n.unit;)s*=n.value,n=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetWidth:t.width());for(;"%"==r.unit;)h*=r.value,r=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetHeight:t.height());this.x=o.x,this.y=o.y,this.width=n*s,this.height=r*h,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)},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}h(this)},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,h(e),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,h(this)},SVG.extend(SVG.RBox,{merge:function(t){var e=new SVG.RBox;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,h(e),e}}),SVG.Element=SVG.invent({create:function(t){this._stroke=SVG.defaults.attrs.stroke,this.trans=SVG.defaults.trans(),(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},extend:{x:function(t){return null!=t&&(t=new SVG.Number(t),t.value/=this.trans.scaleX),this.attr("x",t)},y:function(t){return null!=t&&(t=new SVG.Number(t),t.value/=this.trans.scaleY),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=n(this.bbox(),t,e);return this.attr({width:new SVG.Number(i.width),height:new SVG.Number(i.height)})},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},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(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.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?SVG.defaults.attrs[t]:SVG.regex.isNumber.test(e)?parseFloat(e):e;if("style"==t)return this.style(e);"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),("fill"==t||"stroke"==t)&&(SVG.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof SVG.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new SVG.Number(e):SVG.Color.isColor(e)?e=new SVG.Color(e):Array.isArray(e)&&(e=new SVG.Array(e)),"leading"==t?this.leading&&this.leading(e):"string"==typeof i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!=t&&"x"!=t||this.rebuild(t,e)}return this},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=o(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+" "+(null==t.cx?this.bbox().cx:t.cx)+" "+(null==t.cy?this.bbox().cy:t.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("+new SVG.Number(t.x/t.scaleX)+" "+new SVG.Number(t.y/t.scaleY)+")"),0==i.length?this.node.removeAttribute("transform"):this.node.setAttribute("transform",i.join(" ")),this},style:function(e,i){if(0==arguments.length)return this.node.style.cssText||"";if(2>arguments.length)if("object"==typeof e)for(i in e)this.style(i,e[i]);else{if(!SVG.regex.isCss.test(e))return this.node.style[t(e)];for(e=e.split(";"),i=0;e.length>i;i++)i=e[i].split(":"),this.style(i[0].replace(/\s+/g,""),i[1])}else this.node.style[t(e)]=null===i||SVG.regex.isBlank.test(i)?null:i;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")},toString:function(){return this.attr("id")},_parent:function(t){for(var e=this;null!=e&&!(e instanceof t);)e=e.parent;return e}}}),SVG.Parent=SVG.invent({create:function(t){this.constructor.call(this,t)},inherit:SVG.Element,extend:{children:function(){return this._children||(this._children=[])},add:function(t,e){return this.has(t)||(e=null==e?this.children().length:e,t.parent&&t.parent.children().splice(t.parent.index(t),1),this.children().splice(e,0,t),this.node.insertBefore(t.node,this.node.childNodes[e]||null),t.parent=this),this._defs&&(this.node.removeChild(this._defs.node),this.node.appendChild(this._defs.node)),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return this.children().indexOf(t)},get:function(t){return this.children()[t]},first:function(){return this.children()[0]},last:function(){return this.children()[this.children().length-1]},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;n>i;i++)r[i]instanceof SVG.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof SVG.Container&&r[i].each(t,e);return this},removeElement:function(t){return this.children().splice(this.index(t),1),this.node.removeChild(t.node),t.parent=null,this},clear:function(){for(var t=this.children().length-1;t>=0;t--)this.removeElement(this.children()[t]);return this._defs&&this._defs.clear(),this},defs:function(){return this.doc().defs()}}}),SVG.Container=SVG.invent({create:function(t){this.constructor.call(this,t)},inherit:SVG.Parent,extend:{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))}}}),SVG.FX=SVG.invent({create:function(t){this.target=t},extend:{animate:function(t,e,i){var n,s,h,o,a=this.target,u=this;return"object"==typeof t&&(i=t.delay,e=t.ease,t=t.duration),t="="==t?t:null==t?1e3:new SVG.Number(t).valueOf(),e=e||"<>",u.to=function(t){var i;if(t=0>t?0:t>1?1:t,null==n){n=[];for(o in u.attrs)n.push(o);if(a.morphArray&&(u._plot||n.indexOf("points")>-1)){var l,c=new a.morphArray(u._plot||u.attrs.points||a.array);u._size&&c.size(u._size.width.to,u._size.height.to),l=c.bbox(),u._x?c.move(u._x.to,l.y):u._cx&&c.move(u._cx.to-l.width/2,l.y),l=c.bbox(),u._y?c.move(l.x,u._y.to):u._cy&&c.move(l.x,u._cy.to-l.height/2),delete u._x,delete u._y,delete u._cx,delete u._cy,delete u._size,u._plot=a.array.morph(c)}}if(null==s){s=[];for(o in u.trans)s.push(o)}if(null==h){h=[];for(o in u.styles)h.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,u._plot?a.plot(u._plot.at(t)):(u._x?a.x(u._x.at(t)):u._cx&&a.cx(u._cx.at(t)),u._y?a.y(u._y.at(t)):u._cy&&a.cy(u._cy.at(t)),u._size&&a.size(u._size.width.at(t),u._size.height.at(t))),u._viewbox&&a.viewbox(u._viewbox.x.at(t),u._viewbox.y.at(t),u._viewbox.width.at(t),u._viewbox.height.at(t)),u._leading&&a.leading(u._leading.at(t)),i=n.length-1;i>=0;i--)a.attr(n[i],r(u.attrs[n[i]],t));for(i=s.length-1;i>=0;i--)a.transform(s[i],r(u.trans[s[i]],t));for(i=h.length-1;i>=0;i--)a.style(h[i],r(u.styles[h[i]],t));u._during&&u._during.call(a,t,function(e,i){return r({from:e,to:i},t)})},"number"==typeof t&&(this.timeout=setTimeout(function(){var n=(new Date).getTime();u.situation={interval:1e3/60,start:n,play:!0,finish:n+t,duration:t},u.render=function(){if(u.situation.play===!0){var n=(new Date).getTime(),r=n>u.situation.finish?1:(n-u.situation.start)/t;u.to(r),n>u.situation.finish?(u._plot&&a.plot(new SVG.PointArray(u._plot.destination).settle()),u._loop===!0||"number"==typeof u._loop&&u._loop>1?("number"==typeof u._loop&&--u._loop,u.animate(t,e,i)):u._after?u._after.apply(a,[u]):u.stop()):requestAnimFrame(u.render)}else requestAnimFrame(u.render)},u.render()},new SVG.Number(i).valueOf())),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{var n=this.target.attr(t);this.attrs[t]=SVG.Color.isColor(n)?new SVG.Color(n).morph(e):SVG.regex.unit.test(n)?new SVG.Number(n).morph(e):{from:n,to:e}}return this},transform:function(t,e){if(1==arguments.length){t=o(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=new SVG.Number(this.target.x()).morph(t),this},y:function(t){return this._y=new SVG.Number(this.target.y()).morph(t),this},cx:function(t){return this._cx=new SVG.Number(this.target.cx()).morph(t),this},cy:function(t){return this._cy=new SVG.Number(this.target.cy()).morph(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:new SVG.Number(i.width).morph(t),height:new SVG.Number(i.height).morph(e)}}return this},plot:function(t){return this._plot=t,this},leading:function(t){return this.target._leading&&(this._leading=new SVG.Number(this.target._leading).morph(t)),this},viewbox:function(t,e,i,n){if(this.target instanceof SVG.Container){var r=this.target.viewbox();this._viewbox={x:new SVG.Number(r.x).morph(t),y:new SVG.Number(r.y).morph(e),width:new SVG.Number(r.width).morph(i),height:new SVG.Number(r.height).morph(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},loop:function(t){return this._loop=t||!0,this},stop:function(t){return t===!0?this.animate(0):(clearTimeout(this.timeout),this.attrs={},this.trans={},this.styles={},this.situation={},delete this._x,delete this._y,delete this._cx,delete this._cy,delete this._size,delete this._plot,delete this._loop,delete this._after,delete this._during,delete this._leading,delete this._viewbox),this},pause:function(){return this.situation.play===!0&&(this.situation.play=!1,this.situation.pause=(new Date).getTime()),this},play:function(){if(this.situation.play===!1){var t=(new Date).getTime()-this.situation.pause;this.situation.finish+=t,this.situation.start+=t,this.situation.play=!0}return this}},parent:SVG.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new SVG.FX(this))).stop().animate(t,e,i)},stop:function(t){return this.fx&&this.fx.stop(t),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this}}}),SVG.extend(SVG.Element,SVG.FX,{dx:function(t){return this.x((this.target||this).x()+t)},dy:function(t){return this.y((this.target||this).y()+t)},dmove:function(t,e){return this.dx(t).dy(e)}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave","touchstart","touchmove","touchleave","touchend","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.Defs=SVG.invent({create:"defs",inherit:SVG.Container}),SVG.G=SVG.invent({create:"g",inherit:SVG.Container,extend:{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)},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)}},construct:{group:function(){return this.put(new SVG.G)}}}),SVG.extend(SVG.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();return this.parent.removeElement(this).put(this,t+1)},backward:function(){var t=this.position();return t>0&&this.parent.removeElement(this).add(this,t-1),this},front:function(){return this.parent.removeElement(this).put(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}}),SVG.Mask=SVG.invent({create:function(){this.constructor.call(this,SVG.create("mask")),this.targets=[]},inherit:SVG.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return delete this.targets,this.parent.removeElement(this),this}},construct:{mask:function(){return this.defs().put(new SVG.Mask)}}}),SVG.extend(SVG.Element,{maskWith:function(t){return this.masker=t instanceof SVG.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)}}),SVG.Clip=SVG.invent({create:function(){this.constructor.call(this,SVG.create("clipPath")),this.targets=[]},inherit:SVG.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return delete this.targets,this.parent.removeElement(this),this}},construct:{clip:function(){return this.defs().put(new SVG.Clip)}}}),SVG.extend(SVG.Element,{clipWith:function(t){return this.clipper=t instanceof SVG.Clip?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)}}),SVG.Gradient=SVG.invent({create:function(t){this.constructor.call(this,SVG.create(t+"Gradient")),this.type=t},inherit:SVG.Container,extend:{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,e,i){return this.put(new SVG.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.attr("id")+")"},toString:function(){return this.fill()}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),SVG.extend(SVG.Defs,{gradient:function(t,e){return this.put(new SVG.Gradient(t)).update(e)}}),SVG.Stop=SVG.invent({create:"stop",inherit:SVG.Element,extend:{update:function(t){return("number"==typeof t||t instanceof SVG.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 SVG.Number(t.offset)),this}}}),SVG.Pattern=SVG.invent({create:"pattern",inherit:SVG.Container,extend:{fill:function(){return"url(#"+this.attr("id")+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),SVG.extend(SVG.Defs,{pattern:function(t,e,i){return this.put(new SVG.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),SVG.Doc=SVG.invent({create: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("xmlns:xlink",SVG.xlink,SVG.xmlns),this._defs=new SVG.Defs,this._defs.parent=this,this.node.appendChild(this._defs.node),this.doSpof=!1,this.parent!=this.node&&this.stage()},inherit:SVG.Container,extend:{stage:function(){var t=this;return this.parent.appendChild(this.node),t.spof(),SVG.on(window,"resize",function(){t.spof()}),this},defs:function(){return this._defs},spof:function(){if(this.doSpof){var t=this.node.getScreenCTM();t&&this.style("left",-t.e%1+"px").style("top",-t.f%1+"px")}return this},fixSubPixelOffset:function(){return this.doSpof=!0,this}}}),SVG.Shape=SVG.invent({create:function(t){this.constructor.call(this,t)},inherit:SVG.Element}),SVG.Use=SVG.invent({create:"use",inherit:SVG.Shape,extend:{element:function(t){return this.target=t,this.attr("href","#"+t,SVG.xlink)}},construct:{use:function(t){return this.put(new SVG.Use).element(t)}}}),SVG.Rect=SVG.invent({create:"rect",inherit:SVG.Shape,construct:{rect:function(t,e){return this.put((new SVG.Rect).size(t,e))}}}),SVG.Ellipse=SVG.invent({create:"ellipse",inherit:SVG.Shape,extend:{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))},width:function(t){return null==t?2*this.attr("rx"):this.attr("rx",new SVG.Number(t).divide(2))},height:function(t){return null==t?2*this.attr("ry"):this.attr("ry",new SVG.Number(t).divide(2))},size:function(t,e){var i=n(this.bbox(),t,e);return this.attr({rx:new SVG.Number(i.width).divide(2),ry:new SVG.Number(i.height).divide(2)})}},construct:{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=SVG.invent({create:"line",inherit:SVG.Shape,extend:{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)},width:function(t){var e=this.bbox();return null==t?e.width:this.attr(this.attr("x1")e;e++)this.tspan(t[e]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this._leading:(this._leading=new SVG.Number(t),this.rebuild())},rebuild:function(t){var e=this;return"boolean"==typeof t&&(this._rebuild=t),this._rebuild&&this.lines.each(function(){this.newLined&&(this.textPath||this.attr("x",e.attr("x")),this.attr("dy",e._leading*new SVG.Number(e.attr("font-size"))))}),this},build:function(t){return this._build=!!t,this}},construct:{text:function(t){return this.put(new SVG.Text).text(t)},plain:function(t){return this.put(new SVG.Text).plain(t)}}}),SVG.TSpan=SVG.invent({create:"tspan",inherit:SVG.Shape,extend:{text:function(t){return"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.doc(SVG.Text);return this.newLined=!0,this.dy(t._leading*t.attr("font-size")).attr("x",t.x())}}}),SVG.extend(SVG.Text,SVG.TSpan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(document.createTextNode(this.content=t)),this},tspan:function(t){var e=(this.textPath||this).node,i=new SVG.TSpan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.parent=this,this instanceof SVG.Text&&this.lines.add(i),i.text(t)},clear:function(){for(var t=(this.textPath||this).node;t.hasChildNodes();)t.removeChild(t.lastChild);return this instanceof SVG.Text&&(delete this.lines,this.lines=new SVG.Set,this.content=""),this}}),SVG.TextPath=SVG.invent({create:"textPath",inherit:SVG.Element,parent:SVG.Text,construct:{path:function(t){for(this.textPath=new SVG.TextPath;this.node.hasChildNodes();)this.textPath.node.appendChild(this.node.firstChild);return this.node.appendChild(this.textPath.node),this.track=this.doc().defs().path(t),this.textPath.parent=this,this.textPath.attr("href","#"+this.track,SVG.xlink),this},plot:function(t){return this.track&&this.track.plot(t),this}}}),SVG.Nested=SVG.invent({create:function(){this.constructor.call(this,SVG.create("svg")),this.style("overflow","visible")},inherit:SVG.Container,construct:{nested:function(){return this.put(new SVG.Nested)}}}),SVG.A=SVG.invent({create:"a",inherit:SVG.Container,extend:{to:function(t){return this.attr("href",t,SVG.xlink)},show:function(t){return this.attr("show",t,SVG.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new SVG.A).to(t)}}}),SVG.extend(SVG.Element,{linkTo:function(t){var e=new SVG.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent.put(e).put(this)}});var a={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("string"==typeof i||SVG.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=a[t].length-1;e>=0;e--)null!=i[a[t][e]]&&this.attr(a.prefix(t,a[t][e]),i[a[t][e]]);return this},SVG.extend(SVG.Element,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.extend(SVG.Rect,SVG.Ellipse,SVG.FX,{radius:function(t,e){return this.attr({rx:t,ry:e||t})}}),SVG.extend(SVG.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),SVG.extend(SVG.Parent,SVG.Text,SVG.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}}),SVG.Set=SVG.invent({create:function(){this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;e>t;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;i>e;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},has:function(t){return this.index(t)>=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},valueOf:function(){return this.members},bbox:function(){var t=new SVG.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(){return new SVG.Set}}}),SVG.SetFX=SVG.invent({create:function(t){this.set=t}}),SVG.Set.inherit=function(){var t,e=[];for(var t in SVG.Shape.prototype)"function"==typeof SVG.Shape.prototype[t]&&"function"!=typeof SVG.Set.prototype[t]&&e.push(t);e.forEach(function(t){SVG.Set.prototype[t]=function(){for(var e=0,i=this.members.length;i>e;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 SVG.SetFX(this)):this}}),e=[];for(var t in SVG.FX.prototype)"function"==typeof SVG.FX.prototype[t]&&"function"!=typeof SVG.SetFX.prototype[t]&&e.push(t);e.forEach(function(t){SVG.SetFX.prototype[t]=function(){for(var e=0,i=this.set.members.length;i>e;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},SVG.extend(SVG.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else 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}}),SVG.extend(SVG.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={})}}),"function"==typeof define&&define.amd?define(function(){return SVG}):"undefined"!=typeof exports&&(exports.SVG=SVG),window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}()}).call(this); \ No newline at end of file diff --git a/package.json b/package.json index 551b737..510c985 100755 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ , "keywords": ["svg", "vector", "graphics", "animation"] , "author": "Wout Fierens " , "main": "dist/svg.js" -, "version": "1.0.0-rc.5" +, "version": "1.0.0-rc.6" , "jam": { "include": [ "dist/svg.js" @@ -17,8 +17,8 @@ , "maintainers": [ { "name": "Wout Fierens" - , "email": "wout@impinc.co.uk" - , "web": "http://impinc.co.uk" + , "email": "wout@woutfierens.com" + , "web": "http://woutfierens.com" } ] , "licenses": [ diff --git a/spec/spec/array.js b/spec/spec/array.js index c051976..05ea837 100755 --- a/spec/spec/array.js +++ b/spec/spec/array.js @@ -1,36 +1,42 @@ describe('Array', function () { + var array it('parses a matrix array correctly to string', function() { - var array = new SVG.Array([ .343, .669, .119, 0, 0 + array = new SVG.Array([ .343, .669, .119, 0, 0 , .249, -.626, .130, 0, 0 , .172, .334, .111, 0, 0 , .000, .000, .000, 1, -0 ]) expect(array + '').toBe('0.343 0.669 0.119 0 0 0.249 -0.626 0.13 0 0 0.172 0.334 0.111 0 0 0 0 0 1 0') }) - + describe('reverse()', function() { + it('reverses the array', function() { + array = new SVG.Array([1 ,2 ,3, 4, 5]).reverse() + expect(array.value).toEqual([5, 4, 3, 2, 1]) + }) + it('returns itself', function() { + array = new SVG.Array() + expect(array.reverse()).toBe(array) + }) + }) }) describe('PointArray', function () { - it('parses a string to a point array', function() { var array = new SVG.PointArray('0,1 -.05,7.95 1000.0001,-200.222') expect(array.valueOf()).toEqual([[0, 1], [-0.05, 7.95], [1000.0001, -200.222]]) }) - it('parses a points array correctly to string', function() { var array = new SVG.PointArray([[0,.15], [-100,-3.141592654], [50,100]]) expect(array + '').toBe('0,0.15 -100,-3.141592654 50,100') }) - }) -/* toUpperCase() for Firefox */ describe('PathArray', function () { - var p1, p2 + var p1, p2, p3 beforeEach(function() { p1 = new SVG.PathArray('m10 10 h 80 v 80 h -80 l 300 400 z') diff --git a/spec/spec/element.js b/spec/spec/element.js index 22b09bf..919df93 100755 --- a/spec/spec/element.js +++ b/spec/spec/element.js @@ -57,15 +57,16 @@ describe('Element', function() { }) it('gets the "style" attribute as a string', function() { rect.style('cursor', 'pointer') - expect(stripped(rect.attr('style'))).toBe('cursor:pointer;') + expect(rect.node.style.cursor).toBe('pointer') }) it('redirects to the style() method when setting a style string', function() { rect.attr('style', 'cursor:move;') - expect(stripped(rect.node.getAttribute('style'))).toBe('cursor:move;') + expect(rect.node.style.cursor).toBe('move') }) it('should remove style attribute on node if the style is empty', function() { - rect.style('style', '') - expect(rect.node.getAttribute('style')).toBe(null) + rect.style('cursor', 'move') + rect.style('cursor', '') + expect(rect.style.cursor).toBe(undefined) }) it('should act as a global getter when no arguments are given', function() { rect.fill('#ff0066') diff --git a/spec/spec/text.js b/spec/spec/text.js index f9019a2..6c4d9c6 100755 --- a/spec/spec/text.js +++ b/spec/spec/text.js @@ -1,6 +1,6 @@ // IMPORTANT!!! -// The native getBBox() on text elements is not accurate to the pixel. -// Therefore some values are treated with the approximately() function. +// The native getBBox() on text elements isn't always accurate in the decimals. +// Therefore sometimes some rounding is used to make test work as expected. describe('Text', function() { var text @@ -15,50 +15,50 @@ describe('Text', function() { describe('x()', function() { it('returns the value of x without an argument', function() { - expect(approximately(text.x())).toBe(approximately(0)) + expect(text.x()).toBe(0) }) it('sets the value of x with the first argument', function() { text.x(123) var box = text.bbox() - expect(approximately(box.x, 5)).toBe(approximately(123, 5)) + expect(box.x).toBe(123) }) it('sets the value of x based on the anchor with the first argument', function() { text.x(123, true) var box = text.bbox() - expect(approximately(box.x, 5)).toBe(approximately(123, 5)) + expect(box.x).toBe(123) }) }) describe('y()', function() { it('returns the value of y without an argument', function() { - expect(text.y()).toBe(0) + expect(text.y(0).y()).toBe(0) }) it('sets the value of y with the first argument', function() { text.y(345) var box = text.bbox() - expect(approximately(box.y, 5)).toBe(approximately(345, 5)) + expect(box.y).toBe(345) }) it('sets the value of y based on the anchor with the first argument', function() { text.y(345, true) var box = text.bbox() - expect(approximately(box.y, 5)).toBe(approximately(345, 5)) + expect(box.y).toBe(345) }) }) describe('cx()', function() { it('returns the value of cx without an argument', function() { var box = text.bbox() - expect(approximately(text.cx())).toBe(approximately(box.width / 2)) + expect(text.cx()).toBe(box.width / 2) }) it('sets the value of cx with the first argument', function() { text.cx(123) var box = text.bbox() - expect(approximately(box.cx, 5)).toBe(approximately(123, 5)) + expect(box.cx).toBe(123) }) it('sets the value of cx based on the anchor with the first argument', function() { text.cx(123, true) var box = text.bbox() - expect(approximately(box.cx, 5)).toBe(approximately(123, 5)) + expect(box.cx).toBe(123) }) }) @@ -70,7 +70,7 @@ describe('Text', function() { it('sets the value of cy with the first argument', function() { text.cy(345) var box = text.bbox() - expect(approximately(box.cy, 5)).toBe(approximately(345, 5)) + expect(Math.round(box.cy * 10) / 10).toBe(345) }) }) @@ -87,8 +87,8 @@ describe('Text', function() { it('sets the cx and cy position', function() { text.center(321,567) var box = text.bbox() - expect(approximately(box.cx, 5)).toBe(approximately(321, 5)) - expect(approximately(box.cy, 6)).toBe(approximately(567, 6)) + expect(box.cx).toBe(321) + expect(Math.round(box.cy * 10) / 10).toBe(567) }) }) diff --git a/src/array.js b/src/array.js index b239c78..bc79ceb 100755 --- a/src/array.js +++ b/src/array.js @@ -70,6 +70,12 @@ SVG.extend(SVG.Array, { , split: function(string) { return string.replace(/\s+/g, ' ').replace(/^\s+|\s+$/g,'').split(' ') } + // Reverse array +, reverse: function() { + this.value.reverse() + + return this + } }) diff --git a/src/bbox.js b/src/bbox.js index 603b6c9..c68bec5 100755 --- a/src/bbox.js +++ b/src/bbox.js @@ -1,4 +1,4 @@ - + SVG.BBox = function(element) { var box @@ -31,10 +31,9 @@ SVG.BBox = function(element) { this.width = box.width * element.trans.scaleX this.height = box.height * element.trans.scaleY } - - /* add the center */ - this.cx = this.x + this.width / 2 - this.cy = this.y + this.height / 2 + + /* add center, right and bottom */ + boxProperties(this) } @@ -50,9 +49,8 @@ SVG.extend(SVG.BBox, { b.width = Math.max(this.x + this.width, box.x + box.width) - b.x b.height = Math.max(this.y + this.height, box.y + box.height) - b.y - /* add the center */ - b.cx = b.x + b.width / 2 - b.cy = b.y + b.height / 2 + /* add center, right and bottom */ + boxProperties(b) return b } diff --git a/src/color.js b/src/color.js index e73d7e0..956693c 100755 --- a/src/color.js +++ b/src/color.js @@ -8,7 +8,7 @@ SVG.Color = function(color) { this.b = 0 /* parse color */ - if (typeof color == 'string') { + if (typeof color === 'string') { if (SVG.regex.isRgb.test(color)) { /* get rgb values */ match = SVG.regex.rgb.exec(color.replace(/\s/g,'')) @@ -20,7 +20,7 @@ SVG.Color = function(color) { } else if (SVG.regex.isHex.test(color)) { /* get hex values */ - match = SVG.regex.hex.exec(this._fullHex(color)) + match = SVG.regex.hex.exec(fullHex(color)) /* parse numeric values */ this.r = parseInt(match[1], 16) @@ -29,7 +29,7 @@ SVG.Color = function(color) { } - } else if (typeof color == 'object') { + } else if (typeof color === 'object') { this.r = color.r this.g = color.g this.b = color.b @@ -46,9 +46,9 @@ SVG.extend(SVG.Color, { // Build hex value , toHex: function() { return '#' - + this._compToHex(this.r) - + this._compToHex(this.g) - + this._compToHex(this.b) + + compToHex(this.r) + + compToHex(this.g) + + compToHex(this.b) } // Build rgb value , toRgb: function() { @@ -81,23 +81,11 @@ SVG.extend(SVG.Color, { , b: ~~(this.b + (this.destination.b - this.b) * pos) }) } - // Private: ensure to six-based hex -, _fullHex: function(hex) { - return hex.length == 4 ? - [ '#', - hex.substring(1, 2), hex.substring(1, 2) - , hex.substring(2, 3), hex.substring(2, 3) - , hex.substring(3, 4), hex.substring(3, 4) - ].join('') : hex - } - // Private: component to hex value -, _compToHex: function(comp) { - var hex = comp.toString(16) - return hex.length == 1 ? '0' + hex : hex - } }) +// Testers + // Test if given value is a color string SVG.Color.test = function(color) { color += '' diff --git a/src/element.js b/src/element.js index 116e8d1..1e86104 100755 --- a/src/element.js +++ b/src/element.js @@ -4,14 +4,11 @@ SVG.Element = SVG.invent({ create: function(node) { /* make stroke value accessible dynamically */ this._stroke = SVG.defaults.attrs.stroke - - /* initialize style store */ - this.styles = {} - + /* initialize transformation store with defaults */ this.trans = SVG.defaults.trans() - /* keep reference to the element node */ + /* create circular reference */ if (this.node = node) { this.type = node.nodeName this.node.instance = this @@ -22,7 +19,7 @@ SVG.Element = SVG.invent({ , extend: { // Move over x-axis x: function(x) { - if (x) { + if (x != null) { x = new SVG.Number(x) x.value /= this.trans.scaleX } @@ -30,7 +27,7 @@ SVG.Element = SVG.invent({ } // Move over y-axis , y: function(y) { - if (y) { + if (y != null) { y = new SVG.Number(y) y.value /= this.trans.scaleY } @@ -62,7 +59,7 @@ SVG.Element = SVG.invent({ } // Set element size to given width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr({ width: new SVG.Number(p.width) @@ -134,7 +131,7 @@ SVG.Element = SVG.invent({ a = {} v = this.node.attributes for (n = v.length - 1; n >= 0; n--) - a[v[n].nodeName] = SVG.regex.test(v[n].nodeValue, 'isNumber') ? parseFloat(v[n].nodeValue) : v[n].nodeValue + a[v[n].nodeName] = SVG.regex.isNumber.test(v[n].nodeValue) ? parseFloat(v[n].nodeValue) : v[n].nodeValue return a @@ -151,7 +148,7 @@ SVG.Element = SVG.invent({ v = this.node.getAttribute(a) return v == null ? SVG.defaults.attrs[a] : - SVG.regex.test(v, 'isNumber') ? + SVG.regex.isNumber.test(v) ? parseFloat(v) : v } else if (a == 'style') { @@ -176,14 +173,14 @@ SVG.Element = SVG.invent({ }) } - /* ensure full hex color */ - if (SVG.Color.isColor(v)) - v = new SVG.Color(v) - - /* ensure correct numeric values */ - else if (typeof v === 'number') + /* ensure correct numeric values (also accepts NaN and Infinity) */ + if (typeof v === 'number') v = new SVG.Number(v) + /* ensure full hex color */ + else if (SVG.Color.isColor(v)) + v = new SVG.Color(v) + /* parse array values */ else if (Array.isArray(v)) v = new SVG.Array(v) @@ -194,8 +191,8 @@ SVG.Element = SVG.invent({ if (this.leading) this.leading(v) } else { - /* set give attribute on node */ - n != null ? + /* set given attribute on node */ + typeof n === 'string' ? this.node.setAttributeNS(n, a, v.toString()) : this.node.setAttribute(a, v.toString()) } @@ -230,7 +227,7 @@ SVG.Element = SVG.invent({ var transform = [] /* parse matrix */ - o = this._parseMatrix(o) + o = parseMatrix(o) /* merge values */ for (v in o) @@ -284,7 +281,7 @@ SVG.Element = SVG.invent({ , style: function(s, v) { if (arguments.length == 0) { /* get full style */ - return this.attr('style') || '' + return this.node.style.cssText || '' } else if (arguments.length < 2) { /* apply every style individually if an object is passed */ @@ -296,37 +293,19 @@ SVG.Element = SVG.invent({ s = s.split(';') /* apply every definition individually */ - for (var i = 0; i < s.length; i++) { - v = s[i].split(':') - - if (v.length == 2) - this.style(v[0].replace(/\s+/g, ''), v[1].replace(/^\s+/,'').replace(/\s+$/,'')) + for (v = 0; v < s.length; v++) { + v = s[v].split(':') + this.style(v[0].replace(/\s+/g, ''), v[1]) } } else { /* act as a getter if the first and only argument is not an object */ - return this.styles[s] + return this.node.style[camelCase(s)] } - } else if (v === null || SVG.regex.test(v, 'isBlank')) { - /* remove value */ - delete this.styles[s] - } else { - /* store value */ - this.styles[s] = v + this.node.style[camelCase(s)] = v === null || SVG.regex.isBlank.test(v) ? null : v } - /* rebuild style string */ - s = '' - for (v in this.styles) - s += v + ':' + this.styles[v] + ';' - - /* apply style */ - if (s == '') - this.node.removeAttribute('style') - else - this.node.setAttribute('style', s) - return this } // Get bounding box @@ -371,41 +350,5 @@ SVG.Element = SVG.invent({ return element } - // Private: parse a matrix string - , _parseMatrix: function(o) { - if (o.matrix) { - /* split matrix string */ - var m = o.matrix.replace(/\s/g, '').split(',') - - /* pasrse values */ - if (m.length == 6) { - o.a = parseFloat(m[0]) - o.b = parseFloat(m[1]) - o.c = parseFloat(m[2]) - o.d = parseFloat(m[3]) - o.e = parseFloat(m[4]) - o.f = parseFloat(m[5]) - } - } - - return o - } - // Private: calculate proportional width and height values when necessary - , _proportionalSize: function(width, height) { - if (width == null || height == null) { - var box = this.bbox() - - if (height == null) - height = box.height / box.width * width - else if (width == null) - width = box.width / box.height * height - } - - return { - width: width - , height: height - } - } } - }) \ No newline at end of file diff --git a/src/ellipse.js b/src/ellipse.js index d84f988..0d23e6e 100755 --- a/src/ellipse.js +++ b/src/ellipse.js @@ -33,7 +33,7 @@ SVG.Ellipse = SVG.invent({ } // Custom size function , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr({ rx: new SVG.Number(p.width).divide(2) diff --git a/src/fx.js b/src/fx.js index e64f2ad..424c952 100755 --- a/src/fx.js +++ b/src/fx.js @@ -100,30 +100,34 @@ SVG.FX = SVG.invent({ } else { /* run all x-position properties */ if (fx._x) - element.x(at(fx._x, pos)) + element.x(fx._x.at(pos)) else if (fx._cx) - element.cx(at(fx._cx, pos)) + element.cx(fx._cx.at(pos)) /* run all y-position properties */ if (fx._y) - element.y(at(fx._y, pos)) + element.y(fx._y.at(pos)) else if (fx._cy) - element.cy(at(fx._cy, pos)) + element.cy(fx._cy.at(pos)) /* run all size properties */ if (fx._size) - element.size(at(fx._size.width, pos), at(fx._size.height, pos)) + element.size(fx._size.width.at(pos), fx._size.height.at(pos)) } /* run all viewbox properties */ if (fx._viewbox) element.viewbox( - at(fx._viewbox.x, pos) - , at(fx._viewbox.y, pos) - , at(fx._viewbox.width, pos) - , at(fx._viewbox.height, pos) + fx._viewbox.x.at(pos) + , fx._viewbox.y.at(pos) + , fx._viewbox.width.at(pos) + , fx._viewbox.height.at(pos) ) + /* run leading property */ + if (fx._leading) + element.leading(fx._leading.at(pos)) + /* animate attributes */ for (i = akeys.length - 1; i >= 0; i--) element.attr(akeys[i], at(fx.attrs[akeys[i]], pos)) @@ -158,7 +162,7 @@ SVG.FX = SVG.invent({ } /* render function */ - fx.render = function(){ + fx.render = function() { if (fx.situation.play === true) { // This code was borrowed from the emile.js micro framework by Thomas Fuchs, aka MadRobby. @@ -224,7 +228,7 @@ SVG.FX = SVG.invent({ , transform: function(o, v) { if (arguments.length == 1) { /* parse matrix string */ - o = this.target._parseMatrix(o) + o = parseMatrix(o) /* dlete matrixstring from object */ delete o.matrix @@ -256,25 +260,25 @@ SVG.FX = SVG.invent({ } // Animatable x-axis , x: function(x) { - this._x = { from: this.target.x(), to: x } + this._x = new SVG.Number(this.target.x()).morph(x) return this } // Animatable y-axis , y: function(y) { - this._y = { from: this.target.y(), to: y } + this._y = new SVG.Number(this.target.y()).morph(y) return this } // Animatable center x-axis , cx: function(x) { - this._cx = { from: this.target.cx(), to: x } + this._cx = new SVG.Number(this.target.cx()).morph(x) return this } // Animatable center y-axis , cy: function(y) { - this._cy = { from: this.target.cy(), to: y } + this._cy = new SVG.Number(this.target.cy()).morph(y) return this } @@ -297,8 +301,8 @@ SVG.FX = SVG.invent({ var box = this.target.bbox() this._size = { - width: { from: box.width, to: width } - , height: { from: box.height, to: height } + width: new SVG.Number(box.width).morph(width) + , height: new SVG.Number(box.height).morph(height) } } @@ -310,16 +314,23 @@ SVG.FX = SVG.invent({ return this } + // Add leading method + , leading: function(value) { + if (this.target._leading) + this._leading = new SVG.Number(this.target._leading).morph(value) + + return this + } // Add animatable viewbox , viewbox: function(x, y, width, height) { if (this.target instanceof SVG.Container) { var box = this.target.viewbox() this._viewbox = { - x: { from: box.x, to: x } - , y: { from: box.y, to: y } - , width: { from: box.width, to: width } - , height: { from: box.height, to: height } + x: new SVG.Number(box.x).morph(x) + , y: new SVG.Number(box.y).morph(y) + , width: new SVG.Number(box.width).morph(width) + , height: new SVG.Number(box.height).morph(height) } } @@ -354,28 +365,35 @@ SVG.FX = SVG.invent({ return this } // Stop running animation - , stop: function() { - /* stop current animation */ - clearTimeout(this.timeout) - clearInterval(this.interval) - - /* reset storage for properties that need animation */ - this.attrs = {} - this.trans = {} - this.styles = {} - this.situation = {} - - delete this._x - delete this._y - delete this._cx - delete this._cy - delete this._size - delete this._plot - delete this._loop - delete this._after - delete this._during - delete this._viewbox + , stop: function(fulfill) { + /* fulfill animation */ + if (fulfill === true) { + this.animate(0) + } else { + /* stop current animation */ + clearTimeout(this.timeout) + + /* reset storage for properties that need animation */ + this.attrs = {} + this.trans = {} + this.styles = {} + this.situation = {} + + /* delete destinations */ + delete this._x + delete this._y + delete this._cx + delete this._cy + delete this._size + delete this._plot + delete this._loop + delete this._after + delete this._during + delete this._leading + delete this._viewbox + } + return this } // Pause running animation @@ -412,9 +430,9 @@ SVG.FX = SVG.invent({ return (this.fx || (this.fx = new SVG.FX(this))).stop().animate(d, ease, delay) } // Stop current animation; this is an alias to the fx instance - , stop: function() { + , stop: function(fulfill) { if (this.fx) - this.fx.stop() + this.fx.stop(fulfill) return this } @@ -434,26 +452,4 @@ SVG.FX = SVG.invent({ } } -}) - -// Calculate position according to from and to -function at(o, pos) { - /* number recalculation (don't bother converting to SVG.Number for performance reasons) */ - return typeof o.from == 'number' ? - o.from + (o.to - o.from) * pos : - - /* instance recalculation */ - o instanceof SVG.Color || o instanceof SVG.Number ? o.at(pos) : - - /* for all other values wait until pos has reached 1 to return the final value */ - pos < 1 ? o.from : o.to -} - -// Shim layer with setTimeout fallback by Paul Irish -window.requestAnimFrame = (function(){ - return window.requestAnimationFrame || - window.webkitRequestAnimationFrame || - window.mozRequestAnimationFrame || - window.msRequestAnimationFrame || - function (c) { window.setTimeout(c, 1000 / 60) } -})() \ No newline at end of file +}) \ No newline at end of file diff --git a/src/helpers.js b/src/helpers.js new file mode 100644 index 0000000..5a1dd6d --- /dev/null +++ b/src/helpers.js @@ -0,0 +1,124 @@ +// Convert dash-separated-string to camelCase +function camelCase(s) { + return s.toLowerCase().replace(/-(.)/g, function(m, g) { + return g.toUpperCase() + }) +} + +// Ensure to six-based hex +function fullHex(hex) { + return hex.length == 4 ? + [ '#', + hex.substring(1, 2), hex.substring(1, 2) + , hex.substring(2, 3), hex.substring(2, 3) + , hex.substring(3, 4), hex.substring(3, 4) + ].join('') : hex +} + +// Component to hex value +function compToHex(comp) { + var hex = comp.toString(16) + return hex.length == 1 ? '0' + hex : hex +} + +// Calculate proportional width and height values when necessary +function proportionalSize(box, width, height) { + if (width == null || height == null) { + if (height == null) + height = box.height / box.width * width + else if (width == null) + width = box.width / box.height * height + } + + return { + width: width + , height: height + } +} + +// Calculate position according to from and to +function at(o, pos) { + /* number recalculation (don't bother converting to SVG.Number for performance reasons) */ + return typeof o.from == 'number' ? + o.from + (o.to - o.from) * pos : + + /* instance recalculation */ + o instanceof SVG.Color || o instanceof SVG.Number ? o.at(pos) : + + /* for all other values wait until pos has reached 1 to return the final value */ + pos < 1 ? o.from : o.to +} + +// PathArray Helpers +function arrayToString(a) { + for (var i = 0, il = a.length, s = ''; i < il; i++) { + s += a[i][0] + + if (a[i][1] != null) { + s += a[i][1] + + if (a[i][2] != null) { + s += ' ' + s += a[i][2] + + if (a[i][3] != null) { + s += ' ' + s += a[i][3] + s += ' ' + s += a[i][4] + + if (a[i][5] != null) { + s += ' ' + s += a[i][5] + s += ' ' + s += a[i][6] + + if (a[i][7] != null) { + s += ' ' + s += a[i][7] + } + } + } + } + } + } + + return s + ' ' +} + +// Add more bounding box properties +function boxProperties(b) { + b.x2 = b.x + b.width + b.y2 = b.y + b.height + b.cx = b.x + b.width / 2 + b.cy = b.y + b.height / 2 +} + +// Parse a matrix string +function parseMatrix(o) { + if (o.matrix) { + /* split matrix string */ + var m = o.matrix.replace(/\s/g, '').split(',') + + /* pasrse values */ + if (m.length == 6) { + o.a = parseFloat(m[0]) + o.b = parseFloat(m[1]) + o.c = parseFloat(m[2]) + o.d = parseFloat(m[3]) + o.e = parseFloat(m[4]) + o.f = parseFloat(m[5]) + } + } + + return o +} + +// Shim layer with setTimeout fallback by Paul Irish +window.requestAnimFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.msRequestAnimationFrame || + function (c) { window.setTimeout(c, 1000 / 60) } +})() \ No newline at end of file diff --git a/src/image.js b/src/image.js index 60d57b1..d70cfb4 100755 --- a/src/image.js +++ b/src/image.js @@ -27,7 +27,7 @@ SVG.Image = SVG.invent({ p.size(self.width(), self.height()) /* callback */ - if (typeof self._loaded == 'function') + if (typeof self._loaded === 'function') self._loaded.call(self, { width: img.width , height: img.height @@ -52,4 +52,5 @@ SVG.Image = SVG.invent({ return this.put(new SVG.Image).load(source).size(width || 0, height || width || 0) } } + }) \ No newline at end of file diff --git a/src/line.js b/src/line.js index bdbbcde..c11a734 100755 --- a/src/line.js +++ b/src/line.js @@ -49,7 +49,7 @@ SVG.Line = SVG.invent({ } // Set line size by width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.width(p.width).height(p.height) } diff --git a/src/nested.js b/src/nested.js index cd3a0e0..f856e52 100755 --- a/src/nested.js +++ b/src/nested.js @@ -12,7 +12,7 @@ SVG.Nested = SVG.invent({ // Add parent method , construct: { // Create nested svg document - nested: function() { + nested: function() { return this.put(new SVG.Nested) } } diff --git a/src/number.js b/src/number.js index 697d1dc..92ff796 100755 --- a/src/number.js +++ b/src/number.js @@ -6,36 +6,34 @@ SVG.Number = function(value) { this.unit = '' /* parse value */ - switch(typeof value) { - case 'number': - /* ensure a valid numeric value */ - this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value - break - case 'string': - var match = value.match(SVG.regex.unit) + if (typeof value === 'number') { + /* ensure a valid numeric value */ + this.value = isNaN(value) ? 0 : !isFinite(value) ? (value < 0 ? -3.4e+38 : +3.4e+38) : value - if (match) { - /* make value numeric */ - this.value = parseFloat(match[1]) + } else if (typeof value === 'string') { + var match = value.match(SVG.regex.unit) + + if (match) { + /* make value numeric */ + this.value = parseFloat(match[1]) - /* normalize percent value */ - if (match[2] == '%') - this.value /= 100 - else if (match[2] == 's') - this.value *= 1000 + /* normalize percent value */ + if (match[2] == '%') + this.value /= 100 + else if (match[2] == 's') + this.value *= 1000 - /* store unit */ - this.unit = match[2] - } - - break - default: - if (value instanceof SVG.Number) { - this.value = value.value - this.unit = value.unit - } - break + /* store unit */ + this.unit = match[2] + } + + } else { + if (value instanceof SVG.Number) { + this.value = value.value + this.unit = value.unit + } } + } SVG.extend(SVG.Number, { @@ -93,7 +91,7 @@ SVG.extend(SVG.Number, { /* make sure a destination is defined */ if (!this.destination) return this - /* generate morphed number */ + /* generate new morphed number */ return new SVG.Number(this.destination) .minus(this) .times(pos) diff --git a/src/path.js b/src/path.js index ad231dc..773b3d8 100755 --- a/src/path.js +++ b/src/path.js @@ -25,7 +25,7 @@ SVG.Path = SVG.invent({ } // Set element size to given width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr('d', this.array.size(p.width, p.height)) } diff --git a/src/patharray.js b/src/patharray.js index 2ccb7d5..1a2fdd5 100755 --- a/src/patharray.js +++ b/src/patharray.js @@ -201,41 +201,4 @@ SVG.extend(SVG.PathArray, { return SVG.parser.path.getBBox() } -}) - -// PathArray Helpers -function arrayToString(a) { - for (var i = 0, il = a.length, s = ''; i < il; i++) { - s += a[i][0] - - if (a[i][1] != null) { - s += a[i][1] - - if (a[i][2] != null) { - s += ' ' - s += a[i][2] - - if (a[i][3] != null) { - s += ' ' - s += a[i][3] - s += ' ' - s += a[i][4] - - if (a[i][5] != null) { - s += ' ' - s += a[i][5] - s += ' ' - s += a[i][6] - - if (a[i][7] != null) { - s += ' ' - s += a[i][7] - } - } - } - } - } - } - - return s + ' ' -} \ No newline at end of file +}) \ No newline at end of file diff --git a/src/poly.js b/src/poly.js index 5a0f9b2..1586c77 100755 --- a/src/poly.js +++ b/src/poly.js @@ -64,7 +64,7 @@ SVG.extend(SVG.Polyline, SVG.Polygon, { } // Set element size to given width and height , size: function(width, height) { - var p = this._proportionalSize(width, height) + var p = proportionalSize(this.bbox(), width, height) return this.attr('points', this.array.size(p.width, p.height)) } diff --git a/src/rbox.js b/src/rbox.js index 95cc1e2..30779a4 100755 --- a/src/rbox.js +++ b/src/rbox.js @@ -46,9 +46,8 @@ SVG.RBox = function(element) { this.width = box.width /= zoom this.height = box.height /= zoom - /* add the center */ - this.cx = this.x + this.width / 2 - this.cy = this.y + this.height / 2 + /* add center, right and bottom */ + boxProperties(this) } @@ -64,9 +63,8 @@ SVG.extend(SVG.RBox, { b.width = Math.max(this.x + this.width, box.x + box.width) - b.x b.height = Math.max(this.y + this.height, box.y + box.height) - b.y - /* add the center */ - b.cx = b.x + b.width / 2 - b.cy = b.y + b.height / 2 + /* add center, right and bottom */ + boxProperties(b) return b } diff --git a/src/regex.js b/src/regex.js index c75b46f..c78d9f3 100755 --- a/src/regex.js +++ b/src/regex.js @@ -1,12 +1,7 @@ // Storage for regular expressions SVG.regex = { - /* test a given value */ - test: function(value, test) { - return this[test].test(value) - } - /* parse unit value */ -, unit: /^(-?[\d\.]+)([a-z%]{0,2})$/ + unit: /^(-?[\d\.]+)([a-z%]{0,2})$/ /* parse hex value */ , hex: /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i diff --git a/src/relative.js b/src/relative.js index 7759bb9..6bb11b7 100755 --- a/src/relative.js +++ b/src/relative.js @@ -2,11 +2,11 @@ SVG.extend(SVG.Element, SVG.FX, { // Relative move over x axis dx: function(x) { - return this.x(this.x() + x) + return this.x((this.target || this).x() + x) } // Relative move over y axis , dy: function(y) { - return this.y(this.y() + y) + return this.y((this.target || this).y() + y) } // Relative move over x and y axes , dmove: function(x, y) { diff --git a/src/sugar.js b/src/sugar.js index 1a96c23..4a8fff8 100755 --- a/src/sugar.js +++ b/src/sugar.js @@ -89,7 +89,7 @@ SVG.extend(SVG.Path, { }) -SVG.extend(SVG.Text, SVG.FX, { +SVG.extend(SVG.Parent, SVG.Text, SVG.FX, { // Set font font: function(o) { for (var k in o) diff --git a/src/text.js b/src/text.js index 9d95b55..170b9de 100755 --- a/src/text.js +++ b/src/text.js @@ -4,9 +4,9 @@ SVG.Text = SVG.invent({ create: function() { this.constructor.call(this, SVG.create('text')) - this._leading = new SVG.Number(1.3) /* store leading value for rebuilding */ - this._rebuild = true /* enable automatic updating of dy values */ - this._build = false /* disable build mode for adding multiple lines */ + this._leading = new SVG.Number(1.3) /* store leading value for rebuilding */ + this._rebuild = true /* enable automatic updating of dy values */ + this._build = false /* disable build mode for adding multiple lines */ /* set default font */ this.attr('font-family', SVG.defaults.attrs['font-family']) @@ -31,11 +31,13 @@ SVG.Text = SVG.invent({ } // Move over y-axis , y: function(y) { + var o = this.attr('y') - this.bbox().y + /* act as getter */ if (y == null) - return this.attr('y') + return this.attr('y') - o - return this.attr('y', y + this.attr('y') - this.bbox().y) + return this.attr('y', y + o) } // Move center over x-axis , cx: function(x) { @@ -45,14 +47,6 @@ SVG.Text = SVG.invent({ , cy: function(y) { return y == null ? this.bbox().cy : this.y(y - this.bbox().height / 2) } - // Move element to given x and y values - , move: function(x, y) { - return this.x(x).y(y) - } - // Move element by its center - , center: function(x, y) { - return this.cx(x).cy(y) - } // Set the text content , text: function(text) { /* act as getter */ -- 2.39.5