diff options
41 files changed, 772 insertions, 2055 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index facae13..b1570fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,18 +11,30 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http: ## UNRELEASED 3.0.0 ### Added -- added `'random'` option and `randomize()` method to `SVG.Color` -> __TODO!__ +- added `SVG.$()` and `SVG.$$()` which will query for one/multiple elements +- added `random` option and `randomize()` method to `SVG.Color` -> __TODO!__ - added `precision()` method to round numeric element attributes -> __TODO!__ -- added specs for `SVG.FX` -> __TODO!__ + +### Removed +- removed `SVG.Array.split()` function +- removed workaround for browser bug with stroke-width +- removed polyfills +- removed `ungroup()` in favour of `flatten()` +- removed `SVG.Set` +- removed feature to set style with css string (e.g. "fill:none;display:block;") +- removed `loaded()` and `error()` method on `SVG.Image` ### Changed +- gradients now have there corresponding node as type and not only radial/linear +- `SVG.Path.pointAt()` correctly returns an `SVG.Point` now - made transform-methods relative as default (breaking change) - changed SVG() to use querySelector instead of getElementById (breaking change) -> __TODO!__ -- made `parents()` method on `SVG.Element` return an instance of SVG.Set (breaking change) -> __TODO!__ -- replaced static reference to `masker` in `SVG.Mask` with the `masker()` method (breaking change) -> __TODO!__ -- replaced static reference to `clipper` in `SVG.ClipPath` with the `clipper()` method (breaking change) -> __TODO!__ -- replaced static reference to `targets` in `SVG.Mask` and `SVG.ClipPath` with the `targets()` method (breaking change) -> __TODO!__ -- moved all regexes to `SVG.regex` (in color, element, pointarray, style, transform and viewbox) -> __TODO!__ +- replaced static reference to `masker` in `SVG.Mask` with the `masker()` method +- replaced static reference to `clipper` in `SVG.ClipPath` with the `clipper()` method +- replaced static reference to `targets` in `SVG.Mask` and `SVG.ClipPath` with the `targets()` method +- moved all regexes to `SVG.regex` +- `svg()` will now return the element without svg-wrapper +- new constructor signature for `SVG.Image` and `load()`: `container.image(src, callback) / image.load(src, callback)` ### Fixed - fixed a bug in clipping and masking where empty nodes persists after removal -> __TODO!__ diff --git a/bench/runner.html b/bench/runner.html index 719f385..1a2f727 100644 --- a/bench/runner.html +++ b/bench/runner.html @@ -44,6 +44,7 @@ <script src="tests/10000-rects.js"></script> <script src="tests/10000-circles.js"></script> <script src="tests/10000-paths.js"></script> + <script src="tests/10000-boxes.js"></script> <script> SVG.bench.run() </script> diff --git a/bench/tests/10000-boxes.js b/bench/tests/10000-boxes.js new file mode 100644 index 0000000..0466f64 --- /dev/null +++ b/bench/tests/10000-boxes.js @@ -0,0 +1,55 @@ +SVG.bench.describe('Generate 100000 bbox', function(bench) { + var rect = bench.draw.rect(100,100) + + bench.test('using SVG.js v3.0.0', function() { + for (var i = 0; i < 100000; i++) + rect.bbox() + }) + //bench.test('using vanilla js', function() { + // var node = rect.node + // for (var i = 0; i < 10000; i++) { + // node.getBBox() + // } + //}) + //bench.test('using Snap.svg v0.5.1', function() { + // for (var i = 0; i < 10000; i++) + // bench.snap.rect(50, 50, 100, 100) + //}) +}) + +SVG.bench.describe('Generate 100000 rbox', function(bench) { + var rect = bench.draw.rect(100,100) + + bench.test('using SVG.js v3.0.0', function() { + for (var i = 0; i < 100000; i++) + rect.bbox() + }) + //bench.test('using vanilla js', function() { + // var node = rect.node + // for (var i = 0; i < 10000; i++) { + // node.getBoundingClientRect() + // } + //}) + //bench.test('using Snap.svg v0.5.1', function() { + // for (var i = 0; i < 10000; i++) + // bench.snap.rect(50, 50, 100, 100) + //}) +}) +SVG.bench.describe('Generate 100000 viewbox', function(bench) { + var nested = bench.draw.nested().viewbox(10, 10, 100, 100) + + bench.test('using SVG.js v3.0.0', function() { + for (var i = 0; i < 100000; i++) + nested.viewbox() + }) + //bench.test('using vanilla js', function() { + // var node = rect.node + // for (var i = 0; i < 10000; i++) { + // node.getAttribute('viewBox') + // } + //}) + //bench.test('using Snap.svg v0.5.1', function() { + // for (var i = 0; i < 10000; i++) + // bench.snap.rect(50, 50, 100, 100) + //}) +}) diff --git a/dist/svg.js b/dist/svg.js index 3263c19..35ae5a1 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -1,12 +1,12 @@ /*! * svg.js - A lightweight library for manipulating and animating SVG. -* @version 2.6.0 +* @version 3.0.0 * https://svgdotjs.github.io/ * * @copyright Wout Fierens <wout@mick-wout.com> * @license MIT * -* BUILT: Fri Apr 21 2017 12:48:06 GMT+0200 (Mitteleuropäische Sommerzeit) +* BUILT: Sat Apr 22 2017 20:28:05 GMT+0200 (Mitteleuropäische Sommerzeit) */; (function(root, factory) {
/* istanbul ignore next */
@@ -81,10 +81,6 @@ SVG.extend = function() { if (modules[i])
for (key in methods)
modules[i].prototype[key] = methods[key]
-
- // Make sure SVG.Set inherits any newly added methods
- if (SVG.Set && SVG.Set.inherit)
- SVG.Set.inherit()
}
// Invent new element
@@ -158,7 +154,13 @@ SVG.prepare = function() { // Create parser object
SVG.parser = {
body: body || document.documentElement
- , draw: draw.style('opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden').node
+ , draw: draw.style({
+ opacity:0,
+ position:'absolute',
+ left:'-100%',
+ top:'-100%',
+ overflow:'hidden'
+ }).node
, poly: draw.polyline().node
, path: draw.path().node
, native: SVG.create('svg')
@@ -487,11 +489,7 @@ SVG.extend(SVG.Array, { // if already is an array, no need to parse it
if (Array.isArray(array)) return array
- return this.split(array)
- }
- // Strip unnecessary whitespace
-, split: function(string) {
- return string.trim().split(SVG.regex.delimiter).map(parseFloat)
+ return array.trim().split(SVG.regex.delimiter).map(parseFloat)
}
// Reverse array
, reverse: function() {
@@ -1021,8 +1019,7 @@ SVG.Number = SVG.invent({ SVG.Element = SVG.invent({
// Initialize node
create: function(node) {
- // make stroke value accessible dynamically
- this._stroke = SVG.defaults.attrs.stroke
+ // last fired event on node
this._event = null
// initialize data object
@@ -1032,9 +1029,6 @@ SVG.Element = SVG.invent({ if (this.node = node) {
this.type = node.nodeName
this.node.instance = this
-
- // store current attribute value
- this._stroke = node.getAttribute('stroke') || this._stroke
}
}
@@ -1227,31 +1221,26 @@ SVG.Element = SVG.invent({ }
// Import raw svg
, svg: function(svg) {
- // create temporary holder
- var well = document.createElement('svg')
+ var well, len
// act as a setter if svg is given
if (svg && this instanceof SVG.Parent) {
+
+ // create temporary holder
+ well = document.createElementNS(SVG.ns, 'svg')
// dump raw svg
- well.innerHTML = '<svg>' + svg.replace(/\n/, '').replace(/<(\w+)([^<]+?)\/>/g, '<$1$2></$1>') + '</svg>'
+ well.innerHTML = svg
// transplant nodes
- for (var i = 0, il = well.firstChild.childNodes.length; i < il; i++)
- this.node.appendChild(well.firstChild.firstChild)
+ for (len = well.childNodes.length;len--;)
+ if(well.firstChild.nodeType != 1)
+ well.removeChild(well.firstChild)
+ else
+ this.node.appendChild(well.firstChild)
// otherwise act as a getter
} else {
- // create a wrapping svg element in case of partial content
- well.appendChild(svg = document.createElement('svg'))
-
- // write svgjs data to the dom
- this.writeDataToDom()
-
- // insert a copy of this node
- svg.appendChild(this.node.cloneNode(true))
-
- // return target element
- return well.innerHTML.replace(/^<svg>/, '').replace(/<\/svg>$/, '')
+ return this.node.outerHTML
}
return this
@@ -1260,9 +1249,8 @@ SVG.Element = SVG.invent({ , writeDataToDom: function() {
// dump variables recursively
- if(this.each || this.lines){
- var fn = this.each ? this : this.lines();
- fn.each(function(){
+ if(this.is(SVG.Parent)){
+ this.each(function(){
this.writeDataToDom()
})
}
@@ -2146,7 +2134,7 @@ SVG.extend(SVG.FX, { // Add animatable viewbox
, viewbox: function(x, y, width, height) {
if (this.target() instanceof SVG.Container) {
- this.add('viewbox', new SVG.ViewBox(x, y, width, height))
+ this.add('viewbox', new SVG.Box(x, y, width, height))
}
return this
@@ -2170,175 +2158,6 @@ SVG.extend(SVG.FX, { }
})
-SVG.Box = SVG.invent({
- create: function(x, y, width, height) {
- if (typeof x == 'object' && !(x instanceof SVG.Element)) {
- // chromes getBoundingClientRect has no x and y property
- return SVG.Box.call(this, x.left != null ? x.left : x.x , x.top != null ? x.top : x.y, x.width, x.height)
- } else if (arguments.length == 4) {
- this.x = x
- this.y = y
- this.width = width
- this.height = height
- }
-
- // add center, right, bottom...
- fullBox(this)
- }
-, extend: {
- // Merge rect box with another, return a new instance
- merge: function(box) {
- var b = new this.constructor()
-
- // merge boxes
- b.x = Math.min(this.x, box.x)
- b.y = Math.min(this.y, box.y)
- 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
-
- return fullBox(b)
- }
-
- , transform: function(m) {
- var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, p, bbox
-
- var pts = [
- new SVG.Point(this.x, this.y),
- new SVG.Point(this.x2, this.y),
- new SVG.Point(this.x, this.y2),
- new SVG.Point(this.x2, this.y2)
- ]
-
- pts.forEach(function(p) {
- p = p.transform(m)
- xMin = Math.min(xMin,p.x)
- xMax = Math.max(xMax,p.x)
- yMin = Math.min(yMin,p.y)
- yMax = Math.max(yMax,p.y)
- })
-
- bbox = new this.constructor()
- bbox.x = xMin
- bbox.width = xMax-xMin
- bbox.y = yMin
- bbox.height = yMax-yMin
-
- fullBox(bbox)
-
- return bbox
- }
- }
-})
-
-SVG.BBox = SVG.invent({
- // Initialize
- create: function(element) {
- SVG.Box.apply(this, [].slice.call(arguments))
-
- // get values if element is given
- if (element instanceof SVG.Element) {
- var box
-
- // yes this is ugly, but Firefox can be a bitch when it comes to elements that are not yet rendered
- try {
-
- if (!document.documentElement.contains){
- // This is IE - it does not support contains() for top-level SVGs
- var topParent = element.node
- while (topParent.parentNode){
- topParent = topParent.parentNode
- }
- if (topParent != document) throw new Exception('Element not in the dom')
- } else {
- // the element is NOT in the dom, throw error
- if(!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom')
- }
-
- // find native bbox
- box = element.node.getBBox()
- } catch(e) {
- if(element instanceof SVG.Shape){
- var clone = element.clone(SVG.parser.draw.instance).show()
- box = clone.node.getBBox()
- clone.remove()
- }else{
- box = {
- x: element.node.clientLeft
- , y: element.node.clientTop
- , width: element.node.clientWidth
- , height: element.node.clientHeight
- }
- }
- }
-
- SVG.Box.call(this, box)
- }
-
- }
-
- // Define ancestor
-, inherit: SVG.Box
-
- // Define Parent
-, parent: SVG.Element
-
- // Constructor
-, construct: {
- // Get bounding box
- bbox: function() {
- return new SVG.BBox(this)
- }
- }
-
-})
-
-SVG.BBox.prototype.constructor = SVG.BBox
-
-
-SVG.extend(SVG.Element, {
- tbox: function(){
- console.warn('Use of TBox is deprecated and mapped to RBox. Use .rbox() instead.')
- return this.rbox(this.doc())
- }
-})
-
-SVG.RBox = SVG.invent({
- // Initialize
- create: function(element) {
- SVG.Box.apply(this, [].slice.call(arguments))
-
- if (element instanceof SVG.Element) {
- SVG.Box.call(this, element.node.getBoundingClientRect())
- }
- }
-
-, inherit: SVG.Box
-
- // define Parent
-, parent: SVG.Element
-
-, extend: {
- addOffset: function() {
- // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
- this.x += window.pageXOffset
- this.y += window.pageYOffset
- return this
- }
- }
-
- // Constructor
-, construct: {
- // Get rect box
- rbox: function(el) {
- if (el) return new SVG.RBox(this).transform(el.screenCTM().inverse())
- return new SVG.RBox(this).addOffset()
- }
- }
-
-})
-
-SVG.RBox.prototype.constructor = SVG.RBox
- SVG.Matrix = SVG.invent({
// Initialize
create: function(source) {
@@ -2642,16 +2461,11 @@ SVG.extend(SVG.Element, { parseFloat(v) : v
} else {
- // BUG FIX: some browsers will render a stroke if a color is given even though stroke width is 0
- if (a == 'stroke-width')
- this.attr('stroke', parseFloat(v) > 0 ? this._stroke : null)
- else if (a == 'stroke')
- this._stroke = v
// convert image fill and stroke to patterns
if (a == 'fill' || a == 'stroke') {
if (SVG.regex.isImage.test(v))
- v = this.doc().defs().image(v, 0, 0)
+ v = this.doc().defs().image(v)
if (v instanceof SVG.Image)
v = this.doc().defs().pattern(0, 0, function() {
@@ -3074,17 +2888,6 @@ SVG.extend(SVG.Element, { if (typeof s == 'object') {
for (v in s) this.style(v, s[v])
- } else if (SVG.regex.isCss.test(s)) {
- // parse css string
- s = s.split(/\s*;\s*/)
- // filter out suffix ; and stuff like ;;
- .filter(function(e) { return !!e })
- .map(function(e){ return e.split(/\s*:\s*/) })
-
- // apply every definition individually
- while (v = s.pop()) {
- this.style(v[0], v[1])
- }
} else {
// act as a getter if the first and only argument is not an object
return this.node.style[camelCase(s)]
@@ -3096,7 +2899,8 @@ SVG.extend(SVG.Element, { return this
}
-}) +})
+ SVG.Parent = SVG.invent({
// Initialize node
create: function(element) {
@@ -3189,29 +2993,24 @@ SVG.Parent = SVG.invent({ })
SVG.extend(SVG.Parent, {
-
- ungroup: function(parent, depth) {
- if(depth === 0 || this instanceof SVG.Defs || this.node == SVG.parser.draw) return this
+ flatten: function(parent) {
+ if(this instanceof SVG.Defs) return this
parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent))
- depth = depth || Infinity
this.each(function(){
if(this instanceof SVG.Defs) return this
- if(this instanceof SVG.Parent) return this.ungroup(parent, depth-1)
+ if(this instanceof SVG.Parent) return this.flatten(parent)
return this.toParent(parent)
})
+ // we need this so that SVG.Doc does not get removed
this.node.firstChild || this.remove()
return this
- },
-
- flatten: function(parent, depth) {
- return this.ungroup(parent, depth)
}
-
-}) +})
+ SVG.Container = SVG.invent({
// Initialize node
create: function(element) {
@@ -3222,133 +3021,6 @@ SVG.Container = SVG.invent({ , inherit: SVG.Parent
}) -
-SVG.ViewBox = SVG.invent({
-
- create: function(source) {
- var i, base = [0, 0, 0, 0]
-
- var x, y, width, height, box, view, we, he
- , wm = 1 // width multiplier
- , hm = 1 // height multiplier
- , reg = /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi
-
- if(source instanceof SVG.Element){
-
- we = source
- he = source
- view = (source.attr('viewBox') || '').match(reg)
- box = source.bbox
-
- // get dimensions of current node
- width = new SVG.Number(source.width())
- height = new SVG.Number(source.height())
-
- // find nearest non-percentual dimensions
- while (width.unit == '%') {
- wm *= width.value
- width = new SVG.Number(we instanceof SVG.Doc ? we.parent().offsetWidth : we.parent().width())
- we = we.parent()
- }
- while (height.unit == '%') {
- hm *= height.value
- height = new SVG.Number(he instanceof SVG.Doc ? he.parent().offsetHeight : he.parent().height())
- he = he.parent()
- }
-
- // ensure defaults
- this.x = 0
- this.y = 0
- this.width = width * wm
- this.height = height * hm
- this.zoom = 1
-
- if (view) {
- // get width and height from viewbox
- x = parseFloat(view[0])
- y = parseFloat(view[1])
- width = parseFloat(view[2])
- height = parseFloat(view[3])
-
- // calculate zoom accoring to viewbox
- this.zoom = ((this.width / this.height) > (width / height)) ?
- this.height / height :
- this.width / width
-
- // calculate real pixel dimensions on parent SVG.Doc element
- this.x = x
- this.y = y
- this.width = width
- this.height = height
-
- }
-
- }else{
-
- // ensure source as object
- source = typeof source === 'string' ?
- source.match(reg).map(function(el){ return parseFloat(el) }) :
- Array.isArray(source) ?
- source :
- typeof source == 'object' ?
- [source.x, source.y, source.width, source.height] :
- arguments.length == 4 ?
- [].slice.call(arguments) :
- base
-
- this.x = source[0]
- this.y = source[1]
- this.width = source[2]
- this.height = source[3]
- }
-
-
- }
-
-, extend: {
-
- toString: function() {
- return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
- }
- , morph: function(x, y, width, height){
- this.destination = new SVG.ViewBox(x, y, width, height)
- return this
- }
-
- , at: function(pos) {
-
- if(!this.destination) return this
-
- return new SVG.ViewBox([
- this.x + (this.destination.x - this.x) * pos
- , this.y + (this.destination.y - this.y) * pos
- , this.width + (this.destination.width - this.width) * pos
- , this.height + (this.destination.height - this.height) * pos
- ])
-
- }
-
- }
-
- // Define parent
-, parent: SVG.Container
-
- // Add parent method
-, construct: {
-
- // get/set viewbox
- viewbox: function(x, y, width, height) {
- if (arguments.length == 0)
- // act as a getter if there are no arguments
- return new SVG.ViewBox(this)
-
- // otherwise act as a setter
- return this.attr('viewBox', new SVG.ViewBox(x, y, width, height))
- }
-
- }
-
-}) // Add events to elements
;[ 'click'
, 'dblclick'
@@ -3641,12 +3313,7 @@ SVG.extend(SVG.Element, { }) SVG.Mask = SVG.invent({
// Initialize node
- create: function() {
- this.constructor.call(this, SVG.create('mask'))
-
- // keep references to masked elements
- this.targets = []
- }
+ create: 'mask'
// Inherit from
, inherit: SVG.Container
@@ -3656,15 +3323,16 @@ SVG.Mask = SVG.invent({ // Unmask all masked elements and remove itself
remove: function() {
// unmask all targets
- for (var i = this.targets.length - 1; i >= 0; i--)
- if (this.targets[i])
- this.targets[i].unmask()
- this.targets = []
+ this.targets().forEach(function(el) {
+ el.unmask()
+ })
// remove mask from parent
- this.parent().removeElement(this)
+ return SVG.Element.prototype.remove.call(this)
+ }
- return this
+ , targets: function() {
+ return SVG.select('svg [mask*="' +this.id() +'"]')
}
}
@@ -3682,30 +3350,23 @@ SVG.extend(SVG.Element, { // Distribute mask to svg element
maskWith: function(element) {
// use given mask or create a new one
- this.masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)
-
- // store reverence on self in mask
- this.masker.targets.push(this)
+ var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)
// apply mask
- return this.attr('mask', 'url("#' + this.masker.attr('id') + '")')
+ return this.attr('mask', 'url("#' + masker.attr('id') + '")')
}
// Unmask element
, unmask: function() {
- delete this.masker
return this.attr('mask', null)
}
-
+, masker: function() {
+ return this.reference('mask')
+ }
})
SVG.ClipPath = SVG.invent({
// Initialize node
- create: function() {
- this.constructor.call(this, SVG.create('clipPath'))
-
- // keep references to clipped elements
- this.targets = []
- }
+ create: 'clipPath'
// Inherit from
, inherit: SVG.Container
@@ -3715,15 +3376,16 @@ SVG.ClipPath = SVG.invent({ // Unclip all clipped elements and remove itself
remove: function() {
// unclip all targets
- for (var i = this.targets.length - 1; i >= 0; i--)
- if (this.targets[i])
- this.targets[i].unclip()
- this.targets = []
+ this.targets().forEach(function(el) {
+ el.unclip()
+ })
// remove clipPath from parent
- this.parent().removeElement(this)
+ return SVG.Element.prototype.remove.call(this)
+ }
- return this
+ , targets: function() {
+ return SVG.select('svg [clip-path*="' +this.id() +'"]')
}
}
@@ -3741,28 +3403,24 @@ SVG.extend(SVG.Element, { // Distribute clipPath to svg element
clipWith: function(element) {
// use given clip or create a new one
- this.clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)
-
- // store reverence on self in mask
- this.clipper.targets.push(this)
+ var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)
// apply mask
- return this.attr('clip-path', 'url("#' + this.clipper.attr('id') + '")')
+ return this.attr('clip-path', 'url("#' + clipper.attr('id') + '")')
}
// Unclip element
, unclip: function() {
- delete this.clipper
return this.attr('clip-path', null)
}
+, clipper: function() {
+ return this.reference('clip-path')
+ }
}) SVG.Gradient = SVG.invent({
// Initialize node
create: function(type) {
this.constructor.call(this, SVG.create(type + 'Gradient'))
-
- // store type
- this.type = type
}
// Inherit from
@@ -3813,13 +3471,13 @@ SVG.Gradient = SVG.invent({ SVG.extend(SVG.Gradient, SVG.FX, {
// From position
from: function(x, y) {
- return (this._target || this).type == 'radial' ?
+ return (this._target || this).type == 'radialGradient' ?
this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) }) :
this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) })
}
// To position
, to: function(x, y) {
- return (this._target || this).type == 'radial' ?
+ return (this._target || this).type == 'radialGradient' ?
this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) }) :
this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) })
}
@@ -4429,65 +4087,48 @@ SVG.Image = SVG.invent({ // Add class methods
, extend: {
// (re)load image
- load: function(url) {
+ load: function(url, callback) {
if (!url) return this
- var self = this
- , img = new window.Image()
+ var img = new window.Image()
- // preload image
- SVG.on(img, 'load', function() {
- var p = self.parent(SVG.Pattern)
+ SVG.on(img, 'load', function(e) {
- if(p === null) return
+ var p = this.parent()
// ensure image size
- if (self.width() == 0 && self.height() == 0)
- self.size(img.width, img.height)
+ if (this.width() == 0 && this.height() == 0)
+ this.size(img.width, img.height)
- // ensure pattern size if not set
- if (p && p.width() == 0 && p.height() == 0)
- p.size(self.width(), self.height())
+ if(p instanceof SVG.Pattern) {
+ // ensure pattern size if not set
+ if (p.width() == 0 && p.height() == 0)
+ p.size(this.width(), this.height())
+ }
- // callback
- if (typeof self._loaded === 'function')
- self._loaded.call(self, {
+ if(typeof callback == 'function') {
+ callback.call(this, {
width: img.width
, height: img.height
, ratio: img.width / img.height
, url: url
})
- })
-
- SVG.on(img, 'error', function(e){
- if (typeof self._error === 'function'){
- self._error.call(self, e)
}
- })
+ }, this)
- return this.attr('href', (img.src = this.src = url), SVG.xlink)
- }
- // Add loaded callback
- , loaded: function(loaded) {
- this._loaded = loaded
- return this
- }
-
- , error: function(error) {
- this._error = error
- return this
+ return this.attr('href', (img.src = url), SVG.xlink)
}
}
// Add parent method
, construct: {
// create image element, load image and set its size
- image: function(source, width, height) {
- return this.put(new SVG.Image).load(source).size(width || 0, height || width || 0)
+ image: function(source, callback) {
+ return this.put(new SVG.Image).size(0, 0).load(source, callback)
}
}
-
-}) +})
+ SVG.Text = SVG.invent({
// Initialize node
create: function() {
@@ -4502,7 +4143,7 @@ SVG.Text = SVG.invent({ }
// Inherit from
-, inherit: SVG.Shape
+, inherit: SVG.Parent
// Add class methods
, extend: {
@@ -4587,18 +4228,6 @@ SVG.Text = SVG.invent({ return this.rebuild()
}
- // Get all the first level lines
- , lines: function() {
- var node = (this.textPath && this.textPath() || this).node
-
- // filter tspans and map them to SVG.js instances
- var lines = SVG.utils.map(SVG.utils.filterSVGElements(node.childNodes), function(el){
- return SVG.adopt(el)
- })
-
- // return an instance of SVG.set
- return new SVG.Set(lines)
- }
// Rebuild appearance type
, rebuild: function(rebuild) {
// store new rebuild flag if given
@@ -4611,7 +4240,7 @@ SVG.Text = SVG.invent({ , blankLineOffset = 0
, dy = this.dom.leading * new SVG.Number(this.attr('font-size'))
- this.lines().each(function() {
+ this.each(function() {
if (this.dom.newLined) {
if (!self.textPath())
this.attr('x', self.attr('x'))
@@ -4661,7 +4290,7 @@ SVG.Tspan = SVG.invent({ create: 'tspan'
// Inherit from
-, inherit: SVG.Shape
+, inherit: SVG.Parent
// Add class methods
, extend: {
@@ -4722,16 +4351,6 @@ SVG.extend(SVG.Text, SVG.Tspan, { return tspan.text(text)
}
- // Clear all lines
-, clear: function() {
- var node = (this.textPath && this.textPath() || this).node
-
- // remove existing child nodes
- while (node.hasChildNodes())
- node.removeChild(node.lastChild)
-
- return this
- }
// Get length of text element
, length: function() {
return this.node.getComputedTextLength()
@@ -5029,7 +4648,7 @@ SVG.extend(SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.FX, { // Add x and y radius
radius: function(x, y) {
var type = (this._target || this).type;
- return type == 'radial' || type == 'circle' ?
+ return type == 'radialGradient' || type == 'radialGradient' ?
this.attr('r', new SVG.Number(x)) :
this.rx(x).ry(y == null ? x : y)
}
@@ -5042,7 +4661,7 @@ SVG.extend(SVG.Path, { }
// Get point at length
, pointAt: function(length) {
- return this.node.getPointAtLength(length)
+ return new SVG.Point(this.node.getPointAtLength(length))
}
})
@@ -5063,154 +4682,6 @@ SVG.extend(SVG.Parent, SVG.Text, SVG.Tspan, SVG.FX, { }
})
-SVG.Set = SVG.invent({
- // Initialize
- create: function(members) {
- // Set initial state
- Array.isArray(members) ? this.members = members : this.clear()
- }
-
- // Add class methods
-, extend: {
- // Add element to set
- add: function() {
- var i, il, elements = [].slice.call(arguments)
-
- for (i = 0, il = elements.length; i < il; i++)
- this.members.push(elements[i])
-
- return this
- }
- // Remove element from set
- , remove: function(element) {
- var i = this.index(element)
-
- // remove given child
- if (i > -1)
- this.members.splice(i, 1)
-
- return this
- }
- // Iterate over all members
- , each: function(block) {
- for (var i = 0, il = this.members.length; i < il; i++)
- block.apply(this.members[i], [i, this.members])
-
- return this
- }
- // Restore to defaults
- , clear: function() {
- // initialize store
- this.members = []
-
- return this
- }
- // Get the length of a set
- , length: function() {
- return this.members.length
- }
- // Checks if a given element is present in set
- , has: function(element) {
- return this.index(element) >= 0
- }
- // retuns index of given element in set
- , index: function(element) {
- return this.members.indexOf(element)
- }
- // Get member at given index
- , get: function(i) {
- return this.members[i]
- }
- // Get first member
- , first: function() {
- return this.get(0)
- }
- // Get last member
- , last: function() {
- return this.get(this.members.length - 1)
- }
- // Default value
- , valueOf: function() {
- return this.members
- }
- // Get the bounding box of all members included or empty box if set has no items
- , bbox: function(){
- // return an empty box of there are no members
- if (this.members.length == 0)
- return new SVG.RBox()
-
- // get the first rbox and update the target bbox
- var rbox = this.members[0].rbox(this.members[0].doc())
-
- this.each(function() {
- // user rbox for correct position and visual representation
- rbox = rbox.merge(this.rbox(this.doc()))
- })
-
- return rbox
- }
- }
-
- // Add parent method
-, construct: {
- // Create a new set
- set: function(members) {
- return new SVG.Set(members)
- }
- }
-})
-
-SVG.FX.Set = SVG.invent({
- // Initialize node
- create: function(set) {
- // store reference to set
- this.set = set
- }
-
-})
-
-// Alias methods
-SVG.Set.inherit = function() {
- var m
- , methods = []
-
- // gather shape methods
- for(var m in SVG.Shape.prototype)
- if (typeof SVG.Shape.prototype[m] == 'function' && typeof SVG.Set.prototype[m] != 'function')
- methods.push(m)
-
- // apply shape aliasses
- methods.forEach(function(method) {
- SVG.Set.prototype[method] = function() {
- for (var i = 0, il = this.members.length; i < il; i++)
- if (this.members[i] && typeof this.members[i][method] == 'function')
- this.members[i][method].apply(this.members[i], arguments)
-
- return method == 'animate' ? (this.fx || (this.fx = new SVG.FX.Set(this))) : this
- }
- })
-
- // clear methods for the next round
- methods = []
-
- // gather fx methods
- for(var m in SVG.FX.prototype)
- if (typeof SVG.FX.prototype[m] == 'function' && typeof SVG.FX.Set.prototype[m] != 'function')
- methods.push(m)
-
- // apply fx aliasses
- methods.forEach(function(method) {
- SVG.FX.Set.prototype[method] = function() {
- for (var i = 0, il = this.set.members.length; i < il; i++)
- this.set.members[i].fx[method].apply(this.set.members[i].fx, arguments)
-
- return this
- }
- })
-}
-
-
- SVG.extend(SVG.Element, {
// Store data values on svg nodes
@@ -5284,11 +4755,19 @@ SVG.get = function(id) { // Select elements by query string
SVG.select = function(query, parent) {
- return new SVG.Set(
- SVG.utils.map((parent || document).querySelectorAll(query), function(node) {
- return SVG.adopt(node)
- })
- )
+ return SVG.utils.map((parent || document).querySelectorAll(query), function(node) {
+ return SVG.adopt(node)
+ })
+}
+
+SVG.$$ = function(query, parent) {
+ return SVG.utils.map((parent || document).querySelectorAll(query), function(node) {
+ return SVG.adopt(node)
+ })
+}
+
+SVG.$ = function(query, parent) {
+ return SVG.adopt((parent || document).querySelector(query))
}
SVG.extend(SVG.Parent, {
@@ -5296,8 +4775,22 @@ SVG.extend(SVG.Parent, { select: function(query) {
return SVG.select(query, this.node)
}
+})
+ +function isNulledBox(box) {
+ return !box.w && !box.h && !box.x && !box.y
+}
+
+function domContains(node) {
+ return (document.documentElement.contains || function(node) {
+ // This is IE - it does not support contains() for top-level SVGs
+ while (node.parentNode){
+ node = node.parentNode;
+ }
+ return node == document
+ }).call(document.documentElement, node)
+}
-}) function pathRegReplace(a, b, c, d) {
return c + d.replace(SVG.regex.dots, ' .')
}
@@ -5463,55 +4956,152 @@ function fullBox(b) { // Get id from reference string
function idFromReference(url) {
- var m = url.toString().match(SVG.regex.reference)
+ var m = (url || '').toString().match(SVG.regex.reference)
if (m) return m[1]
}
// Create matrix array for looping
-var abcdef = 'abcdef'.split('') -// Add CustomEvent to IE9 and IE10
-if (typeof window.CustomEvent !== 'function') {
- // Code from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
- var CustomEvent = function(event, options) {
- options = options || { bubbles: false, cancelable: false, detail: undefined }
- var e = document.createEvent('CustomEvent')
- e.initCustomEvent(event, options.bubbles, options.cancelable, options.detail)
- return e
+var abcdef = 'abcdef'.split('')
+ +SVG.Box = SVG.invent({
+ create: function(source) {
+ var base = [0,0,0,0]
+ source = typeof source === 'string' ?
+ source.split(SVG.regex.delimiter).map(parseFloat) :
+ Array.isArray(source) ?
+ source :
+ typeof source == 'object' ?
+ [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] :
+ arguments.length == 4 ?
+ [].slice.call(arguments) :
+ base
+
+ this.x = source[0]
+ this.y = source[1]
+ this.width = source[2]
+ this.height = source[3]
+
+ // add center, right, bottom...
+ fullBox(this)
}
+, extend: {
+ // Merge rect box with another, return a new instance
+ merge: function(box) {
+ var x = Math.min(this.x, box.x)
+ , y = Math.min(this.y, box.y)
- CustomEvent.prototype = window.Event.prototype
+ return new SVG.Box(
+ x, y,
+ Math.max(this.x + this.width, box.x + box.width) - x,
+ Math.max(this.y + this.height, box.y + box.height) - y
+ )
+ }
- window.CustomEvent = CustomEvent
-}
+ , transform: function(m) {
+ var xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity, p, bbox
-// requestAnimationFrame / cancelAnimationFrame Polyfill with fallback based on Paul Irish
-(function(w) {
- var lastTime = 0
- var vendors = ['moz', 'webkit']
+ var pts = [
+ new SVG.Point(this.x, this.y),
+ new SVG.Point(this.x2, this.y),
+ new SVG.Point(this.x, this.y2),
+ new SVG.Point(this.x2, this.y2)
+ ]
+
+ pts.forEach(function(p) {
+ p = p.transform(m)
+ xMin = Math.min(xMin,p.x)
+ xMax = Math.max(xMax,p.x)
+ yMin = Math.min(yMin,p.y)
+ yMax = Math.max(yMax,p.y)
+ })
- for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
- w.requestAnimationFrame = w[vendors[x] + 'RequestAnimationFrame']
- w.cancelAnimationFrame = w[vendors[x] + 'CancelAnimationFrame'] ||
- w[vendors[x] + 'CancelRequestAnimationFrame']
+ return new SVG.Box(
+ xMin, yMin,
+ xMax-xMin,
+ yMax-yMin
+ )
+ }
+
+ , addOffset: function() {
+ // offset by window scroll position, because getBoundingClientRect changes when window is scrolled
+ this.x += window.pageXOffset
+ this.y += window.pageYOffset
+ return this
+ }
+ , toString: function() {
+ return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height
+ }
+ , morph: function(x, y, width, height){
+ this.destination = new SVG.Box(x, y, width, height)
+ return this
+ }
+
+ , at: function(pos) {
+ if(!this.destination) return this
+
+ return new SVG.Box(
+ this.x + (this.destination.x - this.x) * pos
+ , this.y + (this.destination.y - this.y) * pos
+ , this.width + (this.destination.width - this.width) * pos
+ , this.height + (this.destination.height - this.height) * pos
+ )
+
+ }
}
- w.requestAnimationFrame = w.requestAnimationFrame ||
- function(callback) {
- var currTime = new Date().getTime()
- var timeToCall = Math.max(0, 16 - (currTime - lastTime))
+ // Define Parent
+, parent: SVG.Element
- var id = w.setTimeout(function() {
- callback(currTime + timeToCall)
- }, timeToCall)
+ // Constructor
+, construct: {
+ // Get bounding box
+ bbox: function() {
+ var box
+
+ try {
+ // find native bbox
+ box = this.node.getBBox()
+
+ if(isNulledBox(box) && !domContains(this.node)) {
+ throw new Exception('Element not in the dom')
+ }
+ } catch(e) {
+ try {
+ var clone = this.clone(SVG.parser.draw.instance).show()
+ box = clone.node.getBBox()
+ clone.remove()
+ } catch(e) {
+ console.warn('Getting a bounding box of this element is not possible')
+ }
+ }
- lastTime = currTime + timeToCall
- return id
+ return new SVG.Box(box)
+ }
+
+ , rbox: function(el) {
+ // IE11 throws an error when element not in dom
+ try{
+ var box = new SVG.Box(this.node.getBoundingClientRect())
+ if (el) return box.transform(el.screenCTM().inverse())
+ return box.addOffset()
+ } catch(e) {
+ return new SVG.Box()
+ }
}
+ }
+})
- w.cancelAnimationFrame = w.cancelAnimationFrame || w.clearTimeout;
+SVG.extend(SVG.Doc, SVG.Nested, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View, {
+ viewbox: function(x, y, width, height) {
+ // act as getter
+ if(x == null) return new SVG.Box(this.attr('viewBox'))
+
+ // act as setter
+ return this.attr('viewBox', new SVG.Box(x, y, width, height))
+ }
+})
-}(window))
return SVG
diff --git a/dist/svg.min.js b/dist/svg.min.js index 838575c..45932ad 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1,3 +1,2 @@ -/*! svg.js v2.6.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function i(t,e,i,n){return i+n.replace(g.regex.dots," .")}function n(t){for(var e=t.slice(0),i=e.length;i--;)Array.isArray(e[i])&&(e[i]=n(e[i]));return e}function r(t,e){return t instanceof e}function s(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function o(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function a(t){return t.charAt(0).toUpperCase()+t.slice(1)}function h(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 u(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function l(t,e,i){if(null==e||null==i){var n=t.bbox();null==e?e=n.width/n.height*i:null==i&&(i=n.height/n.width*e)}return{width:e,height:i}}function c(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function f(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function d(t){return t instanceof g.Matrix||(t=new g.Matrix(t)),t}function p(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function m(t){for(var e=0,i=t.length,n="";e<i;e++)n+=t[e][0],null!=t[e][1]&&(n+=t[e][1],null!=t[e][2]&&(n+=" ",n+=t[e][2],null!=t[e][3]&&(n+=" ",n+=t[e][3],n+=" ",n+=t[e][4],null!=t[e][5]&&(n+=" ",n+=t[e][5],n+=" ",n+=t[e][6],null!=t[e][7]&&(n+=" ",n+=t[e][7])))));return n+" "}function x(e){for(var i=e.childNodes.length-1;i>=0;i--)e.childNodes[i]instanceof t.SVGElement&&x(e.childNodes[i]);return g.adopt(e).id(g.eid(e.nodeName))}function y(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function v(t){var e=t.toString().match(g.regex.reference);if(e)return e[1]}var g=this.SVG=function(t){if(g.supported)return t=new g.Doc(t),g.parser.draw||g.prepare(),t};if(g.ns="http://www.w3.org/2000/svg",g.xmlns="http://www.w3.org/2000/xmlns/",g.xlink="http://www.w3.org/1999/xlink",g.svgjs="http://svgjs.com/svgjs",g.supported=function(){return!!e.createElementNS&&!!e.createElementNS(g.ns,"svg").createSVGRect}(),!g.supported)return!1;g.did=1e3,g.eid=function(t){return"Svgjs"+a(t)+g.did++},g.create=function(t){var i=e.createElementNS(this.ns,t);return i.setAttribute("id",this.eid(t)),i},g.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];g.Set&&g.Set.inherit&&g.Set.inherit()},g.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,g.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&g.extend(e,t.extend),t.construct&&g.extend(t.parent||g.Container,t.construct),e},g.adopt=function(e){if(!e)return null;if(e.instance)return e.instance;var i;return i="svg"==e.nodeName?e.parentNode instanceof t.SVGElement?new g.Nested:new g.Doc:"linearGradient"==e.nodeName?new g.Gradient("linear"):"radialGradient"==e.nodeName?new g.Gradient("radial"):g[a(e.nodeName)]?new(g[a(e.nodeName)]):new g.Element(e),i.type=e.nodeName,i.node=e,e.instance=i,i instanceof g.Doc&&i.namespace().defs(),i.setData(JSON.parse(e.getAttribute("svgjs:data"))||{}),i},g.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new g.Doc(t):g.adopt(e.documentElement).nested()).size(2,0);g.parser={body:t||e.documentElement,draw:i.style("opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden").node,poly:i.polyline().node,path:i.path().node,native:g.create("svg")}},g.parser={native:g.create("svg")},e.addEventListener("DOMContentLoaded",function(){g.parser.draw||g.prepare()},!1),g.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])\-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},g.utils={map:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)r.push(e(t[i]));return r},filter:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)e(t[i])&&r.push(t[i]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},g.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},g.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?g.regex.isRgb.test(t)?(e=g.regex.rgb.exec(t.replace(g.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):g.regex.isHex.test(t)&&(e=g.regex.hex.exec(h(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))},g.extend(g.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+u(this.r)+u(this.g)+u(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new g.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new g.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}}),g.Color.test=function(t){return t+="",g.regex.isHex.test(t)||g.regex.isRgb.test(t)},g.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},g.Color.isColor=function(t){return g.Color.isRgb(t)||g.Color.test(t)},g.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},g.extend(g.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.indexOf(this.value[t])==-1&&i.push(this.value[t]);return this.value=i},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new g.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:this.split(t)},split:function(t){return t.trim().split(g.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=n(this.value),t}}),g.PointArray=function(t,e){g.Array.call(this,t,e||[[0,0]])},g.PointArray.prototype=new g.Array,g.PointArray.prototype.constructor=g.PointArray,g.extend(g.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.push(this.value[t].join(","));return i.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new g.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(g.regex.delimiter).map(parseFloat);t.length%2!==0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([t[i],t[i+1]]);return e},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)n.width&&(this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x),n.height&&(this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y);return this},bbox:function(){return g.parser.poly.setAttribute("points",this.toString()),g.parser.poly.getBBox()}});for(var w={M:function(t,e,i){return e.x=i.x=t[0],e.y=i.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,i){return e.x=i.x,e.y=i.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},b="mlhvqtcsaz".split(""),C=0,N=b.length;C<N;++C)w[b[C]]=function(t){return function(e,i,n){if("H"==t)e[0]=e[0]+i.x;else if("V"==t)e[0]=e[0]+i.y;else if("A"==t)e[5]=e[5]+i.x,e[6]=e[6]+i.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?i.y:i.x);return w[t](e,i,n)}}(b[C].toUpperCase());g.PathArray=function(t,e){g.Array.call(this,t,e||[["M",0,0]])},g.PathArray.prototype=new g.Array,g.PathArray.prototype.constructor=g.PathArray,g.extend(g.PathArray,{toString:function(){return m(this.value)},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n,r=this.value.length-1;r>=0;r--)n=this.value[r][0],"M"==n||"L"==n||"T"==n?(this.value[r][1]+=t,this.value[r][2]+=e):"H"==n?this.value[r][1]+=t:"V"==n?this.value[r][1]+=e:"C"==n||"S"==n||"Q"==n?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"==n&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"==n&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var i,n,r=this.bbox();for(i=this.value.length-1;i>=0;i--)n=this.value[i][0],"M"==n||"L"==n||"T"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y):"H"==n?this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x:"V"==n?this.value[i][1]=(this.value[i][1]-r.y)*e/r.height+r.y:"C"==n||"S"==n||"Q"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y,this.value[i][3]=(this.value[i][3]-r.x)*t/r.width+r.x,this.value[i][4]=(this.value[i][4]-r.y)*e/r.height+r.y,"C"==n&&(this.value[i][5]=(this.value[i][5]-r.x)*t/r.width+r.x,this.value[i][6]=(this.value[i][6]-r.y)*e/r.height+r.y)):"A"==n&&(this.value[i][1]=this.value[i][1]*t/r.width,this.value[i][2]=this.value[i][2]*e/r.height,this.value[i][6]=(this.value[i][6]-r.x)*t/r.width+r.x,this.value[i][7]=(this.value[i][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,i,n;for(t=new g.PathArray(t),n=this.value.length===t.value.length,e=0,i=this.value.length;n&&e<i;e++)n=this.value[e][0]===t.value[e][0];return n},morph:function(t){return t=new g.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,i,n,r,s=this.value,o=this.destination.value,a=[],h=new g.PathArray;for(e=0,i=s.length;e<i;e++){for(a[e]=[s[e][0]],n=1,r=s[e].length;n<r;n++)a[e][n]=s[e][n]+(o[e][n]-s[e][n])*t;"A"===a[e][0]&&(a[e][4]=+(0!=a[e][4]),a[e][5]=+(0!=a[e][5]))}return h.value=a,h},parse:function(t){if(t instanceof g.PathArray)return t.valueOf();var e,n,r={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7};t="string"==typeof t?t.replace(g.regex.numbersWithDots,i).replace(g.regex.pathLetters," $& ").replace(g.regex.hyphen,"$1 -").trim().split(g.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var n=[],s=new g.Point,o=new g.Point,a=0,h=t.length;do g.regex.isPathLetter.test(t[a])?(e=t[a],++a):"M"==e?e="L":"m"==e&&(e="l"),n.push(w[e].call(null,t.slice(a,a+=r[e.toUpperCase()]).map(parseFloat),s,o));while(h>a);return n},bbox:function(){return g.parser.path.setAttribute("d",this.toString()),g.parser.path.getBBox()}}),g.Number=g.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(g.regex.numberAndUnit),e&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5])):t instanceof g.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new g.Number(t),new g.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new g.Number(t),new g.Number(this-t,this.unit||t.unit)},times:function(t){return t=new g.Number(t),new g.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new g.Number(t),new g.Number(this/t,this.unit||t.unit)},to:function(t){var e=new g.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new g.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new g.Number(this.destination).minus(this).times(t).plus(this):this}}}),g.Element=g.invent({create:function(t){this._stroke=g.defaults.attrs.stroke,this._event=null,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this,this._stroke=t.getAttribute("stroke")||this._stroke)},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=l(this,t,e);return this.width(new g.Number(i.width)).height(new g.Number(i.height))},clone:function(t,e){this.writeDataToDom();var i=x(this.node.cloneNode(!0));return t?t.add(i):this.after(i),i},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return this.attr("id",t)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&t<i.x+i.width&&e<i.y+i.height},show:function(){return this.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(g.regex.delimiter)},hasClass:function(t){return this.classes().indexOf(t)!=-1},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!=t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return g.get(this.attr(t))},parent:function(e){var i=this;if(!i.node.parentNode)return null;if(i=g.adopt(i.node.parentNode),!e)return i;for(;i&&i.node instanceof t.SVGElement;){if("string"==typeof e?i.matches(e):i instanceof e)return i;i=g.adopt(i.node.parentNode)}},doc:function(){return this instanceof g.Doc?this:this.parent(g.Doc)},parents:function(t){var e=[],i=this;do{if(i=i.parent(t),!i||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return s(this.node,t)},native:function(){return this.node},svg:function(t){var i=e.createElement("svg");if(!(t&&this instanceof g.Parent))return i.appendChild(t=e.createElement("svg")),this.writeDataToDom(),t.appendChild(this.node.cloneNode(!0)),i.innerHTML.replace(/^<svg>/,"").replace(/<\/svg>$/,"");i.innerHTML="<svg>"+t.replace(/\n/,"").replace(/<(\w+)([^<]+?)\/>/g,"<$1$2></$1>")+"</svg>";for(var n=0,r=i.firstChild.childNodes.length;n<r;n++)this.node.appendChild(i.firstChild.firstChild);return this},writeDataToDom:function(){if(this.each||this.lines){var t=this.each?this:this.lines();t.each(function(){this.writeDataToDom()})}return this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return r(this,t)}}}),g.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return-Math.cos(t*Math.PI/2)+1}},g.morph=function(t){return function(e,i){return new g.MorphObj(e,i).at(t)}},g.Situation=g.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new g.Number(t.duration).valueOf(),this.delay=new g.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),g.FX=g.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new g.Situation({duration:t||1e3,delay:i||0,ease:g.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var e=new g.Situation({duration:t,delay:0,ease:g.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof g.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof g.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof g.Situation?this.start():this.situation.call(this)),this},initAnimations:function(){var t,e,i=this.situation;if(i.init)return this;for(t in i.animations)e=this.target()[t](),i.animations[t]instanceof g.Number&&(e=new g.Number(e)),i.animations[t]=e.morph(i.animations[t]);for(t in i.attrs)i.attrs[t]=new g.MorphObj(this.target().attr(t),i.attrs[t]);for(t in i.styles)i.styles[t]=new g.MorphObj(this.target().style(t),i.styles[t]);return i.initialTransformation=this.target().matrixify(),i.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var i=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!i&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return this.situation.loops===!0&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var i=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*i,this.situation.finish=this.situation.start+i,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var i=this.last();return i.loops=null==t||t,i.loop=0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return"undefined"==typeof t?e.reversed=!e.reversed:e.reversed=t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this._callStart()},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,g.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)}),this._callStart()},afterAll:function(t){var e=function e(i){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,g.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,i){return this.last()[i||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),this.situation.loops!==!1){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),this.situation.loops===!0||i<this.situation.loops?(this.pos=e-i,n=this.situation.loop,this.situation.loop=i):(this.absPos=this.situation.loops,this.pos=1,n=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!=Boolean((this.situation.loop-n)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1==this.pos&&!this.situation.reversed||this.situation.reversed&&0==this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.target().off(".fx"),this.active=!1),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,i,n=this,r=this.target(),s=this.situation;for(t in s.animations)i=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r[t].apply(r,i);for(t in s.attrs)i=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.attr.apply(r,i);for(t in s.styles)i=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.style.apply(r,i);if(s.transforms.length){for(i=s.initialTransformation,t=0,e=s.transforms.length;t<e;t++){var o=s.transforms[t];o instanceof g.Matrix?i=o.relative?i.multiply((new g.Matrix).morph(o).at(s.ease(this.pos))):i.morph(o).at(s.ease(this.pos)):(o.relative||o.undo(i.extract()),i=i.multiply(o.at(s.ease(this.pos))))}r.matrix(i)}return this},once:function(t,e,i){return i||(t=this.situation.ease(t)),this.situation.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:g.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new g.FX(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new g.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),g.MorphObj=g.invent({create:function(t,e){return g.Color.isColor(e)?new g.Color(t).morph(e):g.regex.numberAndUnit.test(e)?new g.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),g.extend(g.FX,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,e,"attrs");return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof g.G)return this.transform({x:t},e),this;var i=new g.Number(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof g.G)return this.transform({y:t},e),this;var i=new g.Number(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",new g.Number(t))},cy:function(t){return this.add("cy",new g.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof g.Text)this.attr("font-size",t);else{var i;t&&e||(i=this.target().bbox()),t||(t=i.width/i.height*e),e||(e=i.height/i.width*t),this.add("width",new g.Number(t)).add("height",new g.Number(e))}return this},plot:function(){return this.add("plot",arguments.length>1?[].slice.call(arguments):arguments[0])},leading:function(t){return this.target().leading?this.add("leading",new g.Number(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof g.Container&&this.add("viewbox",new g.ViewBox(t,e,i,n)),this},update:function(t){if(this.target()instanceof g.Stop){if("number"==typeof t||t instanceof g.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),g.Box=g.invent({create:function(t,e,i,n){return"object"!=typeof t||t instanceof g.Element?(4==arguments.length&&(this.x=t,this.y=e,this.width=i,this.height=n),void y(this)):g.Box.call(this,null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height)},extend:{merge:function(t){var e=new this.constructor;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,y(e)},transform:function(t){var e,i=1/0,n=-(1/0),r=1/0,s=-(1/0),o=[new g.Point(this.x,this.y),new g.Point(this.x2,this.y),new g.Point(this.x,this.y2),new g.Point(this.x2,this.y2)];return o.forEach(function(e){e=e.transform(t),i=Math.min(i,e.x),n=Math.max(n,e.x),r=Math.min(r,e.y),s=Math.max(s,e.y)}),e=new this.constructor,e.x=i,e.width=n-i,e.y=r,e.height=s-r,y(e),e}}}),g.BBox=g.invent({create:function(t){if(g.Box.apply(this,[].slice.call(arguments)),t instanceof g.Element){var i;try{if(e.documentElement.contains){if(!e.documentElement.contains(t.node))throw new Exception("Element not in the dom")}else{for(var n=t.node;n.parentNode;)n=n.parentNode;if(n!=e)throw new Exception("Element not in the dom")}i=t.node.getBBox()}catch(e){if(t instanceof g.Shape){var r=t.clone(g.parser.draw.instance).show();i=r.node.getBBox(),r.remove()}else i={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}g.Box.call(this,i)}},inherit:g.Box,parent:g.Element,construct:{bbox:function(){return new g.BBox(this)}}}),g.BBox.prototype.constructor=g.BBox,g.extend(g.Element,{tbox:function(){return console.warn("Use of TBox is deprecated and mapped to RBox. Use .rbox() instead."),this.rbox(this.doc())}}),g.RBox=g.invent({create:function(t){g.Box.apply(this,[].slice.call(arguments)),t instanceof g.Element&&g.Box.call(this,t.node.getBoundingClientRect())},inherit:g.Box,parent:g.Element,extend:{addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this}},construct:{rbox:function(t){return t?new g.RBox(this).transform(t.screenCTM().inverse()):new g.RBox(this).addOffset()}}}),g.RBox.prototype.constructor=g.RBox,g.Matrix=g.invent({create:function(t){var e,i=f([1,0,0,1,0,0]);for(t=t instanceof g.Element?t.matrixify():"string"==typeof t?f(t.split(g.regex.delimiter).map(parseFloat)):6==arguments.length?f([].slice.call(arguments)):Array.isArray(t)?f(t):"object"==typeof t?t:i,e=P.length-1;e>=0;--e)this[P[e]]=t&&"number"==typeof t[P[e]]?t[P[e]]:i[P[e]]},extend:{extract:function(){var t=c(this,0,1),e=c(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new g.Matrix(this)}},clone:function(){return new g.Matrix(this)},morph:function(t){return this.destination=new g.Matrix(t),this},at:function(t){if(!this.destination)return this;var e=new g.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t});return e},multiply:function(t){return new g.Matrix(this.native().multiply(d(t).native()))},inverse:function(){return new g.Matrix(this.native().inverse())},translate:function(t,e){return new g.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),this.around(i,n,new g.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=g.utils.radians(t),this.around(e,i,new g.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):"y"==t?this.scale(1,-1,0,e):this.scale(-1,-1,t,null!=e?e:t)},skew:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),t=g.utils.radians(t),e=g.utils.radians(e),this.around(i,n,new g.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,i){return this.skew(t,0,e,i)},skewY:function(t,e,i){return this.skew(0,t,e,i)},around:function(t,e,i){return this.multiply(new g.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new g.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=g.parser.native.createSVGMatrix(),e=P.length-1;e>=0;e--)t[P[e]]=this[P[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:g.Element,construct:{ctm:function(){return new g.Matrix(this.node.getCTM()); -},screenCTM:function(){if(this instanceof g.Nested){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new g.Matrix(e)}return new g.Matrix(this.node.getScreenCTM())}}}),g.Point=g.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new g.Point(this)},morph:function(t,e){return this.destination=new g.Point(t,e),this},at:function(t){if(!this.destination)return this;var e=new g.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=g.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new g.Point(this.native().matrixTransform(t.native()))}}}),g.extend(g.Element,{point:function(t,e){return new g.Point(t,e).transform(this.screenCTM().inverse())}}),g.extend(g.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=g.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?g.defaults.attrs[t]:g.regex.isNumber.test(e)?parseFloat(e):e;"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),"fill"!=t&&"stroke"!=t||(g.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof g.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new g.Number(e):g.Color.isColor(e)?e=new g.Color(e):Array.isArray(e)&&(e=new g.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}}),g.extend(g.Element,{transform:function(t,e){var i,n,r=this;if("object"!=typeof t)return i=new g.Matrix(r).extract(),"string"==typeof t?i[t]:i;if(i=new g.Matrix(r),e=!!e||!!t.relative,null!=t.a)i=e?i.multiply(new g.Matrix(t)):new g.Matrix(t);else if(null!=t.rotation)p(t,r),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(p(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var s=i.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(p(t,r),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var s=i.extract();i=i.multiply((new g.Matrix).skew(s.skewX,s.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new g.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),g.extend(g.FX,{transform:function(t,e){var i,n,r=this.target();return"object"!=typeof t?(i=new g.Matrix(r).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new g.Matrix(t):null!=t.rotation?(p(t,r),i=new g.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(p(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new g.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(p(t,r),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new g.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new g.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(i=new g.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),this._callStart()):this)}}),g.extend(g.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){var t=(this.attr("transform")||"").split(g.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(g.regex.delimiter).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(f(e[1])):t[e[0]].apply(t,e[1])},new g.Matrix);return t},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.screenCTM().inverse();return this.addTo(t).untransform().transform(i.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),g.Transformation=g.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.constructor.call(this,[].slice.call(arguments));if(Array.isArray(t))for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[i];else if("object"==typeof t)for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[this.arguments[i]];this.inversed=!1,e===!0&&(this.inversed=!0)},extend:{arguments:[],method:"",at:function(t){for(var e=[],i=0,n=this.arguments.length;i<n;++i)e.push(this[this.arguments[i]]);var r=this._undo||new g.Matrix;return r=(new g.Matrix).morph(g.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,i=this.arguments.length;e<i;++e)t[this.arguments[e]]="undefined"==typeof this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(g[a(this.method)])(t,!0).at(1),this}}}),g.Translate=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),g.Rotate=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new g.Matrix).rotate((new g.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){return this._undo=t,this}}}),g.Scale=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),g.Skew=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),g.extend(g.Element,{style:function(t,e){if(0==arguments.length)return this.node.style.cssText||"";if(arguments.length<2)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!g.regex.isCss.test(t))return this.node.style[o(t)];for(t=t.split(/\s*;\s*/).filter(function(t){return!!t}).map(function(t){return t.split(/\s*:\s*/)});e=t.pop();)this.style(e[0],e[1])}else this.node.style[o(t)]=null===e||g.regex.isBlank.test(e)?"":e;return this}}),g.Parent=g.invent({create:function(t){this.constructor.call(this,t)},inherit:g.Element,extend:{children:function(){return g.utils.map(g.utils.filterSVGElements(this.node.childNodes),function(t){return g.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return g.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;i<n;i++)r[i]instanceof g.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof g.Container&&r[i].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},defs:function(){return this.doc().defs()}}}),g.extend(g.Parent,{ungroup:function(t,e){return 0===e||this instanceof g.Defs||this.node==g.parser.draw?this:(t=t||(this instanceof g.Doc?this:this.parent(g.Parent)),e=e||1/0,this.each(function(){return this instanceof g.Defs?this:this instanceof g.Parent?this.ungroup(t,e-1):this.toParent(t)}),this.node.firstChild||this.remove(),this)},flatten:function(t,e){return this.ungroup(t,e)}}),g.Container=g.invent({create:function(t){this.constructor.call(this,t)},inherit:g.Parent}),g.ViewBox=g.invent({create:function(t){var e,i,n,r,s,o,a,h,u=[0,0,0,0],l=1,c=1,f=/[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi;if(t instanceof g.Element){for(a=t,h=t,o=(t.attr("viewBox")||"").match(f),s=t.bbox,n=new g.Number(t.width()),r=new g.Number(t.height());"%"==n.unit;)l*=n.value,n=new g.Number(a instanceof g.Doc?a.parent().offsetWidth:a.parent().width()),a=a.parent();for(;"%"==r.unit;)c*=r.value,r=new g.Number(h instanceof g.Doc?h.parent().offsetHeight:h.parent().height()),h=h.parent();this.x=0,this.y=0,this.width=n*l,this.height=r*c,this.zoom=1,o&&(e=parseFloat(o[0]),i=parseFloat(o[1]),n=parseFloat(o[2]),r=parseFloat(o[3]),this.zoom=this.width/this.height>n/r?this.height/r:this.width/n,this.x=e,this.y=i,this.width=n,this.height=r)}else t="string"==typeof t?t.match(f).map(function(t){return parseFloat(t)}):Array.isArray(t)?t:"object"==typeof t?[t.x,t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):u,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3]},extend:{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,i,n){return this.destination=new g.ViewBox(t,e,i,n),this},at:function(t){return this.destination?new g.ViewBox([this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t]):this}},parent:g.Container,construct:{viewbox:function(t,e,i,n){return 0==arguments.length?new g.ViewBox(this):this.attr("viewBox",new g.ViewBox(t,e,i,n))}}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){g.Element.prototype[t]=function(e){return g.on(this.node,t,e),this}}),g.listeners=[],g.handlerMap=[],g.listenerId=0,g.on=function(t,e,i,n,r){var s=i.bind(n||t.instance||t),o=(g.handlerMap.indexOf(t)+1||g.handlerMap.push(t))-1,a=e.split(".")[0],h=e.split(".")[1]||"*";g.listeners[o]=g.listeners[o]||{},g.listeners[o][a]=g.listeners[o][a]||{},g.listeners[o][a][h]=g.listeners[o][a][h]||{},i._svgjsListenerId||(i._svgjsListenerId=++g.listenerId),g.listeners[o][a][h][i._svgjsListenerId]=s,t.addEventListener(a,s,r||!1)},g.off=function(t,e,i){var n=g.handlerMap.indexOf(t),r=e&&e.split(".")[0],s=e&&e.split(".")[1],o="";if(n!=-1)if(i){if("function"==typeof i&&(i=i._svgjsListenerId),!i)return;g.listeners[n][r]&&g.listeners[n][r][s||"*"]&&(t.removeEventListener(r,g.listeners[n][r][s||"*"][i],!1),delete g.listeners[n][r][s||"*"][i])}else if(s&&r){if(g.listeners[n][r]&&g.listeners[n][r][s]){for(i in g.listeners[n][r][s])g.off(t,[r,s].join("."),i);delete g.listeners[n][r][s]}}else if(s)for(e in g.listeners[n])for(o in g.listeners[n][e])s===o&&g.off(t,[e,s].join("."));else if(r){if(g.listeners[n][r]){for(o in g.listeners[n][r])g.off(t,[r,o].join("."));delete g.listeners[n][r]}}else{for(e in g.listeners[n])g.off(t,e);delete g.listeners[n],delete g.handlerMap[n]}},g.extend(g.Element,{on:function(t,e,i,n){return g.on(this.node,t,e,i,n),this},off:function(t,e){return g.off(this.node,t,e),this},fire:function(e,i){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:i,cancelable:!0})),this._event=e,this},event:function(){return this._event}}),g.Defs=g.invent({create:"defs",inherit:g.Container}),g.G=g.invent({create:"g",inherit:g.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new g.G)}}}),g.extend(g.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof g.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof g.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),g.Mask=g.invent({create:function(){this.constructor.call(this,g.create("mask")),this.targets=[]},inherit:g.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return this.targets=[],this.parent().removeElement(this),this}},construct:{mask:function(){return this.defs().put(new g.Mask)}}}),g.extend(g.Element,{maskWith:function(t){return this.masker=t instanceof g.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)}}),g.ClipPath=g.invent({create:function(){this.constructor.call(this,g.create("clipPath")),this.targets=[]},inherit:g.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return this.targets=[],this.parent().removeElement(this),this}},construct:{clip:function(){return this.defs().put(new g.ClipPath)}}}),g.extend(g.Element,{clipWith:function(t){return this.clipper=t instanceof g.ClipPath?t:this.parent().clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),g.Gradient=g.invent({create:function(t){this.constructor.call(this,g.create(t+"Gradient")),this.type=t},inherit:g.Container,extend:{at:function(t,e,i){return this.put(new g.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),g.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),g.extend(g.Gradient,g.FX,{from:function(t,e){return"radial"==(this._target||this).type?this.attr({fx:new g.Number(t),fy:new g.Number(e)}):this.attr({x1:new g.Number(t),y1:new g.Number(e)})},to:function(t,e){return"radial"==(this._target||this).type?this.attr({cx:new g.Number(t),cy:new g.Number(e)}):this.attr({x2:new g.Number(t),y2:new g.Number(e)})}}),g.extend(g.Defs,{gradient:function(t,e){return this.put(new g.Gradient(t)).update(e)}}),g.Stop=g.invent({create:"stop",inherit:g.Element,extend:{update:function(t){return("number"==typeof t||t instanceof g.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 g.Number(t.offset)),this}}}),g.Pattern=g.invent({create:"pattern",inherit:g.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),g.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),g.extend(g.Defs,{pattern:function(t,e,i){return this.put(new g.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),g.Doc=g.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,g.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:g.Container,extend:{namespace:function(){return this.attr({xmlns:g.ns,version:"1.1"}).attr("xmlns:xlink",g.xlink,g.xmlns).attr("xmlns:svgjs",g.svgjs,g.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=g.adopt(t):this._defs=new g.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},spof:function(t){var e=this.node.getScreenCTM();return e&&this.style("left",-e.e%1+"px").style("top",-e.f%1+"px"),this},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,g.parser.draw.parentNode||this.node.appendChild(g.parser.draw),this}}}),g.Shape=g.invent({create:function(t){this.constructor.call(this,t)},inherit:g.Element}),g.Bare=g.invent({create:function(t,e){if(this.constructor.call(this,g.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:g.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),g.extend(g.Parent,{element:function(t,e){return this.put(new g.Bare(t,e))}}),g.Symbol=g.invent({create:"symbol",inherit:g.Container,construct:{symbol:function(){return this.put(new g.Symbol)}}}),g.Use=g.invent({create:"use",inherit:g.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,g.xlink)}},construct:{use:function(t,e){return this.put(new g.Use).element(t,e)}}}),g.Rect=g.invent({create:"rect",inherit:g.Shape,construct:{rect:function(t,e){return this.put(new g.Rect).size(t,e)}}}),g.Circle=g.invent({create:"circle",inherit:g.Shape,construct:{circle:function(t){return this.put(new g.Circle).rx(new g.Number(t).divide(2)).move(0,0)}}}),g.extend(g.Circle,g.FX,{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),g.Ellipse=g.invent({create:"ellipse",inherit:g.Shape,construct:{ellipse:function(t,e){return this.put(new g.Ellipse).size(t,e).move(0,0)}}}),g.extend(g.Ellipse,g.Rect,g.FX,{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),g.extend(g.Circle,g.Ellipse,{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new g.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new g.Number(t).divide(2))},size:function(t,e){var i=l(this,t,e);return this.rx(new g.Number(i.width).divide(2)).ry(new g.Number(i.height).divide(2))}}),g.Line=g.invent({create:"line",inherit:g.Shape,extend:{array:function(){return new g.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return null==t?this.array():(t="undefined"!=typeof e?{x1:t,y1:e,x2:i,y2:n}:new g.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var i=l(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return g.Line.prototype.plot.apply(this.put(new g.Line),null!=t?[t,e,i,n]:[0,0,0,0])}}}),g.Polyline=g.invent({create:"polyline",inherit:g.Shape,construct:{polyline:function(t){return this.put(new g.Polyline).plot(t||new g.PointArray)}}}),g.Polygon=g.invent({create:"polygon",inherit:g.Shape,construct:{polygon:function(t){return this.put(new g.Polygon).plot(t||new g.PointArray)}}}),g.extend(g.Polyline,g.Polygon,{array:function(){return this._array||(this._array=new g.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new g.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=l(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),g.extend(g.Line,g.Polyline,g.Polygon,{morphArray:g.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),g.Path=g.invent({create:"path",inherit:g.Shape,extend:{morphArray:g.PathArray,array:function(){return this._array||(this._array=new g.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new g.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var i=l(this,t,e);return this.attr("d",this.array().size(i.width,i.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new g.Path).plot(t||new g.PathArray)}}}),g.Image=g.invent({create:"image",inherit:g.Shape,extend:{load:function(e){if(!e)return this;var i=this,n=new t.Image;return g.on(n,"load",function(){var t=i.parent(g.Pattern);null!==t&&(0==i.width()&&0==i.height()&&i.size(n.width,n.height),t&&0==t.width()&&0==t.height()&&t.size(i.width(),i.height()),"function"==typeof i._loaded&&i._loaded.call(i,{width:n.width,height:n.height,ratio:n.width/n.height,url:e}))}),g.on(n,"error",function(t){"function"==typeof i._error&&i._error.call(i,t)}),this.attr("href",n.src=this.src=e,g.xlink)},loaded:function(t){return this._loaded=t,this},error:function(t){return this._error=t,this}},construct:{image:function(t,e,i){return this.put(new g.Image).load(t).size(e||0,i||e||0)}}}),g.Text=g.invent({create:function(){this.constructor.call(this,g.create("text")),this.dom.leading=new g.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",g.defaults.attrs["font-family"])},inherit:g.Shape,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),i="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-i:e:this.attr("y","number"==typeof t?t+i:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if("undefined"==typeof t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i<n;++i)0!=i&&3!=e[i].nodeType&&1==g.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var i=0,r=t.length;i<r;i++)this.tspan(t[i]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new g.Number(t),this.rebuild())},lines:function(){var t=(this.textPath&&this.textPath()||this).node,e=g.utils.map(g.utils.filterSVGElements(t.childNodes),function(t){return g.adopt(t)});return new g.Set(e)},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new g.Number(this.attr("font-size"));this.lines().each(function(){this.dom.newLined&&(e.textPath()||this.attr("x",e.attr("x")),"\n"==this.text()?i+=n:(this.attr("dy",n+i),i=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new g.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new g.Text).text(t)},plain:function(t){return this.put(new g.Text).plain(t)}}}),g.Tspan=g.invent({create:"tspan",inherit:g.Shape,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(g.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),g.extend(g.Text,g.Tspan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,i=new g.Tspan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.text(t)},clear:function(){for(var t=(this.textPath&&this.textPath()||this).node;t.hasChildNodes();)t.removeChild(t.lastChild);return this},length:function(){return this.node.getComputedTextLength()}}),g.TextPath=g.invent({create:"textPath",inherit:g.Parent,parent:g.Text,construct:{path:function(t){for(var e=new g.TextPath,i=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+i,g.xlink),this},array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),i=null;return e&&(i=e.plot(t)),null==t?i:this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return g.adopt(this.node.firstChild)}}}),g.Nested=g.invent({create:function(){this.constructor.call(this,g.create("svg")),this.style("overflow","visible")},inherit:g.Container,construct:{nested:function(){return this.put(new g.Nested)}}}),g.A=g.invent({create:"a",inherit:g.Container,extend:{to:function(t){return this.attr("href",t,g.xlink)},show:function(t){return this.attr("show",t,g.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new g.A).to(t)}}}),g.extend(g.Element,{linkTo:function(t){var e=new g.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),g.Marker=g.invent({create:"marker",inherit:g.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,i){return this.defs().marker(t,e,i)}}}),g.extend(g.Defs,{marker:function(t,e,i){return this.put(new g.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),g.extend(g.Line,g.Polyline,g.Polygon,g.Path,{marker:function(t,e,i,n){var r=["marker"];return"all"!=t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof g.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(r,t)}});var M={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"==e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,i={};i[t]=function(i){if("undefined"==typeof i)return this;if("string"==typeof i||g.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=M[t].length-1;e>=0;e--)null!=i[M[t][e]]&&this.attr(M.prefix(t,M[t][e]),i[M[t][e]]);return this},g.extend(g.Element,g.FX,i)}),g.extend(g.Element,g.FX,{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({skew:t,cx:e,cy:i}):this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return e="number"==typeof t?t:e,this.transform({flip:t||"both",offset:e})},matrix:function(t){return this.attr("transform",new g.Matrix(6==arguments.length?[].slice.call(arguments):t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new g.Number(t).plus(this instanceof g.FX?0:this.x()),!0)},dy:function(t){return this.y(new g.Number(t).plus(this instanceof g.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),g.extend(g.Rect,g.Ellipse,g.Circle,g.Gradient,g.FX,{radius:function(t,e){var i=(this._target||this).type;return"radial"==i||"circle"==i?this.attr("r",new g.Number(t)):this.rx(t).ry(null==e?t:e)}}),g.extend(g.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),g.extend(g.Parent,g.Text,g.Tspan,g.FX,{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"==t?this.leading(e):"anchor"==t?this.attr("text-anchor",e):"size"==t||"family"==t||"weight"==t||"stretch"==t||"variant"==t||"style"==t?this.attr("font-"+t,e):this.attr(t,e)}}),g.Set=g.invent({create:function(t){Array.isArray(t)?this.members=t:this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;t<e;t++)this.members.push(i[t]);return this},remove:function(t){var e=this.index(t);return e>-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e<i;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},length:function(){return this.members.length},has:function(t){return this.index(t)>=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},first:function(){return this.get(0)},last:function(){return this.get(this.members.length-1)},valueOf:function(){return this.members},bbox:function(){if(0==this.members.length)return new g.RBox;var t=this.members[0].rbox(this.members[0].doc());return this.each(function(){t=t.merge(this.rbox(this.doc()))}),t}},construct:{set:function(t){return new g.Set(t)}}}),g.FX.Set=g.invent({create:function(t){this.set=t}}),g.Set.inherit=function(){var t,e=[];for(var t in g.Shape.prototype)"function"==typeof g.Shape.prototype[t]&&"function"!=typeof g.Set.prototype[t]&&e.push(t);e.forEach(function(t){g.Set.prototype[t]=function(){for(var e=0,i=this.members.length;e<i;e++)this.members[e]&&"function"==typeof this.members[e][t]&&this.members[e][t].apply(this.members[e],arguments);return"animate"==t?this.fx||(this.fx=new g.FX.Set(this)):this}}),e=[];for(var t in g.FX.prototype)"function"==typeof g.FX.prototype[t]&&"function"!=typeof g.FX.Set.prototype[t]&&e.push(t);e.forEach(function(t){g.FX.Set.prototype[t]=function(){for(var e=0,i=this.set.members.length;e<i;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},g.extend(g.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{ -return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),g.extend(g.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={})}}),g.get=function(t){var i=e.getElementById(v(t)||t);return g.adopt(i)},g.select=function(t,i){return new g.Set(g.utils.map((i||e).querySelectorAll(t),function(t){return g.adopt(t)}))},g.extend(g.Parent,{select:function(t){return g.select(t,this.node)}});var P="abcdef".split("");if("function"!=typeof t.CustomEvent){var A=function(t,i){i=i||{bubbles:!1,cancelable:!1,detail:void 0};var n=e.createEvent("CustomEvent");return n.initCustomEvent(t,i.bubbles,i.cancelable,i.detail),n};A.prototype=t.Event.prototype,t.CustomEvent=A}return function(e){for(var i=0,n=["moz","webkit"],r=0;r<n.length&&!t.requestAnimationFrame;++r)e.requestAnimationFrame=e[n[r]+"RequestAnimationFrame"],e.cancelAnimationFrame=e[n[r]+"CancelAnimationFrame"]||e[n[r]+"CancelRequestAnimationFrame"];e.requestAnimationFrame=e.requestAnimationFrame||function(t){var n=(new Date).getTime(),r=Math.max(0,16-(n-i)),s=e.setTimeout(function(){t(n+r)},r);return i=n+r,s},e.cancelAnimationFrame=e.cancelAnimationFrame||e.clearTimeout}(t),g});
\ No newline at end of file +/*! svg.js v3.0.0 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function i(t){return!(t.w||t.h||t.x||t.y)}function n(t){return(e.documentElement.contains||function(t){for(;t.parentNode;)t=t.parentNode;return t==e}).call(e.documentElement,t)}function r(t,e,i,n){return i+n.replace(b.regex.dots," .")}function s(t){for(var e=t.slice(0),i=e.length;i--;)Array.isArray(e[i])&&(e[i]=s(e[i]));return e}function a(t,e){return t instanceof e}function o(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function h(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function u(t){return t.charAt(0).toUpperCase()+t.slice(1)}function l(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 c(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function f(t,e,i){if(null==e||null==i){var n=t.bbox();null==e?e=n.width/n.height*i:null==i&&(i=n.height/n.width*e)}return{width:e,height:i}}function d(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function p(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function x(t){return t instanceof b.Matrix||(t=new b.Matrix(t)),t}function m(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function y(t){for(var e=0,i=t.length,n="";e<i;e++)n+=t[e][0],null!=t[e][1]&&(n+=t[e][1],null!=t[e][2]&&(n+=" ",n+=t[e][2],null!=t[e][3]&&(n+=" ",n+=t[e][3],n+=" ",n+=t[e][4],null!=t[e][5]&&(n+=" ",n+=t[e][5],n+=" ",n+=t[e][6],null!=t[e][7]&&(n+=" ",n+=t[e][7])))));return n+" "}function v(e){for(var i=e.childNodes.length-1;i>=0;i--)e.childNodes[i]instanceof t.SVGElement&&v(e.childNodes[i]);return b.adopt(e).id(b.eid(e.nodeName))}function g(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function w(t){var e=(t||"").toString().match(b.regex.reference);if(e)return e[1]}var b=this.SVG=function(t){if(b.supported)return t=new b.Doc(t),b.parser.draw||b.prepare(),t};if(b.ns="http://www.w3.org/2000/svg",b.xmlns="http://www.w3.org/2000/xmlns/",b.xlink="http://www.w3.org/1999/xlink",b.svgjs="http://svgjs.com/svgjs",b.supported=function(){return!!e.createElementNS&&!!e.createElementNS(b.ns,"svg").createSVGRect}(),!b.supported)return!1;b.did=1e3,b.eid=function(t){return"Svgjs"+u(t)+b.did++},b.create=function(t){var i=e.createElementNS(this.ns,t);return i.setAttribute("id",this.eid(t)),i},b.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]},b.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,b.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&b.extend(e,t.extend),t.construct&&b.extend(t.parent||b.Container,t.construct),e},b.adopt=function(e){if(!e)return null;if(e.instance)return e.instance;var i;return i="svg"==e.nodeName?e.parentNode instanceof t.SVGElement?new b.Nested:new b.Doc:"linearGradient"==e.nodeName?new b.Gradient("linear"):"radialGradient"==e.nodeName?new b.Gradient("radial"):b[u(e.nodeName)]?new(b[u(e.nodeName)]):new b.Element(e),i.type=e.nodeName,i.node=e,e.instance=i,i instanceof b.Doc&&i.namespace().defs(),i.setData(JSON.parse(e.getAttribute("svgjs:data"))||{}),i},b.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new b.Doc(t):b.adopt(e.documentElement).nested()).size(2,0);b.parser={body:t||e.documentElement,draw:i.style({opacity:0,position:"absolute",left:"-100%",top:"-100%",overflow:"hidden"}).node,poly:i.polyline().node,path:i.path().node,native:b.create("svg")}},b.parser={native:b.create("svg")},e.addEventListener("DOMContentLoaded",function(){b.parser.draw||b.prepare()},!1),b.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,transforms:/\)\s*,?\s*/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,delimiter:/[\s,]+/,hyphen:/([^e])\-/gi,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,numbersWithDots:/((\d?\.\d+(?:e[+-]?\d+)?)((?:\.\d+(?:e[+-]?\d+)?)+))+/gi,dots:/\./g},b.utils={map:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)r.push(e(t[i]));return r},filter:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)e(t[i])&&r.push(t[i]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(e){return this.filter(e,function(e){return e instanceof t.SVGElement})}},b.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},b.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?b.regex.isRgb.test(t)?(e=b.regex.rgb.exec(t.replace(b.regex.whitespace,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):b.regex.isHex.test(t)&&(e=b.regex.hex.exec(l(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))},b.extend(b.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+c(this.r)+c(this.g)+c(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new b.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new b.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}}),b.Color.test=function(t){return t+="",b.regex.isHex.test(t)||b.regex.isRgb.test(t)},b.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},b.Color.isColor=function(t){return b.Color.isRgb(t)||b.Color.test(t)},b.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},b.extend(b.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.indexOf(this.value[t])==-1&&i.push(this.value[t]);return this.value=i},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new b.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:t.trim().split(b.regex.delimiter).map(parseFloat)},reverse:function(){return this.value.reverse(),this},clone:function(){var t=new this.constructor;return t.value=s(this.value),t}}),b.PointArray=function(t,e){b.Array.call(this,t,e||[[0,0]])},b.PointArray.prototype=new b.Array,b.PointArray.prototype.constructor=b.PointArray,b.extend(b.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.push(this.value[t].join(","));return i.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new b.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t)){if(Array.isArray(t[0]))return t}else t=t.trim().split(b.regex.delimiter).map(parseFloat);t.length%2!==0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([t[i],t[i+1]]);return e},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)n.width&&(this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x),n.height&&(this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y);return this},bbox:function(){return b.parser.poly.setAttribute("points",this.toString()),b.parser.poly.getBBox()}});for(var C={M:function(t,e,i){return e.x=i.x=t[0],e.y=i.y=t[1],["M",e.x,e.y]},L:function(t,e){return e.x=t[0],e.y=t[1],["L",t[0],t[1]]},H:function(t,e){return e.x=t[0],["H",t[0]]},V:function(t,e){return e.y=t[0],["V",t[0]]},C:function(t,e){return e.x=t[4],e.y=t[5],["C",t[0],t[1],t[2],t[3],t[4],t[5]]},S:function(t,e){return e.x=t[2],e.y=t[3],["S",t[0],t[1],t[2],t[3]]},Q:function(t,e){return e.x=t[2],e.y=t[3],["Q",t[0],t[1],t[2],t[3]]},T:function(t,e){return e.x=t[0],e.y=t[1],["T",t[0],t[1]]},Z:function(t,e,i){return e.x=i.x,e.y=i.y,["Z"]},A:function(t,e){return e.x=t[5],e.y=t[6],["A",t[0],t[1],t[2],t[3],t[4],t[5],t[6]]}},M="mlhvqtcsaz".split(""),P=0,N=M.length;P<N;++P)C[M[P]]=function(t){return function(e,i,n){if("H"==t)e[0]=e[0]+i.x;else if("V"==t)e[0]=e[0]+i.y;else if("A"==t)e[5]=e[5]+i.x,e[6]=e[6]+i.y;else for(var r=0,s=e.length;r<s;++r)e[r]=e[r]+(r%2?i.y:i.x);return C[t](e,i,n)}}(M[P].toUpperCase());b.PathArray=function(t,e){b.Array.call(this,t,e||[["M",0,0]])},b.PathArray.prototype=new b.Array,b.PathArray.prototype.constructor=b.PathArray,b.extend(b.PathArray,{toString:function(){return y(this.value)},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n,r=this.value.length-1;r>=0;r--)n=this.value[r][0],"M"==n||"L"==n||"T"==n?(this.value[r][1]+=t,this.value[r][2]+=e):"H"==n?this.value[r][1]+=t:"V"==n?this.value[r][1]+=e:"C"==n||"S"==n||"Q"==n?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"==n&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"==n&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var i,n,r=this.bbox();for(i=this.value.length-1;i>=0;i--)n=this.value[i][0],"M"==n||"L"==n||"T"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y):"H"==n?this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x:"V"==n?this.value[i][1]=(this.value[i][1]-r.y)*e/r.height+r.y:"C"==n||"S"==n||"Q"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y,this.value[i][3]=(this.value[i][3]-r.x)*t/r.width+r.x,this.value[i][4]=(this.value[i][4]-r.y)*e/r.height+r.y,"C"==n&&(this.value[i][5]=(this.value[i][5]-r.x)*t/r.width+r.x,this.value[i][6]=(this.value[i][6]-r.y)*e/r.height+r.y)):"A"==n&&(this.value[i][1]=this.value[i][1]*t/r.width,this.value[i][2]=this.value[i][2]*e/r.height,this.value[i][6]=(this.value[i][6]-r.x)*t/r.width+r.x,this.value[i][7]=(this.value[i][7]-r.y)*e/r.height+r.y);return this},equalCommands:function(t){var e,i,n;for(t=new b.PathArray(t),n=this.value.length===t.value.length,e=0,i=this.value.length;n&&e<i;e++)n=this.value[e][0]===t.value[e][0];return n},morph:function(t){return t=new b.PathArray(t),this.equalCommands(t)?this.destination=t:this.destination=null,this},at:function(t){if(!this.destination)return this;var e,i,n,r,s=this.value,a=this.destination.value,o=[],h=new b.PathArray;for(e=0,i=s.length;e<i;e++){for(o[e]=[s[e][0]],n=1,r=s[e].length;n<r;n++)o[e][n]=s[e][n]+(a[e][n]-s[e][n])*t;"A"===o[e][0]&&(o[e][4]=+(0!=o[e][4]),o[e][5]=+(0!=o[e][5]))}return h.value=o,h},parse:function(t){if(t instanceof b.PathArray)return t.valueOf();var e,i,n={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7};t="string"==typeof t?t.replace(b.regex.numbersWithDots,r).replace(b.regex.pathLetters," $& ").replace(b.regex.hyphen,"$1 -").trim().split(b.regex.delimiter):t.reduce(function(t,e){return[].concat.call(t,e)},[]);var i=[],s=new b.Point,a=new b.Point,o=0,h=t.length;do b.regex.isPathLetter.test(t[o])?(e=t[o],++o):"M"==e?e="L":"m"==e&&(e="l"),i.push(C[e].call(null,t.slice(o,o+=n[e.toUpperCase()]).map(parseFloat),s,a));while(h>o);return i},bbox:function(){return b.parser.path.setAttribute("d",this.toString()),b.parser.path.getBBox()}}),b.Number=b.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(b.regex.numberAndUnit),e&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5])):t instanceof b.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return t=new b.Number(t),new b.Number(this+t,this.unit||t.unit)},minus:function(t){return t=new b.Number(t),new b.Number(this-t,this.unit||t.unit)},times:function(t){return t=new b.Number(t),new b.Number(this*t,this.unit||t.unit)},divide:function(t){return t=new b.Number(t),new b.Number(this/t,this.unit||t.unit)},to:function(t){var e=new b.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new b.Number(t),t.relative&&(this.destination.value+=this.value),this},at:function(t){return this.destination?new b.Number(this.destination).minus(this).times(t).plus(this):this}}}),b.Element=b.invent({create:function(t){this._event=null,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=f(this,t,e);return this.width(new b.Number(i.width)).height(new b.Number(i.height))},clone:function(t,e){this.writeDataToDom();var i=v(this.node.cloneNode(!0));return t?t.add(i):this.after(i),i},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return this.attr("id",t)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&t<i.x+i.width&&e<i.y+i.height},show:function(){return this.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(b.regex.delimiter)},hasClass:function(t){return this.classes().indexOf(t)!=-1},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!=t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return b.get(this.attr(t))},parent:function(e){var i=this;if(!i.node.parentNode)return null;if(i=b.adopt(i.node.parentNode),!e)return i;for(;i&&i.node instanceof t.SVGElement;){if("string"==typeof e?i.matches(e):i instanceof e)return i;i=b.adopt(i.node.parentNode)}},doc:function(){return this instanceof b.Doc?this:this.parent(b.Doc)},parents:function(t){var e=[],i=this;do{if(i=i.parent(t),!i||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return o(this.node,t)},native:function(){return this.node},svg:function(t){var i,n;if(!(t&&this instanceof b.Parent))return this.node.outerHTML;for(i=e.createElementNS(b.ns,"svg"),i.innerHTML=t,n=i.childNodes.length;n--;)1!=i.firstChild.nodeType?i.removeChild(i.firstChild):this.node.appendChild(i.firstChild);return this},writeDataToDom:function(){return this.is(b.Parent)&&this.each(function(){this.writeDataToDom()}),this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return a(this,t)}}}),b.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return-Math.cos(t*Math.PI/2)+1}},b.morph=function(t){return function(e,i){return new b.MorphObj(e,i).at(t)}},b.Situation=b.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new b.Number(t.duration).valueOf(),this.delay=new b.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),b.FX=b.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new b.Situation({duration:t||1e3,delay:i||0,ease:b.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var e=new b.Situation({duration:t,delay:0,ease:b.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof b.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=t.requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){t.cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof b.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof b.Situation?this.start():this.situation.call(this)),this},initAnimations:function(){var t,e,i=this.situation;if(i.init)return this;for(t in i.animations)e=this.target()[t](),i.animations[t]instanceof b.Number&&(e=new b.Number(e)),i.animations[t]=e.morph(i.animations[t]);for(t in i.attrs)i.attrs[t]=new b.MorphObj(this.target().attr(t),i.attrs[t]);for(t in i.styles)i.styles[t]=new b.MorphObj(this.target().style(t),i.styles[t]);return i.initialTransformation=this.target().matrixify(),i.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){var i=this.active;return this.active=!1,e&&this.clearQueue(),t&&this.situation&&(!i&&this.startCurrent(),this.atEnd()),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return this.situation.loops===!0&&(this.situation.loops=this.situation.loop+1),"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var i=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*i,this.situation.finish=this.situation.start+i,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var i=this.last();return i.loops=null==t||t,i.loop=0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return"undefined"==typeof t?e.reversed=!e.reversed:e.reversed=t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this._callStart()},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,b.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)}),this._callStart()},afterAll:function(t){var e=function e(i){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this._callStart()},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,b.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)}),this._callStart()},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,i){return this.last()[i||"animations"][t]=e,this._callStart()},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),this.situation.loops!==!1){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),this.situation.loops===!0||i<this.situation.loops?(this.pos=e-i,n=this.situation.loop,this.situation.loop=i):(this.absPos=this.situation.loops,this.pos=1,n=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!=Boolean((this.situation.loop-n)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1==this.pos&&!this.situation.reversed||this.situation.reversed&&0==this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.target().off(".fx"),this.active=!1),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,i,n=this,r=this.target(),s=this.situation;for(t in s.animations)i=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r[t].apply(r,i);for(t in s.attrs)i=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.attr.apply(r,i);for(t in s.styles)i=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(n.pos),n.pos):t}),r.style.apply(r,i);if(s.transforms.length){for(i=s.initialTransformation,t=0,e=s.transforms.length;t<e;t++){var a=s.transforms[t];a instanceof b.Matrix?i=a.relative?i.multiply((new b.Matrix).morph(a).at(s.ease(this.pos))):i.morph(a).at(s.ease(this.pos)):(a.relative||a.undo(i.extract()),i=i.multiply(a.at(s.ease(this.pos))))}r.matrix(i)}return this},once:function(t,e,i){return i||(t=this.situation.ease(t)),this.situation.once[t]=e,this},_callStart:function(){return setTimeout(function(){this.start()}.bind(this),0),this}},parent:b.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new b.FX(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new b.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),b.MorphObj=b.invent({create:function(t,e){return b.Color.isColor(e)?new b.Color(t).morph(e):b.regex.numberAndUnit.test(e)?new b.Number(t).morph(e):(this.value=t,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),b.extend(b.FX,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,e,"attrs");return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.add(t,e,"styles");return this},x:function(t,e){if(this.target()instanceof b.G)return this.transform({x:t},e),this;var i=new b.Number(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof b.G)return this.transform({y:t},e),this;var i=new b.Number(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",new b.Number(t))},cy:function(t){return this.add("cy",new b.Number(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof b.Text)this.attr("font-size",t);else{var i;t&&e||(i=this.target().bbox()),t||(t=i.width/i.height*e),e||(e=i.height/i.width*t),this.add("width",new b.Number(t)).add("height",new b.Number(e))}return this},plot:function(){return this.add("plot",arguments.length>1?[].slice.call(arguments):arguments[0])},leading:function(t){return this.target().leading?this.add("leading",new b.Number(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof b.Container&&this.add("viewbox",new b.Box(t,e,i,n)),this},update:function(t){if(this.target()instanceof b.Stop){if("number"==typeof t||t instanceof b.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),b.Matrix=b.invent({create:function(t){var e,i=p([1,0,0,1,0,0]);for(t=t instanceof b.Element?t.matrixify():"string"==typeof t?p(t.split(b.regex.delimiter).map(parseFloat)):6==arguments.length?p([].slice.call(arguments)):Array.isArray(t)?p(t):"object"==typeof t?t:i,e=A.length-1;e>=0;--e)this[A[e]]=t&&"number"==typeof t[A[e]]?t[A[e]]:i[A[e]]},extend:{extract:function(){var t=d(this,0,1),e=d(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new b.Matrix(this)}},clone:function(){return new b.Matrix(this)},morph:function(t){return this.destination=new b.Matrix(t),this},at:function(t){if(!this.destination)return this;var e=new b.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t});return e},multiply:function(t){return new b.Matrix(this.native().multiply(x(t).native()))},inverse:function(){return new b.Matrix(this.native().inverse())},translate:function(t,e){return new b.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),this.around(i,n,new b.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=b.utils.radians(t),this.around(e,i,new b.Matrix(Math.cos(t),Math.sin(t),-Math.sin(t),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):"y"==t?this.scale(1,-1,0,e):this.scale(-1,-1,t,null!=e?e:t)},skew:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),t=b.utils.radians(t),e=b.utils.radians(e),this.around(i,n,new b.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,i){return this.skew(t,0,e,i)},skewY:function(t,e,i){return this.skew(0,t,e,i)},around:function(t,e,i){return this.multiply(new b.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new b.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=b.parser.native.createSVGMatrix(),e=A.length-1;e>=0;e--)t[A[e]]=this[A[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:b.Element,construct:{ctm:function(){return new b.Matrix(this.node.getCTM())},screenCTM:function(){if(this instanceof b.Nested){var t=this.rect(1,1),e=t.node.getScreenCTM();return t.remove(),new b.Matrix(e)}return new b.Matrix(this.node.getScreenCTM())}}}),b.Point=b.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new b.Point(this)},morph:function(t,e){return this.destination=new b.Point(t,e),this},at:function(t){if(!this.destination)return this;var e=new b.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=b.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new b.Point(this.native().matrixTransform(t.native()))}}}),b.extend(b.Element,{point:function(t,e){return new b.Point(t,e).transform(this.screenCTM().inverse())}}),b.extend(b.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=b.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?b.defaults.attrs[t]:b.regex.isNumber.test(e)?parseFloat(e):e;"fill"!=t&&"stroke"!=t||(b.regex.isImage.test(e)&&(e=this.doc().defs().image(e)),e instanceof b.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new b.Number(e):b.Color.isColor(e)?e=new b.Color(e):Array.isArray(e)&&(e=new b.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}}),b.extend(b.Element,{transform:function(t,e){var i,n,r=this;if("object"!=typeof t)return i=new b.Matrix(r).extract(),"string"==typeof t?i[t]:i;if(i=new b.Matrix(r),e=!!e||!!t.relative,null!=t.a)i=e?i.multiply(new b.Matrix(t)):new b.Matrix(t);else if(null!=t.rotation)m(t,r),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(m(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1, +!e){var s=i.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(m(t,r),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var s=i.extract();i=i.multiply((new b.Matrix).skew(s.skewX,s.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),b.extend(b.FX,{transform:function(t,e){var i,n,r=this.target();return"object"!=typeof t?(i=new b.Matrix(r).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new b.Matrix(t):null!=t.rotation?(m(t,r),i=new b.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(m(t,r),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new b.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(m(t,r),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new b.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?("x"==t.flip||"y"==t.flip?t.offset=null==t.offset?r.bbox()["c"+t.flip]:t.offset:null==t.offset?(n=r.bbox(),t.flip=n.cx,t.offset=n.cy):t.flip=t.offset,i=(new b.Matrix).flip(t.flip,t.offset)):null==t.x&&null==t.y||(i=new b.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),this._callStart()):this)}}),b.extend(b.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){var t=(this.attr("transform")||"").split(b.regex.transforms).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(b.regex.delimiter).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(p(e[1])):t[e[0]].apply(t,e[1])},new b.Matrix);return t},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.screenCTM().inverse();return this.addTo(t).untransform().transform(i.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),b.Transformation=b.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.constructor.call(this,[].slice.call(arguments));if(Array.isArray(t))for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[i];else if("object"==typeof t)for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[this.arguments[i]];this.inversed=!1,e===!0&&(this.inversed=!0)},extend:{arguments:[],method:"",at:function(t){for(var e=[],i=0,n=this.arguments.length;i<n;++i)e.push(this[this.arguments[i]]);var r=this._undo||new b.Matrix;return r=(new b.Matrix).morph(b.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,i=this.arguments.length;e<i;++e)t[this.arguments[e]]="undefined"==typeof this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(b[u(this.method)])(t,!0).at(1),this}}}),b.Translate=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),b.Rotate=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new b.Matrix).rotate((new b.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){return this._undo=t,this}}}),b.Scale=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),b.Skew=b.invent({parent:b.Matrix,inherit:b.Transformation,create:function(t,e){this.constructor.apply(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),b.extend(b.Element,{style:function(t,e){if(0==arguments.length)return this.node.style.cssText||"";if(arguments.length<2){if("object"!=typeof t)return this.node.style[h(t)];for(e in t)this.style(e,t[e])}else this.node.style[h(t)]=null===e||b.regex.isBlank.test(e)?"":e;return this}}),b.Parent=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Element,extend:{children:function(){return b.utils.map(b.utils.filterSVGElements(this.node.childNodes),function(t){return b.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return b.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;i<n;i++)r[i]instanceof b.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof b.Container&&r[i].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},defs:function(){return this.doc().defs()}}}),b.extend(b.Parent,{flatten:function(t){return this instanceof b.Defs?this:(t=t||(this instanceof b.Doc?this:this.parent(b.Parent)),this.each(function(){return this instanceof b.Defs?this:this instanceof b.Parent?this.flatten(t):this.toParent(t)}),this.node.firstChild||this.remove(),this)}}),b.Container=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Parent}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){b.Element.prototype[t]=function(e){return b.on(this.node,t,e),this}}),b.listeners=[],b.handlerMap=[],b.listenerId=0,b.on=function(t,e,i,n,r){var s=i.bind(n||t.instance||t),a=(b.handlerMap.indexOf(t)+1||b.handlerMap.push(t))-1,o=e.split(".")[0],h=e.split(".")[1]||"*";b.listeners[a]=b.listeners[a]||{},b.listeners[a][o]=b.listeners[a][o]||{},b.listeners[a][o][h]=b.listeners[a][o][h]||{},i._svgjsListenerId||(i._svgjsListenerId=++b.listenerId),b.listeners[a][o][h][i._svgjsListenerId]=s,t.addEventListener(o,s,r||!1)},b.off=function(t,e,i){var n=b.handlerMap.indexOf(t),r=e&&e.split(".")[0],s=e&&e.split(".")[1],a="";if(n!=-1)if(i){if("function"==typeof i&&(i=i._svgjsListenerId),!i)return;b.listeners[n][r]&&b.listeners[n][r][s||"*"]&&(t.removeEventListener(r,b.listeners[n][r][s||"*"][i],!1),delete b.listeners[n][r][s||"*"][i])}else if(s&&r){if(b.listeners[n][r]&&b.listeners[n][r][s]){for(i in b.listeners[n][r][s])b.off(t,[r,s].join("."),i);delete b.listeners[n][r][s]}}else if(s)for(e in b.listeners[n])for(a in b.listeners[n][e])s===a&&b.off(t,[e,s].join("."));else if(r){if(b.listeners[n][r]){for(a in b.listeners[n][r])b.off(t,[r,a].join("."));delete b.listeners[n][r]}}else{for(e in b.listeners[n])b.off(t,e);delete b.listeners[n],delete b.handlerMap[n]}},b.extend(b.Element,{on:function(t,e,i,n){return b.on(this.node,t,e,i,n),this},off:function(t,e){return b.off(this.node,t,e),this},fire:function(e,i){return e instanceof t.Event?this.node.dispatchEvent(e):this.node.dispatchEvent(e=new t.CustomEvent(e,{detail:i,cancelable:!0})),this._event=e,this},event:function(){return this._event}}),b.Defs=b.invent({create:"defs",inherit:b.Container}),b.G=b.invent({create:"g",inherit:b.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new b.G)}}}),b.extend(b.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof b.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof b.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),b.Mask=b.invent({create:"mask",inherit:b.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unmask()}),b.Element.prototype.remove.call(this)},targets:function(){return b.select('svg [mask*="'+this.id()+'"]')}},construct:{mask:function(){return this.defs().put(new b.Mask)}}}),b.extend(b.Element,{maskWith:function(t){var e=t instanceof b.Mask?t:this.parent().mask().add(t);return this.attr("mask",'url("#'+e.attr("id")+'")')},unmask:function(){return this.attr("mask",null)},masker:function(){return this.reference("mask")}}),b.ClipPath=b.invent({create:"clipPath",inherit:b.Container,extend:{remove:function(){return this.targets().forEach(function(t){t.unclip()}),b.Element.prototype.remove.call(this)},targets:function(){return b.select('svg [clip-path*="'+this.id()+'"]')}},construct:{clip:function(){return this.defs().put(new b.ClipPath)}}}),b.extend(b.Element,{clipWith:function(t){var e=t instanceof b.ClipPath?t:this.parent().clip().add(t);return this.attr("clip-path",'url("#'+e.attr("id")+'")')},unclip:function(){return this.attr("clip-path",null)},clipper:function(){return this.reference("clip-path")}}),b.Gradient=b.invent({create:function(t){this.constructor.call(this,b.create(t+"Gradient"))},inherit:b.Container,extend:{at:function(t,e,i){return this.put(new b.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),b.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),b.extend(b.Gradient,b.FX,{from:function(t,e){return"radialGradient"==(this._target||this).type?this.attr({fx:new b.Number(t),fy:new b.Number(e)}):this.attr({x1:new b.Number(t),y1:new b.Number(e)})},to:function(t,e){return"radialGradient"==(this._target||this).type?this.attr({cx:new b.Number(t),cy:new b.Number(e)}):this.attr({x2:new b.Number(t),y2:new b.Number(e)})}}),b.extend(b.Defs,{gradient:function(t,e){return this.put(new b.Gradient(t)).update(e)}}),b.Stop=b.invent({create:"stop",inherit:b.Element,extend:{update:function(t){return("number"==typeof t||t instanceof b.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 b.Number(t.offset)),this}}}),b.Pattern=b.invent({create:"pattern",inherit:b.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),b.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),b.extend(b.Defs,{pattern:function(t,e,i){return this.put(new b.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),b.Doc=b.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,b.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:b.Container,extend:{namespace:function(){return this.attr({xmlns:b.ns,version:"1.1"}).attr("xmlns:xlink",b.xlink,b.xmlns).attr("xmlns:svgjs",b.svgjs,b.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=b.adopt(t):this._defs=new b.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},spof:function(t){var e=this.node.getScreenCTM();return e&&this.style("left",-e.e%1+"px").style("top",-e.f%1+"px"),this},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,b.parser.draw.parentNode||this.node.appendChild(b.parser.draw),this}}}),b.Shape=b.invent({create:function(t){this.constructor.call(this,t)},inherit:b.Element}),b.Bare=b.invent({create:function(t,e){if(this.constructor.call(this,b.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:b.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),b.extend(b.Parent,{element:function(t,e){return this.put(new b.Bare(t,e))}}),b.Symbol=b.invent({create:"symbol",inherit:b.Container,construct:{symbol:function(){return this.put(new b.Symbol)}}}),b.Use=b.invent({create:"use",inherit:b.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,b.xlink)}},construct:{use:function(t,e){return this.put(new b.Use).element(t,e)}}}),b.Rect=b.invent({create:"rect",inherit:b.Shape,construct:{rect:function(t,e){return this.put(new b.Rect).size(t,e)}}}),b.Circle=b.invent({create:"circle",inherit:b.Shape,construct:{circle:function(t){return this.put(new b.Circle).rx(new b.Number(t).divide(2)).move(0,0)}}}),b.extend(b.Circle,b.FX,{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),b.Ellipse=b.invent({create:"ellipse",inherit:b.Shape,construct:{ellipse:function(t,e){return this.put(new b.Ellipse).size(t,e).move(0,0)}}}),b.extend(b.Ellipse,b.Rect,b.FX,{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),b.extend(b.Circle,b.Ellipse,{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new b.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new b.Number(t).divide(2))},size:function(t,e){var i=f(this,t,e);return this.rx(new b.Number(i.width).divide(2)).ry(new b.Number(i.height).divide(2))}}),b.Line=b.invent({create:"line",inherit:b.Shape,extend:{array:function(){return new b.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return null==t?this.array():(t="undefined"!=typeof e?{x1:t,y1:e,x2:i,y2:n}:new b.PointArray(t).toLine(),this.attr(t))},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var i=f(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return b.Line.prototype.plot.apply(this.put(new b.Line),null!=t?[t,e,i,n]:[0,0,0,0])}}}),b.Polyline=b.invent({create:"polyline",inherit:b.Shape,construct:{polyline:function(t){return this.put(new b.Polyline).plot(t||new b.PointArray)}}}),b.Polygon=b.invent({create:"polygon",inherit:b.Shape,construct:{polygon:function(t){return this.put(new b.Polygon).plot(t||new b.PointArray)}}}),b.extend(b.Polyline,b.Polygon,{array:function(){return this._array||(this._array=new b.PointArray(this.attr("points")))},plot:function(t){return null==t?this.array():this.clear().attr("points","string"==typeof t?t:this._array=new b.PointArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=f(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),b.extend(b.Line,b.Polyline,b.Polygon,{morphArray:b.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),b.Path=b.invent({create:"path",inherit:b.Shape,extend:{morphArray:b.PathArray,array:function(){return this._array||(this._array=new b.PathArray(this.attr("d")))},plot:function(t){return null==t?this.array():this.clear().attr("d","string"==typeof t?t:this._array=new b.PathArray(t))},clear:function(){return delete this._array,this},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var i=f(this,t,e);return this.attr("d",this.array().size(i.width,i.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new b.Path).plot(t||new b.PathArray)}}}),b.Image=b.invent({create:"image",inherit:b.Shape,extend:{load:function(e,i){if(!e)return this;var n=new t.Image;return b.on(n,"load",function(t){var r=this.parent();0==this.width()&&0==this.height()&&this.size(n.width,n.height),r instanceof b.Pattern&&0==r.width()&&0==r.height()&&r.size(this.width(),this.height()),"function"==typeof i&&i.call(this,{width:n.width,height:n.height,ratio:n.width/n.height,url:e})},this),this.attr("href",n.src=e,b.xlink)}},construct:{image:function(t,e){return this.put(new b.Image).size(0,0).load(t,e)}}}),b.Text=b.invent({create:function(){this.constructor.call(this,b.create("text")),this.dom.leading=new b.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",b.defaults.attrs["font-family"])},inherit:b.Parent,extend:{x:function(t){return null==t?this.attr("x"):this.attr("x",t)},y:function(t){var e=this.attr("y"),i="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-i:e:this.attr("y","number"==typeof t?t+i:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if("undefined"==typeof t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i<n;++i)0!=i&&3!=e[i].nodeType&&1==b.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var i=0,r=t.length;i<r;i++)this.tspan(t[i]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new b.Number(t),this.rebuild())},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new b.Number(this.attr("font-size"));this.each(function(){this.dom.newLined&&(e.textPath()||this.attr("x",e.attr("x")),"\n"==this.text()?i+=n:(this.attr("dy",n+i),i=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new b.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new b.Text).text(t)},plain:function(t){return this.put(new b.Text).plain(t)}}}),b.Tspan=b.invent({create:"tspan",inherit:b.Parent,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(b.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),b.extend(b.Text,b.Tspan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,i=new b.Tspan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.text(t)},length:function(){return this.node.getComputedTextLength()}}),b.TextPath=b.invent({create:"textPath",inherit:b.Parent,parent:b.Text,construct:{path:function(t){for(var e=new b.TextPath,i=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+i,b.xlink),this},array:function(){var t=this.track();return t?t.array():null},plot:function(t){var e=this.track(),i=null;return e&&(i=e.plot(t)),null==t?i:this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return b.adopt(this.node.firstChild)}}}),b.Nested=b.invent({create:function(){this.constructor.call(this,b.create("svg")),this.style("overflow","visible")},inherit:b.Container,construct:{nested:function(){return this.put(new b.Nested)}}}),b.A=b.invent({create:"a",inherit:b.Container,extend:{to:function(t){return this.attr("href",t,b.xlink)},show:function(t){return this.attr("show",t,b.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new b.A).to(t)}}}),b.extend(b.Element,{linkTo:function(t){var e=new b.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),b.Marker=b.invent({create:"marker",inherit:b.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,i){return this.defs().marker(t,e,i)}}}),b.extend(b.Defs,{marker:function(t,e,i){return this.put(new b.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),b.extend(b.Line,b.Polyline,b.Polygon,b.Path,{marker:function(t,e,i,n){var r=["marker"];return"all"!=t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof b.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(r,t)}});var k={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"==e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,i={};i[t]=function(i){if("undefined"==typeof i)return this;if("string"==typeof i||b.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=k[t].length-1;e>=0;e--)null!=i[k[t][e]]&&this.attr(k.prefix(t,k[t][e]),i[k[t][e]]);return this},b.extend(b.Element,b.FX,i)}),b.extend(b.Element,b.FX,{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({skew:t,cx:e,cy:i}):this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return e="number"==typeof t?t:e,this.transform({flip:t||"both",offset:e})},matrix:function(t){return this.attr("transform",new b.Matrix(6==arguments.length?[].slice.call(arguments):t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x(new b.Number(t).plus(this instanceof b.FX?0:this.x()),!0)},dy:function(t){return this.y(new b.Number(t).plus(this instanceof b.FX?0:this.y()),!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),b.extend(b.Rect,b.Ellipse,b.Circle,b.Gradient,b.FX,{radius:function(t,e){var i=(this._target||this).type;return"radialGradient"==i||"radialGradient"==i?this.attr("r",new b.Number(t)):this.rx(t).ry(null==e?t:e)}}),b.extend(b.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return new b.Point(this.node.getPointAtLength(t))}}),b.extend(b.Parent,b.Text,b.Tspan,b.FX,{font:function(t,e){if("object"==typeof t)for(e in t)this.font(e,t[e]);return"leading"==t?this.leading(e):"anchor"==t?this.attr("text-anchor",e):"size"==t||"family"==t||"weight"==t||"stretch"==t||"variant"==t||"style"==t?this.attr("font-"+t,e):this.attr(t,e)}}),b.extend(b.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),b.extend(b.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={})}}),b.get=function(t){var i=e.getElementById(w(t)||t);return b.adopt(i)},b.select=function(t,i){return b.utils.map((i||e).querySelectorAll(t),function(t){return b.adopt(t)})},b.$$=function(t,i){return b.utils.map((i||e).querySelectorAll(t),function(t){return b.adopt(t)})},b.$=function(t,i){return b.adopt((i||e).querySelector(t))},b.extend(b.Parent,{select:function(t){return b.select(t,this.node)}});var A="abcdef".split("");return b.Box=b.invent({create:function(t){var e=[0,0,0,0];t="string"==typeof t?t.split(b.regex.delimiter).map(parseFloat):Array.isArray(t)?t:"object"==typeof t?[null!=t.left?t.left:t.x,null!=t.top?t.top:t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):e,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3],g(this)},extend:{merge:function(t){var e=Math.min(this.x,t.x),i=Math.min(this.y,t.y);return new b.Box(e,i,Math.max(this.x+this.width,t.x+t.width)-e,Math.max(this.y+this.height,t.y+t.height)-i)},transform:function(t){var e=1/0,i=-(1/0),n=1/0,r=-(1/0),s=[new b.Point(this.x,this.y),new b.Point(this.x2,this.y),new b.Point(this.x,this.y2),new b.Point(this.x2,this.y2)];return s.forEach(function(s){s=s.transform(t),e=Math.min(e,s.x),i=Math.max(i,s.x),n=Math.min(n,s.y),r=Math.max(r,s.y)}),new b.Box(e,n,i-e,r-n)},addOffset:function(){return this.x+=t.pageXOffset,this.y+=t.pageYOffset,this},toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t,e,i,n){return this.destination=new b.Box(t,e,i,n),this},at:function(t){return this.destination?new b.Box(this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t):this}},parent:b.Element,construct:{bbox:function(){var t;try{if(t=this.node.getBBox(),i(t)&&!n(this.node))throw new Exception("Element not in the dom")}catch(i){try{var e=this.clone(b.parser.draw.instance).show();t=e.node.getBBox(),e.remove()}catch(t){console.warn("Getting a bounding box of this element is not possible")}}return new b.Box(t)},rbox:function(t){try{var e=new b.Box(this.node.getBoundingClientRect());return t?e.transform(t.screenCTM().inverse()):e.addOffset()}catch(t){return new b.Box}}}}),b.extend(b.Doc,b.Nested,b.Symbol,b.Image,b.Pattern,b.Marker,b.ForeignObject,b.View,{viewbox:function(t,e,i,n){return null==t?new b.Box(this.attr("viewBox")):this.attr("viewBox",new b.Box(t,e,i,n))}}),b});
\ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index 1ea682f..08ba58f 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -40,16 +40,14 @@ var parts = [ , 'src/number.js'
, 'src/element.js'
, 'src/fx.js'
-, 'src/boxes.js'
, 'src/matrix.js'
, 'src/point.js'
, 'src/attr.js'
, 'src/transform.js'
, 'src/style.js'
, 'src/parent.js'
-, 'src/ungroup.js'
+, 'src/flatten.js'
, 'src/container.js'
-, 'src/viewbox.js'
, 'src/event.js'
, 'src/defs.js'
, 'src/group.js'
@@ -82,6 +80,7 @@ var parts = [ , 'src/selector.js'
, 'src/helpers.js'
, 'src/polyfill.js'
+, 'src/boxes.js'
]
gulp.task('clean', function() {
diff --git a/package.json b/package.json index 68b937d..7853409 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "svg.js", - "version": "2.6.0", + "version": "3.0.0", "description": "A lightweight library for manipulating and animating SVG.", "url": "https://svgdotjs.github.io/", "homepage": "https://svgdotjs.github.io/", @@ -57,7 +57,8 @@ "build": "gulp", "build:test": "gulp unify", "test": "karma start .config/karma.conf.js --single-run", - "test:quick": "karma start .config/karma.quick.js" + "test:quick": "karma start .config/karma.quick.js", + "lint": "standard --verbose | snazzy" }, "devDependencies": { "coveralls": "^2.11.15", @@ -79,6 +80,17 @@ "karma-jasmine": "^1.0.2", "karma-phantomjs-launcher": "^1.0.2", "request": "^2.78.0", + "snazzy": "^6.0.0", + "standard": "^9.0.1", "svgdom": "latest" + }, + "standard": { + "ignore": [ + "/dist", + "/src/umd.js" + ], + "globals": [ + "SVG" + ] } } diff --git a/spec/SpecRunner.html b/spec/SpecRunner.html index 3093ad1..0da16b0 100644 --- a/spec/SpecRunner.html +++ b/spec/SpecRunner.html @@ -94,7 +94,6 @@ <script src="spec/rect.js"></script> <script src="spec/regex.js"></script> <script src="spec/selector.js"></script> - <script src="spec/set.js"></script> <script src="spec/sugar.js"></script> <script src="spec/svg.js"></script> <script src="spec/symbol.js"></script> diff --git a/spec/spec/adopter.js b/spec/spec/adopter.js index a73bc35..7f2f45b 100644 --- a/spec/spec/adopter.js +++ b/spec/spec/adopter.js @@ -3,10 +3,10 @@ describe('Adopter', function() { beforeEach(function() { path = SVG.get('lineAB') - polyline = SVG.get('inlineSVG').select('polyline').first() - polygon = SVG.get('inlineSVG').select('polygon').first() - linearGradient = SVG.get('inlineSVG').select('linearGradient').first() - radialGradient = SVG.get('inlineSVG').select('radialGradient').first() + polyline = SVG.get('inlineSVG').select('polyline')[0] + polygon = SVG.get('inlineSVG').select('polygon')[0] + linearGradient = SVG.get('inlineSVG').select('linearGradient')[0] + radialGradient = SVG.get('inlineSVG').select('radialGradient')[0] }) describe('with SVG.Doc instance', function() { @@ -56,7 +56,7 @@ describe('Adopter', function() { it('is instance of SVG.Gradient', function() { expect(linearGradient instanceof SVG.Gradient).toBeTruthy() }) - it('has type of linear', function() { + it('has type of linearGradient', function() { expect(linearGradient.type).toBe('linearGradient') // actually it should be 'linear'. see #606 }) }) @@ -65,14 +65,14 @@ describe('Adopter', function() { it('is instance of SVG.Gradient', function() { expect(radialGradient instanceof SVG.Gradient).toBeTruthy() }) - it('has type of radial', function() { + it('has type of radialGradient', function() { expect(radialGradient.type).toBe('radialGradient') // actually it should be 'radial'. see #606 }) }) describe('with node that has no matching svg.js class', function() { it('wraps the node in the base SVG.Element class', function() { - var desc = SVG.get('inlineSVG').select('desc').first() + var desc = SVG.get('inlineSVG').select('desc')[0] expect(desc instanceof SVG.Element).toBeTruthy() }) }) diff --git a/spec/spec/boxes.js b/spec/spec/boxes.js index b3c9685..9e33c60 100644 --- a/spec/spec/boxes.js +++ b/spec/spec/boxes.js @@ -1,29 +1,81 @@ describe('Box', function() { - it('creates a new instance without passing anything', function() { - var box = new SVG.Box + describe('initialization', function() { + var box - expect(box instanceof SVG.Box).toBe(true) - expect(box).toEqual(jasmine.objectContaining({ - x:0, y:0, cx:0, cy:0, width:0, height:0 - })) - }) + it('creates a new box with default values', function() { + box = new SVG.Box - it('creates a new instance with 4 arguments given', function() { - var box = new SVG.Box(10, 20, 100, 50) + expect(box instanceof SVG.Box).toBe(true) + expect(box).toEqual(jasmine.objectContaining({ + x:0, y:0, cx:0, cy:0, width:0, height:0 + })) + }) - expect(box instanceof SVG.Box).toBe(true) - expect(box).toEqual(jasmine.objectContaining({ - x:10, y:20, cx:60, cy:45, width:100, height:50 - })) - }) + it('creates a new box from parsed string', function() { + box = new SVG.Box('10. 100 200 300') + expect(box.x).toBe(10) + expect(box.y).toBe(100) + expect(box.width).toBe(200) + expect(box.height).toBe(300) + expect(box.cx).toBe(110) + expect(box.cy).toBe(250) + expect(box.x2).toBe(210) + expect(box.y2).toBe(400) + }) + + it('creates a new box from parsed string with comma as delimiter', function() { + box = new SVG.Box('10,100, 200 , 300') + expect(box.x).toBe(10) + expect(box.y).toBe(100) + expect(box.width).toBe(200) + expect(box.height).toBe(300) + }) + + it('creates a new box from array', function() { + box = new SVG.Box([10, 100, 200, 300]) + + expect(box.x).toBe(10) + expect(box.y).toBe(100) + expect(box.width).toBe(200) + expect(box.height).toBe(300) + }) + + it('creates a new box from object', function() { + box = new SVG.Box({x:10, y:100, width:200, height:300}) + + expect(box.x).toBe(10) + expect(box.y).toBe(100) + expect(box.width).toBe(200) + expect(box.height).toBe(300) + }) + + it('creates a new box from object width left and top instead of x and y', function() { + box = new SVG.Box({left:10, top:100, width:200, height:300}) + + expect(box.x).toBe(10) + expect(box.y).toBe(100) + expect(box.width).toBe(200) + expect(box.height).toBe(300) + }) - it('creates a new instance with object given', function() { - var box = new SVG.Box({x:10, y:20, width: 100, height:50}) + it('creates a new viewbox from 4 arguments', function() { + box = new SVG.Box(10, 100, 200, 300) + + expect(box.x).toBe(10) + expect(box.y).toBe(100) + expect(box.width).toBe(200) + expect(box.height).toBe(300) + }) + + it('creates a new box from parsed string with exponential values', function() { + box = new SVG.Box('-1.12e1 1e-2 +2e2 +.3e+4') + + expect(box.x).toBe(-11.2) + expect(box.y).toBe(0.01) + expect(box.width).toBe(200) + expect(box.height).toBe(3000) + }) - expect(box instanceof SVG.Box).toBe(true) - expect(box).toEqual(jasmine.objectContaining({ - x:10, y:20, cx:60, cy:45, width:100, height:50 - })) }) describe('merge()', function() { @@ -67,86 +119,43 @@ describe('Box', function() { })) }) }) -}) - -describe('BBox', function() { - - afterEach(function() { - draw.clear() - }) - it('creates a new instance from an element', function() { - var rect = draw.rect(100, 100).move(100, 25) - var box = new SVG.BBox(rect) - - expect(box).toEqual(jasmine.objectContaining({ - x: 100, y: 25, cx: 150, cy: 75, width: 100, height: 100 - })) - }) + describe('morph()', function() { + it('stores a given box for morphing', function() { + var box1 = new SVG.Box(10, 100, 200, 300) + , box2 = new SVG.Box(50, -100, 300, 300) - describe('merge()', function() { - it('returns an instance of SVG.BBox', function() { - var box1 = new SVG.BBox(50, 50, 100, 100) - var box2 = new SVG.BBox(300, 400, 100, 100) - var merged = box1.merge(box2) + box1.morph(box2) - expect(merged instanceof SVG.BBox).toBe(true) + expect(box1.destination).toEqual(box2) }) - }) - -}) - -describe('TBox', function() { - - afterEach(function() { - draw.clear() - }) + it('stores a clone, not the given viewbox itself', function() { + var box1 = new SVG.Box(10, 100, 200, 300) + , box2 = new SVG.Box(50, -100, 300, 300) - it('should map to RBox and be removed in 3.x', function() { - var rect = draw.rect(100, 100).move(100, 25).stroke({width:0}) - var tbox = rect.tbox() - - expect(tbox.x).toBe(100) - expect(tbox.y).toBeCloseTo(25) - - rect.transform({ scale: 1.5 }) - tbox = rect.tbox() - expect(tbox.x).toBe(75) - expect(tbox.y).toBe(0) - - rect.transform({ skewX: 5 }) - tbox = rect.tbox() - expect(tbox.x|0).toBe(68) - expect(tbox.y|0).toBe(0) - }) - -}) - -describe('RBox', function() { - - afterEach(function() { - draw.clear() + box1.morph(box2) + expect(box1.destination).not.toBe(box2) + }) }) - it('creates a new instance from an element', function() { - var rect = draw.rect(100, 100).move(100, 25).stroke({width:0}) - var box = new SVG.RBox(rect).transform(rect.doc().screenCTM().inverse()).addOffset() - expect(window.roundBox(box)).toEqual(jasmine.objectContaining({ - x: 100, y: 25, cx: 150, cy: 75, width: 100, height: 100 - })) - }) + describe('at()', function() { + it('returns a morphed box at a given position', function() { + var box1 = new SVG.Box(10, 100, 200, 300) + , box2 = new SVG.Box(50, -100, 300, 300) + , box3 = box1.morph(box2).at(0.5) - describe('merge()', function() { - it('returns an instance of SVG.RBox', function() { - var box1 = new SVG.RBox(50, 50, 100, 100) - var box2 = new SVG.RBox(300, 400, 100, 100) - var merged = box1.merge(box2) - - expect(merged instanceof SVG.RBox).toBe(true) + expect(box1.toString()).toBe('10 100 200 300') + expect(box2.toString()).toBe('50 -100 300 300') + expect(box3.toString()).toBe('30 0 250 300') + }) + it('returns itself when no destination given', function() { + var box = new SVG.Box(10, 100, 200, 300) + expect(box.at(0.5)).toBe(box) }) }) }) + describe('Boxes', function() { var rect, nested, offset @@ -161,8 +170,8 @@ describe('Boxes', function() { }) describe('bbox()', function() { - it('returns an instance of SVG.BBox', function() { - expect(rect.bbox() instanceof SVG.BBox).toBeTruthy() + it('returns an instance of SVG.Box', function() { + expect(rect.bbox() instanceof SVG.Box).toBeTruthy() }) it('matches the size of the target element, ignoring transformations', function() { var box = rect.bbox() @@ -194,8 +203,8 @@ describe('Boxes', function() { }) describe('rbox()', function() { - it('returns an instance of SVG.RBox', function() { - expect(rect.rbox() instanceof SVG.RBox).toBeTruthy() + it('returns an instance of SVG.Box', function() { + expect(rect.rbox() instanceof SVG.Box).toBeTruthy() }) it('returns the elements box in absolute screen coordinates by default', function() { @@ -224,6 +233,41 @@ describe('Boxes', function() { }) }) + describe('viewbox()', function() { + + beforeEach(function() { + draw.attr('viewBox', null) + }) + + it('should set the viewbox when four arguments are provided', function() { + draw.viewbox(0,0,100,100) + expect(draw.node.getAttribute('viewBox')).toBe('0 0 100 100') + }) + it('should set the viewbox when an object is provided as first argument', function() { + draw.viewbox({ x: 0, y: 0, width: 50, height: 50 }) + expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50') + }) + it('should set the viewbox when a string is provided as first argument', function() { + draw.viewbox('0 0 50 50') + expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50') + }) + it('should set the viewbox when an array is provided as first argument', function() { + draw.viewbox([0, 0, 50, 50]) + expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50') + }) + it('should accept negative values', function() { + draw.size(100,100).viewbox(-100, -100, 50, 50) + expect(draw.node.getAttribute('viewBox')).toEqual('-100 -100 50 50') + }) + it('should get the viewbox if no arguments are given', function() { + draw.viewbox(0, 0, 100, 100) + expect(draw.viewbox()).toEqual(new SVG.Box(0,0,100,100)) + }) + it('should get a nulled viewbox when no viewbox attribute is set', function() { + expect(draw.viewbox()).toEqual(new SVG.Box()) + }) + }) + }) diff --git a/spec/spec/clip.js b/spec/spec/clip.js index c641c4c..f2c4ed2 100644 --- a/spec/spec/clip.js +++ b/spec/spec/clip.js @@ -24,20 +24,20 @@ describe('ClipPath', function() { }) it('references the clip element in the masked element', function() { - expect(rect.clipper).toBe(circle.parent()) + expect(rect.clipper()).toBe(circle.parent()) }) it('references the clipped element in the clipPath target list', function() { - expect(rect.clipper.targets.indexOf(rect) > -1).toBe(true) + expect(rect.clipper().targets().indexOf(rect) > -1).toBe(true) }) it('reuses clip element when clip was given', function() { - var clip = rect.clipper - expect(draw.rect(100,100).clipWith(clip).clipper).toBe(clip) + var clip = rect.clipper() + expect(draw.rect(100,100).clipWith(clip).clipper()).toBe(clip) }) it('unclips all clipped elements when being removed', function() { - rect.clipper.remove() + rect.clipper().remove() expect(rect.attr('clip-path')).toBe(undefined) }) @@ -50,7 +50,7 @@ describe('ClipPath', function() { it('removes the reference to the clipping element', function() { rect.unclip() - expect(rect.clipper).toBe(undefined) + expect(rect.clipper()).toBe(null) }) it('returns the clipPath element', function() { diff --git a/spec/spec/container.js b/spec/spec/container.js index b9fabe7..53c51b3 100644 --- a/spec/spec/container.js +++ b/spec/spec/container.js @@ -147,20 +147,20 @@ describe('Container', function() { describe('image()', function() { it('should increase children by 1', function() { var initial = draw.children().length - draw.image(imageUrl, 100, 100) + draw.image(imageUrl) expect(draw.children().length).toBe(initial + 1) }) it('should create a rect', function() { - expect(draw.image(imageUrl, 100, 100).type).toBe('image') + expect(draw.image(imageUrl).type).toBe('image') }) it('should create an instance of SVG.Rect', function() { - expect(draw.image(imageUrl, 100, 100) instanceof SVG.Image).toBe(true) + expect(draw.image(imageUrl) instanceof SVG.Image).toBe(true) }) it('should be an instance of SVG.Shape', function() { - expect(draw.image(imageUrl, 100, 100) instanceof SVG.Shape).toBe(true) + expect(draw.image(imageUrl) instanceof SVG.Shape).toBe(true) }) it('should be an instance of SVG.Element', function() { - expect(draw.image(imageUrl, 100, 100) instanceof SVG.Element).toBe(true) + expect(draw.image(imageUrl) instanceof SVG.Element).toBe(true) }) }) @@ -173,11 +173,11 @@ describe('Container', function() { it('creates a text element', function() { expect(draw.text(loremIpsum).type).toBe('text') }) - it('creates an instance of SVG.Rect', function() { + it('creates an instance of SVG.Text', function() { expect(draw.text(loremIpsum) instanceof SVG.Text).toBe(true) }) - it('is an instance of SVG.Shape', function() { - expect(draw.text(loremIpsum) instanceof SVG.Shape).toBe(true) + it('is an instance of SVG.Parent', function() { + expect(draw.text(loremIpsum) instanceof SVG.Parent).toBe(true) }) it('is an instance of SVG.Element', function() { expect(draw.text(loremIpsum) instanceof SVG.Element).toBe(true) @@ -196,8 +196,8 @@ describe('Container', function() { it('creates an instance of SVG.Rect', function() { expect(draw.plain(loremIpsum) instanceof SVG.Text).toBe(true) }) - it('is an instance of SVG.Shape', function() { - expect(draw.plain(loremIpsum) instanceof SVG.Shape).toBe(true) + it('is an instance of SVG.Parent', function() { + expect(draw.plain(loremIpsum) instanceof SVG.Parent).toBe(true) }) it('is an instance of SVG.Element', function() { expect(draw.plain(loremIpsum) instanceof SVG.Element).toBe(true) diff --git a/spec/spec/element.js b/spec/spec/element.js index 28f30dd..70642f5 100644 --- a/spec/spec/element.js +++ b/spec/spec/element.js @@ -26,7 +26,8 @@ describe('Element', function() { afterEach(function() { rect.remove() - draw.defs().select('pattern').each(function() { this.remove() }) + //draw.defs().select('pattern').forEach(function(el) { el.remove() }) + draw.defs().clear() }) it('sets one attribute when two arguments are given', function() { @@ -94,15 +95,15 @@ describe('Element', function() { }) it('creates an image in defs when image path is specified for fill', function() { rect.attr('fill', imageUrl) - expect(draw.defs().select('pattern').length()).toBe(1) - expect(draw.defs().select('pattern image').length()).toBe(1) - expect(draw.defs().select('pattern image').first().src).toBe(imageUrl) + expect(draw.defs().select('pattern').length).toBe(1) + expect(draw.defs().select('pattern image').length).toBe(1) + expect(draw.defs().select('pattern image')[0].attr('href')).toBe(imageUrl) }) it('creates pattern in defs when image object is specified for fill', function() { rect.attr('fill', new SVG.Image().load(imageUrl)) - expect(draw.defs().select('pattern').length()).toBe(1) - expect(draw.defs().select('pattern image').length()).toBe(1) - expect(draw.defs().select('pattern image').first().src).toBe(imageUrl) + expect(draw.defs().select('pattern').length).toBe(1) + expect(draw.defs().select('pattern image').length).toBe(1) + expect(draw.defs().select('pattern image')[0].attr('href')).toBe(imageUrl) }) it('correctly creates SVG.Array if array given', function() { rect.attr('something', [2,3,4]) @@ -145,12 +146,6 @@ describe('Element', function() { expect(window.stripped(rect.node.style.cssText)).toMatch(/display:block/) expect(window.stripped(rect.node.style.cssText).length).toBe(('display:block;cursor:help').length) }) - it('sets multiple styles with a css string as the first argument', function() { - var rect = draw.rect(100,100).style('cursor: help; display: block;') - expect(window.stripped(rect.node.style.cssText)).toMatch(/cursor:help/) - expect(window.stripped(rect.node.style.cssText)).toMatch(/display:block/) - expect(window.stripped(rect.node.style.cssText).length).toBe(('display:block;cursor:help').length) - }) it('gets a style with a string key as the fists argument', function() { var rect = draw.rect(100,100).style({ cursor: 'progress', display: 'block' }) expect(rect.style('cursor')).toBe('progress') @@ -423,7 +418,7 @@ describe('Element', function() { }) }) - describe('ungroup()', function() { + describe('flatten()', function() { var nested, g1, g2, rect1 beforeEach(function() { @@ -440,12 +435,12 @@ describe('Element', function() { }) it('returns itself when depths is 0 or this is SVG.Defs', function() { - expect(draw.defs().ungroup()).toBe(draw.defs()) - expect(g1.ungroup(null, 0)).toBe(g1) + expect(draw.defs().flatten()).toBe(draw.defs()) + expect(g1.flatten(null, 0)).toBe(g1) }) it('breaks up all container and move the elements to the parent', function() { - g1.ungroup() + g1.flatten() expect(rect1.parent()).toBe(nested) expect(rect2.parent()).toBe(nested) @@ -461,7 +456,7 @@ describe('Element', function() { }) it('ungroups everything to the doc root when called on SVG.Doc / does not ungroup defs/parser', function() { - draw.ungroup() + draw.flatten() expect(rect1.parent()).toBe(draw) expect(rect2.parent()).toBe(draw) @@ -480,14 +475,6 @@ describe('Element', function() { }) }) - describe('flatten()', function() { - it('redirects the call to ungroup()', function() { - spyOn(draw, 'ungroup') - draw.flatten() - expect(draw.ungroup).toHaveBeenCalled() - }) - }) - describe('ctm()', function() { var rect @@ -580,13 +567,13 @@ describe('Element', function() { }) describe('rbox()', function() { - it('returns an instance of SVG.RBox', function() { + it('returns an instance of SVG.Box', function() { var rect = draw.rect(100,100) - expect(rect.rbox() instanceof SVG.RBox).toBe(true) + expect(rect.rbox() instanceof SVG.Box).toBe(true) }) it('returns the correct rectangular box', function() { // stroke has to be set in order to get the correct result when calling getBoundingClientRect in IE11 - var rect = draw.size(200, 150).viewbox(0, 0, 200, 150).rect(105, 210).move(2, 12).stroke({width:0}) + var rect = draw.size(200, 150).viewbox(0, 0, 200, 150).rect(105, 210).move(2, 12)//.stroke({width:0}) var box = rect.rbox(draw) expect(box.x).toBeCloseTo(2) expect(box.y).toBeCloseTo(12) @@ -907,12 +894,6 @@ describe('Element', function() { expect(g.attr('svgjs:data')).toBe('{"foo":"bar"}') expect(rect.attr('svgjs:data')).toBe('{"number":"3px"}') }) - it('uses lines() instead of each() when dealing with text', function() { - var text = draw.text('Hello\nWorld') - text.writeDataToDom() - expect(text.attr('svgjs:data')).toBe('{"leading":"1.3"}') - expect(text.lines().first().attr('svgjs:data')).toBe('{"newLined":true}') - }) }) describe('setData()', function() { diff --git a/spec/spec/image.js b/spec/spec/image.js index 4b51a9b..f5de893 100644 --- a/spec/spec/image.js +++ b/spec/spec/image.js @@ -1,8 +1,10 @@ describe('Image', function() { - var image + var image, loadCb - beforeEach(function() { - image = draw.image(imageUrl, 100, 100) + beforeEach(function(done) { + loadCb = {cb: function(){ done() }} + spyOn(loadCb, 'cb').and.callThrough() + image = draw.image(imageUrl, loadCb.cb).size(100,100) }) afterEach(function() { @@ -12,36 +14,23 @@ describe('Image', function() { describe('()', function() { it('should set width and height automatically if no size is given', function(done) { - image = draw.image(imageUrl).loaded(function() { + image = draw.image(imageUrl, function() { expect(image.node.getAttribute('height')).toBe('1') expect(image.node.getAttribute('width')).toBe('1') done() }) }) - it('should set width and height if size is given', function(done) { - image = draw.image(imageUrl, 100, 100).loaded(function() { + it('should not change with and height when size already set', function(done) { + image = draw.image(imageUrl, function() { expect(image.node.getAttribute('height')).toBe('100') expect(image.node.getAttribute('width')).toBe('100') done() - }) + }).size(100,100) }) it('returns itself when no url given', function() { var img = new SVG.Image() expect(img.load()).toBe(img) }) - }) - - describe('loaded()', function() { - beforeEach(function(done) { - loadCb = {cb: function(){ done() }} - errorCb = jasmine.createSpy('errorCb') - spyOn(loadCb, 'cb').and.callThrough() - image = draw.image(imageUrl, 100, 100).loaded(loadCb.cb).error(errorCb) - }) - - it('should set the load callback', function() { - expect(image._loaded).toBe(loadCb.cb) - }) it('executes the load callback', function() { expect(loadCb.cb).toHaveBeenCalledWith({ width: 1, @@ -50,177 +39,5 @@ describe('Image', function() { url: jasmine.any(String) }) }) - it('does not execute the error callback', function() { - expect(errorCb).not.toHaveBeenCalled() - }) - }) - - describe('error()', function() { - beforeEach(function(done) { - loadCb = jasmine.createSpy('loadCb') - errorCb = {cb: function(){ done() }} - spyOn(errorCb, 'cb').and.callThrough() - image = draw.image('not_existant.jpg', 100, 100).loaded(loadCb).error(errorCb.cb) - }) - - it('should set the error callback', function() { - expect(image._error).toBe(errorCb.cb) - }) - it('executes the error callback', function() { - expect(errorCb.cb).toHaveBeenCalledWith(jasmine.any(window.Event)) - }) - it('does not execute the load callback', function() { - expect(loadCb).not.toHaveBeenCalled() - }) }) - - - describe('x()', function() { - it('should return the value of x without an argument', function() { - expect(image.x()).toBe(0) - }) - it('should set the value of x with the first argument', function() { - image.x(123) - var box = image.bbox() - expect(box.x).toBe(123) - }) - }) - - describe('y()', function() { - it('should return the value of y without an argument', function() { - expect(image.y()).toBe(0) - }) - it('should set the value of y with the first argument', function() { - image.y(345) - var box = image.bbox() - expect(box.y).toBe(345) - }) - }) - - describe('cx()', function() { - it('should return the value of cx without an argument', function() { - expect(image.cx()).toBe(50) - }) - it('should set the value of cx with the first argument', function() { - image.cx(123) - var box = image.bbox() - expect(box.cx).toBe(123) - }) - }) - - describe('cy()', function() { - it('should return the value of cy without an argument', function() { - expect(image.cy()).toBe(50) - }) - it('should set the value of cy with the first argument', function() { - image.cy(345) - var box = image.bbox() - expect(box.cy).toBe(345) - }) - }) - - describe('move()', function() { - it('should set the x and y position', function() { - image.move(123,456) - expect(image.node.getAttribute('x')).toBe('123') - expect(image.node.getAttribute('y')).toBe('456') - }) - }) - - describe('dx()', function() { - it('moves the x positon of the element relative to the current position', function() { - image.move(50,60) - image.dx(100) - expect(image.node.getAttribute('x')).toBe('150') - }) - }) - - describe('dy()', function() { - it('moves the y positon of the element relative to the current position', function() { - image.move(50,60) - image.dy(120) - expect(image.node.getAttribute('y')).toBe('180') - }) - }) - - describe('dmove()', function() { - it('moves the x and y positon of the element relative to the current position', function() { - image.move(50,60) - image.dmove(80, 25) - expect(image.node.getAttribute('x')).toBe('130') - expect(image.node.getAttribute('y')).toBe('85') - }) - }) - - describe('center()', function() { - it('should set the cx and cy position', function() { - image.center(321,567) - var box = image.bbox() - expect(box.cx).toBe(321) - expect(box.cy).toBe(567) - }) - }) - - describe('width()', function() { - it('sets the width of the element', function() { - image.width(789) - expect(image.node.getAttribute('width')).toBe('789') - }) - it('gets the width of the element if the argument is null', function() { - expect(image.width().toString()).toBe(image.node.getAttribute('width')) - }) - }) - - describe('height()', function() { - it('sets the height of the element', function() { - image.height(1236) - expect(image.node.getAttribute('height')).toBe('1236') - }) - it('gets the height of the element if the argument is null', function() { - expect(image.height().toString()).toBe(image.node.getAttribute('height')) - }) - }) - - describe('size()', function() { - it('should define the width and height of the element', function() { - image.size(987,654) - expect(image.node.getAttribute('width')).toBe('987') - expect(image.node.getAttribute('height')).toBe('654') - }) - it('defines the width and height proportionally with only the width value given', function() { - var box = image.bbox() - image.size(500) - expect(image.width()).toBe(500) - expect(image.width() / image.height()).toBe(box.width / box.height) - }) - it('defines the width and height proportionally with only the height value given', function() { - var box = image.bbox() - image.size(null, 525) - expect(image.height()).toBe(525) - expect(image.width() / image.height()).toBe(box.width / box.height) - }) - }) - - describe('scale()', function() { - it('should scale the element universally with one argument', function() { - var box = image.scale(2).rbox() - - expect(box.width).toBe(image.attr('width') * 2) - expect(box.height).toBe(image.attr('height') * 2) - }) - it('should scale the element over individual x and y axes with two arguments', function() { - var box = image.scale(2, 3.5).rbox() - - expect(box.width).toBe(image.attr('width') * 2) - expect(box.height).toBe(image.attr('height') * 3.5) - }) - }) - - describe('translate()', function() { - it('should set the translation of an element', function() { - image.transform({ x: 12, y: 12 }) - expect(image.node.getAttribute('transform')).toBe('matrix(1,0,0,1,12,12)') - }) - }) - }) diff --git a/spec/spec/mask.js b/spec/spec/mask.js index a7cd6d1..d6921cc 100644 --- a/spec/spec/mask.js +++ b/spec/spec/mask.js @@ -24,20 +24,20 @@ describe('Mask', function() { }) it('references the mask element in the masked element', function() { - expect(rect.masker).toBe(circle.parent()) + expect(rect.masker()).toBe(circle.parent()) }) it('references the masked element in the mask target list', function() { - expect(rect.masker.targets.indexOf(rect) > -1).toBe(true) + expect(rect.masker().targets().indexOf(rect) > -1).toBe(true) }) it('reuses mask element when mask was given', function() { - var mask = rect.masker - expect(draw.rect(100,100).maskWith(mask).masker).toBe(mask) + var mask = rect.masker() + expect(draw.rect(100,100).maskWith(mask).masker()).toBe(mask) }) it('unmasks all masked elements when being removed', function() { - rect.masker.remove() + rect.masker().remove() expect(rect.attr('mask')).toBe(undefined) }) @@ -50,7 +50,7 @@ describe('Mask', function() { it('removes the reference to the masking element', function() { rect.unmask() - expect(rect.masker).toBe(undefined) + expect(rect.masker()).toBe(null) }) it('returns the element itslef', function() { diff --git a/spec/spec/path.js b/spec/spec/path.js index f5b99ca..e0b5f25 100644 --- a/spec/spec/path.js +++ b/spec/spec/path.js @@ -246,7 +246,7 @@ describe('Path', function() { describe('pointAt()', function() { it('gets a point at given length', function() { - expect(path.pointAt(100)).toEqual(path.node.getPointAtLength(100)) + expect(path.pointAt(100)).toEqual(new SVG.Point(path.node.getPointAtLength(100))) }) }) }) diff --git a/spec/spec/selector.js b/spec/spec/selector.js index b28213d..ea49a6e 100644 --- a/spec/spec/selector.js +++ b/spec/spec/selector.js @@ -36,8 +36,8 @@ describe('Selector', function() { it('gets all elements with a given class name', function() { expect(SVG.select('rect.selectable-element').valueOf()).toEqual([e1, e3, e5]) }) - it('returns an instance of SVG.Set', function() { - expect(SVG.select('rect.selectable-element') instanceof SVG.Set).toBe(true) + it('returns an Array', function() { + expect(SVG.select('rect.selectable-element') instanceof Array).toBe(true) }) }) diff --git a/spec/spec/set.js b/spec/spec/set.js deleted file mode 100644 index 50c3126..0000000 --- a/spec/spec/set.js +++ /dev/null @@ -1,215 +0,0 @@ -describe('Set', function() { - var set, e1, e2, e3, e4, e5 - - beforeEach(function() { - draw.attr('viewBox', null) - set = draw.set() - e1 = draw.rect(100,100).attr('id', 'e1').move(200,250) - e2 = draw.ellipse(100,100).attr('id', 'e2') - e3 = draw.line(0,0,100,100).attr('id', 'e3') - e4 = draw.circle(50).attr('id', 'e4') - e5 = draw.polyline('0,0 10,20 30,50 80,100').attr('id', 'e5') - }) - - afterEach(function() { - draw.clear() - }) - - it('creates the set method on SVG.Container instances', function() { - expect(draw.set() instanceof SVG.Set).toBeTruthy() - }) - - it('creates a set with initial value', function() { - var members = [1, 2, 4] - - expect(draw.set(members).valueOf()).toBe(members) - }) - - describe('add()', function() { - it('returns the set instance', function() { - expect(set.add(e1)).toBe(set) - }) - it('stores given element', function() { - set.add(e1).add(e2).add(e3) - expect(set.valueOf()).toEqual([e1,e2,e3]) - expect(set.members.length).toBe(3) - }) - it('accepts multiple elements at once', function() { - set.add(e1, e2, e3, e4, e5) - expect(set.valueOf()).toEqual([e1, e2, e3, e4, e5]) - expect(set.members.length).toBe(5) - }) - }) - - describe('remove()', function() { - it('returns the set instance', function() { - set.add(e1) - expect(set.remove(e1)).toBe(set) - }) - it('removes given element', function() { - set.add(e1).add(e2).add(e3).remove(e2) - expect(set.valueOf()).toEqual([e1,e3]) - expect(set.members.length).toBe(2) - }) - }) - - describe('each()', function() { - it('returns the set instance', function() { - expect(set.each(function(){})).toBe(set) - }) - it('iterates over all members of the set', function() { - var ids = [] - set.add(e1).add(e2).add(e3) - - set.each(function() { - ids.push(this.attr('id')) - }) - - expect(ids.length).toBe(3) - expect(ids).toEqual(['e1','e2','e3']) - }) - }) - - describe('clear()', function() { - it('returns the set instance', function() { - expect(set.clear()).toBe(set) - }) - it('removes all members from set', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5).clear() - expect(set.members.length).toBe(0) - }) - }) - - describe('get()', function() { - it('returns member at given index', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5) - expect(set.get(2)).toBe(e3) - }) - }) - - describe('first()', function() { - it('returns first member', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5) - expect(set.first()).toBe(e1) - }) - }) - - describe('last()', function() { - it('returns last member', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5) - expect(set.last()).toBe(e5) - }) - }) - - describe('has()', function() { - it('checks if a given element is present in set', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5) - expect(set.has(e4)).toBeTruthy() - }) - }) - - describe('length()', function() { - it('gets the length of the set', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5) - expect(set.length()).toBe(5) - }) - }) - - describe('index()', function() { - it('returns the index of a given element within the set', function() { - set.add(e1).add(e2).add(e3).add(e5) - expect(set.index(e1)).toBe(0) - expect(set.index(e2)).toBe(1) - expect(set.index(e3)).toBe(2) - expect(set.index(e4)).toBe(-1) - expect(set.index(e5)).toBe(3) - }) - }) - - describe('valueOf()', function() { - it('returns the members array', function() { - set.add(e1) - expect(set.valueOf()).toBe(set.members) - }) - }) - - describe('bbox()', function() { - it('returns the bounding box of all elements', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5) - - var box = set.bbox() - - expect(box.x).toBeCloseTo(0) - expect(box.y).toBeCloseTo(0, 0) - expect(box.width).toBeCloseTo(300) - expect(box.height).toBeCloseTo(350) - }) - it('returns an instance of SVG.RBox', function() { - set.add(e1).add(e2).add(e3).add(e4).add(e5) - - expect(set.bbox() instanceof SVG.RBox).toBeTruthy() - }) - it('returns an empty bounding box wiht no members', function() { - var box = set.bbox() - - expect(box.x).toBe(0) - expect(box.y).toBe(0) - expect(box.width).toBe(0) - expect(box.height).toBe(0) - }) - }) - - describe('method alias', function() { - - describe('attr()', function() { - it('is applied to every member of the set', function() { - var fills = [] - - set.add(e1).add(e2).add(e3).add(e4).add(e5).attr('fill', '#ff0099') - set.each(function() { - fills.push(this.attr('fill')) - }) - - expect(fills).toEqual(['#ff0099','#ff0099','#ff0099','#ff0099','#ff0099']) - }) - }) - - }) - - describe('method inheritance', function() { - - beforeEach(function() { - SVG.extend(SVG.Element, { - orange: function() { - this.fill('#ff6600') - } - }) - }) - - it('inherits newly added element methods after initialisation', function() { - expect(typeof set.orange).toBe('function') - }) - - it('applies newly inherited methods properly to members', function() { - var fills = [] - - set.add(e1).add(e2).add(e3).add(e4).add(e5).orange() - set.each(function() { - fills.push(this.attr('fill')) - }) - - expect(fills).toEqual(['#ff6600','#ff6600','#ff6600','#ff6600','#ff6600']) - }) - - }) - -}) - - - - - - - - - diff --git a/spec/spec/svg.js b/spec/spec/svg.js index 7738b0e..35f42e8 100644 --- a/spec/spec/svg.js +++ b/spec/spec/svg.js @@ -104,12 +104,11 @@ describe('SVG', function() { expect(SVG.parser.draw.nodeName).toBe('svg') }) it('hides the parser', function() { - expect(window.stripped(SVG.parser.draw.getAttribute('style'))).toBe('overflow:hidden;top:-100%;left:-100%;position:absolute;opacity:0') + expect(window.stripped(SVG.parser.draw.getAttribute('style'))).toBe('opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden') }) it('holds polyline and path', function() { - expect(SVG.select('polyline', SVG.parser.draw).first().type).toBe('polyline') - expect(SVG.select('path', SVG.parser.draw).first().type).toBe('path') + expect(SVG.select('polyline', SVG.parser.draw.node)[0].type).toBe('polyline') + expect(SVG.select('path', SVG.parser.draw.node)[0].type).toBe('path') }) }) - -})
\ No newline at end of file +}) diff --git a/spec/spec/text.js b/spec/spec/text.js index 83b1596..61533de 100644 --- a/spec/spec/text.js +++ b/spec/spec/text.js @@ -31,9 +31,9 @@ describe('Text', function() { expect(text.rebuild(true)._rebuild).toBeTruthy() }) it('rebuilds the text without an argument given', function() { - var dy = text.lines().get(2).attr('dy') + var dy = text.get(2).attr('dy') text.leading(1.7) - expect(dy == text.lines().get(2).attr('dy')).toBeFalsy() + expect(dy == text.get(2).attr('dy')).toBeFalsy() }) }) @@ -47,7 +47,7 @@ describe('Text', function() { }) it('sets the value of all lines', function() { text.x(200) - text.lines().each(function() { + text.each(function() { expect(this.x()).toBe(200) }) }) @@ -234,10 +234,10 @@ describe('Text', function() { l2 = add.tspan('The second.') l3 = add.tspan('The third.') }) - expect(text.lines().length()).toBe(3) - expect(text.lines().get(0)).toBe(l1) - expect(text.lines().get(1)).toBe(l2) - expect(text.lines().get(2)).toBe(l3) + expect(text.children().length).toBe(3) + expect(text.get(0)).toBe(l1) + expect(text.get(1)).toBe(l2) + expect(text.get(2)).toBe(l3) }) }) @@ -248,7 +248,7 @@ describe('Text', function() { add.tspan('The second.') add.tspan('The third.') }) - expect(text.length()).toBeCloseTo(text.lines().get(0).length() + text.lines().get(1).length() + text.lines().get(2).length(), 3) + expect(text.length()).toBeCloseTo(text.get(0).length() + text.get(1).length() + text.get(2).length(), 3) }) }) diff --git a/spec/spec/viewbox.js b/spec/spec/viewbox.js deleted file mode 100644 index cf6ec5c..0000000 --- a/spec/spec/viewbox.js +++ /dev/null @@ -1,162 +0,0 @@ -describe('Viewbox', function() { - var viewbox - - beforeEach(function() { - draw.clear() - }) - - describe('initialization', function() { - - - it('creates a new viewbox with default values', function() { - viewbox = new SVG.ViewBox() - - expect(viewbox.x).toBe(0) - expect(viewbox.y).toBe(0) - expect(viewbox.width).toBe(0) - expect(viewbox.height).toBe(0) - }) - - - - it('creates a new viewbox from parsed string', function() { - viewbox = new SVG.ViewBox('10. 100 200 300') - - expect(viewbox.x).toBe(10) - expect(viewbox.y).toBe(100) - expect(viewbox.width).toBe(200) - expect(viewbox.height).toBe(300) - }) - - - - it('creates a new viewbox from array', function() { - viewbox = new SVG.ViewBox([10, 100, 200, 300]) - - expect(viewbox.x).toBe(10) - expect(viewbox.y).toBe(100) - expect(viewbox.width).toBe(200) - expect(viewbox.height).toBe(300) - }) - - - - it('creates a new viewbox from object', function() { - viewbox = new SVG.ViewBox({x:10, y:100, width:200, height:300}) - - expect(viewbox.x).toBe(10) - expect(viewbox.y).toBe(100) - expect(viewbox.width).toBe(200) - expect(viewbox.height).toBe(300) - }) - - - - it('creates a new viewbox from 4 arguments given', function() { - viewbox = new SVG.ViewBox(10, 100, 200, 300) - - expect(viewbox.x).toBe(10) - expect(viewbox.y).toBe(100) - expect(viewbox.width).toBe(200) - expect(viewbox.height).toBe(300) - }) - - - it('creates a new viewbox from parsed string with exponential values', function() { - viewbox = new SVG.ViewBox('-1.12e1 1e-2 +2e2 +.3e+4') - - expect(viewbox.x).toBe(-11.2) - expect(viewbox.y).toBe(0.01) - expect(viewbox.width).toBe(200) - expect(viewbox.height).toBe(3000) - }) - - it('creates a new viewbox with element given', function() { - draw.attr('viewBox', '-1.12e1 1e-2 +2e2 +.3e+4') - viewbox = new SVG.ViewBox(draw) - - expect(viewbox.x).toBe(-11.2) - expect(viewbox.y).toBe(0.01) - expect(viewbox.width).toBe(200) - expect(viewbox.height).toBe(3000) - }) - - }) - - - describe('viewbox()', function() { - - beforeEach(function() { - draw.attr('viewBox', null) - }) - afterEach(function() { - draw.attr('viewBox', null) - }) - - it('should set the viewbox when four arguments are provided', function() { - draw.viewbox(0,0,100,100) - expect(draw.node.getAttribute('viewBox')).toBe('0 0 100 100') - }) - it('should set the viewbox when an object is provided as first argument', function() { - draw.viewbox({ x: 0, y: 0, width: 50, height: 50 }) - expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50') - }) - it('should set the viewbox when a string is provided as first argument', function() { - draw.viewbox('0 0 50 50') - expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50') - }) - it('should set the viewbox when an array is provided as first argument', function() { - draw.viewbox([0, 0, 50, 50]) - expect(draw.node.getAttribute('viewBox')).toBe('0 0 50 50') - }) - it('should accept negative values', function() { - draw.size(100,100).viewbox(-100, -100, 50, 50) - expect(draw.node.getAttribute('viewBox')).toEqual('-100 -100 50 50') - }) - it('should get the viewbox if no arguments are given', function() { - draw.viewbox(0, 0, 100, 100) - expect(draw.viewbox()).toEqual(new SVG.ViewBox(draw)) - }) - it('should define the zoom of the viewbox in relation to the canvas size', function() { - draw.size(100,100).viewbox(0,0,50,50) - expect(draw.viewbox().zoom).toEqual(100 / 50) - }) - - }) - - describe('morph()', function() { - it('stores a given viewbox for morphing', function() { - var viewbox1 = new SVG.ViewBox(10, 100, 200, 300) - , viewbox2 = new SVG.ViewBox(50, -100, 300, 300) - - viewbox1.morph(viewbox2) - - expect(viewbox1.destination).toEqual(viewbox2) - }) - it('stores a clone, not the given viewbox itself', function() { - var viewbox1 = new SVG.ViewBox(10, 100, 200, 300) - , viewbox2 = new SVG.ViewBox(50, -100, 300, 300) - - viewbox1.morph(viewbox2) - - expect(viewbox1.destination).not.toBe(viewbox2) - }) - }) - - describe('at()', function() { - it('returns a morphed viewbox at a given position', function() { - var viewbox1 = new SVG.ViewBox(10, 100, 200, 300) - , viewbox2 = new SVG.ViewBox(50, -100, 300, 300) - , viewbox3 = viewbox1.morph(viewbox2).at(0.5) - - expect(viewbox1.toString()).toBe('10 100 200 300') - expect(viewbox2.toString()).toBe('50 -100 300 300') - expect(viewbox3.toString()).toBe('30 0 250 300') - }) - it('returns itself when no destination given', function() { - var viewbox = new SVG.ViewBox(10, 100, 200, 300) - expect(viewbox.at(0.5)).toBe(viewbox) - }) - }) - -})
\ No newline at end of file diff --git a/src/array.js b/src/array.js index 9947242..b532296 100644 --- a/src/array.js +++ b/src/array.js @@ -64,11 +64,7 @@ SVG.extend(SVG.Array, { // if already is an array, no need to parse it if (Array.isArray(array)) return array - return this.split(array) - } - // Strip unnecessary whitespace -, split: function(string) { - return string.trim().split(SVG.regex.delimiter).map(parseFloat) + return array.trim().split(SVG.regex.delimiter).map(parseFloat) } // Reverse array , reverse: function() { diff --git a/src/attr.js b/src/attr.js index 134ac19..bc09fe3 100644 --- a/src/attr.js +++ b/src/attr.js @@ -28,16 +28,11 @@ SVG.extend(SVG.Element, { parseFloat(v) : v } else { - // BUG FIX: some browsers will render a stroke if a color is given even though stroke width is 0 - if (a == 'stroke-width') - this.attr('stroke', parseFloat(v) > 0 ? this._stroke : null) - else if (a == 'stroke') - this._stroke = v // convert image fill and stroke to patterns if (a == 'fill' || a == 'stroke') { if (SVG.regex.isImage.test(v)) - v = this.doc().defs().image(v, 0, 0) + v = this.doc().defs().image(v) if (v instanceof SVG.Image) v = this.doc().defs().pattern(0, 0, function() { diff --git a/src/boxes.js b/src/boxes.js index 4a3af8e..ce9dc48 100644 --- a/src/boxes.js +++ b/src/boxes.js @@ -1,14 +1,20 @@ SVG.Box = SVG.invent({ - create: function(x, y, width, height) { - if (typeof x == 'object' && !(x instanceof SVG.Element)) { - // chromes getBoundingClientRect has no x and y property - return SVG.Box.call(this, x.left != null ? x.left : x.x , x.top != null ? x.top : x.y, x.width, x.height) - } else if (arguments.length == 4) { - this.x = x - this.y = y - this.width = width - this.height = height - } + create: function(source) { + var base = [0,0,0,0] + source = typeof source === 'string' ? + source.split(SVG.regex.delimiter).map(parseFloat) : + Array.isArray(source) ? + source : + typeof source == 'object' ? + [source.left != null ? source.left : source.x, source.top != null ? source.top : source.y, source.width, source.height] : + arguments.length == 4 ? + [].slice.call(arguments) : + base + + this.x = source[0] + this.y = source[1] + this.width = source[2] + this.height = source[3] // add center, right, bottom... fullBox(this) @@ -16,15 +22,14 @@ SVG.Box = SVG.invent({ , extend: { // Merge rect box with another, return a new instance merge: function(box) { - var b = new this.constructor() - - // merge boxes - b.x = Math.min(this.x, box.x) - b.y = Math.min(this.y, box.y) - 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 - - return fullBox(b) + var x = Math.min(this.x, box.x) + , y = Math.min(this.y, box.y) + + return new SVG.Box( + x, y, + Math.max(this.x + this.width, box.x + box.width) - x, + Math.max(this.y + this.height, box.y + box.height) - y + ) } , transform: function(m) { @@ -45,124 +50,88 @@ SVG.Box = SVG.invent({ yMax = Math.max(yMax,p.y) }) - bbox = new this.constructor() - bbox.x = xMin - bbox.width = xMax-xMin - bbox.y = yMin - bbox.height = yMax-yMin + return new SVG.Box( + xMin, yMin, + xMax-xMin, + yMax-yMin + ) + } - fullBox(bbox) + , addOffset: function() { + // offset by window scroll position, because getBoundingClientRect changes when window is scrolled + this.x += window.pageXOffset + this.y += window.pageYOffset + return this + } + , toString: function() { + return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height + } + , morph: function(x, y, width, height){ + this.destination = new SVG.Box(x, y, width, height) + return this + } + + , at: function(pos) { + if(!this.destination) return this + + return new SVG.Box( + this.x + (this.destination.x - this.x) * pos + , this.y + (this.destination.y - this.y) * pos + , this.width + (this.destination.width - this.width) * pos + , this.height + (this.destination.height - this.height) * pos + ) - return bbox } } -}) -SVG.BBox = SVG.invent({ - // Initialize - create: function(element) { - SVG.Box.apply(this, [].slice.call(arguments)) + // Define Parent +, parent: SVG.Element - // get values if element is given - if (element instanceof SVG.Element) { + // Constructor +, construct: { + // Get bounding box + bbox: function() { var box - // yes this is ugly, but Firefox can be a bitch when it comes to elements that are not yet rendered try { + // find native bbox + box = this.node.getBBox() - if (!document.documentElement.contains){ - // This is IE - it does not support contains() for top-level SVGs - var topParent = element.node - while (topParent.parentNode){ - topParent = topParent.parentNode - } - if (topParent != document) throw new Exception('Element not in the dom') - } else { - // the element is NOT in the dom, throw error - if(!document.documentElement.contains(element.node)) throw new Exception('Element not in the dom') + if(isNulledBox(box) && !domContains(this.node)) { + throw new Exception('Element not in the dom') } - - // find native bbox - box = element.node.getBBox() } catch(e) { - if(element instanceof SVG.Shape){ - var clone = element.clone(SVG.parser.draw.instance).show() + try { + var clone = this.clone(SVG.parser.draw.instance).show() box = clone.node.getBBox() clone.remove() - }else{ - box = { - x: element.node.clientLeft - , y: element.node.clientTop - , width: element.node.clientWidth - , height: element.node.clientHeight - } + } catch(e) { + console.warn('Getting a bounding box of this element is not possible') } } - SVG.Box.call(this, box) + return new SVG.Box(box) } - } - - // Define ancestor -, inherit: SVG.Box - - // Define Parent -, parent: SVG.Element - - // Constructor -, construct: { - // Get bounding box - bbox: function() { - return new SVG.BBox(this) + , rbox: function(el) { + // IE11 throws an error when element not in dom + try{ + var box = new SVG.Box(this.node.getBoundingClientRect()) + if (el) return box.transform(el.screenCTM().inverse()) + return box.addOffset() + } catch(e) { + return new SVG.Box() + } } } - }) -SVG.BBox.prototype.constructor = SVG.BBox - +SVG.extend(SVG.Doc, SVG.Nested, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View, { + viewbox: function(x, y, width, height) { + // act as getter + if(x == null) return new SVG.Box(this.attr('viewBox')) -SVG.extend(SVG.Element, { - tbox: function(){ - console.warn('Use of TBox is deprecated and mapped to RBox. Use .rbox() instead.') - return this.rbox(this.doc()) + // act as setter + return this.attr('viewBox', new SVG.Box(x, y, width, height)) } }) - -SVG.RBox = SVG.invent({ - // Initialize - create: function(element) { - SVG.Box.apply(this, [].slice.call(arguments)) - - if (element instanceof SVG.Element) { - SVG.Box.call(this, element.node.getBoundingClientRect()) - } - } - -, inherit: SVG.Box - - // define Parent -, parent: SVG.Element - -, extend: { - addOffset: function() { - // offset by window scroll position, because getBoundingClientRect changes when window is scrolled - this.x += window.pageXOffset - this.y += window.pageYOffset - return this - } - } - - // Constructor -, construct: { - // Get rect box - rbox: function(el) { - if (el) return new SVG.RBox(this).transform(el.screenCTM().inverse()) - return new SVG.RBox(this).addOffset() - } - } - -}) - -SVG.RBox.prototype.constructor = SVG.RBox diff --git a/src/clip.js b/src/clip.js index 2a92e44..dd2f7b7 100644 --- a/src/clip.js +++ b/src/clip.js @@ -1,11 +1,6 @@ SVG.ClipPath = SVG.invent({ // Initialize node - create: function() { - this.constructor.call(this, SVG.create('clipPath')) - - // keep references to clipped elements - this.targets = [] - } + create: 'clipPath' // Inherit from , inherit: SVG.Container @@ -14,19 +9,20 @@ SVG.ClipPath = SVG.invent({ , extend: { // Unclip all clipped elements and remove itself remove: function() { - // unclip all targets - for (var i = this.targets.length - 1; i >= 0; i--) - if (this.targets[i]) - this.targets[i].unclip() - this.targets = [] + // unclip all targets + this.targets().forEach(function(el) { + el.unclip() + }) - // remove clipPath from parent - this.parent().removeElement(this) - - return this + // remove clipPath from parent + return SVG.Element.prototype.remove.call(this) + } + + , targets: function() { + return SVG.select('svg [clip-path*="' +this.id() +'"]') } } - + // Add parent method , construct: { // Create clipping element @@ -40,19 +36,18 @@ SVG.ClipPath = SVG.invent({ SVG.extend(SVG.Element, { // Distribute clipPath to svg element clipWith: function(element) { - // use given clip or create a new one - this.clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element) + // use given clip or create a new one + var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element) - // store reverence on self in mask - this.clipper.targets.push(this) - - // apply mask - return this.attr('clip-path', 'url("#' + this.clipper.attr('id') + '")') + // apply mask + return this.attr('clip-path', 'url("#' + clipper.attr('id') + '")') } // Unclip element , unclip: function() { - delete this.clipper return this.attr('clip-path', null) } - +, clipper: function() { + return this.reference('clip-path') + } + })
\ No newline at end of file diff --git a/src/element.js b/src/element.js index 1c35b42..24770b1 100644 --- a/src/element.js +++ b/src/element.js @@ -2,8 +2,7 @@ SVG.Element = SVG.invent({ // Initialize node create: function(node) { - // make stroke value accessible dynamically - this._stroke = SVG.defaults.attrs.stroke + // last fired event on node this._event = null // initialize data object @@ -13,9 +12,6 @@ SVG.Element = SVG.invent({ if (this.node = node) { this.type = node.nodeName this.node.instance = this - - // store current attribute value - this._stroke = node.getAttribute('stroke') || this._stroke } } @@ -208,31 +204,26 @@ SVG.Element = SVG.invent({ } // Import raw svg , svg: function(svg) { - // create temporary holder - var well = document.createElement('svg') + var well, len // act as a setter if svg is given if (svg && this instanceof SVG.Parent) { + + // create temporary holder + well = document.createElementNS(SVG.ns, 'svg') // dump raw svg - well.innerHTML = '<svg>' + svg.replace(/\n/, '').replace(/<(\w+)([^<]+?)\/>/g, '<$1$2></$1>') + '</svg>' + well.innerHTML = svg // transplant nodes - for (var i = 0, il = well.firstChild.childNodes.length; i < il; i++) - this.node.appendChild(well.firstChild.firstChild) + for (len = well.childNodes.length;len--;) + if(well.firstChild.nodeType != 1) + well.removeChild(well.firstChild) + else + this.node.appendChild(well.firstChild) // otherwise act as a getter } else { - // create a wrapping svg element in case of partial content - well.appendChild(svg = document.createElement('svg')) - - // write svgjs data to the dom - this.writeDataToDom() - - // insert a copy of this node - svg.appendChild(this.node.cloneNode(true)) - - // return target element - return well.innerHTML.replace(/^<svg>/, '').replace(/<\/svg>$/, '') + return this.node.outerHTML } return this @@ -241,9 +232,8 @@ SVG.Element = SVG.invent({ , writeDataToDom: function() { // dump variables recursively - if(this.each || this.lines){ - var fn = this.each ? this : this.lines(); - fn.each(function(){ + if(this.is(SVG.Parent)){ + this.each(function(){ this.writeDataToDom() }) } diff --git a/src/flatten.js b/src/flatten.js new file mode 100644 index 0000000..db9b9df --- /dev/null +++ b/src/flatten.js @@ -0,0 +1,18 @@ +SVG.extend(SVG.Parent, { + flatten: function(parent) { + if(this instanceof SVG.Defs) return this + + parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent)) + + this.each(function(){ + if(this instanceof SVG.Defs) return this + if(this instanceof SVG.Parent) return this.flatten(parent) + return this.toParent(parent) + }) + + // we need this so that SVG.Doc does not get removed + this.node.firstChild || this.remove() + + return this + } +}) @@ -858,7 +858,7 @@ SVG.extend(SVG.FX, { // Add animatable viewbox , viewbox: function(x, y, width, height) { if (this.target() instanceof SVG.Container) { - this.add('viewbox', new SVG.ViewBox(x, y, width, height)) + this.add('viewbox', new SVG.Box(x, y, width, height)) } return this diff --git a/src/gradient.js b/src/gradient.js index 17145e6..a16c092 100644 --- a/src/gradient.js +++ b/src/gradient.js @@ -2,9 +2,6 @@ SVG.Gradient = SVG.invent({ // Initialize node create: function(type) { this.constructor.call(this, SVG.create(type + 'Gradient')) - - // store type - this.type = type } // Inherit from @@ -55,13 +52,13 @@ SVG.Gradient = SVG.invent({ SVG.extend(SVG.Gradient, SVG.FX, { // From position from: function(x, y) { - return (this._target || this).type == 'radial' ? + return (this._target || this).type == 'radialGradient' ? this.attr({ fx: new SVG.Number(x), fy: new SVG.Number(y) }) : this.attr({ x1: new SVG.Number(x), y1: new SVG.Number(y) }) } // To position , to: function(x, y) { - return (this._target || this).type == 'radial' ? + return (this._target || this).type == 'radialGradient' ? this.attr({ cx: new SVG.Number(x), cy: new SVG.Number(y) }) : this.attr({ x2: new SVG.Number(x), y2: new SVG.Number(y) }) } diff --git a/src/helpers.js b/src/helpers.js index 90c4995..461975a 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1,3 +1,17 @@ +function isNulledBox(box) { + return !box.w && !box.h && !box.x && !box.y +} + +function domContains(node) { + return (document.documentElement.contains || function(node) { + // This is IE - it does not support contains() for top-level SVGs + while (node.parentNode){ + node = node.parentNode; + } + return node == document + }).call(document.documentElement, node) +} + function pathRegReplace(a, b, c, d) { return c + d.replace(SVG.regex.dots, ' .') } @@ -163,10 +177,10 @@ function fullBox(b) { // Get id from reference string function idFromReference(url) { - var m = url.toString().match(SVG.regex.reference) + var m = (url || '').toString().match(SVG.regex.reference) if (m) return m[1] } // Create matrix array for looping -var abcdef = 'abcdef'.split('')
\ No newline at end of file +var abcdef = 'abcdef'.split('') diff --git a/src/image.js b/src/image.js index feb369e..84063de 100644 --- a/src/image.js +++ b/src/image.js @@ -8,62 +8,44 @@ SVG.Image = SVG.invent({ // Add class methods , extend: { // (re)load image - load: function(url) { + load: function(url, callback) { if (!url) return this - var self = this - , img = new window.Image() - - // preload image - SVG.on(img, 'load', function() { - var p = self.parent(SVG.Pattern) + var img = new window.Image() - if(p === null) return + SVG.on(img, 'load', function(e) { + var p = this.parent() + // ensure image size - if (self.width() == 0 && self.height() == 0) - self.size(img.width, img.height) + if (this.width() == 0 && this.height() == 0) + this.size(img.width, img.height) - // ensure pattern size if not set - if (p && p.width() == 0 && p.height() == 0) - p.size(self.width(), self.height()) - - // callback - if (typeof self._loaded === 'function') - self._loaded.call(self, { + if(p instanceof SVG.Pattern) { + // ensure pattern size if not set + if (p.width() == 0 && p.height() == 0) + p.size(this.width(), this.height()) + } + + if(typeof callback == 'function') { + callback.call(this, { width: img.width , height: img.height , ratio: img.width / img.height , url: url }) - }) - - SVG.on(img, 'error', function(e){ - if (typeof self._error === 'function'){ - self._error.call(self, e) } - }) + }, this) - return this.attr('href', (img.src = this.src = url), SVG.xlink) - } - // Add loaded callback - , loaded: function(loaded) { - this._loaded = loaded - return this - } - - , error: function(error) { - this._error = error - return this + return this.attr('href', (img.src = url), SVG.xlink) } } - + // Add parent method , construct: { // create image element, load image and set its size - image: function(source, width, height) { - return this.put(new SVG.Image).load(source).size(width || 0, height || width || 0) + image: function(source, callback) { + return this.put(new SVG.Image).size(0, 0).load(source, callback) } } - -})
\ No newline at end of file +}) diff --git a/src/mask.js b/src/mask.js index 51e61e9..4371b37 100644 --- a/src/mask.js +++ b/src/mask.js @@ -1,11 +1,6 @@ SVG.Mask = SVG.invent({ // Initialize node - create: function() { - this.constructor.call(this, SVG.create('mask')) - - // keep references to masked elements - this.targets = [] - } + create: 'mask' // Inherit from , inherit: SVG.Container @@ -14,19 +9,20 @@ SVG.Mask = SVG.invent({ , extend: { // Unmask all masked elements and remove itself remove: function() { - // unmask all targets - for (var i = this.targets.length - 1; i >= 0; i--) - if (this.targets[i]) - this.targets[i].unmask() - this.targets = [] - - // remove mask from parent - this.parent().removeElement(this) - - return this + // unmask all targets + this.targets().forEach(function(el) { + el.unmask() + }) + + // remove mask from parent + return SVG.Element.prototype.remove.call(this) + } + + , targets: function() { + return SVG.select('svg [mask*="' +this.id() +'"]') } } - + // Add parent method , construct: { // Create masking element @@ -40,19 +36,17 @@ SVG.Mask = SVG.invent({ SVG.extend(SVG.Element, { // Distribute mask to svg element maskWith: function(element) { - // use given mask or create a new one - this.masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element) - - // store reverence on self in mask - this.masker.targets.push(this) - - // apply mask - return this.attr('mask', 'url("#' + this.masker.attr('id') + '")') + // use given mask or create a new one + var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element) + + // apply mask + return this.attr('mask', 'url("#' + masker.attr('id') + '")') } // Unmask element , unmask: function() { - delete this.masker return this.attr('mask', null) } - +, masker: function() { + return this.reference('mask') + } }) diff --git a/src/polyfill.js b/src/polyfill.js deleted file mode 100644 index d99ab76..0000000 --- a/src/polyfill.js +++ /dev/null @@ -1,42 +0,0 @@ -// Add CustomEvent to IE9 and IE10 -if (typeof window.CustomEvent !== 'function') { - // Code from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent - var CustomEvent = function(event, options) { - options = options || { bubbles: false, cancelable: false, detail: undefined } - var e = document.createEvent('CustomEvent') - e.initCustomEvent(event, options.bubbles, options.cancelable, options.detail) - return e - } - - CustomEvent.prototype = window.Event.prototype - - window.CustomEvent = CustomEvent -} - -// requestAnimationFrame / cancelAnimationFrame Polyfill with fallback based on Paul Irish -(function(w) { - var lastTime = 0 - var vendors = ['moz', 'webkit'] - - for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { - w.requestAnimationFrame = w[vendors[x] + 'RequestAnimationFrame'] - w.cancelAnimationFrame = w[vendors[x] + 'CancelAnimationFrame'] || - w[vendors[x] + 'CancelRequestAnimationFrame'] - } - - w.requestAnimationFrame = w.requestAnimationFrame || - function(callback) { - var currTime = new Date().getTime() - var timeToCall = Math.max(0, 16 - (currTime - lastTime)) - - var id = w.setTimeout(function() { - callback(currTime + timeToCall) - }, timeToCall) - - lastTime = currTime + timeToCall - return id - } - - w.cancelAnimationFrame = w.cancelAnimationFrame || w.clearTimeout; - -}(window))
\ No newline at end of file diff --git a/src/selector.js b/src/selector.js index fe87e4e..afe006d 100644 --- a/src/selector.js +++ b/src/selector.js @@ -6,11 +6,19 @@ SVG.get = function(id) { // Select elements by query string SVG.select = function(query, parent) { - return new SVG.Set( - SVG.utils.map((parent || document).querySelectorAll(query), function(node) { - return SVG.adopt(node) - }) - ) + return SVG.utils.map((parent || document).querySelectorAll(query), function(node) { + return SVG.adopt(node) + }) +} + +SVG.$$ = function(query, parent) { + return SVG.utils.map((parent || document).querySelectorAll(query), function(node) { + return SVG.adopt(node) + }) +} + +SVG.$ = function(query, parent) { + return SVG.adopt((parent || document).querySelector(query)) } SVG.extend(SVG.Parent, { @@ -18,5 +26,4 @@ SVG.extend(SVG.Parent, { select: function(query) { return SVG.select(query, this.node) } - -})
\ No newline at end of file +}) diff --git a/src/set.js b/src/set.js deleted file mode 100644 index 9da52c7..0000000 --- a/src/set.js +++ /dev/null @@ -1,147 +0,0 @@ -SVG.Set = SVG.invent({ - // Initialize - create: function(members) { - // Set initial state - Array.isArray(members) ? this.members = members : this.clear() - } - - // Add class methods -, extend: { - // Add element to set - add: function() { - var i, il, elements = [].slice.call(arguments) - - for (i = 0, il = elements.length; i < il; i++) - this.members.push(elements[i]) - - return this - } - // Remove element from set - , remove: function(element) { - var i = this.index(element) - - // remove given child - if (i > -1) - this.members.splice(i, 1) - - return this - } - // Iterate over all members - , each: function(block) { - for (var i = 0, il = this.members.length; i < il; i++) - block.apply(this.members[i], [i, this.members]) - - return this - } - // Restore to defaults - , clear: function() { - // initialize store - this.members = [] - - return this - } - // Get the length of a set - , length: function() { - return this.members.length - } - // Checks if a given element is present in set - , has: function(element) { - return this.index(element) >= 0 - } - // retuns index of given element in set - , index: function(element) { - return this.members.indexOf(element) - } - // Get member at given index - , get: function(i) { - return this.members[i] - } - // Get first member - , first: function() { - return this.get(0) - } - // Get last member - , last: function() { - return this.get(this.members.length - 1) - } - // Default value - , valueOf: function() { - return this.members - } - // Get the bounding box of all members included or empty box if set has no items - , bbox: function(){ - // return an empty box of there are no members - if (this.members.length == 0) - return new SVG.RBox() - - // get the first rbox and update the target bbox - var rbox = this.members[0].rbox(this.members[0].doc()) - - this.each(function() { - // user rbox for correct position and visual representation - rbox = rbox.merge(this.rbox(this.doc())) - }) - - return rbox - } - } - - // Add parent method -, construct: { - // Create a new set - set: function(members) { - return new SVG.Set(members) - } - } -}) - -SVG.FX.Set = SVG.invent({ - // Initialize node - create: function(set) { - // store reference to set - this.set = set - } - -}) - -// Alias methods -SVG.Set.inherit = function() { - var m - , methods = [] - - // gather shape methods - for(var m in SVG.Shape.prototype) - if (typeof SVG.Shape.prototype[m] == 'function' && typeof SVG.Set.prototype[m] != 'function') - methods.push(m) - - // apply shape aliasses - methods.forEach(function(method) { - SVG.Set.prototype[method] = function() { - for (var i = 0, il = this.members.length; i < il; i++) - if (this.members[i] && typeof this.members[i][method] == 'function') - this.members[i][method].apply(this.members[i], arguments) - - return method == 'animate' ? (this.fx || (this.fx = new SVG.FX.Set(this))) : this - } - }) - - // clear methods for the next round - methods = [] - - // gather fx methods - for(var m in SVG.FX.prototype) - if (typeof SVG.FX.prototype[m] == 'function' && typeof SVG.FX.Set.prototype[m] != 'function') - methods.push(m) - - // apply fx aliasses - methods.forEach(function(method) { - SVG.FX.Set.prototype[method] = function() { - for (var i = 0, il = this.set.members.length; i < il; i++) - this.set.members[i].fx[method].apply(this.set.members[i].fx, arguments) - - return this - } - }) -} - - diff --git a/src/style.js b/src/style.js index 053d606..b5f2702 100644 --- a/src/style.js +++ b/src/style.js @@ -2,34 +2,23 @@ SVG.extend(SVG.Element, { // Dynamic style generator style: function(s, v) { if (arguments.length == 0) { - // get full style + // get full style return this.node.style.cssText || '' - + } else if (arguments.length < 2) { - // apply every style individually if an object is passed + // apply every style individually if an object is passed if (typeof s == 'object') { for (v in s) this.style(v, s[v]) - - } else if (SVG.regex.isCss.test(s)) { - // parse css string - s = s.split(/\s*;\s*/) - // filter out suffix ; and stuff like ;; - .filter(function(e) { return !!e }) - .map(function(e){ return e.split(/\s*:\s*/) }) - // apply every definition individually - while (v = s.pop()) { - this.style(v[0], v[1]) - } } else { - // act as a getter if the first and only argument is not an object + // act as a getter if the first and only argument is not an object return this.node.style[camelCase(s)] } - + } else { this.node.style[camelCase(s)] = v === null || SVG.regex.isBlank.test(v) ? '' : v } - + return this } -})
\ No newline at end of file +}) diff --git a/src/sugar.js b/src/sugar.js index e577ea7..d58c6c8 100644 --- a/src/sugar.js +++ b/src/sugar.js @@ -82,7 +82,7 @@ SVG.extend(SVG.Rect, SVG.Ellipse, SVG.Circle, SVG.Gradient, SVG.FX, { // Add x and y radius radius: function(x, y) { var type = (this._target || this).type; - return type == 'radial' || type == 'circle' ? + return type == 'radialGradient' || type == 'radialGradient' ? this.attr('r', new SVG.Number(x)) : this.rx(x).ry(y == null ? x : y) } @@ -95,7 +95,7 @@ SVG.extend(SVG.Path, { } // Get point at length , pointAt: function(length) { - return this.node.getPointAtLength(length) + return new SVG.Point(this.node.getPointAtLength(length)) } }) @@ -58,10 +58,6 @@ SVG.extend = function() { if (modules[i]) for (key in methods) modules[i].prototype[key] = methods[key] - - // Make sure SVG.Set inherits any newly added methods - if (SVG.Set && SVG.Set.inherit) - SVG.Set.inherit() } // Invent new element @@ -135,7 +131,13 @@ SVG.prepare = function() { // Create parser object SVG.parser = { body: body || document.documentElement - , draw: draw.style('opacity:0;position:absolute;left:-100%;top:-100%;overflow:hidden').node + , draw: draw.style({ + opacity:0, + position:'absolute', + left:'-100%', + top:'-100%', + overflow:'hidden' + }).node , poly: draw.polyline().node , path: draw.path().node , native: SVG.create('svg') diff --git a/src/text.js b/src/text.js index 20c2c1e..67b1c2e 100644 --- a/src/text.js +++ b/src/text.js @@ -12,7 +12,7 @@ SVG.Text = SVG.invent({ } // Inherit from -, inherit: SVG.Shape +, inherit: SVG.Parent // Add class methods , extend: { @@ -97,18 +97,6 @@ SVG.Text = SVG.invent({ return this.rebuild() } - // Get all the first level lines - , lines: function() { - var node = (this.textPath && this.textPath() || this).node - - // filter tspans and map them to SVG.js instances - var lines = SVG.utils.map(SVG.utils.filterSVGElements(node.childNodes), function(el){ - return SVG.adopt(el) - }) - - // return an instance of SVG.set - return new SVG.Set(lines) - } // Rebuild appearance type , rebuild: function(rebuild) { // store new rebuild flag if given @@ -121,7 +109,7 @@ SVG.Text = SVG.invent({ , blankLineOffset = 0 , dy = this.dom.leading * new SVG.Number(this.attr('font-size')) - this.lines().each(function() { + this.each(function() { if (this.dom.newLined) { if (!self.textPath()) this.attr('x', self.attr('x')) @@ -171,7 +159,7 @@ SVG.Tspan = SVG.invent({ create: 'tspan' // Inherit from -, inherit: SVG.Shape +, inherit: SVG.Parent // Add class methods , extend: { @@ -232,16 +220,6 @@ SVG.extend(SVG.Text, SVG.Tspan, { return tspan.text(text) } - // Clear all lines -, clear: function() { - var node = (this.textPath && this.textPath() || this).node - - // remove existing child nodes - while (node.hasChildNodes()) - node.removeChild(node.lastChild) - - return this - } // Get length of text element , length: function() { return this.node.getComputedTextLength() diff --git a/src/ungroup.js b/src/ungroup.js deleted file mode 100644 index a76a5a6..0000000 --- a/src/ungroup.js +++ /dev/null @@ -1,24 +0,0 @@ -SVG.extend(SVG.Parent, { - - ungroup: function(parent, depth) { - if(depth === 0 || this instanceof SVG.Defs || this.node == SVG.parser.draw) return this - - parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent)) - depth = depth || Infinity - - this.each(function(){ - if(this instanceof SVG.Defs) return this - if(this instanceof SVG.Parent) return this.ungroup(parent, depth-1) - return this.toParent(parent) - }) - - this.node.firstChild || this.remove() - - return this - }, - - flatten: function(parent, depth) { - return this.ungroup(parent, depth) - } - -})
\ No newline at end of file diff --git a/src/viewbox.js b/src/viewbox.js deleted file mode 100644 index 8ce7e04..0000000 --- a/src/viewbox.js +++ /dev/null @@ -1,127 +0,0 @@ - -SVG.ViewBox = SVG.invent({ - - create: function(source) { - var i, base = [0, 0, 0, 0] - - var x, y, width, height, box, view, we, he - , wm = 1 // width multiplier - , hm = 1 // height multiplier - , reg = /[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi - - if(source instanceof SVG.Element){ - - we = source - he = source - view = (source.attr('viewBox') || '').match(reg) - box = source.bbox - - // get dimensions of current node - width = new SVG.Number(source.width()) - height = new SVG.Number(source.height()) - - // find nearest non-percentual dimensions - while (width.unit == '%') { - wm *= width.value - width = new SVG.Number(we instanceof SVG.Doc ? we.parent().offsetWidth : we.parent().width()) - we = we.parent() - } - while (height.unit == '%') { - hm *= height.value - height = new SVG.Number(he instanceof SVG.Doc ? he.parent().offsetHeight : he.parent().height()) - he = he.parent() - } - - // ensure defaults - this.x = 0 - this.y = 0 - this.width = width * wm - this.height = height * hm - this.zoom = 1 - - if (view) { - // get width and height from viewbox - x = parseFloat(view[0]) - y = parseFloat(view[1]) - width = parseFloat(view[2]) - height = parseFloat(view[3]) - - // calculate zoom accoring to viewbox - this.zoom = ((this.width / this.height) > (width / height)) ? - this.height / height : - this.width / width - - // calculate real pixel dimensions on parent SVG.Doc element - this.x = x - this.y = y - this.width = width - this.height = height - - } - - }else{ - - // ensure source as object - source = typeof source === 'string' ? - source.match(reg).map(function(el){ return parseFloat(el) }) : - Array.isArray(source) ? - source : - typeof source == 'object' ? - [source.x, source.y, source.width, source.height] : - arguments.length == 4 ? - [].slice.call(arguments) : - base - - this.x = source[0] - this.y = source[1] - this.width = source[2] - this.height = source[3] - } - - - } - -, extend: { - - toString: function() { - return this.x + ' ' + this.y + ' ' + this.width + ' ' + this.height - } - , morph: function(x, y, width, height){ - this.destination = new SVG.ViewBox(x, y, width, height) - return this - } - - , at: function(pos) { - - if(!this.destination) return this - - return new SVG.ViewBox([ - this.x + (this.destination.x - this.x) * pos - , this.y + (this.destination.y - this.y) * pos - , this.width + (this.destination.width - this.width) * pos - , this.height + (this.destination.height - this.height) * pos - ]) - - } - - } - - // Define parent -, parent: SVG.Container - - // Add parent method -, construct: { - - // get/set viewbox - viewbox: function(x, y, width, height) { - if (arguments.length == 0) - // act as a getter if there are no arguments - return new SVG.ViewBox(this) - - // otherwise act as a setter - return this.attr('viewBox', new SVG.ViewBox(x, y, width, height)) - } - - } - -})
\ No newline at end of file |