]> source.dussan.org Git - svg.js.git/commitdiff
Added SVG.PathArray, updated data() and bumped to v1.0rc1
authorwout <wout@impinc.co.uk>
Wed, 29 Jan 2014 20:20:58 +0000 (21:20 +0100)
committerwout <wout@impinc.co.uk>
Wed, 29 Jan 2014 20:20:58 +0000 (21:20 +0100)
29 files changed:
CHANGELOG.md
README.md
Rakefile
dist/svg.js
dist/svg.min.js
spec/index.html
spec/spec/element.js
spec/spec/ellipse.js
spec/spec/gradient.js
spec/spec/helper.js
spec/spec/image.js
spec/spec/line.js
spec/spec/path.js
spec/spec/polygon.js
spec/spec/polyline.js
spec/spec/rect.js
src/array.js
src/arraycache.js [new file with mode: 0644]
src/data.js [new file with mode: 0644]
src/doc.js
src/element.js
src/ellipse.js
src/fx.js
src/line.js
src/path.js
src/patharray.js [new file with mode: 0644]
src/pointarray.js
src/poly.js
src/svg.js

index 172fc5c77ffbcfe6028d8576200845bccc88e605..0fbf26c6b5842aa569464354e9e95d6a0a6e3777 100644 (file)
@@ -1,3 +1,12 @@
+# v1.0rc1 (30/01/2014)
+
+- added `SVG.PathArray` for real path transformations
+- removed `unbiased` system for paths
+- added caching on `SVG.PointArray` and `SVG.PathArray` for animations
+- enabled proportional resizing on `size()` method with `null` for either `width` or `height` values
+- moved data module to separate file
+- `data()` method now accepts object for for multiple key / value assignments
+
 # v0.38 (28/01/2014)
 
 - added `loop()` method to `SVG.FX`
index 848a13432ad8db103892b432dae26bf69d3876b4..83fa1d4acdfc48a840b4e8d6f93e9525071cc7f5 100644 (file)
--- a/README.md
+++ b/README.md
@@ -279,20 +279,9 @@ _Javascript inheritance stack: `SVG.Polygon` < `SVG.Shape` < `SVG.Element`_
 The path string is similar to the polygon string but much more complex in order to support curves:
 
 ```javascript
-// path('path data')
 var path = draw.path('M10,20L30,40')
 ```
 
-For more details on path data strings, please refer to the SVG documentation:
-http://www.w3.org/TR/SVG/paths.html#PathData
-
-Note that paths will always be positioned at x=0, y=0 on creation. This is to make the unified `move()` api possible. Svg.js assumes you are creating a path to move it afterwards. If you need to constantly update your path you probably don't want to use the `move()` method at all. In that case you can create an "unbiased" path like so:
-
-```javascript
-// path('path data', unbiased)
-var path = draw.path('M10,20L30,40', true)
-```
-
 Paths can be updated using the `plot()` method:
 
 ```javascript
@@ -301,6 +290,9 @@ path.plot('M100,200L300,400')
 
 _Javascript inheritance stack: `SVG.Path` < `SVG.Shape` < `SVG.Element`_
 
+For more details on path data strings, please refer to the SVG documentation:
+http://www.w3.org/TR/SVG/paths.html#PathData
+
 
 ### Image
 When creating images the `width` and `height` values should be defined:
@@ -768,6 +760,18 @@ Set the size of an element by a given `width` and `height`:
 rect.size(200, 300)
 ```
 
+Proporional resizing is also possible by leaving out `height`:
+
+```javascript
+rect.size(200)
+```
+
+Or by passing `null` as the value for `width`:
+
+```javascript
+rect.size(null, 200)
+```
+
 Same as with `move()` the size of an element could be set by using `attr()`. But because every type of element is handles its size differently the `size()` method is much more convenient.
 
 
@@ -921,7 +925,7 @@ path.bbox()
 This will return an instance of `SVG.BBox` containing the following values:
 
 ```javascript
-{ height: 20, width: 20, y: 20, x: 10, cx: 30, cy: 20 } 
+{ width: 20, height: 20, x: 10, y: 20, cx: 30, cy: 20 } 
 ```
 
 As opposed to the native `getBBox()` method any translations used with the `transform()` method will be taken into account.
@@ -955,42 +959,6 @@ rect.inside(60, 70) //-> returns true
 
 Note: the `x` and `y` positions are tested against the relative position of the element. Any offset on the parent element is not taken into account.
 
-## Colors
-
-Svg.js has a dedicated color module handling different types of colors. Accepted values are:
-
-- hex string; three based (e.g. #f06) or six based (e.g. #ff0066) `new SVG.Color('#f06')`
-- rgb string; e.g. rgb(255, 0, 102) `new SVG.Color('rgb(255, 0, 102)')`
-- rgb object; e.g. { r: 255, g: 0, b: 102 } `new SVG.Color({ r: 255, g: 0, b: 102 })`
-
-Note that when working with objects is important to provide all three values every time.
-
-The `SVG.Color` instance has a few methods of its own.
-
-### toHex()
-Get hex value:
-
-```javascript
-color.toHex() //-> returns '#ff0066'
-```
-
-### toRgb()
-Get rgb string value:
-
-```javascript
-color.toRgb() //-> returns 'rgb(255,0,102)'
-```
-
-### brightness()
-Get the brightness of a color:
-
-```javascript
-color.brightness() //-> returns 0.344
-```
-
-This is the perceived brighness where `0` is black and `1` is white.
-
-
 
 ## Animating elements
 
@@ -1312,7 +1280,7 @@ Or:
 rect.masker.remove()
 ```
 
-### References
+### masker
 For your convenience, the masking element is also referenced in the masked element. This can be useful in case you want to change the mask:
 
 ```javascript
@@ -1323,32 +1291,54 @@ _This functionality requires the mask.js module which is included in the default
 
 
 ## Clipping elements
-Clipping elements is exactly the same as masking elements:
+Clipping elements works exactly the same as masking elements. The only difference is that clipped elements will adopt the geometry of the clipping element. Therefore events are only triggered when entering the clipping element whereas with masks the masked element triggers the event. Another difference is that masks can define opacity with their fill color and clipPaths don't.
 
+### clipWith()
 ```javascript
-var ellipse = draw.ellipse(80, 40).move(10, 10).fill({ color: '#fff' })
+var ellipse = draw.ellipse(80, 40).move(10, 10)
 
 rect.clipWith(ellipse)
 ```
 
-Similar to masking, the clipping element can be referenced in the clipped element:
+### clip()
+Clip multiple elements:
 
 ```javascript
-rect.clipper.move(20,30)
+var ellipse = draw.ellipse(80, 40).move(10, 10)
+var text = draw.text('SVG.JS').move(10, 10).font({ size: 36 })
+
+var clip = draw.clip().add(text).add(ellipse)
+
+rect.clipWith(clip)
 ```
 
+### unclip()
 Unclipping the elements can be done with the `unclip()` method:
 
 ```javascript
 rect.unclip()
 ```
 
-Removing the clipPath alltogether will also `unclip()` all clipped elements:
+### remove()
+Removing the clip alltogether will also `unclip()` all clipped elements as well:
+
+```javascript
+clip.remove()
+```
+
+Or:
 
 ```javascript
 rect.clipper.remove()
 ```
 
+### clipper
+For your convenience, the clipping element is also referenced in the clipped element. This can be useful in case you want to change the clipPath:
+
+```javascript
+rect.clipper.move(10, 10)
+```
+
 _This functionality requires the clip.js module which is included in the default distribution._
 
 
@@ -1602,6 +1592,94 @@ gradient.fill() //-> returns 'url(#SvgjsGradient1234)'
 _This functionality requires the gradient.js module which is included in the default distribution._
 
 
+## Data
+
+### Setting
+The `data()` method allows you to bind arbitrary objects, strings and numbers to SVG elements:
+
+```javascript
+rect.data('key', { value: { data: 0.3 }})
+```
+
+Or set multiple values at once:
+
+```javascript
+rect.data({
+  forbidden: 'fruit'
+, multiple: {
+    values: 'in'
+  , an: 'object'
+  }
+})
+```
+
+### Getting
+Fetching the values is similar to the `attr()` method:
+
+```javascript
+rect.data('key')
+```
+
+### Removing
+Removing the data altogether:
+
+```javascript
+rect.data('key', null)
+```
+
+### Sustaining data types
+Your values will always be stored as JSON and in some cases this might not be desirable. If you want to store the value as-is, just pass true as the third argument:
+
+```javascript
+rect.data('key', 'value', true)
+```
+
+
+## Memory
+
+### remember() 
+Storing data in-memory is very much like setting attributes:
+
+```javascript
+rect.remember('oldBBox', rect.bbox())
+```
+
+Multiple values can also be remembered at once:
+
+```javascript
+rect.remember({
+  oldFill:    rect.attr('fill')
+, oldStroke:  rect.attr('stroke')
+})
+```
+
+To retrieve a memory
+
+```javascript
+rect.remember('oldBBox')
+```
+
+
+### forget()
+Erasing a single memory:
+
+```javascript
+rect.forget('oldBBox')
+```
+
+Or erasing multiple memories at once:
+
+
+```javascript
+rect.forget('oldFill', 'oldStroke')
+```
+
+And finally, just erasing the whole memory:
+
+```javascript
+rect.forget()
+```
+
 ## Events
 
 ### Basic events
@@ -1653,79 +1731,173 @@ Obviously unbinding is practically the same:
 SVG.off(window, 'click', click)
 ```
 
-## Data
-The `data()` method allows you to bind arbitrary objects, strings and numbers to SVG elements:
+## Colors
+
+Svg.js has a dedicated color module handling different types of colors. Accepted values are:
+
+- hex string; three based (e.g. #f06) or six based (e.g. #ff0066) `new SVG.Color('#f06')`
+- rgb string; e.g. rgb(255, 0, 102) `new SVG.Color('rgb(255, 0, 102)')`
+- rgb object; e.g. { r: 255, g: 0, b: 102 } `new SVG.Color({ r: 255, g: 0, b: 102 })`
+
+Note that when working with objects is important to provide all three values every time.
+
+The `SVG.Color` instance has a few methods of its own.
+
+### toHex()
+Get hex value:
 
 ```javascript
-rect.data('key', { value: { data: 0.3 }})
+color.toHex() //-> returns '#ff0066'
 ```
 
-Fetching the values is similar to the `attr()` method:
+### toRgb()
+Get rgb string value:
 
 ```javascript
-rect.data('key')
+color.toRgb() //-> returns 'rgb(255,0,102)'
 ```
 
-Removing the data altogether:
+### brightness()
+Get the brightness of a color:
 
 ```javascript
-rect.data('key', null)
+color.brightness() //-> returns 0.344
 ```
 
-Your values will always be stored as JSON and in some cases this might not be desirable. If you want to store the value as-is, just pass true as the third argument:
+This is the perceived brighness where `0` is black and `1` is white.
+
+
+## Arrays
+In svg.js every value list string can be cast and passed as an array. This makes writing them more convenient but also adds a lot of key functionality to them.
+
+### SVG.Array
+Is for simple, whitespace separated value strings:
 
 ```javascript
-rect.data('key', 'value', true)
+'0.343 0.669 0.119 0 0 0.249 -0.626 0.13 0 0 0.172 0.334 0.111 0 0 0 0 0 1 0'
 ```
 
+Can also be passed like this in a more manageable format:
 
-## Memory
+```javascript
+new SVG.Array([ .343,  .669, .119, 0,   0 
+              , .249, -.626, .130, 0,   0
+              , .172,  .334, .111, 0,   0
+              , .000,  .000, .000, 1,  -0 ])
+```
 
-### remember() 
-Storing data in-memory is very much like setting attributes:
+### SVG.PointArray 
+Is a bit more complex and is used for polyline and polygon elements. This is a poly-point string:
 
 ```javascript
-rect.remember('oldBBox', rect.bbox())
+'0,0 100,100'
 ```
 
-Multiple values can also be remembered at once:
+The dynamic representation:
 
 ```javascript
-rect.remember({
-  oldFill:    rect.attr('fill')
-, oldStroke:  rect.attr('stroke')
-})
+new SVG.PointArray([[0, 0], [100, 100]])
 ```
 
-To retrieve a memory
+Note that every instance of `SVG.Polyline` and `SVG.Polygon` carry a reference to the `SVG.PointArray` instance:
 
 ```javascript
-rect.remember('oldBBox')
+polygon.array //-> returns the SVG.PointArray instance
 ```
 
+_`SVG.PointArray` inherits from `SVG.Array`_
 
-### forget()
-Erasing a single memory:
+### SVG.PathArray
+Path arrays carry object with the representation of the path string:
 
 ```javascript
-rect.forget('oldBBox')
+'M 0 0 L 100 100 z'
 ```
 
-Or erasing multiple memories at once:
+The dynamic representation:
+
+```javascript
+new SVG.PathArray([
+  { type: 'M', x: 0, y: 0 }
+, { type: 'L', x: 100, y: 100 }
+, { type: 'z' }
+])
+```
 
+Note that every instance of `SVG.Path` carries a reference to the `SVG.PathArray` instance:
 
 ```javascript
-rect.forget('oldFill', 'oldStroke')
+polygon.array //-> returns the SVG.PointArray instance
 ```
 
-And finally, just erasing the whole memory:
+_`SVG.PathArray` inherits from `SVG.Array`_
+
+
+### morph()
+In order to animate array values the `morph()` method lets you pass a destination value. This can be either the string value, a plain array or an instance of the same type of svg.js array:
 
 ```javascript
-rect.forget()
+var array = new SVG.PointArray([[0, 0], [100, 100]])
+array.morph('100,0 0,100 200,200')
 ```
 
+This method will prepare the array ensuring both the source and destination arrays have the same length.
+
+Note that this method is currently not available on `SVG.PathArray` but will be soon.
+
+### at()
+This method will morph the array to a given position between `0` and `1`. Continuing with the previous example:
+
+```javascript
+array.at(0.27).toString() //-> returns '27,0 73,100 127,127'
+```
+
+Note that this method is currently not available on `SVG.PathArray` but will be soon.
+
+### settle()
+When morphing is done the `settle()` method will eliminate any transitional points like duplicates:
+
+```javascript
+array.settle()
+```
+
+Note that this method is currently not available on `SVG.PathArray` but will be soon.
+
+### move()
+Moves geometry of the array with the given `x` and `y` values:
+
+```javascript
+var array = new SVG.PointArray([[0, 0], [100, 100]])
+array.move(33,75)
+array.toString() //-> returns '33,75 133,175'
+```
+
+Note that this method is only available on `SVG.PointArray` and `SVG.PathArray`
+
+### size()
+Resizes geometry of the array by the given `width` and `height` values:
+
+```javascript
+var array = new SVG.PointArray([[0, 0], [100, 100]])
+array.move(100,100).size(222,333)
+array.toString() //-> returns '100,100 322,433'
+```
+
+Note that this method is only available on `SVG.PointArray` and `SVG.PathArray`
+
+### bbox()
+Gets the bounding box of the geometry of the array:
+
+```javascript
+array.bbox()
+```
+
+Note that this method is only available on `SVG.PointArray` and `SVG.PathArray`
+
 
 ## Extending functionality
+
+### SVG.extend
 Svg.js has a modular structure. It is very easy to add you own methods at different levels. Let's say we want to add a method to all shape types then we would add our method to SVG.Shape:
 
 ```javascript
@@ -1775,21 +1947,41 @@ SVG.extend(SVG.Ellipse, SVG.Path, SVG.Polygon, {
 ```
 
 
-
 ## Plugins
 Here are a few nice plugins that are available for svg.js:
 
-- [svg.draggable.js](https://github.com/wout/svg.draggable.js) to make elements draggable.
-- [svg.easing.js](https://github.com/wout/svg.easing.js) for more easing methods on animations.
-- [svg.export.js](https://github.com/wout/svg.export.js) export raw SVG.
-- [svg.filter.js](https://github.com/wout/svg.filter.js) adding svg filters to elements.
-- [svg.foreignobject.js](https://github.com/john-memloom/svg.foreignobject.js) foreignObject implementation (by john-memloom).
-- [svg.import.js](https://github.com/wout/svg.import.js) import raw SVG data.
-- [svg.math.js](https://github.com/otm/svg.math.js) a math extension (by Nils Lagerkvist).
-- [svg.path.js](https://github.com/otm/svg.path.js) for manually drawing paths (by Nils Lagerkvist).
-- [svg.pattern.js](https://github.com/wout/svg.pattern.js) add fill patterns.
-- [svg.shapes.js](https://github.com/wout/svg.shapes.js) for more polygon based shapes.
-- [svg.topath.js](https://github.com/wout/svg.topath.js) to convert any other shape to a path.
+### draggable
+[svg.draggable.js](https://github.com/wout/svg.draggable.js) to make elements draggable.
+
+### easing
+[svg.easing.js](https://github.com/wout/svg.easing.js) for more easing methods on animations.
+
+### export
+[svg.export.js](https://github.com/wout/svg.export.js) export raw SVG.
+
+### filter
+[svg.filter.js](https://github.com/wout/svg.filter.js) adding svg filters to elements.
+
+### foreignobject
+[svg.foreignobject.js](https://github.com/john-memloom/svg.foreignobject.js) foreignObject implementation (by john-memloom).
+
+### import
+[svg.import.js](https://github.com/wout/svg.import.js) import raw SVG data.
+
+### math
+[svg.math.js](https://github.com/otm/svg.math.js) a math extension (by Nils Lagerkvist).
+
+### path
+[svg.path.js](https://github.com/otm/svg.path.js) for manually drawing paths (by Nils Lagerkvist).
+
+### pattern
+[svg.pattern.js](https://github.com/wout/svg.pattern.js) add fill patterns.
+
+### shapes
+[svg.shapes.js](https://github.com/wout/svg.shapes.js) for more polygon based shapes.
+
+### topath
+[svg.topath.js](https://github.com/wout/svg.topath.js) to convert any other shape to a path.
 
 
 ## Building
index db513461837f3b84d55187c2363c85d1c73ce229..31670107c49543bf7cf3d9d1943bb4f1145aa729 100644 (file)
--- a/Rakefile
+++ b/Rakefile
@@ -1,7 +1,7 @@
-SVGJS_VERSION = '0.38'
+SVGJS_VERSION = 'v1.0rc1'
 
 # all available modules in the correct loading order
-MODULES = %w[ svg regex default color array pointarray number viewbox bbox rbox element parent container fx event defs group arrange mask clip gradient doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set memory loader ]
+MODULES = %w[ svg regex default color array pointarray patharray arraycache number viewbox bbox rbox element parent container fx event defs group arrange mask clip gradient doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set data memory loader ]
 
 # how many bytes in a "kilobyte"
 KILO = 1024
index cf9159b8d740a25c7a668673608a7da7df384936..aea380f8d0ca6ca3ffc451f6b33c8661d0b90457 100644 (file)
@@ -1,4 +1,4 @@
-/* svg.js v0.38 - svg regex default color array pointarray number viewbox bbox rbox element parent container fx event defs group arrange mask clip gradient doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set memory loader - svgjs.com/license */
+/* svg.js v1.0rc1 - svg regex default color array pointarray patharray arraycache number viewbox bbox rbox element parent container fx event defs group arrange mask clip gradient doc shape use rect ellipse line poly path image text textpath nested hyperlink sugar set data memory loader - svgjs.com/license */
 ;(function() {
 
   this.SVG = function(element) {
@@ -7,7 +7,8 @@
   }
   
   // Default namespaces
-  SVG.ns = 'http://www.w3.org/2000/svg'
+  SVG.ns    = 'http://www.w3.org/2000/svg'
+  SVG.xmlns = 'http://www.w3.org/2000/xmlns/'
   SVG.xlink = 'http://www.w3.org/1999/xlink'
   
   // Element id sequence
   })()
   
   if (!SVG.supported) return false
+  
+  // Initialize parsing element
+  SVG.parser = (function() {
+    /* select document body and create svg element*/
+    var body = document.getElementsByTagName('body')[0] || document.getElementsByTagName('svg')[0]
+      , svg  = SVG.create('svg')
+      , poly = SVG.create('polygon')
+      , path = SVG.create('path')
+  
+    /* make svg element presently invisible to ensure geometry  */
+    svg.setAttributeNS(SVG.xmlns, 'xmlns:xlink', SVG.xlink)
+    svg.setAttribute('style', 'opacity:0;position:fixed;left:100%;top:100%')
+    svg.setAttribute('width', '2')
+    svg.setAttribute('height', '2')
+  
+    /* build node structure */
+    body.appendChild(svg)
+    svg.appendChild(poly)
+    svg.appendChild(path)
+  
+    /* return parser object */
+    return {
+      body: body
+    , doc:  svg
+    , poly: poly
+    , path: path
+    }
+  
+  })()
 
   SVG.regex = {
     /* test a given value */
     }
     // Clean up any duplicate points
   , settle: function() {
-      var i, seen = []
-  
       /* find all unique values */
-      for (i = this.value.length - 1; i >= 0; i--)
+      for (var i = 0, il = this.value.length, seen = []; i < il; i++)
         if (seen.indexOf(this.value[i]) == -1)
           seen.push(this.value[i])
   
     }
     // Get bounding box of points
   , bbox: function() {
-      if (this.value.length == 0)
-        return { x: 0, y: 0, width: 0, height: 0 }
+      if (this._cachedBBox) return this._cachedBBox
+  
+      SVG.parser.poly.setAttribute('points', this.toString())
+  
+      return SVG.parser.poly.getBBox()
+    }
+  
+  })
+
+  SVG.PathArray = function(array, fallback) {
+    this.constructor.call(this, array, fallback)
+  }
   
-      var i
-      , x = this.value[0][0]
-      , y = this.value[0][1]
-      , box = { x: x, y: y }
+  // Inherit from SVG.Array
+  SVG.PathArray.prototype = new SVG.Array
+  
+  SVG.extend(SVG.PathArray, {
+    // Convert array to string
+    toString: function() {
+      for (var s, i = 0, il = this.value.length, array = []; i < il; i++) {
+        s = [this.value[i].type]
+        
+        switch(this.value[i].type) {
+          case 'H':
+            s.push(this.value[i].x)
+          break
+          case 'V':
+            s.push(this.value[i].y)
+          break
+          case 'M':
+          case 'L':
+          case 'T':
+          case 'S':
+          case 'Q':
+          case 'C':
+            if (/[QC]/.test(this.value[i].type))
+              s.push(this.value[i].x1, this.value[i].y1)
+            if (/[CS]/.test(this.value[i].type))
+              s.push(this.value[i].x2, this.value[i].y2)
+  
+            s.push(this.value[i].x, this.value[i].y)
+  
+          break
+          case 'A':
+            s.push(
+              this.value[i].rx
+            , this.value[i].ry
+            , this.value[i].angle
+            , this.value[i].largeArcFlag
+            , this.value[i].sweepFlag
+            , this.value[i].x
+            , this.value[i].y
+            )
+          break
+        }
+  
+        /* add to array */
+        array.push(s.join(' '))
+      }
       
-      /* find position */
-      for (i = this.value.length - 1; i >= 0; i--) {
-        if (this.value[i][0] < box.x)
-          box.x = this.value[i][0]
-        if (this.value[i][1] < box.y)
-          box.y = this.value[i][1]
-        if (this.value[i][0] > x)
-          x = this.value[i][0]
-        if (this.value[i][1] > y)
-          y = this.value[i][1]
+      return array.join(' ')
+    }
+    // Move path string
+  , move: function(x, y) {
+               /* get bounding box of current situation */
+               var box = this.bbox()
+               
+      /* get relative offset */
+      x -= box.x
+      y -= box.y
+  
+      if (!isNaN(x) && !isNaN(y)) {
+        /* move every point */
+        for (var i = this.value.length - 1; i >= 0; i--) {
+          switch (this.value[i].type) {
+            case 'H':
+              /* move along x axis only */
+              this.value[i].x += x
+            break
+            case 'V':
+              /* move along y axis only */
+              this.value[i].y += y
+            break
+            case 'M':
+            case 'L':
+            case 'T':
+            case 'S':
+            case 'Q':
+            case 'C':
+              /* move first point along x and y axes */
+              this.value[i].x += x
+              this.value[i].y += y
+  
+              /* move third points along x and y axes */
+              if (/[CQ]/.test(this.value[i].type)) {
+                this.value[i].x1 += x
+                this.value[i].y1 += y
+              }
+  
+              /* move second points along x and y axes */
+              if (/[CS]/.test(this.value[i].type)) {
+                this.value[i].x2 += x
+                this.value[i].y2 += y
+              }
+  
+            break
+            case 'A':
+              /* only move position values */
+              this.value[i].x += x
+              this.value[i].y += y
+            break
+          }
+        }
       }
   
-      /* calculate size */
-      box.width  = x - box.x
-      box.height = y - box.y
+      return this
+    }
+    // Resize path string
+  , size: function(width, height) {
+               /* get bounding box of current situation */
+               var box = this.bbox()
+  
+      /* recalculate position of all points according to new size */
+      for (var i = this.value.length - 1; i >= 0; i--) {
+        switch (this.value[i].type) {
+          case 'H':
+            /* move along x axis only */
+            this.value[i].x = ((this.value[i].x - box.x) * width)  / box.width  + box.x
+          break
+          case 'V':
+            /* move along y axis only */
+            this.value[i].y = ((this.value[i].y - box.y) * height) / box.height + box.y
+          break
+          case 'M':
+          case 'L':
+          case 'T':
+          case 'S':
+          case 'Q':
+          case 'C':
+            this.value[i].x = ((this.value[i].x - box.x) * width)  / box.width  + box.x
+            this.value[i].y = ((this.value[i].y - box.y) * height) / box.height + box.y
+  
+            /* move third points along x and y axes */
+            if (/[CQ]/.test(this.value[i].type)) {
+              this.value[i].x1 = ((this.value[i].x1 - box.x) * width)  / box.width  + box.x
+              this.value[i].y1 = ((this.value[i].y1 - box.y) * height) / box.height + box.y
+            }
+  
+            /* move second points along x and y axes */
+            if (/[CS]/.test(this.value[i].type)) {
+              this.value[i].x2 = ((this.value[i].x2 - box.x) * width)  / box.width  + box.x
+              this.value[i].y2 = ((this.value[i].y2 - box.y) * height) / box.height + box.y
+            }
   
-      return box
+          break
+          case 'A':
+            /* resize radii */
+            this.value[i].values.rx = (this.value[i].values.rx * width)  / box.width
+            this.value[i].values.ry = (this.value[i].values.ry * height) / box.height
+  
+            /* move position values */
+            this.value[i].values.x = ((this.value[i].values.x - box.x) * width)  / box.width  + box.x
+            this.value[i].values.y = ((this.value[i].values.y - box.y) * height) / box.height + box.y
+          break
+        }
+      }
+  
+      return this
+    }
+    // Absolutize and parse path to array
+  , parse: function(array) {
+      array = array.valueOf()
+  
+      /* if already is an array, no need to parse it */
+      if (Array.isArray(array)) return array
+  
+      /* prepare for parsing */
+      var i, il, x0, y0, x1, y1, x2, y2, s, seg, segs
+        , x = 0
+        , y = 0
+      
+      /* populate working path */
+      SVG.parser.path.setAttribute('d', array)
+      
+      /* get segments */
+      segs = SVG.parser.path.pathSegList
+  
+      for (i = 0, il = segs.numberOfItems; i < il; ++i) {
+        seg = segs.getItem(i)
+        s = seg.pathSegTypeAsLetter
+  
+        if (/[MLHVCSQTA]/.test(s)) {
+          if ('x' in seg) x = seg.x
+          if ('y' in seg) y = seg.y
+  
+        } else {
+          if ('x1' in seg) x1 = x + seg.x1
+          if ('x2' in seg) x2 = x + seg.x2
+          if ('y1' in seg) y1 = y + seg.y1
+          if ('y2' in seg) y2 = y + seg.y2
+          if ('x'  in seg) x += seg.x
+          if ('y'  in seg) y += seg.y
+  
+          switch(s){
+            case 'm': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegMovetoAbs(x, y), i)
+            break
+            case 'l': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoAbs(x, y), i)
+            break
+            case 'h': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoHorizontalAbs(x), i)
+            break
+            case 'v': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoVerticalAbs(y), i)
+            break
+            case 'c': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i)
+            break
+            case 's': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i)
+            break
+            case 'q': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i)
+            break
+            case 't': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i)
+            break
+            case 'a': 
+              segs.replaceItem(SVG.parser.path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i) 
+            break
+            case 'z':
+            case 'Z':
+              x = x0
+              y = y0
+            break
+          }
+        }
+  
+        /* record the start of a subpath */
+        if (/[Mm]/.test(s)) {
+          x0 = x
+          y0 = y
+        }
+      }
+  
+      /* build internal representation */
+      array = []
+      segs = SVG.parser.path.pathSegList
+      
+      for (i = 0, il = segs.numberOfItems; i < il; ++i) {
+        seg = segs.getItem(i)
+        s = {}
+  
+        switch (seg.pathSegTypeAsLetter) {
+          case 'M':
+          case 'L':
+          case 'T':
+          case 'S':
+          case 'Q':
+          case 'C':
+            if (/[QC]/.test(seg.pathSegTypeAsLetter)) {
+              s.x1 = seg.x1
+              s.y1 = seg.y1
+            }
+  
+            if (/[SC]/.test(seg.pathSegTypeAsLetter)) {
+              s.x2 = seg.x2
+              s.y2 = seg.y2
+            }
+  
+          break
+          case 'A':
+            s = {
+              r1:           seg.r1
+            , r2:           seg.r2
+            , angle:        seg.angle
+            , largeArcFlag: seg.largeArcFlag
+            , sweepFlag:    seg.sweepFlag
+            }
+          break
+        }
+  
+        /* make the letter, x and y values accessible as key/values */
+        s.type = seg.pathSegTypeAsLetter
+        s.x = seg.x
+        s.y = seg.y
+  
+        /* store segment */
+        array.push(s)
+      }
+      
+      return array
+    }
+    // Get bounding box of path
+  , bbox: function() {
+               if (this._cachedBBox) return this._cachedBBox
+  
+      SVG.parser.path.setAttribute('d', this.toString())
+  
+      return SVG.parser.path.getBBox()
     }
   
   })
 
+  SVG.extend(SVG.PointArray, SVG.PathArray, {
+       // Cache bbox
+    cache: function() {
+               this._cachedBBox = this.uncache().bbox()
+  
+               return this
+    }
+    // Remove cache
+  , uncache: function() {
+               delete this._cachedBBox
+               return this
+       }
+  
+  })
+
   SVG.Number = function(value) {
   
     /* initialize defaults */
     }
     // Set element size to given width and height
   , size: function(width, height) {
+      var p = this._proportionalSize(width, height)
+  
       return this.attr({
-        width:  new SVG.Number(width)
-      , height: new SVG.Number(height)
+        width:  new SVG.Number(p.width)
+      , height: new SVG.Number(p.height)
       })
     }
     // Clone element
       if (o.x != 0 || o.y != 0)
         transform.push('translate(' + new SVG.Number(o.x / o.scaleX) + ' ' + new SVG.Number(o.y / o.scaleY) + ')')
       
-      /* add offset translation */
-       if (this._offset && this._offset.x != 0 && this._offset.y != 0)
-         transform.push('translate(' + (-this._offset.x) + ' ' + (-this._offset.y) + ')')
-      
       /* update transformations, even if there are none */
       if (transform.length == 0)
         this.node.removeAttribute('transform')
       
       return this
     }
-    // Store data values on svg nodes
-  , data: function(a, v, r) {
-      if (arguments.length < 2) {
-        try {
-          return JSON.parse(this.attr('data-' + a))
-        } catch(e) {
-          return this.attr('data-' + a)
-        }
-        
-      } else {
-        this.attr(
-          'data-' + a
-        , v === null ?
-            null :
-          r === true || typeof v === 'string' || typeof v === 'number' ?
-            v :
-            JSON.stringify(v)
-        )
-      }
-      
-      return this
-    }
     // Get bounding box
   , bbox: function() {
       return new SVG.BBox(this)
       
       return o
     }
+    // Private: calculate proportional width and height values when necessary
+  , _proportionalSize: function(width, height) {
+      if (width == null || height == null) {
+        var box = this.bbox()
+  
+        if (height == null)
+          height = box.height / box.width * width
+        else if (width == null)
+          width = box.width / box.height * height
+      }
+      
+      return {
+        width:  width
+      , height: height
+      }
+    }
     
   })
 
             akeys.push(key)
   
           /* make sure morphable elements are scaled, translated and morphed all together */
-          if (element.morphArray) {
+          if (element.morphArray && akeys.indexOf('points') > -1) {
             /* get destination */
             var box
-              , p = new element.morphArray(fx._plot || element.points.toString())
+              , p = new element.morphArray(fx._plot || element.array)
   
             /* add size */
             if (fx._size) p.size(fx._size.width.to, fx._size.height.to)
             delete fx._cy
             delete fx._size
   
-            fx._plot = element.points.morph(p)
+            fx._plot = element.array.morph(p)
           }
         }
   
         typeof ease == 'function' ?
           ease(pos) :
           pos
-  
-        /* run all x-position properties */
-        if (fx._x)
-          element.x(fx._at(fx._x, pos))
-        else if (fx._cx)
-          element.cx(fx._at(fx._cx, pos))
-  
-        /* run all y-position properties */
-        if (fx._y)
-          element.y(fx._at(fx._y, pos))
-        else if (fx._cy)
-          element.cy(fx._at(fx._cy, pos))
-  
-        /* run all size properties */
-        if (fx._size)
-          element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos))
-  
+        
         /* run plot function */
-        if (fx._plot)
+        if (fx._plot) {
           element.plot(fx._plot.at(pos))
   
+        } else {
+          if (element.array)
+            element.array.cache()
+  
+          /* run all x-position properties */
+          if (fx._x)
+            element.x(fx._at(fx._x, pos))
+          else if (fx._cx)
+            element.cx(fx._at(fx._cx, pos))
+  
+          /* run all y-position properties */
+          if (fx._y)
+            element.y(fx._at(fx._y, pos))
+          else if (fx._cy)
+            element.cy(fx._at(fx._cy, pos))
+  
+          /* run all size properties */
+          if (fx._size)
+            element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos))
+  
+          if (element.array)
+            element.array.uncache()
+        }
+  
         /* run all viewbox properties */
         if (fx._viewbox)
           element.viewbox(
     /* set svg element attributes */
     this
       .attr({ xmlns: SVG.ns, version: '1.1', width: '100%', height: '100%' })
-      .attr('xlink', SVG.xlink, SVG.ns)
+      .attr('xmlns:xlink', SVG.xlink, SVG.xmlns)
     
     /* create the <defs> node */
     this._defs = new SVG.Defs
     }
     // Custom size function
   , size: function(width, height) {
+      var p = this._proportionalSize(width, height)
+  
       return this.attr({
-        rx: new SVG.Number(width).divide(2)
-      , ry: new SVG.Number(height).divide(2)
+        rx: new SVG.Number(p.width).divide(2)
+      , ry: new SVG.Number(p.height).divide(2)
       })
     }
     
     }
     // Set line size by width and height
   , size: function(width, height) {
-      return this.width(width).height(height)
+      var p = this._proportionalSize(width, height)
+  
+      return this.width(p.width).height(p.height)
     }
     // Set path data
   , plot: function(x1, y1, x2, y2) {
     morphArray:  SVG.PointArray
     // Plot new path
   , plot: function(p) {
-      return this.attr('points', (this.points = new SVG.PointArray(p, [[0,0]])))
+      return this.attr('points', (this.array = new SVG.PointArray(p, [[0,0]])))
     }
     // Move by left top corner
   , move: function(x, y) {
-      return this.attr('points', this.points.move(x, y))
+      return this.attr('points', this.array.move(x, y))
     }
     // Move by left top corner over x-axis
   , x: function(x) {
     }
     // Set element size to given width and height
   , size: function(width, height) {
-      return this.attr('points', this.points.size(width, height))
+      var p = this._proportionalSize(width, height)
+  
+      return this.attr('points', this.array.size(p.width, p.height))
     }
   
   })
   
   })
 
-  SVG.Path = function(unbiased) {
+  SVG.Path = function() {
     this.constructor.call(this, SVG.create('path'))
-    
-    this.unbiased = !!unbiased
   }
   
   // Inherit from SVG.Shape
   SVG.Path.prototype = new SVG.Shape
   
   SVG.extend(SVG.Path, {
-    // Move over x-axis
-    x: function(x) {
-      return x == null ? this.bbox().x : this.transform('x', x)
+    // Plot new poly points
+    plot: function(p) {
+      return this.attr('d', (this.array = new SVG.PathArray(p, [{ type:'M',x:0,y:0 }])))
     }
-    // Move over y-axis
-  , y: function(y) {
-      return y == null ? this.bbox().y : this.transform('y', y)
+    // Move by left top corner
+  , move: function(x, y) {
+      return this.attr('d', this.array.move(x, y))
     }
-    // Set width of element
-  , width: function(width) {
-      var b = this.bbox()
-  
-      return width == null ? b.width : this.size(width, b.height)
+    // Move by left top corner over x-axis
+  , x: function(x) {
+      return x == null ? this.bbox().x : this.move(x, this.bbox().y)
     }
-    // Set height of element
-  , height: function(height) {
-      var b = this.bbox()
-  
-      return height == null ? b.height : this.size(b.width, height)
+    // Move by left top corner over y-axis
+  , y: function(y) {
+      return y == null ? this.bbox().y : this.move(this.bbox().x, y)
     }
-    // Set the actual size in pixels
+    // Set element size to given width and height
   , size: function(width, height) {
-      var scale = width / this._offset.width
+      var p = this._proportionalSize(width, height)
       
-      return this.transform({
-        scaleX: scale
-      , scaleY: height != null ? height / this._offset.height : scale
-      })
+      return this.attr('d', this.array.size(p.width, p.height))
     }
-    // Set path data
-  , plot: function(data) {
-      var x = this.trans.scaleX
-        , y = this.trans.scaleY
-      
-      /* native plot */
-      this._plot(data)
-      
-      /* store offset */
-      this._offset = this.transform({ scaleX: 1, scaleY: 1 }).bbox()
-      
-      /* get and store the actual offset of the element */
-      if (this.unbiased) {
-        this._offset.x = this._offset.y = 0
-      } else {
-        this._offset.x -= this.trans.x
-        this._offset.y -= this.trans.y
-      }
-      
-      return this.transform({ scaleX: x, scaleY: y })
+    // Set width of element
+  , width: function(width) {
+      return width == null ? this.bbox().width : this.size(width, this.bbox().height)
     }
-    // Private: Native plot
-  , _plot: function(data) {
-      return this.attr('d', data || 'M0,0')
+    // Set height of element
+  , height: function(height) {
+      return height == null ? this.bbox().height : this.size(this.bbox().width, height)
     }
-    
+  
   })
   
   //
   SVG.extend(SVG.Container, {
     // Create a wrapped path element
-    path: function(data, unbiased) {
-      return this.put(new SVG.Path(unbiased)).plot(data)
+    path: function(d) {
+      return this.put(new SVG.Path).plot(d)
     }
   
   })
   
 
 
+  SVG.extend(SVG.Element, {
+       // Store data values on svg nodes
+    data: function(a, v, r) {
+       if (typeof a == 'object') {
+               for (v in a)
+                       this.data(v, a[v])
+  
+      } else if (arguments.length < 2) {
+        try {
+          return JSON.parse(this.attr('data-' + a))
+        } catch(e) {
+          return this.attr('data-' + a)
+        }
+        
+      } else {
+        this.attr(
+          'data-' + a
+        , v === null ?
+            null :
+          r === true || typeof v === 'string' || typeof v === 'number' ?
+            v :
+            JSON.stringify(v)
+        )
+      }
+      
+      return this
+    }
+  })
+
   SVG.extend(SVG.Element, {
     // Remember arbitrary data
     remember: function(k, v) {
index 59ee1ebdf285f8a7cf57452570961fe4a4182754..425f7917c0e56e464cccdf546c44029ce8239f3b 100644 (file)
@@ -1,2 +1,2 @@
-(function(){if(this.SVG=function(t){return SVG.supported?new SVG.Doc(t):void 0},SVG.ns="http://www.w3.org/2000/svg",SVG.xlink="http://www.w3.org/1999/xlink",SVG.did=1e3,SVG.eid=function(t){return"Svgjs"+t.charAt(0).toUpperCase()+t.slice(1)+SVG.did++},SVG.create=function(t){var e=document.createElementNS(this.ns,t);return e.setAttribute("id",this.eid(t)),e},SVG.extend=function(){var t,e,i,n;for(t=[].slice.call(arguments),e=t.pop(),n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i];SVG.Set&&SVG.Set.inherit&&SVG.Set.inherit()},SVG.get=function(t){var e=document.getElementById(t);return e?e.instance:void 0},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}(),!SVG.supported)return!1;SVG.regex={test:function(t,e){return this[e].test(t)},unit:/^(-?[\d\.]+)([a-z%]{0,2})$/,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isStyle:/^font|text|leading|cursor/,isBlank:/^(\s+)?$/,isNumber:/^-?[\d\.]+$/,isPercent:/^-?[\d\.]+%$/},SVG.defaults={matrix:"1 0 0 1 0 0",attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"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"},trans:function(){return{x:0,y:0,scaleX:1,scaleY:1,rotation:0,skewX:0,skewY:0,matrix:this.matrix,a:1,b:0,c:0,d:1,e:0,f:0}}},SVG.Color=function(t){var e;this.r=0,this.g=0,this.b=0,"string"==typeof t?SVG.regex.isRgb.test(t)?(e=SVG.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):SVG.regex.isHex.test(t)&&(e=SVG.regex.hex.exec(this._fullHex(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b)},SVG.extend(SVG.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+this._compToHex(this.r)+this._compToHex(this.g)+this._compToHex(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return.3*(this.r/255)+.59*(this.g/255)+.11*(this.b/255)},_fullHex:function(t){return 4==t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t},_compToHex:function(t){var e=t.toString(16);return 1==e.length?"0"+e:e}}),SVG.Color.test=function(t){return t+="",SVG.regex.isHex.test(t)||SVG.regex.isRgb.test(t)},SVG.Color.isRgb=function(t){return t&&"number"==typeof t.r},SVG.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},SVG.extend(SVG.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){var t,e=[];for(t=this.value.length-1;t>=0;t--)-1==e.indexOf(this.value[t])&&e.push(this.value[t]);return this.value=e},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];i>e;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new SVG.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:this.split(t)},split:function(t){return t.replace(/\s+/g," ").replace(/^\s+|\s+$/g,"").split(" ")}}),SVG.PointArray=function(){this.constructor.apply(this,arguments)},SVG.PointArray.prototype=new SVG.Array,SVG.extend(SVG.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];e>t;t++)i.push(this.value[t].join(","));return i.join(" ")},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];i>e;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new SVG.PointArray(n)},parse:function(t){if(t=t.valueOf(),Array.isArray(t))return t;t=this.split(t);for(var e,i=0,n=t.length,r=[];n>i;i++)e=t[i].split(","),r.push([parseFloat(e[0]),parseFloat(e[1])]);return r},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x,this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.x;return this},bbox:function(){if(0==this.value.length)return{x:0,y:0,width:0,height:0};var t,e=this.value[0][0],i=this.value[0][1],n={x:e,y:i};for(t=this.value.length-1;t>=0;t--)this.value[t][0]<n.x&&(n.x=this.value[t][0]),this.value[t][1]<n.y&&(n.y=this.value[t][1]),this.value[t][0]>e&&(e=this.value[t][0]),this.value[t][1]>i&&(i=this.value[t][1]);return n.width=e-n.x,n.height=i-n.y,n}}),SVG.Number=function(t){switch(this.value=0,this.unit="",typeof t){case"number":this.value=isNaN(t)?0:isFinite(t)?t:0>t?-3.4e38:3.4e38;break;case"string":var e=t.match(SVG.regex.unit);e&&(this.value=parseFloat(e[1]),"%"==e[2]&&(this.value/=100),this.unit=e[2]);break;default:t instanceof SVG.Number&&(this.value=t.value,this.unit=t.unit)}},SVG.extend(SVG.Number,{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:this.value)+this.unit},valueOf:function(){return this.value},to:function(t){return"string"==typeof t&&(this.unit=t),this},plus:function(t){return this.value=this+new SVG.Number(t),this},minus:function(t){return this.plus(-new SVG.Number(t))},times:function(t){return this.value=this*new SVG.Number(t),this},divide:function(t){return this.value=this/new SVG.Number(t),this}}),SVG.ViewBox=function(t){var e,i,n,r,s=1,h=1,o=t.bbox(),a=(t.attr("viewBox")||"").match(/-?[\d\.]+/g);for(n=new SVG.Number(t.width()),r=new SVG.Number(t.height());"%"==n.unit;)s*=n.value,n=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetWidth:t.width());for(;"%"==r.unit;)h*=r.value,r=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetHeight:t.height());this.x=o.x,this.y=o.y,this.width=n*s,this.height=r*h,this.zoom=1,a&&(e=parseFloat(a[0]),i=parseFloat(a[1]),n=parseFloat(a[2]),r=parseFloat(a[3]),this.zoom=this.width/this.height>n/r?this.height/r:this.width/n,this.x=e,this.y=i,this.width=n,this.height=r)},SVG.extend(SVG.ViewBox,{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height}}),SVG.BBox=function(t){var e;if(this.x=0,this.y=0,this.width=0,this.height=0,t){try{e=t.node.getBBox()}catch(i){e={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=e.x+t.trans.x,this.y=e.y+t.trans.y,this.width=e.width*t.trans.scaleX,this.height=e.height*t.trans.scaleY}this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.extend(SVG.BBox,{merge:function(t){var e=new SVG.BBox;return e.x=Math.min(this.x,t.x),e.y=Math.min(this.y,t.y),e.width=Math.max(this.x+this.width,t.x+t.width)-e.x,e.height=Math.max(this.y+this.height,t.y+t.height)-e.y,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2,e}}),SVG.RBox=function(t){var e,i,n={};if(this.x=0,this.y=0,this.width=0,this.height=0,t){for(e=t.doc().parent,i=t.doc().viewbox().zoom,n=t.node.getBoundingClientRect(),this.x=n.left,this.y=n.top,this.x-=e.offsetLeft,this.y-=e.offsetTop;e=e.offsetParent;)this.x-=e.offsetLeft,this.y-=e.offsetTop;for(e=t;e=e.parent;)"svg"==e.type&&e.viewbox&&(i*=e.viewbox().zoom,this.x-=e.x()||0,this.y-=e.y()||0)}this.x/=i,this.y/=i,this.width=n.width/=i,this.height=n.height/=i,this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.extend(SVG.RBox,{merge:function(t){var e=new SVG.RBox;return e.x=Math.min(this.x,t.x),e.y=Math.min(this.y,t.y),e.width=Math.max(this.x+this.width,t.x+t.width)-e.x,e.height=Math.max(this.y+this.height,t.y+t.height)-e.y,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2,e}}),SVG.Element=function(t){this._stroke=SVG.defaults.attrs.stroke,this.styles={},this.trans=SVG.defaults.trans(),(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},SVG.extend(SVG.Element,{x:function(t){return t&&(t=new SVG.Number(t),t.value/=this.trans.scaleX),this.attr("x",t)},y:function(t){return t&&(t=new SVG.Number(t),t.value/=this.trans.scaleY),this.attr("y",t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){return this.attr({width:new SVG.Number(t),height:new SVG.Number(e)})},clone:function(){var t,e,i=this.type;return t="rect"==i||"ellipse"==i?this.parent[i](0,0):"line"==i?this.parent[i](0,0,0,0):"image"==i?this.parent[i](this.src):"text"==i?this.parent[i](this.content):"path"==i?this.parent[i](this.attr("d")):"polyline"==i||"polygon"==i?this.parent[i](this.attr("points")):"g"==i?this.parent.group():this.parent[i](),e=this.attr(),delete e.id,t.attr(e),t.trans=this.trans,t.transform({})},remove:function(){return this.parent&&this.parent.removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},doc:function(t){return this._parent(t||SVG.Doc)},attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=SVG.regex.test(e[i].nodeValue,"isNumber")?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return this._isStyle(t)?"text"==t?this.content:"leading"==t&&this.leading?this.leading():this.style(t):(e=this.node.getAttribute(t),null==e?SVG.defaults.attrs[t]:SVG.regex.test(e,"isNumber")?parseFloat(e):e);if("style"==t)return this.style(e);if("x"==t&&Array.isArray(this.lines))for(i=this.lines.length-1;i>=0;i--)this.lines[i].attr(t,e);"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),SVG.Color.test(e)||SVG.Color.isRgb(e)?e=new SVG.Color(e):"number"==typeof e?e=new SVG.Number(e):Array.isArray(e)&&(e=new SVG.Array(e)),null!=i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),this._isStyle(t)&&("text"==t?this.text(e):"leading"==t&&this.leading?this.leading(e):this.style(t,e),this.rebuild&&this.rebuild(t,e))}return this},transform:function(t,e){if(0==arguments.length)return this.trans;if("string"==typeof t){if(2>arguments.length)return this.trans[t];var i={};return i[t]=e,this.transform(i)}var i=[];t=this._parseMatrix(t);for(e in t)null!=t[e]&&(this.trans[e]=t[e]);return this.trans.matrix=this.trans.a+" "+this.trans.b+" "+this.trans.c+" "+this.trans.d+" "+this.trans.e+" "+this.trans.f,t=this.trans,t.matrix!=SVG.defaults.matrix&&i.push("matrix("+t.matrix+")"),0!=t.rotation&&i.push("rotate("+t.rotation+" "+(null==t.cx?this.bbox().cx:t.cx)+" "+(null==t.cy?this.bbox().cy:t.cy)+")"),(1!=t.scaleX||1!=t.scaleY)&&i.push("scale("+t.scaleX+" "+t.scaleY+")"),0!=t.skewX&&i.push("skewX("+t.skewX+")"),0!=t.skewY&&i.push("skewY("+t.skewY+")"),(0!=t.x||0!=t.y)&&i.push("translate("+new SVG.Number(t.x/t.scaleX)+" "+new SVG.Number(t.y/t.scaleY)+")"),this._offset&&0!=this._offset.x&&0!=this._offset.y&&i.push("translate("+-this._offset.x+" "+-this._offset.y+")"),0==i.length?this.node.removeAttribute("transform"):this.node.setAttribute("transform",i.join(" ")),this},style:function(t,e){if(0==arguments.length)return this.attr("style")||"";if(2>arguments.length)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!SVG.regex.isCss.test(t))return this.styles[t];t=t.split(";");for(var i=0;t.length>i;i++)e=t[i].split(":"),2==e.length&&this.style(e[0].replace(/\s+/g,""),e[1].replace(/^\s+/,"").replace(/\s+$/,""))}else null===e||SVG.regex.test(e,"isBlank")?delete this.styles[t]:this.styles[t]=e;t="";for(e in this.styles)t+=e+":"+this.styles[e]+";";return""==t?this.node.removeAttribute("style"):this.node.setAttribute("style",t),this},data:function(t,e,i){if(2>arguments.length)try{return JSON.parse(this.attr("data-"+t))}catch(n){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this},bbox:function(){return new SVG.BBox(this)},rbox:function(){return new SVG.RBox(this)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&i.x+i.width>t&&i.y+i.height>e},show:function(){return this.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},_parent:function(t){for(var e=this;null!=e&&!(e instanceof t);)e=e.parent;return e},_isStyle:function(t){return"string"==typeof t?SVG.regex.test(t,"isStyle"):!1},_parseMatrix:function(t){if(t.matrix){var e=t.matrix.replace(/\s/g,"").split(",");6==e.length&&(t.a=parseFloat(e[0]),t.b=parseFloat(e[1]),t.c=parseFloat(e[2]),t.d=parseFloat(e[3]),t.e=parseFloat(e[4]),t.f=parseFloat(e[5]))}return t}}),SVG.Parent=function(t){this.constructor.call(this,t)},SVG.Parent.prototype=new SVG.Element,SVG.extend(SVG.Parent,{children:function(){return this._children||(this._children=[])},add:function(t,e){if(!this.has(t)){if(e=null==e?this.children().length:e,t.parent){var i=t.parent.children().indexOf(t);t.parent.children().splice(i,1)}this.children().splice(e,0,t),this.node.insertBefore(t.node,this.node.childNodes[e]||null),t.parent=this}return this._defs&&(this.node.removeChild(this._defs.node),this.node.appendChild(this._defs.node)),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.children().indexOf(t)>=0},get:function(t){return this.children()[t]},first:function(){return this.children()[0]},last:function(){return this.children()[this.children().length-1]},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;n>i;i++)r[i]instanceof SVG.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof SVG.Container&&r[i].each(t,e);return this},removeElement:function(t){var e=this.children().indexOf(t);return this.children().splice(e,1),this.node.removeChild(t.node),t.parent=null,this},clear:function(){for(var t=this.children().length-1;t>=0;t--)this.removeElement(this.children()[t]);return this._defs&&this._defs.clear(),this},defs:function(){return this.doc().defs()}}),SVG.Container=function(t){this.constructor.call(this,t)},SVG.Container.prototype=new SVG.Parent,SVG.extend(SVG.Container,{viewbox:function(t){return 0==arguments.length?new SVG.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t))}}),SVG.FX=function(t){this.target=t},SVG.extend(SVG.FX,{animate:function(t,e,i){var n,r,s,h,o=this.target,a=this;return"object"==typeof t&&(i=t.delay,e=t.ease,t=t.duration),t=null==t?1e3:t,e=e||"<>",a.to=function(t){var i;if(t=0>t?0:t>1?1:t,null==n){n=[];for(h in a.attrs)n.push(h);if(o.morphArray){var u,l=new o.morphArray(a._plot||o.points.toString());a._size&&l.size(a._size.width.to,a._size.height.to),u=l.bbox(),a._x?l.move(a._x.to,u.y):a._cx&&l.move(a._cx.to-u.width/2,u.y),u=l.bbox(),a._y?l.move(u.x,a._y.to):a._cy&&l.move(u.x,a._cy.to-u.height/2),delete a._x,delete a._y,delete a._cx,delete a._cy,delete a._size,a._plot=o.points.morph(l)}}if(null==r){r=[];for(h in a.trans)r.push(h)}if(null==s){s=[];for(h in a.styles)s.push(h)}for(t="<>"==e?-Math.cos(t*Math.PI)/2+.5:">"==e?Math.sin(t*Math.PI/2):"<"==e?-Math.cos(t*Math.PI/2)+1:"-"==e?t:"function"==typeof e?e(t):t,a._x?o.x(a._at(a._x,t)):a._cx&&o.cx(a._at(a._cx,t)),a._y?o.y(a._at(a._y,t)):a._cy&&o.cy(a._at(a._cy,t)),a._size&&o.size(a._at(a._size.width,t),a._at(a._size.height,t)),a._plot&&o.plot(a._plot.at(t)),a._viewbox&&o.viewbox(a._at(a._viewbox.x,t),a._at(a._viewbox.y,t),a._at(a._viewbox.width,t),a._at(a._viewbox.height,t)),i=n.length-1;i>=0;i--)o.attr(n[i],a._at(a.attrs[n[i]],t));for(i=r.length-1;i>=0;i--)o.transform(r[i],a._at(a.trans[r[i]],t));for(i=s.length-1;i>=0;i--)o.style(s[i],a._at(a.styles[s[i]],t));a._during&&a._during.call(o,t,function(e,i){return a._at({from:e,to:i},t)})},"number"==typeof t&&(this.timeout=setTimeout(function(){var n=(new Date).getTime();a.situation={interval:1e3/60,start:n,play:!0,finish:n+t,duration:t},a.render=function(){if(a.situation.play===!0){var n=(new Date).getTime(),r=n>a.situation.finish?1:(n-a.situation.start)/t;a.to(r),n>a.situation.finish?(a._plot&&o.plot(new SVG.PointArray(a._plot.destination).settle()),a._loop===!0||"number"==typeof a._loop&&a._loop>1?("number"==typeof a._loop&&--a._loop,a.animate(t,e,i)):a._after?a._after.apply(o,[a]):a.stop()):requestAnimFrame(a.render)}else requestAnimFrame(a.render)},a.render()},i||0)),this},bbox:function(){return this.target.bbox()},attr:function(t,e){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.attrs[t]={from:this.target.attr(t),to:e};return this},transform:function(t,e){if(1==arguments.length){t=this.target._parseMatrix(t),delete t.matrix;for(e in t)this.trans[e]={from:this.target.trans[e],to:t[e]}}else{var i={};i[t]=e,this.transform(i)}return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.styles[t]={from:this.target.style(t),to:e};return this},x:function(t){return this._x={from:this.target.x(),to:t},this},y:function(t){return this._y={from:this.target.y(),to:t},this},cx:function(t){return this._cx={from:this.target.cx(),to:t},this},cy:function(t){return this._cy={from:this.target.cy(),to:t},this},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target instanceof SVG.Text)this.attr("font-size",t);else{var i=this.target.bbox();this._size={width:{from:i.width,to:t},height:{from:i.height,to:e}}}return this},plot:function(t){return this._plot=t,this},viewbox:function(t,e,i,n){if(this.target instanceof SVG.Container){var r=this.target.viewbox();this._viewbox={x:{from:r.x,to:t},y:{from:r.y,to:e},width:{from:r.width,to:i},height:{from:r.height,to:n}}}return this},update:function(t){return this.target instanceof SVG.Stop&&(null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new SVG.Number(t.offset))),this},during:function(t){return this._during=t,this},after:function(t){return this._after=t,this},loop:function(t){return this._loop=t||!0,this},stop:function(){return clearTimeout(this.timeout),clearInterval(this.interval),this.attrs={},this.trans={},this.styles={},this.situation={},delete this._x,delete this._y,delete this._cx,delete this._cy,delete this._size,delete this._plot,delete this._loop,delete this._after,delete this._during,delete this._viewbox,this},pause:function(){return this.situation.play===!0&&(this.situation.play=!1,this.situation.pause=(new Date).getTime()),this},play:function(){if(this.situation.play===!1){var t=(new Date).getTime()-this.situation.pause;this.situation.finish+=t,this.situation.start+=t,this.situation.play=!0}return this},_at:function(t,e){return"number"==typeof t.from?t.from+(t.to-t.from)*e:SVG.regex.unit.test(t.to)?new SVG.Number(t.to).minus(new SVG.Number(t.from)).times(e).plus(new SVG.Number(t.from)):t.to&&(t.to.r||SVG.Color.test(t.to))?this._color(t,e):1>e?t.from:t.to},_color:function(t,e){var i,n;return e=0>e?0:e>1?1:e,i=new SVG.Color(t.from),n=new SVG.Color(t.to),new SVG.Color({r:~~(i.r+(n.r-i.r)*e),g:~~(i.g+(n.g-i.g)*e),b:~~(i.b+(n.b-i.b)*e)}).toHex()}}),SVG.extend(SVG.Element,{animate:function(t,e,i){return(this.fx||(this.fx=new SVG.FX(this))).stop().animate(t,e,i)},stop:function(){return this.fx&&this.fx.stop(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this}}),window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}(),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave"].forEach(function(t){SVG.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),SVG.on=function(t,e,i){t.addEventListener?t.addEventListener(e,i,!1):t.attachEvent("on"+e,i)},SVG.off=function(t,e,i){t.removeEventListener?t.removeEventListener(e,i,!1):t.detachEvent("on"+e,i)},SVG.extend(SVG.Element,{on:function(t,e){return SVG.on(this.node,t,e),this},off:function(t,e){return SVG.off(this.node,t,e),this}}),SVG.Defs=function(){this.constructor.call(this,SVG.create("defs"))},SVG.Defs.prototype=new SVG.Container,SVG.G=function(){this.constructor.call(this,SVG.create("g"))},SVG.G.prototype=new SVG.Container,SVG.extend(SVG.G,{x:function(t){return null==t?this.trans.x:this.transform("x",t)},y:function(t){return null==t?this.trans.y:this.transform("y",t)}}),SVG.extend(SVG.Container,{group:function(){return this.put(new SVG.G)}}),SVG.extend(SVG.Element,{siblings:function(){return this.parent.children()},position:function(){var t=this.siblings();return t.indexOf(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position();return this.parent.removeElement(this).put(this,t+1)},backward:function(){var t=this.position();return t>0&&this.parent.removeElement(this).add(this,t-1),this},front:function(){return this.parent.removeElement(this).put(this)},back:function(){return this.position()>0&&this.parent.removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent.add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent.add(t,e+1),this}}),SVG.Mask=function(){this.constructor.call(this,SVG.create("mask")),this.targets=[]},SVG.Mask.prototype=new SVG.Container,SVG.extend(SVG.Mask,{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return delete this.targets,this.parent.removeElement(this),this}}),SVG.extend(SVG.Element,{maskWith:function(t){return this.masker=t instanceof SVG.Mask?t:this.parent.mask().add(t),this.masker.targets.push(this),this.attr("mask",'url("#'+this.masker.attr("id")+'")')},unmask:function(){return delete this.masker,this.attr("mask",null)}}),SVG.extend(SVG.Container,{mask:function(){return this.defs().put(new SVG.Mask)}}),SVG.Clip=function(){this.constructor.call(this,SVG.create("clipPath")),this.targets=[]},SVG.Clip.prototype=new SVG.Container,SVG.extend(SVG.Clip,{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return delete this.targets,this.parent.removeElement(this),this}}),SVG.extend(SVG.Element,{clipWith:function(t){return this.clipper=t instanceof SVG.Clip?t:this.parent.clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),SVG.extend(SVG.Container,{clip:function(){return this.defs().put(new SVG.Clip)}}),SVG.Gradient=function(t){this.constructor.call(this,SVG.create(t+"Gradient")),this.type=t},SVG.Gradient.prototype=new SVG.Container,SVG.extend(SVG.Gradient,{from:function(t,e){return"radial"==this.type?this.attr({fx:new SVG.Number(t),fy:new SVG.Number(e)}):this.attr({x1:new SVG.Number(t),y1:new SVG.Number(e)})},to:function(t,e){return"radial"==this.type?this.attr({cx:new SVG.Number(t),cy:new SVG.Number(e)}):this.attr({x2:new SVG.Number(t),y2:new SVG.Number(e)})},radius:function(t){return"radial"==this.type?this.attr({r:new SVG.Number(t)}):this},at:function(t){return this.put(new SVG.Stop(t))},update:function(t){return this.clear(),t(this),this},fill:function(){return"url(#"+this.attr("id")+")"},toString:function(){return this.fill()}}),SVG.extend(SVG.Defs,{gradient:function(t,e){var i=this.put(new SVG.Gradient(t));return e(i),i}}),SVG.extend(SVG.Container,{gradient:function(t,e){return this.defs().gradient(t,e)}}),SVG.Stop=function(t){this.constructor.call(this,SVG.create("stop")),this.update(t)},SVG.Stop.prototype=new SVG.Element,SVG.extend(SVG.Stop,{update:function(t){return null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new SVG.Number(t.offset)),this}}),SVG.Doc=function(t){this.parent="string"==typeof t?document.getElementById(t):t,this.constructor.call(this,"svg"==this.parent.nodeName?this.parent:SVG.create("svg")),this.attr({xmlns:SVG.ns,version:"1.1",width:"100%",height:"100%"}).attr("xlink",SVG.xlink,SVG.ns),this._defs=new SVG.Defs,this._defs.parent=this,this.node.appendChild(this._defs.node),this.doSubPixelOffsetFix=!1,"svg"!=this.parent.nodeName&&this.stage()},SVG.Doc.prototype=new SVG.Container,SVG.extend(SVG.Doc,{stage:function(){var t,e=this,i=document.createElement("div");return i.style.cssText="position:relative;height:100%;",e.parent.appendChild(i),i.appendChild(e.node),t=function(){"complete"===document.readyState?(e.style("position:absolute;"),setTimeout(function(){e.style("position:relative;overflow:hidden;"),e.parent.removeChild(e.node.parentNode),e.node.parentNode.removeChild(e.node),e.parent.appendChild(e.node),e.subPixelOffsetFix(),SVG.on(window,"resize",function(){e.subPixelOffsetFix()})},5)):setTimeout(t,10)},t(),this},defs:function(){return this._defs},subPixelOffsetFix:function(){if(this.doSubPixelOffsetFix){var t=this.node.getScreenCTM();t&&this.style("left",-t.e%1+"px").style("top",-t.f%1+"px")}return this},fixSubPixelOffset:function(){return this.doSubPixelOffsetFix=!0,this}}),SVG.Shape=function(t){this.constructor.call(this,t)},SVG.Shape.prototype=new SVG.Element,SVG.Use=function(){this.constructor.call(this,SVG.create("use"))},SVG.Use.prototype=new SVG.Shape,SVG.extend(SVG.Use,{element:function(t){return this.target=t,this.attr("href","#"+t,SVG.xlink)}}),SVG.extend(SVG.Container,{use:function(t){return this.put(new SVG.Use).element(t)}}),SVG.Rect=function(){this.constructor.call(this,SVG.create("rect"))},SVG.Rect.prototype=new SVG.Shape,SVG.extend(SVG.Container,{rect:function(t,e){return this.put((new SVG.Rect).size(t,e))}}),SVG.Ellipse=function(){this.constructor.call(this,SVG.create("ellipse"))},SVG.Ellipse.prototype=new SVG.Shape,SVG.extend(SVG.Ellipse,{x:function(t){return null==t?this.cx()-this.attr("rx"):this.cx(t+this.attr("rx"))},y:function(t){return null==t?this.cy()-this.attr("ry"):this.cy(t+this.attr("ry"))},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",new SVG.Number(t).divide(this.trans.scaleX))},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",new SVG.Number(t).divide(this.trans.scaleY))},width:function(t){return null==t?2*this.attr("rx"):this.attr("rx",new SVG.Number(t).divide(2))},height:function(t){return null==t?2*this.attr("ry"):this.attr("ry",new SVG.Number(t).divide(2))},size:function(t,e){return this.attr({rx:new SVG.Number(t).divide(2),ry:new SVG.Number(e).divide(2)})}}),SVG.extend(SVG.Container,{circle:function(t){return this.ellipse(t,t)},ellipse:function(t,e){return this.put(new SVG.Ellipse).size(t,e).move(0,0)}}),SVG.Line=function(){this.constructor.call(this,SVG.create("line"))},SVG.Line.prototype=new SVG.Shape,SVG.extend(SVG.Line,{x:function(t){var e=this.bbox();return null==t?e.x:this.attr({x1:this.attr("x1")-e.x+t,x2:this.attr("x2")-e.x+t})},y:function(t){var e=this.bbox();return null==t?e.y:this.attr({y1:this.attr("y1")-e.y+t,y2:this.attr("y2")-e.y+t})},cx:function(t){var e=this.bbox().width/2;return null==t?this.x()+e:this.x(t-e)},cy:function(t){var e=this.bbox().height/2;return null==t?this.y()+e:this.y(t-e)},width:function(t){var e=this.bbox();return null==t?e.width:this.attr(this.attr("x1")<this.attr("x2")?"x2":"x1",e.x+t)},height:function(t){var e=this.bbox();return null==t?e.height:this.attr(this.attr("y1")<this.attr("y2")?"y2":"y1",e.y+t)},size:function(t,e){return this.width(t).height(e)},plot:function(t,e,i,n){return this.attr({x1:t,y1:e,x2:i,y2:n})}}),SVG.extend(SVG.Container,{line:function(t,e,i,n){return this.put((new SVG.Line).plot(t,e,i,n))}}),SVG.Polyline=function(){this.constructor.call(this,SVG.create("polyline"))},SVG.Polyline.prototype=new SVG.Shape,SVG.Polygon=function(){this.constructor.call(this,SVG.create("polygon"))},SVG.Polygon.prototype=new SVG.Shape,SVG.extend(SVG.Polyline,SVG.Polygon,{morphArray:SVG.PointArray,plot:function(t){return this.attr("points",this.points=new SVG.PointArray(t,[[0,0]]))},move:function(t,e){return this.attr("points",this.points.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)},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)},size:function(t,e){return this.attr("points",this.points.size(t,e))}}),SVG.extend(SVG.Container,{polyline:function(t){return this.put(new SVG.Polyline).plot(t)},polygon:function(t){return this.put(new SVG.Polygon).plot(t)}}),SVG.Path=function(t){this.constructor.call(this,SVG.create("path")),this.unbiased=!!t},SVG.Path.prototype=new SVG.Shape,SVG.extend(SVG.Path,{x:function(t){return null==t?this.bbox().x:this.transform("x",t)},y:function(t){return null==t?this.bbox().y:this.transform("y",t)},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)},size:function(t,e){var i=t/this._offset.width;return this.transform({scaleX:i,scaleY:null!=e?e/this._offset.height:i})},plot:function(t){var e=this.trans.scaleX,i=this.trans.scaleY;return this._plot(t),this._offset=this.transform({scaleX:1,scaleY:1}).bbox(),this.unbiased?this._offset.x=this._offset.y=0:(this._offset.x-=this.trans.x,this._offset.y-=this.trans.y),this.transform({scaleX:e,scaleY:i})},_plot:function(t){return this.attr("d",t||"M0,0")}}),SVG.extend(SVG.Container,{path:function(t,e){return this.put(new SVG.Path(e)).plot(t)}}),SVG.Image=function(){this.constructor.call(this,SVG.create("image"))},SVG.Image.prototype=new SVG.Shape,SVG.extend(SVG.Image,{load:function(t){return t?this.attr("href",this.src=t,SVG.xlink):this}}),SVG.extend(SVG.Container,{image:function(t,e,i){return e=null!=e?e:100,this.put((new SVG.Image).load(t).size(e,null!=i?i:e))}});var t="size family weight stretch variant style".split(" ");SVG.Text=function(){this.constructor.call(this,SVG.create("text")),this.styles={"font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"},this._leading=new SVG.Number("1.2em"),this._rebuild=!0},SVG.Text.prototype=new SVG.Shape,SVG.extend(SVG.Text,{x:function(t,e){return null==t?e?this.attr("x"):this.bbox().x:(e||(e=this.style("text-anchor"),t="start"==e?t:"end"==e?t+this.bbox().width:t+this.bbox().width/2),this.textPath||this.lines.each(function(){this.newLined&&this.x(t)}),this.attr("x",t))},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t,e){return null==t?this.bbox().cy:this.y(e?t:t-this.bbox().height/2)},move:function(t,e,i){return this.x(t,i).y(e)},center:function(t,e,i){return this.cx(t,i).cy(e,i)},text:function(t){if(null==t)return this.content;if(this.clear(),"function"==typeof t)this._rebuild=!1,t(this);else{this._rebuild=!0,t=SVG.regex.isBlank.test(t)?"text":t;var e,i,n=t.split("\n");for(e=0,i=n.length;i>e;e++)this.tspan(n[e]).newLine();this.rebuild()}return this},tspan:function(t){var e=this.textPath?this.textPath.node:this.node,i=(new SVG.TSpan).text(t),n=this.style();return e.appendChild(i.node),this.lines.add(i),SVG.regex.isBlank.test(n)||i.style(n),this.content+=t,i.parent=this,i},size:function(t){return this.attr("font-size",t)},leading:function(t){return null==t?this._leading:(t=new SVG.Number(t),this._leading=t,this.lines.each(function(){this.newLined&&this.attr("dy",t)}),this)},rebuild:function(){return this._rebuild&&this.lines.attr({x:this.attr("x"),dy:this._leading,style:this.style()}),this},clear:function(){for(var t=this.textPath?this.textPath.node:this.node;t.hasChildNodes();)t.removeChild(t.lastChild);return delete this.lines,this.lines=new SVG.Set,this.content="",this}}),SVG.extend(SVG.Container,{text:function(t){return this.put(new SVG.Text).text(t)}}),SVG.TSpan=function(){this.constructor.call(this,SVG.create("tspan"))},SVG.TSpan.prototype=new SVG.Shape,SVG.extend(SVG.TSpan,{text:function(t){return this.node.appendChild(document.createTextNode(t)),this},dx:function(t){return this.attr("dx",t)
-},dy:function(t){return this.attr("dy",t)},newLine:function(){return this.newLined=!0,this.parent.content+="\n",this.dy(this.parent._leading),this.attr("x",this.parent.x())}}),SVG.TextPath=function(){this.constructor.call(this,SVG.create("textPath"))},SVG.TextPath.prototype=new SVG.Element,SVG.extend(SVG.Text,{path:function(t){for(this.textPath=new SVG.TextPath;this.node.hasChildNodes();)this.textPath.node.appendChild(this.node.firstChild);return this.node.appendChild(this.textPath.node),this.track=this.doc().defs().path(t,!0),this.textPath.parent=this,this.textPath.attr("href","#"+this.track,SVG.xlink),this},plot:function(t){return this.track&&this.track.plot(t),this}}),SVG.Nested=function(){this.constructor.call(this,SVG.create("svg")),this.style("overflow","visible")},SVG.Nested.prototype=new SVG.Container,SVG.extend(SVG.Container,{nested:function(){return this.put(new SVG.Nested)}}),SVG.A=function(){this.constructor.call(this,SVG.create("a"))},SVG.A.prototype=new SVG.Container,SVG.extend(SVG.A,{to:function(t){return this.attr("href",t,SVG.xlink)},show:function(t){return this.attr("show",t,SVG.xlink)},target:function(t){return this.attr("target",t)}}),SVG.extend(SVG.Container,{link:function(t){return this.put(new SVG.A).to(t)}}),SVG.extend(SVG.Element,{linkTo:function(t){var e=new SVG.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent.put(e).put(this)}}),SVG._stroke=["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],SVG._fill=["color","opacity","rule"];var e=function(t,e){return"color"==e?t:t+"-"+e};["fill","stroke"].forEach(function(t){var i={};i[t]=function(i){if("string"==typeof i||SVG.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(index=SVG["_"+t].length-1;index>=0;index--)null!=i[SVG["_"+t][index]]&&this.attr(e(t,SVG["_"+t][index]),i[SVG["_"+t][index]]);return this},SVG.extend(SVG.Element,SVG.FX,i)}),SVG.extend(SVG.Element,SVG.FX,{rotate:function(t,e,i){return this.transform({rotation:t||0,cx:e,cy:i})},skew:function(t,e){return this.transform({skewX:t||0,skewY:e||0})},scale:function(t,e){return this.transform({scaleX:t,scaleY:null==e?t:e})},translate:function(t,e){return this.transform({x:t,y:e})},matrix:function(t){return this.transform({matrix:t})},opacity:function(t){return this.attr("opacity",t)}}),SVG.extend(SVG.Rect,SVG.Ellipse,{radius:function(t,e){return this.attr({rx:t,ry:e||t})}}),SVG.Text&&SVG.extend(SVG.Text,SVG.FX,{font:function(e){for(var i in e)"anchor"==i?this.attr("text-anchor",e[i]):t.indexOf(i)>-1?this.attr("font-"+i,e[i]):this.attr(i,e[i]);return this}}),SVG.Set=function(){this.clear()},SVG.SetFX=function(t){this.set=t},SVG.extend(SVG.Set,{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;e>t;t++)this.members.push(i[t]);return this},remove:function(t){var e=this.members.indexOf(t);return e>-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;i>e;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},has:function(t){return this.members.indexOf(t)>=0},get:function(t){return this.members[t]},valueOf:function(){return this.members}}),SVG.Set.inherit=function(){var t,e=[];for(var t in SVG.Shape.prototype)"function"==typeof SVG.Shape.prototype[t]&&"function"!=typeof SVG.Set.prototype[t]&&e.push(t);e.forEach(function(t){SVG.Set.prototype[t]=function(){for(var e=0,i=this.members.length;i>e;e++)this.members[e]&&"function"==typeof this.members[e][t]&&this.members[e][t].apply(this.members[e],arguments);return"animate"==t?this.fx||(this.fx=new SVG.SetFX(this)):this}}),e=[];for(var t in SVG.FX.prototype)"function"==typeof SVG.FX.prototype[t]&&"function"!=typeof SVG.SetFX.prototype[t]&&e.push(t);e.forEach(function(t){SVG.SetFX.prototype[t]=function(){for(var e=0,i=this.set.members.length;i>e;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},SVG.extend(SVG.Container,{set:function(){return new SVG.Set}}),SVG.extend(SVG.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var e in t)this.remember(e,t[e]);else{if(1==arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0==arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),"function"==typeof define&&define.amd?define(function(){return SVG}):"undefined"!=typeof exports&&(exports.SVG=SVG)}).call(this);
\ No newline at end of file
+(function(){if(this.SVG=function(t){return SVG.supported?new SVG.Doc(t):void 0},SVG.ns="http://www.w3.org/2000/svg",SVG.xmlns="http://www.w3.org/2000/xmlns/",SVG.xlink="http://www.w3.org/1999/xlink",SVG.did=1e3,SVG.eid=function(t){return"Svgjs"+t.charAt(0).toUpperCase()+t.slice(1)+SVG.did++},SVG.create=function(t){var e=document.createElementNS(this.ns,t);return e.setAttribute("id",this.eid(t)),e},SVG.extend=function(){var t,e,i,n;for(t=[].slice.call(arguments),e=t.pop(),n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i];SVG.Set&&SVG.Set.inherit&&SVG.Set.inherit()},SVG.get=function(t){var e=document.getElementById(t);return e?e.instance:void 0},SVG.supported=function(){return!!document.createElementNS&&!!document.createElementNS(SVG.ns,"svg").createSVGRect}(),!SVG.supported)return!1;SVG.parser=function(){var t=document.getElementsByTagName("body")[0]||document.getElementsByTagName("svg")[0],e=SVG.create("svg"),i=SVG.create("polygon"),n=SVG.create("path");return e.setAttributeNS(SVG.xmlns,"xmlns:xlink",SVG.xlink),e.setAttribute("style","opacity:0;position:fixed;left:100%;top:100%"),e.setAttribute("width","2"),e.setAttribute("height","2"),t.appendChild(e),e.appendChild(i),e.appendChild(n),{body:t,doc:e,poly:i,path:n}}(),SVG.regex={test:function(t,e){return this[e].test(t)},unit:/^(-?[\d\.]+)([a-z%]{0,2})$/,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isStyle:/^font|text|leading|cursor/,isBlank:/^(\s+)?$/,isNumber:/^-?[\d\.]+$/,isPercent:/^-?[\d\.]+%$/},SVG.defaults={matrix:"1 0 0 1 0 0",attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"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"},trans:function(){return{x:0,y:0,scaleX:1,scaleY:1,rotation:0,skewX:0,skewY:0,matrix:this.matrix,a:1,b:0,c:0,d:1,e:0,f:0}}},SVG.Color=function(t){var e;this.r=0,this.g=0,this.b=0,"string"==typeof t?SVG.regex.isRgb.test(t)?(e=SVG.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):SVG.regex.isHex.test(t)&&(e=SVG.regex.hex.exec(this._fullHex(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b)},SVG.extend(SVG.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+this._compToHex(this.r)+this._compToHex(this.g)+this._compToHex(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return.3*(this.r/255)+.59*(this.g/255)+.11*(this.b/255)},_fullHex:function(t){return 4==t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t},_compToHex:function(t){var e=t.toString(16);return 1==e.length?"0"+e:e}}),SVG.Color.test=function(t){return t+="",SVG.regex.isHex.test(t)||SVG.regex.isRgb.test(t)},SVG.Color.isRgb=function(t){return t&&"number"==typeof t.r},SVG.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},SVG.extend(SVG.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,i=[];e>t;t++)-1==i.indexOf(this.value[t])&&i.push(this.value[t]);return this.value=i},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];i>e;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new SVG.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:this.split(t)},split:function(t){return t.replace(/\s+/g," ").replace(/^\s+|\s+$/g,"").split(" ")}}),SVG.PointArray=function(){this.constructor.apply(this,arguments)},SVG.PointArray.prototype=new SVG.Array,SVG.extend(SVG.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];e>t;t++)i.push(this.value[t].join(","));return i.join(" ")},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];i>e;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new SVG.PointArray(n)},parse:function(t){if(t=t.valueOf(),Array.isArray(t))return t;t=this.split(t);for(var e,i=0,n=t.length,r=[];n>i;i++)e=t[i].split(","),r.push([parseFloat(e[0]),parseFloat(e[1])]);return r},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x,this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.x;return this},bbox:function(){return this._cachedBBox?this._cachedBBox:(SVG.parser.poly.setAttribute("points",this.toString()),SVG.parser.poly.getBBox())}}),SVG.PathArray=function(t,e){this.constructor.call(this,t,e)},SVG.PathArray.prototype=new SVG.Array,SVG.extend(SVG.PathArray,{toString:function(){for(var t,e=0,i=this.value.length,n=[];i>e;e++){switch(t=[this.value[e].type],this.value[e].type){case"H":t.push(this.value[e].x);break;case"V":t.push(this.value[e].y);break;case"M":case"L":case"T":case"S":case"Q":case"C":/[QC]/.test(this.value[e].type)&&t.push(this.value[e].x1,this.value[e].y1),/[CS]/.test(this.value[e].type)&&t.push(this.value[e].x2,this.value[e].y2),t.push(this.value[e].x,this.value[e].y);break;case"A":t.push(this.value[e].rx,this.value[e].ry,this.value[e].angle,this.value[e].largeArcFlag,this.value[e].sweepFlag,this.value[e].x,this.value[e].y)}n.push(t.join(" "))}return n.join(" ")},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--)switch(this.value[n].type){case"H":this.value[n].x+=t;break;case"V":this.value[n].y+=e;break;case"M":case"L":case"T":case"S":case"Q":case"C":this.value[n].x+=t,this.value[n].y+=e,/[CQ]/.test(this.value[n].type)&&(this.value[n].x1+=t,this.value[n].y1+=e),/[CS]/.test(this.value[n].type)&&(this.value[n].x2+=t,this.value[n].y2+=e);break;case"A":this.value[n].x+=t,this.value[n].y+=e}return this},size:function(t,e){for(var i=this.bbox(),n=this.value.length-1;n>=0;n--)switch(this.value[n].type){case"H":this.value[n].x=(this.value[n].x-i.x)*t/i.width+i.x;break;case"V":this.value[n].y=(this.value[n].y-i.y)*e/i.height+i.y;break;case"M":case"L":case"T":case"S":case"Q":case"C":this.value[n].x=(this.value[n].x-i.x)*t/i.width+i.x,this.value[n].y=(this.value[n].y-i.y)*e/i.height+i.y,/[CQ]/.test(this.value[n].type)&&(this.value[n].x1=(this.value[n].x1-i.x)*t/i.width+i.x,this.value[n].y1=(this.value[n].y1-i.y)*e/i.height+i.y),/[CS]/.test(this.value[n].type)&&(this.value[n].x2=(this.value[n].x2-i.x)*t/i.width+i.x,this.value[n].y2=(this.value[n].y2-i.y)*e/i.height+i.y);break;case"A":this.value[n].values.rx=this.value[n].values.rx*t/i.width,this.value[n].values.ry=this.value[n].values.ry*e/i.height,this.value[n].values.x=(this.value[n].values.x-i.x)*t/i.width+i.x,this.value[n].values.y=(this.value[n].values.y-i.y)*e/i.height+i.y}return this},parse:function(t){if(t=t.valueOf(),Array.isArray(t))return t;var e,i,n,r,s,h,o,a,u,l,c,f=0,p=0;for(SVG.parser.path.setAttribute("d",t),c=SVG.parser.path.pathSegList,e=0,i=c.numberOfItems;i>e;++e){if(l=c.getItem(e),u=l.pathSegTypeAsLetter,/[MLHVCSQTA]/.test(u))"x"in l&&(f=l.x),"y"in l&&(p=l.y);else switch("x1"in l&&(s=f+l.x1),"x2"in l&&(o=f+l.x2),"y1"in l&&(h=p+l.y1),"y2"in l&&(a=p+l.y2),"x"in l&&(f+=l.x),"y"in l&&(p+=l.y),u){case"m":c.replaceItem(SVG.parser.path.createSVGPathSegMovetoAbs(f,p),e);break;case"l":c.replaceItem(SVG.parser.path.createSVGPathSegLinetoAbs(f,p),e);break;case"h":c.replaceItem(SVG.parser.path.createSVGPathSegLinetoHorizontalAbs(f),e);break;case"v":c.replaceItem(SVG.parser.path.createSVGPathSegLinetoVerticalAbs(p),e);break;case"c":c.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicAbs(f,p,s,h,o,a),e);break;case"s":c.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicSmoothAbs(f,p,o,a),e);break;case"q":c.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticAbs(f,p,s,h),e);break;case"t":c.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticSmoothAbs(f,p),e);break;case"a":c.replaceItem(SVG.parser.path.createSVGPathSegArcAbs(f,p,l.r1,l.r2,l.angle,l.largeArcFlag,l.sweepFlag),e);break;case"z":case"Z":f=n,p=r}/[Mm]/.test(u)&&(n=f,r=p)}for(t=[],c=SVG.parser.path.pathSegList,e=0,i=c.numberOfItems;i>e;++e){switch(l=c.getItem(e),u={},l.pathSegTypeAsLetter){case"M":case"L":case"T":case"S":case"Q":case"C":/[QC]/.test(l.pathSegTypeAsLetter)&&(u.x1=l.x1,u.y1=l.y1),/[SC]/.test(l.pathSegTypeAsLetter)&&(u.x2=l.x2,u.y2=l.y2);break;case"A":u={r1:l.r1,r2:l.r2,angle:l.angle,largeArcFlag:l.largeArcFlag,sweepFlag:l.sweepFlag}}u.type=l.pathSegTypeAsLetter,u.x=l.x,u.y=l.y,t.push(u)}return t},bbox:function(){return this._cachedBBox?this._cachedBBox:(SVG.parser.path.setAttribute("d",this.toString()),SVG.parser.path.getBBox())}}),SVG.extend(SVG.PointArray,SVG.PathArray,{cache:function(){return this._cachedBBox=this.uncache().bbox(),this},uncache:function(){return delete this._cachedBBox,this}}),SVG.Number=function(t){switch(this.value=0,this.unit="",typeof t){case"number":this.value=isNaN(t)?0:isFinite(t)?t:0>t?-3.4e38:3.4e38;break;case"string":var e=t.match(SVG.regex.unit);e&&(this.value=parseFloat(e[1]),"%"==e[2]&&(this.value/=100),this.unit=e[2]);break;default:t instanceof SVG.Number&&(this.value=t.value,this.unit=t.unit)}},SVG.extend(SVG.Number,{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:this.value)+this.unit},valueOf:function(){return this.value},to:function(t){return"string"==typeof t&&(this.unit=t),this},plus:function(t){return this.value=this+new SVG.Number(t),this},minus:function(t){return this.plus(-new SVG.Number(t))},times:function(t){return this.value=this*new SVG.Number(t),this},divide:function(t){return this.value=this/new SVG.Number(t),this}}),SVG.ViewBox=function(t){var e,i,n,r,s=1,h=1,o=t.bbox(),a=(t.attr("viewBox")||"").match(/-?[\d\.]+/g);for(n=new SVG.Number(t.width()),r=new SVG.Number(t.height());"%"==n.unit;)s*=n.value,n=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetWidth:t.width());for(;"%"==r.unit;)h*=r.value,r=new SVG.Number(t instanceof SVG.Doc?t.parent.offsetHeight:t.height());this.x=o.x,this.y=o.y,this.width=n*s,this.height=r*h,this.zoom=1,a&&(e=parseFloat(a[0]),i=parseFloat(a[1]),n=parseFloat(a[2]),r=parseFloat(a[3]),this.zoom=this.width/this.height>n/r?this.height/r:this.width/n,this.x=e,this.y=i,this.width=n,this.height=r)},SVG.extend(SVG.ViewBox,{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height}}),SVG.BBox=function(t){var e;if(this.x=0,this.y=0,this.width=0,this.height=0,t){try{e=t.node.getBBox()}catch(i){e={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=e.x+t.trans.x,this.y=e.y+t.trans.y,this.width=e.width*t.trans.scaleX,this.height=e.height*t.trans.scaleY}this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.extend(SVG.BBox,{merge:function(t){var e=new SVG.BBox;return e.x=Math.min(this.x,t.x),e.y=Math.min(this.y,t.y),e.width=Math.max(this.x+this.width,t.x+t.width)-e.x,e.height=Math.max(this.y+this.height,t.y+t.height)-e.y,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2,e}}),SVG.RBox=function(t){var e,i,n={};if(this.x=0,this.y=0,this.width=0,this.height=0,t){for(e=t.doc().parent,i=t.doc().viewbox().zoom,n=t.node.getBoundingClientRect(),this.x=n.left,this.y=n.top,this.x-=e.offsetLeft,this.y-=e.offsetTop;e=e.offsetParent;)this.x-=e.offsetLeft,this.y-=e.offsetTop;for(e=t;e=e.parent;)"svg"==e.type&&e.viewbox&&(i*=e.viewbox().zoom,this.x-=e.x()||0,this.y-=e.y()||0)}this.x/=i,this.y/=i,this.width=n.width/=i,this.height=n.height/=i,this.cx=this.x+this.width/2,this.cy=this.y+this.height/2},SVG.extend(SVG.RBox,{merge:function(t){var e=new SVG.RBox;return e.x=Math.min(this.x,t.x),e.y=Math.min(this.y,t.y),e.width=Math.max(this.x+this.width,t.x+t.width)-e.x,e.height=Math.max(this.y+this.height,t.y+t.height)-e.y,e.cx=e.x+e.width/2,e.cy=e.y+e.height/2,e}}),SVG.Element=function(t){this._stroke=SVG.defaults.attrs.stroke,this.styles={},this.trans=SVG.defaults.trans(),(this.node=t)&&(this.type=t.nodeName,this.node.instance=this)},SVG.extend(SVG.Element,{x:function(t){return t&&(t=new SVG.Number(t),t.value/=this.trans.scaleX),this.attr("x",t)},y:function(t){return t&&(t=new SVG.Number(t),t.value/=this.trans.scaleY),this.attr("y",t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=this._proportionalSize(t,e);return this.attr({width:new SVG.Number(i.width),height:new SVG.Number(i.height)})},clone:function(){var t,e,i=this.type;return t="rect"==i||"ellipse"==i?this.parent[i](0,0):"line"==i?this.parent[i](0,0,0,0):"image"==i?this.parent[i](this.src):"text"==i?this.parent[i](this.content):"path"==i?this.parent[i](this.attr("d")):"polyline"==i||"polygon"==i?this.parent[i](this.attr("points")):"g"==i?this.parent.group():this.parent[i](),e=this.attr(),delete e.id,t.attr(e),t.trans=this.trans,t.transform({})},remove:function(){return this.parent&&this.parent.removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},doc:function(t){return this._parent(t||SVG.Doc)},attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=SVG.regex.test(e[i].nodeValue,"isNumber")?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return this._isStyle(t)?"text"==t?this.content:"leading"==t&&this.leading?this.leading():this.style(t):(e=this.node.getAttribute(t),null==e?SVG.defaults.attrs[t]:SVG.regex.test(e,"isNumber")?parseFloat(e):e);if("style"==t)return this.style(e);if("x"==t&&Array.isArray(this.lines))for(i=this.lines.length-1;i>=0;i--)this.lines[i].attr(t,e);"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),SVG.Color.test(e)||SVG.Color.isRgb(e)?e=new SVG.Color(e):"number"==typeof e?e=new SVG.Number(e):Array.isArray(e)&&(e=new SVG.Array(e)),null!=i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),this._isStyle(t)&&("text"==t?this.text(e):"leading"==t&&this.leading?this.leading(e):this.style(t,e),this.rebuild&&this.rebuild(t,e))}return this},transform:function(t,e){if(0==arguments.length)return this.trans;if("string"==typeof t){if(2>arguments.length)return this.trans[t];var i={};return i[t]=e,this.transform(i)}var i=[];t=this._parseMatrix(t);for(e in t)null!=t[e]&&(this.trans[e]=t[e]);return this.trans.matrix=this.trans.a+" "+this.trans.b+" "+this.trans.c+" "+this.trans.d+" "+this.trans.e+" "+this.trans.f,t=this.trans,t.matrix!=SVG.defaults.matrix&&i.push("matrix("+t.matrix+")"),0!=t.rotation&&i.push("rotate("+t.rotation+" "+(null==t.cx?this.bbox().cx:t.cx)+" "+(null==t.cy?this.bbox().cy:t.cy)+")"),(1!=t.scaleX||1!=t.scaleY)&&i.push("scale("+t.scaleX+" "+t.scaleY+")"),0!=t.skewX&&i.push("skewX("+t.skewX+")"),0!=t.skewY&&i.push("skewY("+t.skewY+")"),(0!=t.x||0!=t.y)&&i.push("translate("+new SVG.Number(t.x/t.scaleX)+" "+new SVG.Number(t.y/t.scaleY)+")"),0==i.length?this.node.removeAttribute("transform"):this.node.setAttribute("transform",i.join(" ")),this},style:function(t,e){if(0==arguments.length)return this.attr("style")||"";if(2>arguments.length)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!SVG.regex.isCss.test(t))return this.styles[t];t=t.split(";");for(var i=0;t.length>i;i++)e=t[i].split(":"),2==e.length&&this.style(e[0].replace(/\s+/g,""),e[1].replace(/^\s+/,"").replace(/\s+$/,""))}else null===e||SVG.regex.test(e,"isBlank")?delete this.styles[t]:this.styles[t]=e;t="";for(e in this.styles)t+=e+":"+this.styles[e]+";";return""==t?this.node.removeAttribute("style"):this.node.setAttribute("style",t),this},bbox:function(){return new SVG.BBox(this)},rbox:function(){return new SVG.RBox(this)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&i.x+i.width>t&&i.y+i.height>e},show:function(){return this.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},_parent:function(t){for(var e=this;null!=e&&!(e instanceof t);)e=e.parent;return e},_isStyle:function(t){return"string"==typeof t?SVG.regex.test(t,"isStyle"):!1},_parseMatrix:function(t){if(t.matrix){var e=t.matrix.replace(/\s/g,"").split(",");6==e.length&&(t.a=parseFloat(e[0]),t.b=parseFloat(e[1]),t.c=parseFloat(e[2]),t.d=parseFloat(e[3]),t.e=parseFloat(e[4]),t.f=parseFloat(e[5]))}return t},_proportionalSize:function(t,e){if(null==t||null==e){var i=this.bbox();null==e?e=i.height/i.width*t:null==t&&(t=i.width/i.height*e)}return{width:t,height:e}}}),SVG.Parent=function(t){this.constructor.call(this,t)},SVG.Parent.prototype=new SVG.Element,SVG.extend(SVG.Parent,{children:function(){return this._children||(this._children=[])},add:function(t,e){if(!this.has(t)){if(e=null==e?this.children().length:e,t.parent){var i=t.parent.children().indexOf(t);t.parent.children().splice(i,1)}this.children().splice(e,0,t),this.node.insertBefore(t.node,this.node.childNodes[e]||null),t.parent=this}return this._defs&&(this.node.removeChild(this._defs.node),this.node.appendChild(this._defs.node)),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.children().indexOf(t)>=0},get:function(t){return this.children()[t]},first:function(){return this.children()[0]},last:function(){return this.children()[this.children().length-1]},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;n>i;i++)r[i]instanceof SVG.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof SVG.Container&&r[i].each(t,e);return this},removeElement:function(t){var e=this.children().indexOf(t);return this.children().splice(e,1),this.node.removeChild(t.node),t.parent=null,this},clear:function(){for(var t=this.children().length-1;t>=0;t--)this.removeElement(this.children()[t]);return this._defs&&this._defs.clear(),this},defs:function(){return this.doc().defs()}}),SVG.Container=function(t){this.constructor.call(this,t)},SVG.Container.prototype=new SVG.Parent,SVG.extend(SVG.Container,{viewbox:function(t){return 0==arguments.length?new SVG.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t))}}),SVG.FX=function(t){this.target=t},SVG.extend(SVG.FX,{animate:function(t,e,i){var n,r,s,h,o=this.target,a=this;return"object"==typeof t&&(i=t.delay,e=t.ease,t=t.duration),t=null==t?1e3:t,e=e||"<>",a.to=function(t){var i;if(t=0>t?0:t>1?1:t,null==n){n=[];for(h in a.attrs)n.push(h);if(o.morphArray&&n.indexOf("points")>-1){var u,l=new o.morphArray(a._plot||o.array);a._size&&l.size(a._size.width.to,a._size.height.to),u=l.bbox(),a._x?l.move(a._x.to,u.y):a._cx&&l.move(a._cx.to-u.width/2,u.y),u=l.bbox(),a._y?l.move(u.x,a._y.to):a._cy&&l.move(u.x,a._cy.to-u.height/2),delete a._x,delete a._y,delete a._cx,delete a._cy,delete a._size,a._plot=o.array.morph(l)}}if(null==r){r=[];for(h in a.trans)r.push(h)}if(null==s){s=[];for(h in a.styles)s.push(h)}for(t="<>"==e?-Math.cos(t*Math.PI)/2+.5:">"==e?Math.sin(t*Math.PI/2):"<"==e?-Math.cos(t*Math.PI/2)+1:"-"==e?t:"function"==typeof e?e(t):t,a._plot?o.plot(a._plot.at(t)):(o.array&&o.array.cache(),a._x?o.x(a._at(a._x,t)):a._cx&&o.cx(a._at(a._cx,t)),a._y?o.y(a._at(a._y,t)):a._cy&&o.cy(a._at(a._cy,t)),a._size&&o.size(a._at(a._size.width,t),a._at(a._size.height,t)),o.array&&o.array.uncache()),a._viewbox&&o.viewbox(a._at(a._viewbox.x,t),a._at(a._viewbox.y,t),a._at(a._viewbox.width,t),a._at(a._viewbox.height,t)),i=n.length-1;i>=0;i--)o.attr(n[i],a._at(a.attrs[n[i]],t));for(i=r.length-1;i>=0;i--)o.transform(r[i],a._at(a.trans[r[i]],t));for(i=s.length-1;i>=0;i--)o.style(s[i],a._at(a.styles[s[i]],t));a._during&&a._during.call(o,t,function(e,i){return a._at({from:e,to:i},t)})},"number"==typeof t&&(this.timeout=setTimeout(function(){var n=(new Date).getTime();a.situation={interval:1e3/60,start:n,play:!0,finish:n+t,duration:t},a.render=function(){if(a.situation.play===!0){var n=(new Date).getTime(),r=n>a.situation.finish?1:(n-a.situation.start)/t;a.to(r),n>a.situation.finish?(a._plot&&o.plot(new SVG.PointArray(a._plot.destination).settle()),a._loop===!0||"number"==typeof a._loop&&a._loop>1?("number"==typeof a._loop&&--a._loop,a.animate(t,e,i)):a._after?a._after.apply(o,[a]):a.stop()):requestAnimFrame(a.render)}else requestAnimFrame(a.render)},a.render()},i||0)),this},bbox:function(){return this.target.bbox()},attr:function(t,e){if("object"==typeof t)for(var i in t)this.attr(i,t[i]);else this.attrs[t]={from:this.target.attr(t),to:e};return this},transform:function(t,e){if(1==arguments.length){t=this.target._parseMatrix(t),delete t.matrix;for(e in t)this.trans[e]={from:this.target.trans[e],to:t[e]}}else{var i={};i[t]=e,this.transform(i)}return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.styles[t]={from:this.target.style(t),to:e};return this},x:function(t){return this._x={from:this.target.x(),to:t},this},y:function(t){return this._y={from:this.target.y(),to:t},this},cx:function(t){return this._cx={from:this.target.cx(),to:t},this},cy:function(t){return this._cy={from:this.target.cy(),to:t},this},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target instanceof SVG.Text)this.attr("font-size",t);else{var i=this.target.bbox();this._size={width:{from:i.width,to:t},height:{from:i.height,to:e}}}return this},plot:function(t){return this._plot=t,this},viewbox:function(t,e,i,n){if(this.target instanceof SVG.Container){var r=this.target.viewbox();this._viewbox={x:{from:r.x,to:t},y:{from:r.y,to:e},width:{from:r.width,to:i},height:{from:r.height,to:n}}}return this},update:function(t){return this.target instanceof SVG.Stop&&(null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new SVG.Number(t.offset))),this},during:function(t){return this._during=t,this},after:function(t){return this._after=t,this},loop:function(t){return this._loop=t||!0,this},stop:function(){return clearTimeout(this.timeout),clearInterval(this.interval),this.attrs={},this.trans={},this.styles={},this.situation={},delete this._x,delete this._y,delete this._cx,delete this._cy,delete this._size,delete this._plot,delete this._loop,delete this._after,delete this._during,delete this._viewbox,this},pause:function(){return this.situation.play===!0&&(this.situation.play=!1,this.situation.pause=(new Date).getTime()),this},play:function(){if(this.situation.play===!1){var t=(new Date).getTime()-this.situation.pause;this.situation.finish+=t,this.situation.start+=t,this.situation.play=!0}return this},_at:function(t,e){return"number"==typeof t.from?t.from+(t.to-t.from)*e:SVG.regex.unit.test(t.to)?new SVG.Number(t.to).minus(new SVG.Number(t.from)).times(e).plus(new SVG.Number(t.from)):t.to&&(t.to.r||SVG.Color.test(t.to))?this._color(t,e):1>e?t.from:t.to},_color:function(t,e){var i,n;return e=0>e?0:e>1?1:e,i=new SVG.Color(t.from),n=new SVG.Color(t.to),new SVG.Color({r:~~(i.r+(n.r-i.r)*e),g:~~(i.g+(n.g-i.g)*e),b:~~(i.b+(n.b-i.b)*e)}).toHex()}}),SVG.extend(SVG.Element,{animate:function(t,e,i){return(this.fx||(this.fx=new SVG.FX(this))).stop().animate(t,e,i)},stop:function(){return this.fx&&this.fx.stop(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this}}),window.requestAnimFrame=function(){return window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||function(t){window.setTimeout(t,1e3/60)}}(),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","mouseenter","mouseleave"].forEach(function(t){SVG.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),SVG.on=function(t,e,i){t.addEventListener?t.addEventListener(e,i,!1):t.attachEvent("on"+e,i)},SVG.off=function(t,e,i){t.removeEventListener?t.removeEventListener(e,i,!1):t.detachEvent("on"+e,i)},SVG.extend(SVG.Element,{on:function(t,e){return SVG.on(this.node,t,e),this},off:function(t,e){return SVG.off(this.node,t,e),this}}),SVG.Defs=function(){this.constructor.call(this,SVG.create("defs"))},SVG.Defs.prototype=new SVG.Container,SVG.G=function(){this.constructor.call(this,SVG.create("g"))},SVG.G.prototype=new SVG.Container,SVG.extend(SVG.G,{x:function(t){return null==t?this.trans.x:this.transform("x",t)},y:function(t){return null==t?this.trans.y:this.transform("y",t)}}),SVG.extend(SVG.Container,{group:function(){return this.put(new SVG.G)}}),SVG.extend(SVG.Element,{siblings:function(){return this.parent.children()},position:function(){var t=this.siblings();return t.indexOf(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position();return this.parent.removeElement(this).put(this,t+1)},backward:function(){var t=this.position();return t>0&&this.parent.removeElement(this).add(this,t-1),this},front:function(){return this.parent.removeElement(this).put(this)},back:function(){return this.position()>0&&this.parent.removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent.add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent.add(t,e+1),this}}),SVG.Mask=function(){this.constructor.call(this,SVG.create("mask")),this.targets=[]},SVG.Mask.prototype=new SVG.Container,SVG.extend(SVG.Mask,{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return delete this.targets,this.parent.removeElement(this),this}}),SVG.extend(SVG.Element,{maskWith:function(t){return this.masker=t instanceof SVG.Mask?t:this.parent.mask().add(t),this.masker.targets.push(this),this.attr("mask",'url("#'+this.masker.attr("id")+'")')},unmask:function(){return delete this.masker,this.attr("mask",null)}}),SVG.extend(SVG.Container,{mask:function(){return this.defs().put(new SVG.Mask)}}),SVG.Clip=function(){this.constructor.call(this,SVG.create("clipPath")),this.targets=[]},SVG.Clip.prototype=new SVG.Container,SVG.extend(SVG.Clip,{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return delete this.targets,this.parent.removeElement(this),this}}),SVG.extend(SVG.Element,{clipWith:function(t){return this.clipper=t instanceof SVG.Clip?t:this.parent.clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),SVG.extend(SVG.Container,{clip:function(){return this.defs().put(new SVG.Clip)}}),SVG.Gradient=function(t){this.constructor.call(this,SVG.create(t+"Gradient")),this.type=t},SVG.Gradient.prototype=new SVG.Container,SVG.extend(SVG.Gradient,{from:function(t,e){return"radial"==this.type?this.attr({fx:new SVG.Number(t),fy:new SVG.Number(e)}):this.attr({x1:new SVG.Number(t),y1:new SVG.Number(e)})},to:function(t,e){return"radial"==this.type?this.attr({cx:new SVG.Number(t),cy:new SVG.Number(e)}):this.attr({x2:new SVG.Number(t),y2:new SVG.Number(e)})},radius:function(t){return"radial"==this.type?this.attr({r:new SVG.Number(t)}):this},at:function(t){return this.put(new SVG.Stop(t))},update:function(t){return this.clear(),t(this),this},fill:function(){return"url(#"+this.attr("id")+")"},toString:function(){return this.fill()}}),SVG.extend(SVG.Defs,{gradient:function(t,e){var i=this.put(new SVG.Gradient(t));return e(i),i}}),SVG.extend(SVG.Container,{gradient:function(t,e){return this.defs().gradient(t,e)}}),SVG.Stop=function(t){this.constructor.call(this,SVG.create("stop")),this.update(t)},SVG.Stop.prototype=new SVG.Element,SVG.extend(SVG.Stop,{update:function(t){return null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new SVG.Number(t.offset)),this}}),SVG.Doc=function(t){this.parent="string"==typeof t?document.getElementById(t):t,this.constructor.call(this,"svg"==this.parent.nodeName?this.parent:SVG.create("svg")),this.attr({xmlns:SVG.ns,version:"1.1",width:"100%",height:"100%"}).attr("xmlns:xlink",SVG.xlink,SVG.xmlns),this._defs=new SVG.Defs,this._defs.parent=this,this.node.appendChild(this._defs.node),this.doSubPixelOffsetFix=!1,"svg"!=this.parent.nodeName&&this.stage()},SVG.Doc.prototype=new SVG.Container,SVG.extend(SVG.Doc,{stage:function(){var t,e=this,i=document.createElement("div");return i.style.cssText="position:relative;height:100%;",e.parent.appendChild(i),i.appendChild(e.node),t=function(){"complete"===document.readyState?(e.style("position:absolute;"),setTimeout(function(){e.style("position:relative;overflow:hidden;"),e.parent.removeChild(e.node.parentNode),e.node.parentNode.removeChild(e.node),e.parent.appendChild(e.node),e.subPixelOffsetFix(),SVG.on(window,"resize",function(){e.subPixelOffsetFix()})},5)):setTimeout(t,10)},t(),this},defs:function(){return this._defs},subPixelOffsetFix:function(){if(this.doSubPixelOffsetFix){var t=this.node.getScreenCTM();t&&this.style("left",-t.e%1+"px").style("top",-t.f%1+"px")}return this},fixSubPixelOffset:function(){return this.doSubPixelOffsetFix=!0,this}}),SVG.Shape=function(t){this.constructor.call(this,t)},SVG.Shape.prototype=new SVG.Element,SVG.Use=function(){this.constructor.call(this,SVG.create("use"))},SVG.Use.prototype=new SVG.Shape,SVG.extend(SVG.Use,{element:function(t){return this.target=t,this.attr("href","#"+t,SVG.xlink)}}),SVG.extend(SVG.Container,{use:function(t){return this.put(new SVG.Use).element(t)}}),SVG.Rect=function(){this.constructor.call(this,SVG.create("rect"))},SVG.Rect.prototype=new SVG.Shape,SVG.extend(SVG.Container,{rect:function(t,e){return this.put((new SVG.Rect).size(t,e))}}),SVG.Ellipse=function(){this.constructor.call(this,SVG.create("ellipse"))},SVG.Ellipse.prototype=new SVG.Shape,SVG.extend(SVG.Ellipse,{x:function(t){return null==t?this.cx()-this.attr("rx"):this.cx(t+this.attr("rx"))},y:function(t){return null==t?this.cy()-this.attr("ry"):this.cy(t+this.attr("ry"))},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",new SVG.Number(t).divide(this.trans.scaleX))},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",new SVG.Number(t).divide(this.trans.scaleY))},width:function(t){return null==t?2*this.attr("rx"):this.attr("rx",new SVG.Number(t).divide(2))},height:function(t){return null==t?2*this.attr("ry"):this.attr("ry",new SVG.Number(t).divide(2))},size:function(t,e){var i=this._proportionalSize(t,e);return this.attr({rx:new SVG.Number(i.width).divide(2),ry:new SVG.Number(i.height).divide(2)})}}),SVG.extend(SVG.Container,{circle:function(t){return this.ellipse(t,t)},ellipse:function(t,e){return this.put(new SVG.Ellipse).size(t,e).move(0,0)}}),SVG.Line=function(){this.constructor.call(this,SVG.create("line"))},SVG.Line.prototype=new SVG.Shape,SVG.extend(SVG.Line,{x:function(t){var e=this.bbox();return null==t?e.x:this.attr({x1:this.attr("x1")-e.x+t,x2:this.attr("x2")-e.x+t})},y:function(t){var e=this.bbox();return null==t?e.y:this.attr({y1:this.attr("y1")-e.y+t,y2:this.attr("y2")-e.y+t})},cx:function(t){var e=this.bbox().width/2;return null==t?this.x()+e:this.x(t-e)},cy:function(t){var e=this.bbox().height/2;return null==t?this.y()+e:this.y(t-e)},width:function(t){var e=this.bbox();return null==t?e.width:this.attr(this.attr("x1")<this.attr("x2")?"x2":"x1",e.x+t)},height:function(t){var e=this.bbox();return null==t?e.height:this.attr(this.attr("y1")<this.attr("y2")?"y2":"y1",e.y+t)},size:function(t,e){var i=this._proportionalSize(t,e);return this.width(i.width).height(i.height)},plot:function(t,e,i,n){return this.attr({x1:t,y1:e,x2:i,y2:n})}}),SVG.extend(SVG.Container,{line:function(t,e,i,n){return this.put((new SVG.Line).plot(t,e,i,n))
+}}),SVG.Polyline=function(){this.constructor.call(this,SVG.create("polyline"))},SVG.Polyline.prototype=new SVG.Shape,SVG.Polygon=function(){this.constructor.call(this,SVG.create("polygon"))},SVG.Polygon.prototype=new SVG.Shape,SVG.extend(SVG.Polyline,SVG.Polygon,{morphArray:SVG.PointArray,plot:function(t){return this.attr("points",this.array=new SVG.PointArray(t,[[0,0]]))},move:function(t,e){return this.attr("points",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)},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)},size:function(t,e){var i=this._proportionalSize(t,e);return this.attr("points",this.array.size(i.width,i.height))}}),SVG.extend(SVG.Container,{polyline:function(t){return this.put(new SVG.Polyline).plot(t)},polygon:function(t){return this.put(new SVG.Polygon).plot(t)}}),SVG.Path=function(){this.constructor.call(this,SVG.create("path"))},SVG.Path.prototype=new SVG.Shape,SVG.extend(SVG.Path,{plot:function(t){return this.attr("d",this.array=new SVG.PathArray(t,[{type:"M",x:0,y:0}]))},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=this._proportionalSize(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)}}),SVG.extend(SVG.Container,{path:function(t){return this.put(new SVG.Path).plot(t)}}),SVG.Image=function(){this.constructor.call(this,SVG.create("image"))},SVG.Image.prototype=new SVG.Shape,SVG.extend(SVG.Image,{load:function(t){return t?this.attr("href",this.src=t,SVG.xlink):this}}),SVG.extend(SVG.Container,{image:function(t,e,i){return e=null!=e?e:100,this.put((new SVG.Image).load(t).size(e,null!=i?i:e))}});var t="size family weight stretch variant style".split(" ");SVG.Text=function(){this.constructor.call(this,SVG.create("text")),this.styles={"font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"},this._leading=new SVG.Number("1.2em"),this._rebuild=!0},SVG.Text.prototype=new SVG.Shape,SVG.extend(SVG.Text,{x:function(t,e){return null==t?e?this.attr("x"):this.bbox().x:(e||(e=this.style("text-anchor"),t="start"==e?t:"end"==e?t+this.bbox().width:t+this.bbox().width/2),this.textPath||this.lines.each(function(){this.newLined&&this.x(t)}),this.attr("x",t))},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t,e){return null==t?this.bbox().cy:this.y(e?t:t-this.bbox().height/2)},move:function(t,e,i){return this.x(t,i).y(e)},center:function(t,e,i){return this.cx(t,i).cy(e,i)},text:function(t){if(null==t)return this.content;if(this.clear(),"function"==typeof t)this._rebuild=!1,t(this);else{this._rebuild=!0,t=SVG.regex.isBlank.test(t)?"text":t;var e,i,n=t.split("\n");for(e=0,i=n.length;i>e;e++)this.tspan(n[e]).newLine();this.rebuild()}return this},tspan:function(t){var e=this.textPath?this.textPath.node:this.node,i=(new SVG.TSpan).text(t),n=this.style();return e.appendChild(i.node),this.lines.add(i),SVG.regex.isBlank.test(n)||i.style(n),this.content+=t,i.parent=this,i},size:function(t){return this.attr("font-size",t)},leading:function(t){return null==t?this._leading:(t=new SVG.Number(t),this._leading=t,this.lines.each(function(){this.newLined&&this.attr("dy",t)}),this)},rebuild:function(){return this._rebuild&&this.lines.attr({x:this.attr("x"),dy:this._leading,style:this.style()}),this},clear:function(){for(var t=this.textPath?this.textPath.node:this.node;t.hasChildNodes();)t.removeChild(t.lastChild);return delete this.lines,this.lines=new SVG.Set,this.content="",this}}),SVG.extend(SVG.Container,{text:function(t){return this.put(new SVG.Text).text(t)}}),SVG.TSpan=function(){this.constructor.call(this,SVG.create("tspan"))},SVG.TSpan.prototype=new SVG.Shape,SVG.extend(SVG.TSpan,{text:function(t){return this.node.appendChild(document.createTextNode(t)),this},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){return this.newLined=!0,this.parent.content+="\n",this.dy(this.parent._leading),this.attr("x",this.parent.x())}}),SVG.TextPath=function(){this.constructor.call(this,SVG.create("textPath"))},SVG.TextPath.prototype=new SVG.Element,SVG.extend(SVG.Text,{path:function(t){for(this.textPath=new SVG.TextPath;this.node.hasChildNodes();)this.textPath.node.appendChild(this.node.firstChild);return this.node.appendChild(this.textPath.node),this.track=this.doc().defs().path(t,!0),this.textPath.parent=this,this.textPath.attr("href","#"+this.track,SVG.xlink),this},plot:function(t){return this.track&&this.track.plot(t),this}}),SVG.Nested=function(){this.constructor.call(this,SVG.create("svg")),this.style("overflow","visible")},SVG.Nested.prototype=new SVG.Container,SVG.extend(SVG.Container,{nested:function(){return this.put(new SVG.Nested)}}),SVG.A=function(){this.constructor.call(this,SVG.create("a"))},SVG.A.prototype=new SVG.Container,SVG.extend(SVG.A,{to:function(t){return this.attr("href",t,SVG.xlink)},show:function(t){return this.attr("show",t,SVG.xlink)},target:function(t){return this.attr("target",t)}}),SVG.extend(SVG.Container,{link:function(t){return this.put(new SVG.A).to(t)}}),SVG.extend(SVG.Element,{linkTo:function(t){var e=new SVG.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent.put(e).put(this)}}),SVG._stroke=["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],SVG._fill=["color","opacity","rule"];var e=function(t,e){return"color"==e?t:t+"-"+e};["fill","stroke"].forEach(function(t){var i={};i[t]=function(i){if("string"==typeof i||SVG.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(index=SVG["_"+t].length-1;index>=0;index--)null!=i[SVG["_"+t][index]]&&this.attr(e(t,SVG["_"+t][index]),i[SVG["_"+t][index]]);return this},SVG.extend(SVG.Element,SVG.FX,i)}),SVG.extend(SVG.Element,SVG.FX,{rotate:function(t,e,i){return this.transform({rotation:t||0,cx:e,cy:i})},skew:function(t,e){return this.transform({skewX:t||0,skewY:e||0})},scale:function(t,e){return this.transform({scaleX:t,scaleY:null==e?t:e})},translate:function(t,e){return this.transform({x:t,y:e})},matrix:function(t){return this.transform({matrix:t})},opacity:function(t){return this.attr("opacity",t)}}),SVG.extend(SVG.Rect,SVG.Ellipse,{radius:function(t,e){return this.attr({rx:t,ry:e||t})}}),SVG.Text&&SVG.extend(SVG.Text,SVG.FX,{font:function(e){for(var i in e)"anchor"==i?this.attr("text-anchor",e[i]):t.indexOf(i)>-1?this.attr("font-"+i,e[i]):this.attr(i,e[i]);return this}}),SVG.Set=function(){this.clear()},SVG.SetFX=function(t){this.set=t},SVG.extend(SVG.Set,{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;e>t;t++)this.members.push(i[t]);return this},remove:function(t){var e=this.members.indexOf(t);return e>-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;i>e;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},has:function(t){return this.members.indexOf(t)>=0},get:function(t){return this.members[t]},valueOf:function(){return this.members}}),SVG.Set.inherit=function(){var t,e=[];for(var t in SVG.Shape.prototype)"function"==typeof SVG.Shape.prototype[t]&&"function"!=typeof SVG.Set.prototype[t]&&e.push(t);e.forEach(function(t){SVG.Set.prototype[t]=function(){for(var e=0,i=this.members.length;i>e;e++)this.members[e]&&"function"==typeof this.members[e][t]&&this.members[e][t].apply(this.members[e],arguments);return"animate"==t?this.fx||(this.fx=new SVG.SetFX(this)):this}}),e=[];for(var t in SVG.FX.prototype)"function"==typeof SVG.FX.prototype[t]&&"function"!=typeof SVG.SetFX.prototype[t]&&e.push(t);e.forEach(function(t){SVG.SetFX.prototype[t]=function(){for(var e=0,i=this.set.members.length;i>e;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},SVG.extend(SVG.Container,{set:function(){return new SVG.Set}}),SVG.extend(SVG.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(2>arguments.length)try{return JSON.parse(this.attr("data-"+t))}catch(n){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),SVG.extend(SVG.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var e in t)this.remember(e,t[e]);else{if(1==arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0==arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),"function"==typeof define&&define.amd?define(function(){return SVG}):"undefined"!=typeof exports&&(exports.SVG=SVG)}).call(this);
\ No newline at end of file
index b5e4d991e15dc14a7f4327f81f2958c91cd3063f..f7e01ec4b42a748f607011f4451c722e5cdbf13f 100644 (file)
@@ -8,10 +8,11 @@
   <link rel="stylesheet" type="text/css" href="lib/jasmine-1.3.1/jasmine.css">
   
   <style type="text/css" media="screen">
-    #canvas {
-      width: 1px;
-      height: 1px;
-      overflow: hidden;
+    #drawing {
+      width: 500px;
+      height: 500px;
+      position: absolute;
+      z-index: -10;
     }
   </style>
 
@@ -27,7 +28,6 @@
 <script src="../dist/svg.js" type="text/javascript" charset="utf-8"></script>
 
 <!-- include spec files here... -->
-<script type="text/javascript" src="spec/helper.js"></script>
 <script type="text/javascript" src="spec/svg.js"></script>
 <script type="text/javascript" src="spec/container.js"></script>
 <script type="text/javascript" src="spec/element.js"></script>
@@ -84,4 +84,6 @@
   })();
 </script>
 
+<script type="text/javascript" src="spec/helper.js"></script>
+
 </html>
index f1edb01400bf947c26c75c13bbd927e54700bf56..22b09bf8a61ec10464c02017b784514fe619e0e0 100644 (file)
@@ -158,23 +158,34 @@ describe('Element', function() {
   })
   
   describe('data()', function() {
-    it('should set a data attribute and convert value to json', function() {
+    it('sets a data attribute and convert value to json', function() {
       var rect = draw.rect(100,100).data('test', 'value')
       expect(rect.node.getAttribute('data-test')).toBe('value')
     })
-    it('should set a data attribute and not convert value to json if flagged raw', function() {
+    it('sets a data attribute and not convert value to json if flagged raw', function() {
       var rect = draw.rect(100,100).data('test', 'value', true)
       expect(rect.node.getAttribute('data-test')).toBe('value')
     })
-    it('should get data value in ony one argument is passed', function() {
+    it('sets multiple data attributes and convert values to json when an object is passed', function() {
+      var rect = draw.rect(100,100).data({
+        forbidden: 'fruit'
+      , multiple: {
+          values: 'in'
+        , an: 'object'
+        }
+      })
+      expect(rect.node.getAttribute('data-forbidden')).toBe('fruit')
+      expect(rect.node.getAttribute('data-multiple')).toEqual('{"values":"in","an":"object"}')
+    })
+    it('gets data value if only one argument is passed', function() {
       var rect = draw.rect(100,100).data('test', 101)
       expect(rect.data('test')).toBe(101)
     })
-    it('should maintain data type for a number', function() {
+    it('maintains data type for a number', function() {
       var rect = draw.rect(100,100).data('test', 101)
       expect(typeof rect.data('test')).toBe('number')
     })
-    it('should maintain data type for an object', function() {
+    it('maintains data type for an object', function() {
       var rect = draw.rect(100,100).data('test', { string: 'value', array: [1,2,3] })
       expect(typeof rect.data('test')).toBe('object')
       expect(Array.isArray(rect.data('test').array)).toBe(true) 
index 27d18408c1ce4476939330694a687bbf1eb95e48..7d7101a3c93fedd6f092889a2f1da0fac9cd645b 100644 (file)
@@ -110,6 +110,18 @@ describe('Ellipse', function() {
       expect(ellipse.node.getAttribute('rx')).toBe((987 / 2).toString())
       expect(ellipse.node.getAttribute('ry')).toBe((654 / 2).toString())
     })
+    it('defines the width and height proportionally with only the width value given', function() {
+      var box = ellipse.bbox()
+      ellipse.size(500)
+      expect(ellipse.width()).toBe(500)
+      expect(ellipse.width() / ellipse.height()).toBe(box.width / box.height)
+    })
+    it('defines the width and height proportionally with only the height value given', function() {
+      var box = ellipse.bbox()
+      ellipse.size(null, 525)
+      expect(ellipse.height()).toBe(525)
+      expect(ellipse.width() / ellipse.height()).toBe(box.width / box.height)
+    })
   })
   
   describe('scale()', function() {
index e13e113b770ff9858e6f736202adfc5b4c60a401..7072164a05dc52f4110cc389fd4f8ac5b615f8eb 100644 (file)
@@ -1,9 +1,18 @@
 describe('Gradient', function() {
-  var rect = draw.rect(100,100)
-    , gradient = draw.gradient('linear', function(stop) {
+  var rect, gradient
+
+  beforeEach(function() {
+    rect = draw.rect(100,100)
+    gradient = draw.gradient('linear', function(stop) {
       stop.at({ offset: 0, color: '#333', opacity: 1 })
       stop.at({ offset: 1, color: '#fff', opacity: 1 })
     })
+  })
+
+  afterEach(function() {
+    rect.remove()
+    gradient.remove()
+  })
   
   it('is an instance of SVG.Gradient', function() {
     expect(gradient instanceof SVG.Gradient).toBe(true)
index 7394754604232910a578bd92c20fa7fb35d33e8f..552ca6cbfc1338524e98c40438a7e01ae0b311b5 100644 (file)
@@ -1,8 +1,8 @@
 /* create canavs */
-var canvas = document.createElement('div')
-canvas.id = 'canvas'
-document.getElementsByTagName('body')[0].appendChild(canvas)
-draw = SVG(canvas).size(100,100)
+var drawing = document.createElement('div')
+drawing.id = 'drawing'
+document.getElementsByTagName('body')[0].appendChild(drawing)
+draw = SVG(drawing).size(100,100)
 
 /* raw path data */
 svgPath = 'M88.006,61.994c3.203,0,6.216-1.248,8.481-3.514C98.752,56.215,100,53.203,100,50c0-3.204-1.248-6.216-3.513-8.481 c-2.266-2.265-5.278-3.513-8.481-3.513c-2.687,0-5.237,0.877-7.327,2.496h-7.746l5.479-5.479 c5.891-0.757,10.457-5.803,10.457-11.896c0-6.614-5.381-11.995-11.994-11.995c-6.093,0-11.14,4.567-11.896,10.457l-5.479,5.479 v-7.747c1.618-2.089,2.495-4.641,2.495-7.327c0-3.204-1.247-6.216-3.513-8.481C56.216,1.248,53.204,0,50,0 c-3.204,0-6.216,1.248-8.481,3.513c-2.265,2.265-3.513,5.277-3.513,8.481c0,2.686,0.877,5.237,2.495,7.327v7.747l-5.479-5.479 c-0.757-5.89-5.803-10.457-11.896-10.457c-6.614,0-11.995,5.381-11.995,11.995c0,6.093,4.567,11.139,10.458,11.896l5.479,5.479 h-7.747c-2.089-1.619-4.641-2.496-7.327-2.496c-3.204,0-6.216,1.248-8.481,3.513C1.248,43.784,0,46.796,0,50 c0,3.203,1.248,6.216,3.513,8.48c2.265,2.266,5.277,3.514,8.481,3.514c2.686,0,5.237-0.877,7.327-2.496h7.747l-5.479,5.479 c-5.891,0.757-10.458,5.804-10.458,11.896c0,6.614,5.381,11.994,11.995,11.994c6.093,0,11.139-4.566,11.896-10.457l5.479-5.479 v7.749c-3.63,4.7-3.291,11.497,1.018,15.806C43.784,98.752,46.796,100,50,100c3.204,0,6.216-1.248,8.481-3.514 c4.309-4.309,4.647-11.105,1.018-15.806v-7.749l5.479,5.479c0.757,5.891,5.804,10.457,11.896,10.457 c6.613,0,11.994-5.38,11.994-11.994c0-6.093-4.566-11.14-10.457-11.896l-5.479-5.479h7.746 C82.769,61.117,85.319,61.994,88.006,61.994z M76.874,68.354c4.705,0,8.52,3.814,8.52,8.521c0,4.705-3.814,8.52-8.52,8.52 s-8.52-3.814-8.52-8.52l-12.33-12.33V81.98c3.327,3.328,3.327,8.723,0,12.049c-3.327,3.328-8.722,3.328-12.049,0 c-3.327-3.326-3.327-8.721,0-12.049V64.544l-12.33,12.33c0,4.705-3.814,8.52-8.52,8.52s-8.52-3.814-8.52-8.52 c0-4.706,3.814-8.521,8.52-8.521l12.33-12.33H18.019c-3.327,3.328-8.722,3.328-12.049,0c-3.327-3.326-3.327-8.721,0-12.048 s8.722-3.327,12.049,0h17.438l-12.33-12.33c-4.706,0-8.52-3.814-8.52-8.52c0-4.706,3.814-8.52,8.52-8.52s8.52,3.814,8.52,8.52 l12.33,12.33V18.019c-3.327-3.327-3.327-8.722,0-12.049s8.722-3.327,12.049,0s3.327,8.722,0,12.049v17.438l12.33-12.33 c0-4.706,3.814-8.52,8.52-8.52s8.52,3.814,8.52,8.52c0,4.705-3.814,8.52-8.52,8.52l-12.33,12.33h17.438 c3.327-3.327,8.722-3.327,12.049,0s3.327,8.722,0,12.048c-3.327,3.328-8.722,3.328-12.049,0H64.544L76.874,68.354z'
index 798ea086978c30be7e44664242eb0eb8772631f4..b24835be397cb514bbac1c6d8aad7b252635c527 100644 (file)
@@ -96,6 +96,18 @@ describe('Image', function() {
       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() {
index 1ed45fbfc8e5db7ecde80af7bb513d9e84926282..cb9d6f69954675e12e4d7017dd69de75e01c63da 100644 (file)
@@ -112,6 +112,18 @@ describe('Line', function() {
       expect(box.x + box.width).toBe(987)
       expect(box.y).toBe(0)
     })
+    it('defines the width and height proportionally with only the width value given', function() {
+      var box = line.bbox()
+      line.size(500)
+      expect(line.width()).toBe(500)
+      expect(line.width() / line.height()).toBe(box.width / box.height)
+    })
+    it('defines the width and height proportionally with only the height value given', function() {
+      var box = line.bbox()
+      line.size(null, 525)
+      expect(line.height()).toBe(525)
+      expect(line.width() / line.height()).toBe(box.width / box.height)
+    })
   })
   
   describe('scale()', function() {
index a64f8aa7032bfdca618bd1ea5db019ac46f9345e..9503e3bed3fbc18378d1c4f6d9daa028a4fbd4a9 100644 (file)
@@ -102,12 +102,24 @@ describe('Path', function() {
   })
   
   describe('size()', function() {
-    it('should define the width and height of the element', function() {
+    it('defines the width and height of the element', function() {
       path.size(987,654)
       var box = path.bbox()
       expect(approximately(box.width, 0.1)).toBe(987)
       expect(approximately(box.height, 0.1)).toBe(654)
     })
+    it('defines the width and height proportionally with only the width value given', function() {
+      var box = path.bbox()
+      path.size(500)
+      expect(path.width()).toBe(500)
+      expect(path.width() / path.height()).toBe(box.width / box.height)
+    })
+    it('defines the width and height proportionally with only the height value given', function() {
+      var box = path.bbox()
+      path.size(null, 525)
+      expect(path.height()).toBe(525)
+      expect(path.width() / path.height()).toBe(box.width / box.height)
+    })
   })
   
   describe('scale()', function() {
@@ -137,7 +149,7 @@ describe('Path', function() {
   describe('plot()', function() {
     it('falls back to a single point without an argument', function() {
       path = draw.path()
-      expect(path.node.getAttribute('d')).toBe('M0,0')
+      expect(path.node.getAttribute('d')).toBe('M 0 0')
     })
   })
   
index a12479602ca93419d8aa67306853c832359f59d2..e94facd14325b459939f4aceaf4d4c686daed02a 100644 (file)
@@ -102,6 +102,18 @@ describe('Polygon', function() {
       expect(approximately(box.width, 0.1)).toBe(987)
       expect(approximately(box.height, 0.1)).toBe(654)
     })
+    it('defines the width and height proportionally with only the width value given', function() {
+      var box = polygon.bbox()
+      polygon.size(500)
+      expect(polygon.width()).toBe(500)
+      expect(polygon.width() / polygon.height()).toBe(box.width / box.height)
+    })
+    it('defines the width and height proportionally with only the height value given', function() {
+      var box = polygon.bbox()
+      polygon.size(null, 525)
+      expect(polygon.height()).toBe(525)
+      expect(polygon.width() / polygon.height()).toBe(box.width / box.height)
+    })
   })
   
   describe('scale()', function() {
index 9272d78d9c581c21a5ac27a3a0eea179aa521558..204cfa77083ede19ecefa7c2ba21e7a9af381410 100644 (file)
@@ -102,6 +102,18 @@ describe('Polyline', function() {
       expect(approximately(box.width, 0.1)).toBe(987)
       expect(approximately(box.height, 0.1)).toBe(654)
     })
+    it('defines the width and height proportionally with only the width value given', function() {
+      var box = polyline.bbox()
+      polyline.size(500)
+      expect(polyline.width()).toBe(500)
+      expect(polyline.width() / polyline.height()).toBe(box.width / box.height)
+    })
+    it('defines the width and height proportionally with only the height value given', function() {
+      var box = polyline.bbox()
+      polyline.size(null, 525)
+      expect(polyline.height()).toBe(525)
+      expect(polyline.width() / polyline.height()).toBe(box.width / box.height)
+    })
   })
   
   describe('scale()', function() {
index 4b9ef2f67841889d8238c5bb45a484a9f612c779..36d4925472f45273d3398eb016867b989e556768 100644 (file)
@@ -109,6 +109,18 @@ describe('Rect', function() {
       expect(rect.node.getAttribute('width')).toBe('987')
       expect(rect.node.getAttribute('height')).toBe('654')
     })
+    it('defines the width and height proportionally with only the width value given', function() {
+      var box = rect.bbox()
+      rect.size(500)
+      expect(rect.width()).toBe(500)
+      expect(rect.width() / rect.height()).toBe(box.width / box.height)
+    })
+    it('defines the width and height proportionally with only the height value given', function() {
+      var box = rect.bbox()
+      rect.size(null, 525)
+      expect(rect.height()).toBe(525)
+      expect(rect.width() / rect.height()).toBe(box.width / box.height)
+    })
   })
   
   describe('scale()', function() {
index 671c8e852cc997615f4e37364f79af799a40d495..b239c78c173e41312ed587dd57e5b91675603126 100755 (executable)
@@ -30,10 +30,8 @@ SVG.extend(SVG.Array, {
   }
   // Clean up any duplicate points
 , settle: function() {
-    var i, seen = []
-
     /* find all unique values */
-    for (i = this.value.length - 1; i >= 0; i--)
+    for (var i = 0, il = this.value.length, seen = []; i < il; i++)
       if (seen.indexOf(this.value[i]) == -1)
         seen.push(this.value[i])
 
diff --git a/src/arraycache.js b/src/arraycache.js
new file mode 100644 (file)
index 0000000..41fdbcd
--- /dev/null
@@ -0,0 +1,14 @@
+SVG.extend(SVG.PointArray, SVG.PathArray, {
+       // Cache bbox
+  cache: function() {
+               this._cachedBBox = this.uncache().bbox()
+
+               return this
+  }
+  // Remove cache
+, uncache: function() {
+               delete this._cachedBBox
+               return this
+       }
+
+})
\ No newline at end of file
diff --git a/src/data.js b/src/data.js
new file mode 100644 (file)
index 0000000..1adbd52
--- /dev/null
@@ -0,0 +1,29 @@
+//
+SVG.extend(SVG.Element, {
+       // Store data values on svg nodes
+  data: function(a, v, r) {
+       if (typeof a == 'object') {
+               for (v in a)
+                       this.data(v, a[v])
+
+    } else if (arguments.length < 2) {
+      try {
+        return JSON.parse(this.attr('data-' + a))
+      } catch(e) {
+        return this.attr('data-' + a)
+      }
+      
+    } else {
+      this.attr(
+        'data-' + a
+      , v === null ?
+          null :
+        r === true || typeof v === 'string' || typeof v === 'number' ?
+          v :
+          JSON.stringify(v)
+      )
+    }
+    
+    return this
+  }
+})
\ No newline at end of file
index 462fd84392d1aa940a030dd28dc2a9fd909fd372..7e9eef3cb0197a2fd4b005edeb670117c1b30b0c 100755 (executable)
@@ -15,7 +15,7 @@ SVG.Doc = function(element) {
   /* set svg element attributes */
   this
     .attr({ xmlns: SVG.ns, version: '1.1', width: '100%', height: '100%' })
-    .attr('xlink', SVG.xlink, SVG.ns)
+    .attr('xmlns:xlink', SVG.xlink, SVG.xmlns)
   
   /* create the <defs> node */
   this._defs = new SVG.Defs
index ad0fc4a6fd3bc650f51c133382f069ac9d5a23e0..50edc85f999d2440d43e55a69e8cf98cced62f15 100755 (executable)
@@ -63,9 +63,11 @@ SVG.extend(SVG.Element, {
   }
   // Set element size to given width and height
 , size: function(width, height) {
+    var p = this._proportionalSize(width, height)
+
     return this.attr({
-      width:  new SVG.Number(width)
-    , height: new SVG.Number(height)
+      width:  new SVG.Number(p.width)
+    , height: new SVG.Number(p.height)
     })
   }
   // Clone element
@@ -277,10 +279,6 @@ SVG.extend(SVG.Element, {
     if (o.x != 0 || o.y != 0)
       transform.push('translate(' + new SVG.Number(o.x / o.scaleX) + ' ' + new SVG.Number(o.y / o.scaleY) + ')')
     
-    /* add offset translation */
-     if (this._offset && this._offset.x != 0 && this._offset.y != 0)
-       transform.push('translate(' + (-this._offset.x) + ' ' + (-this._offset.y) + ')')
-    
     /* update transformations, even if there are none */
     if (transform.length == 0)
       this.node.removeAttribute('transform')
@@ -338,28 +336,6 @@ SVG.extend(SVG.Element, {
     
     return this
   }
-  // Store data values on svg nodes
-, data: function(a, v, r) {
-    if (arguments.length < 2) {
-      try {
-        return JSON.parse(this.attr('data-' + a))
-      } catch(e) {
-        return this.attr('data-' + a)
-      }
-      
-    } else {
-      this.attr(
-        'data-' + a
-      , v === null ?
-          null :
-        r === true || typeof v === 'string' || typeof v === 'number' ?
-          v :
-          JSON.stringify(v)
-      )
-    }
-    
-    return this
-  }
   // Get bounding box
 , bbox: function() {
     return new SVG.BBox(this)
@@ -425,5 +401,21 @@ SVG.extend(SVG.Element, {
     
     return o
   }
+  // Private: calculate proportional width and height values when necessary
+, _proportionalSize: function(width, height) {
+    if (width == null || height == null) {
+      var box = this.bbox()
+
+      if (height == null)
+        height = box.height / box.width * width
+      else if (width == null)
+        width = box.width / box.height * height
+    }
+    
+    return {
+      width:  width
+    , height: height
+    }
+  }
   
 })
\ No newline at end of file
index 86186c99f85f8fcb43db65008939d049b1884b56..237a5cae5bbd86a4b788ddc2ba1d02ad219a037a 100755 (executable)
@@ -34,9 +34,11 @@ SVG.extend(SVG.Ellipse, {
   }
   // Custom size function
 , size: function(width, height) {
+    var p = this._proportionalSize(width, height)
+
     return this.attr({
-      rx: new SVG.Number(width).divide(2)
-    , ry: new SVG.Number(height).divide(2)
+      rx: new SVG.Number(p.width).divide(2)
+    , ry: new SVG.Number(p.height).divide(2)
     })
   }
   
index acaeea55fda1bf1ebe8b825cd77d27603c1ecd87..779d038b6df76dbb774442ea63afa59e82b3bc2c 100755 (executable)
--- a/src/fx.js
+++ b/src/fx.js
@@ -36,10 +36,10 @@ SVG.extend(SVG.FX, {
           akeys.push(key)
 
         /* make sure morphable elements are scaled, translated and morphed all together */
-        if (element.morphArray) {
+        if (element.morphArray && akeys.indexOf('points') > -1) {
           /* get destination */
           var box
-            , p = new element.morphArray(fx._plot || element.points.toString())
+            , p = new element.morphArray(fx._plot || element.array)
 
           /* add size */
           if (fx._size) p.size(fx._size.width.to, fx._size.height.to)
@@ -60,7 +60,7 @@ SVG.extend(SVG.FX, {
           delete fx._cy
           delete fx._size
 
-          fx._plot = element.points.morph(p)
+          fx._plot = element.array.morph(p)
         }
       }
 
@@ -90,26 +90,34 @@ SVG.extend(SVG.FX, {
       typeof ease == 'function' ?
         ease(pos) :
         pos
+      
+      /* run plot function */
+      if (fx._plot) {
+        element.plot(fx._plot.at(pos))
 
-      /* run all x-position properties */
-      if (fx._x)
-        element.x(fx._at(fx._x, pos))
-      else if (fx._cx)
-        element.cx(fx._at(fx._cx, pos))
+      } else {
+        if (element.array)
+          element.array.cache()
 
-      /* run all y-position properties */
-      if (fx._y)
-        element.y(fx._at(fx._y, pos))
-      else if (fx._cy)
-        element.cy(fx._at(fx._cy, pos))
+        /* run all x-position properties */
+        if (fx._x)
+          element.x(fx._at(fx._x, pos))
+        else if (fx._cx)
+          element.cx(fx._at(fx._cx, pos))
 
-      /* run all size properties */
-      if (fx._size)
-        element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos))
+        /* run all y-position properties */
+        if (fx._y)
+          element.y(fx._at(fx._y, pos))
+        else if (fx._cy)
+          element.cy(fx._at(fx._cy, pos))
 
-      /* run plot function */
-      if (fx._plot)
-        element.plot(fx._plot.at(pos))
+        /* run all size properties */
+        if (fx._size)
+          element.size(fx._at(fx._size.width, pos), fx._at(fx._size.height, pos))
+
+        if (element.array)
+          element.array.uncache()
+      }
 
       /* run all viewbox properties */
       if (fx._viewbox)
index a5a9b09dcf9e2340fc0ec3abb07eb66e736ffa3f..e049ccbd119f4887901aab14b94d1fb103dc38f4 100755 (executable)
@@ -49,7 +49,9 @@ SVG.extend(SVG.Line, {
   }
   // Set line size by width and height
 , size: function(width, height) {
-    return this.width(width).height(height)
+    var p = this._proportionalSize(width, height)
+
+    return this.width(p.width).height(p.height)
   }
   // Set path data
 , plot: function(x1, y1, x2, y2) {
index e9f4735669bedb9da8b537723fac2fc6672b5422..60e6c73979c19cfca0082aafe26f247ed5948e4c 100755 (executable)
@@ -1,75 +1,49 @@
-SVG.Path = function(unbiased) {
+SVG.Path = function() {
   this.constructor.call(this, SVG.create('path'))
-  
-  this.unbiased = !!unbiased
 }
 
 // Inherit from SVG.Shape
 SVG.Path.prototype = new SVG.Shape
 
 SVG.extend(SVG.Path, {
-  // Move over x-axis
-  x: function(x) {
-    return x == null ? this.bbox().x : this.transform('x', x)
+  // Plot new poly points
+  plot: function(p) {
+    return this.attr('d', (this.array = new SVG.PathArray(p, [{ type:'M',x:0,y:0 }])))
   }
-  // Move over y-axis
-, y: function(y) {
-    return y == null ? this.bbox().y : this.transform('y', y)
+  // Move by left top corner
+, move: function(x, y) {
+    return this.attr('d', this.array.move(x, y))
   }
-  // Set width of element
-, width: function(width) {
-    var b = this.bbox()
-
-    return width == null ? b.width : this.size(width, b.height)
+  // Move by left top corner over x-axis
+, x: function(x) {
+    return x == null ? this.bbox().x : this.move(x, this.bbox().y)
   }
-  // Set height of element
-, height: function(height) {
-    var b = this.bbox()
-
-    return height == null ? b.height : this.size(b.width, height)
+  // Move by left top corner over y-axis
+, y: function(y) {
+    return y == null ? this.bbox().y : this.move(this.bbox().x, y)
   }
-  // Set the actual size in pixels
+  // Set element size to given width and height
 , size: function(width, height) {
-    var scale = width / this._offset.width
+    var p = this._proportionalSize(width, height)
     
-    return this.transform({
-      scaleX: scale
-    , scaleY: height != null ? height / this._offset.height : scale
-    })
+    return this.attr('d', this.array.size(p.width, p.height))
   }
-  // Set path data
-, plot: function(data) {
-    var x = this.trans.scaleX
-      , y = this.trans.scaleY
-    
-    /* native plot */
-    this._plot(data)
-    
-    /* store offset */
-    this._offset = this.transform({ scaleX: 1, scaleY: 1 }).bbox()
-    
-    /* get and store the actual offset of the element */
-    if (this.unbiased) {
-      this._offset.x = this._offset.y = 0
-    } else {
-      this._offset.x -= this.trans.x
-      this._offset.y -= this.trans.y
-    }
-    
-    return this.transform({ scaleX: x, scaleY: y })
+  // Set width of element
+, width: function(width) {
+    return width == null ? this.bbox().width : this.size(width, this.bbox().height)
   }
-  // Private: Native plot
-, _plot: function(data) {
-    return this.attr('d', data || 'M0,0')
+  // Set height of element
+, height: function(height) {
+    return height == null ? this.bbox().height : this.size(this.bbox().width, height)
   }
-  
+
 })
 
 //
 SVG.extend(SVG.Container, {
   // Create a wrapped path element
-  path: function(data, unbiased) {
-    return this.put(new SVG.Path(unbiased)).plot(data)
+  path: function(d) {
+    return this.put(new SVG.Path).plot(d)
   }
 
 })
\ No newline at end of file
diff --git a/src/patharray.js b/src/patharray.js
new file mode 100644 (file)
index 0000000..68252c8
--- /dev/null
@@ -0,0 +1,296 @@
+// Path points array
+SVG.PathArray = function(array, fallback) {
+  this.constructor.call(this, array, fallback)
+}
+
+// Inherit from SVG.Array
+SVG.PathArray.prototype = new SVG.Array
+
+SVG.extend(SVG.PathArray, {
+  // Convert array to string
+  toString: function() {
+    for (var s, i = 0, il = this.value.length, array = []; i < il; i++) {
+      s = [this.value[i].type]
+      
+      switch(this.value[i].type) {
+        case 'H':
+          s.push(this.value[i].x)
+        break
+        case 'V':
+          s.push(this.value[i].y)
+        break
+        case 'M':
+        case 'L':
+        case 'T':
+        case 'S':
+        case 'Q':
+        case 'C':
+          if (/[QC]/.test(this.value[i].type))
+            s.push(this.value[i].x1, this.value[i].y1)
+          if (/[CS]/.test(this.value[i].type))
+            s.push(this.value[i].x2, this.value[i].y2)
+
+          s.push(this.value[i].x, this.value[i].y)
+
+        break
+        case 'A':
+          s.push(
+            this.value[i].rx
+          , this.value[i].ry
+          , this.value[i].angle
+          , this.value[i].largeArcFlag
+          , this.value[i].sweepFlag
+          , this.value[i].x
+          , this.value[i].y
+          )
+        break
+      }
+
+      /* add to array */
+      array.push(s.join(' '))
+    }
+    
+    return array.join(' ')
+  }
+  // Move path string
+, move: function(x, y) {
+               /* get bounding box of current situation */
+               var box = this.bbox()
+               
+    /* get relative offset */
+    x -= box.x
+    y -= box.y
+
+    if (!isNaN(x) && !isNaN(y)) {
+      /* move every point */
+      for (var i = this.value.length - 1; i >= 0; i--) {
+        switch (this.value[i].type) {
+          case 'H':
+            /* move along x axis only */
+            this.value[i].x += x
+          break
+          case 'V':
+            /* move along y axis only */
+            this.value[i].y += y
+          break
+          case 'M':
+          case 'L':
+          case 'T':
+          case 'S':
+          case 'Q':
+          case 'C':
+            /* move first point along x and y axes */
+            this.value[i].x += x
+            this.value[i].y += y
+
+            /* move third points along x and y axes */
+            if (/[CQ]/.test(this.value[i].type)) {
+              this.value[i].x1 += x
+              this.value[i].y1 += y
+            }
+
+            /* move second points along x and y axes */
+            if (/[CS]/.test(this.value[i].type)) {
+              this.value[i].x2 += x
+              this.value[i].y2 += y
+            }
+
+          break
+          case 'A':
+            /* only move position values */
+            this.value[i].x += x
+            this.value[i].y += y
+          break
+        }
+      }
+    }
+
+    return this
+  }
+  // Resize path string
+, size: function(width, height) {
+               /* get bounding box of current situation */
+               var box = this.bbox()
+
+    /* recalculate position of all points according to new size */
+    for (var i = this.value.length - 1; i >= 0; i--) {
+      switch (this.value[i].type) {
+        case 'H':
+          /* move along x axis only */
+          this.value[i].x = ((this.value[i].x - box.x) * width)  / box.width  + box.x
+        break
+        case 'V':
+          /* move along y axis only */
+          this.value[i].y = ((this.value[i].y - box.y) * height) / box.height + box.y
+        break
+        case 'M':
+        case 'L':
+        case 'T':
+        case 'S':
+        case 'Q':
+        case 'C':
+          this.value[i].x = ((this.value[i].x - box.x) * width)  / box.width  + box.x
+          this.value[i].y = ((this.value[i].y - box.y) * height) / box.height + box.y
+
+          /* move third points along x and y axes */
+          if (/[CQ]/.test(this.value[i].type)) {
+            this.value[i].x1 = ((this.value[i].x1 - box.x) * width)  / box.width  + box.x
+            this.value[i].y1 = ((this.value[i].y1 - box.y) * height) / box.height + box.y
+          }
+
+          /* move second points along x and y axes */
+          if (/[CS]/.test(this.value[i].type)) {
+            this.value[i].x2 = ((this.value[i].x2 - box.x) * width)  / box.width  + box.x
+            this.value[i].y2 = ((this.value[i].y2 - box.y) * height) / box.height + box.y
+          }
+
+        break
+        case 'A':
+          /* resize radii */
+          this.value[i].values.rx = (this.value[i].values.rx * width)  / box.width
+          this.value[i].values.ry = (this.value[i].values.ry * height) / box.height
+
+          /* move position values */
+          this.value[i].values.x = ((this.value[i].values.x - box.x) * width)  / box.width  + box.x
+          this.value[i].values.y = ((this.value[i].values.y - box.y) * height) / box.height + box.y
+        break
+      }
+    }
+
+    return this
+  }
+  // Absolutize and parse path to array
+, parse: function(array) {
+    array = array.valueOf()
+
+    /* if already is an array, no need to parse it */
+    if (Array.isArray(array)) return array
+
+    /* prepare for parsing */
+    var i, il, x0, y0, x1, y1, x2, y2, s, seg, segs
+      , x = 0
+      , y = 0
+    
+    /* populate working path */
+    SVG.parser.path.setAttribute('d', array)
+    
+    /* get segments */
+    segs = SVG.parser.path.pathSegList
+
+    for (i = 0, il = segs.numberOfItems; i < il; ++i) {
+      seg = segs.getItem(i)
+      s = seg.pathSegTypeAsLetter
+
+      if (/[MLHVCSQTA]/.test(s)) {
+        if ('x' in seg) x = seg.x
+        if ('y' in seg) y = seg.y
+
+      } else {
+        if ('x1' in seg) x1 = x + seg.x1
+        if ('x2' in seg) x2 = x + seg.x2
+        if ('y1' in seg) y1 = y + seg.y1
+        if ('y2' in seg) y2 = y + seg.y2
+        if ('x'  in seg) x += seg.x
+        if ('y'  in seg) y += seg.y
+
+        switch(s){
+          case 'm': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegMovetoAbs(x, y), i)
+          break
+          case 'l': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoAbs(x, y), i)
+          break
+          case 'h': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoHorizontalAbs(x), i)
+          break
+          case 'v': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegLinetoVerticalAbs(y), i)
+          break
+          case 'c': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2), i)
+          break
+          case 's': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2), i)
+          break
+          case 'q': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1), i)
+          break
+          case 't': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegCurvetoQuadraticSmoothAbs(x, y), i)
+          break
+          case 'a': 
+            segs.replaceItem(SVG.parser.path.createSVGPathSegArcAbs(x, y, seg.r1, seg.r2, seg.angle, seg.largeArcFlag, seg.sweepFlag), i) 
+          break
+          case 'z':
+          case 'Z':
+            x = x0
+            y = y0
+          break
+        }
+      }
+
+      /* record the start of a subpath */
+      if (/[Mm]/.test(s)) {
+        x0 = x
+        y0 = y
+      }
+    }
+
+    /* build internal representation */
+    array = []
+    segs = SVG.parser.path.pathSegList
+    
+    for (i = 0, il = segs.numberOfItems; i < il; ++i) {
+      seg = segs.getItem(i)
+      s = {}
+
+      switch (seg.pathSegTypeAsLetter) {
+        case 'M':
+        case 'L':
+        case 'T':
+        case 'S':
+        case 'Q':
+        case 'C':
+          if (/[QC]/.test(seg.pathSegTypeAsLetter)) {
+            s.x1 = seg.x1
+            s.y1 = seg.y1
+          }
+
+          if (/[SC]/.test(seg.pathSegTypeAsLetter)) {
+            s.x2 = seg.x2
+            s.y2 = seg.y2
+          }
+
+        break
+        case 'A':
+          s = {
+            r1:           seg.r1
+          , r2:           seg.r2
+          , angle:        seg.angle
+          , largeArcFlag: seg.largeArcFlag
+          , sweepFlag:    seg.sweepFlag
+          }
+        break
+      }
+
+      /* make the letter, x and y values accessible as key/values */
+      s.type = seg.pathSegTypeAsLetter
+      s.x = seg.x
+      s.y = seg.y
+
+      /* store segment */
+      array.push(s)
+    }
+    
+    return array
+  }
+  // Get bounding box of path
+, bbox: function() {
+               if (this._cachedBBox) return this._cachedBBox
+
+    SVG.parser.path.setAttribute('d', this.toString())
+
+    return SVG.parser.path.getBBox()
+  }
+
+})
\ No newline at end of file
index 8df49ae3141b6a572e3dcdaaf3e4869dc8d1ead7..28dbf3ee2a8993eb00e7ebf2b7cf1e5e15fe17e4 100644 (file)
@@ -76,31 +76,11 @@ SVG.extend(SVG.PointArray, {
   }
   // Get bounding box of points
 , bbox: function() {
-    if (this.value.length == 0)
-      return { x: 0, y: 0, width: 0, height: 0 }
-
-    var i
-    , x = this.value[0][0]
-    , y = this.value[0][1]
-    , box = { x: x, y: y }
-    
-    /* find position */
-    for (i = this.value.length - 1; i >= 0; i--) {
-      if (this.value[i][0] < box.x)
-        box.x = this.value[i][0]
-      if (this.value[i][1] < box.y)
-        box.y = this.value[i][1]
-      if (this.value[i][0] > x)
-        x = this.value[i][0]
-      if (this.value[i][1] > y)
-        y = this.value[i][1]
-    }
+    if (this._cachedBBox) return this._cachedBBox
 
-    /* calculate size */
-    box.width  = x - box.x
-    box.height = y - box.y
+    SVG.parser.poly.setAttribute('points', this.toString())
 
-    return box
+    return SVG.parser.poly.getBBox()
   }
 
 })
\ No newline at end of file
index 93a40fdc871fc2ec94cfda40b48fe659849d8580..247ab8f1af232ca4839368a21d65b7e52fa25d1e 100755 (executable)
@@ -18,11 +18,11 @@ SVG.extend(SVG.Polyline, SVG.Polygon, {
   morphArray:  SVG.PointArray
   // Plot new path
 , plot: function(p) {
-    return this.attr('points', (this.points = new SVG.PointArray(p, [[0,0]])))
+    return this.attr('points', (this.array = new SVG.PointArray(p, [[0,0]])))
   }
   // Move by left top corner
 , move: function(x, y) {
-    return this.attr('points', this.points.move(x, y))
+    return this.attr('points', this.array.move(x, y))
   }
   // Move by left top corner over x-axis
 , x: function(x) {
@@ -46,7 +46,9 @@ SVG.extend(SVG.Polyline, SVG.Polygon, {
   }
   // Set element size to given width and height
 , size: function(width, height) {
-    return this.attr('points', this.points.size(width, height))
+    var p = this._proportionalSize(width, height)
+
+    return this.attr('points', this.array.size(p.width, p.height))
   }
 
 })
index 89c23e4c330d7dafa676c21fa9c12d7d6bf5c898..abd3bc3d90ea102d7ddda09b13d9f1541b7591f3 100755 (executable)
@@ -13,7 +13,8 @@ this.SVG = function(element) {
 }
 
 // Default namespaces
-SVG.ns = 'http://www.w3.org/2000/svg'
+SVG.ns    = 'http://www.w3.org/2000/svg'
+SVG.xmlns = 'http://www.w3.org/2000/xmlns/'
 SVG.xlink = 'http://www.w3.org/1999/xlink'
 
 // Element id sequence
@@ -67,4 +68,33 @@ SVG.supported = (function() {
          !! document.createElementNS(SVG.ns,'svg').createSVGRect
 })()
 
-if (!SVG.supported) return false
\ No newline at end of file
+if (!SVG.supported) return false
+
+// Initialize parsing element
+SVG.parser = (function() {
+  /* select document body and create svg element*/
+  var body = document.getElementsByTagName('body')[0] || document.getElementsByTagName('svg')[0]
+    , svg  = SVG.create('svg')
+    , poly = SVG.create('polygon')
+    , path = SVG.create('path')
+
+  /* make svg element presently invisible to ensure geometry  */
+  svg.setAttributeNS(SVG.xmlns, 'xmlns:xlink', SVG.xlink)
+  svg.setAttribute('style', 'opacity:0;position:fixed;left:100%;top:100%')
+  svg.setAttribute('width', '2')
+  svg.setAttribute('height', '2')
+
+  /* build node structure */
+  body.appendChild(svg)
+  svg.appendChild(poly)
+  svg.appendChild(path)
+
+  /* return parser object */
+  return {
+    body: body
+  , doc:  svg
+  , poly: poly
+  , path: path
+  }
+
+})()
\ No newline at end of file