]> source.dussan.org Git - svg.js.git/commitdiff
Implement the morph method of SVG.PathArray
authorRémi Tétreault <tetreault.remi@gmail.com>
Tue, 20 Dec 2016 09:09:22 +0000 (04:09 -0500)
committerdotnetCarpenter <jon.ronnenberg@gmail.com>
Sat, 14 Jan 2017 06:22:26 +0000 (07:22 +0100)
Also add methods to SVG.Point that allow to perform operations
between two points.

dist/svg.js
dist/svg.min.js
gulpfile.js
spec/spec/array.js
spec/spec/makepathsmorphable.js [new file with mode: 0644]
spec/spec/point.js
src/makepathsmorphable.js [new file with mode: 0644]
src/patharray.js
src/point.js

index 6fcb165279289e7e590d88e19bc540c5abba6307..c693656b5f688cf6c44d81abe49be2eed154aaba 100644 (file)
@@ -1,12 +1,12 @@
 /*!
 * svg.js - A lightweight library for manipulating and animating SVG.
-* @version 2.3.6
+* @version 2.3.7
 * https://svgdotjs.github.io/
 *
 * @copyright Wout Fierens <wout@mick-wout.com>
 * @license MIT
 *
-* BUILT: Sat Jan 14 2017 05:53:26 GMT+0100 (CET)
+* BUILT: Sat Jan 14 2017 07:22:23 GMT+0100 (CET)
 */;
 (function(root, factory) {
   if (typeof define === 'function' && define.amd) {
@@ -705,6 +705,71 @@ SVG.extend(SVG.PathArray, {
 
     return this
   }
+  // Test if the passed path array use the same commands as this path array
+, haveSameCommands: function(pathArray) {
+    var i, il, haveSameCommands
+
+    pathArray = new SVG.PathArray(pathArray)
+
+    haveSameCommands = this.value.length === pathArray.value.length
+    for(i = 0, il = this.value.length; haveSameCommands && i < il; i++) {
+      haveSameCommands = this.value[i][0] === pathArray.value[i][0]
+    }
+
+    return haveSameCommands
+  }
+  // Make path array morphable
+, morph: function(pathArray) {
+    var pathsMorphable
+
+    this.destination = new SVG.PathArray(pathArray)
+
+    if(this.haveSameCommands(this.destination)) {
+      this.sourceMorphable = this
+      this.destinationMorphable = this.destination
+    } else {
+      pathsMorphable = SVG.utils.makePathsMorphable(this.value, this.destination)
+      this.sourceMorphable = pathsMorphable[0]
+      this.destinationMorphable = pathsMorphable[1]
+    }
+
+    return this
+  }
+  // Get morphed path array at given position
+, at: function(pos) {
+    if(pos === 1) {
+      return this.destination
+    } else if(pos === 0) {
+      return this
+    } else {
+      var sourceArray = this.sourceMorphable.value
+        , destinationArray = this.destinationMorphable.value
+        , array = [], pathArray = new SVG.PathArray()
+        , i, il, j, jl
+
+      // Animate has specified in the SVG spec
+      // See: https://www.w3.org/TR/SVG11/paths.html#PathElement
+      for (i = 0, il = sourceArray.length; i < il; i++) {
+        array[i] = [sourceArray[i][0]]
+        for(j=1, jl = sourceArray[i].length; j < jl; j++) {
+          array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos
+        }
+        // For the two flags of the elliptical arc command, the SVG spec say:
+        // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
+        // Elliptical arc command as an array followed by corresponding indexes:
+        // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
+        //   0    1   2        3                 4             5      6  7
+        if(array[i][0] === 'A') {
+          array[i][4] = +(array[i][4] != 0)
+          array[i][5] = +(array[i][5] != 0)
+        }
+      }
+
+      // Directly modify the value of a path array, this is done this way for performance
+      pathArray.value = array
+      return pathArray
+    }
+  }
   // Absolutize and parse path to array
 , parse: function(array) {
     // if it's already a patharray, no need to parse it
@@ -846,6 +911,7 @@ SVG.extend(SVG.PathArray, {
   }
 
 })
+
 // Module for unit convertions
 SVG.Number = SVG.invent({
   // Initialize
@@ -2484,9 +2550,9 @@ SVG.Point = SVG.invent({
       {x:x[0], y:x[1]} :
     typeof x === 'object' ?
       {x:x.x, y:x.y} :
-    y != null ?
-      {x:x, y:y} : base
-
+    x != null ?
+      {x:x, y:(y != null ? y : x)} : base // If y has no value, then x is used has its value
+                                          // This allow element-wise operations to be passed a single number
     // merge source
     this.x = source.x
     this.y = source.y
@@ -2499,9 +2565,9 @@ SVG.Point = SVG.invent({
       return new SVG.Point(this)
     }
     // Morph one point into another
-  , morph: function(point) {
+  , morph: function(x, y) {
       // store new destination
-      this.destination = new SVG.Point(point)
+      this.destination = new SVG.Point(x, y)
 
       return this
     }
@@ -2533,7 +2599,38 @@ SVG.Point = SVG.invent({
   , transform: function(matrix) {
       return new SVG.Point(this.native().matrixTransform(matrix.native()))
     }
-
+    // return an array of the x and y coordinates
+  , toArray: function() {
+      return [this.x, this.y]
+    }
+    // perform an element-wise addition with the passed point or number
+  , plus: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x + point.x, this.y + point.y)
+    }
+    // perform an element-wise subtraction with the passed point or number
+  , minus: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x - point.x, this.y - point.y)
+    }
+    // perform an element-wise multiplication with the passed point or number
+  , times: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x * point.x, this.y * point.y)
+    }
+    // perform an element-wise division with the passed point or number
+  , divide: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x / point.x, this.y / point.y)
+    }
+    // calculate the Euclidean norm
+  , norm: function() {
+      return Math.sqrt(this.x*this.x + this.y*this.y)
+    }
+    // calculate the distance to the passed point
+  , distance: function(x, y) {
+      return this.minus(x, y).norm()
+    }
   }
 
 })
@@ -5366,6 +5463,543 @@ function idFromReference(url) {
 
 // Create matrix array for looping
 var abcdef = 'abcdef'.split('')
+// Take two path array that don't have the same commands (which mean that they
+// cannot be morphed in one another) and return 2 equivalent path array (meaning
+// that they produce the same shape as the passed path array) that have the
+// same commands (moveto and curveto)
+//
+// Algorithm used:
+// First, convert every path segment of the two passed paths into equivalent cubic Bezier curves.
+// Then, calculate the positions relative to the total length of the path of the endpoint of all those cubic Bezier curves.
+// After that, split the Bezier curves of the source at the positions that the destination have that are not common to the source and vice versa.
+// Finally, make the source and destination have the same number of subpaths.
+SVG.utils.makePathsMorphable = function (sourcePathArray, destinationPathArray) {
+  var source, sourcePositions, sourcePositionsToSplitAt
+    , destination, destinationPositions, destinationPositionsToSplitAt
+    , i, il, j, jl
+    , s, d
+    , sourceSubpath, destinationSubpath, lastSegPt
+
+  // Convert every path segments into equivalent cubic Bezier curves
+  source = cubicSuperPath(sourcePathArray)
+  destination = cubicSuperPath(destinationPathArray)
+
+  // The positions relative to the total length of the path is calculated for the endpoint of all those cubic bezier curves
+  sourcePositions = cspPositions(source)
+  destinationPositions = cspPositions(destination)
+
+  // Find the positions that the destination have that are not in the source and vice versa
+  sourcePositionsToSplitAt = []
+  destinationPositionsToSplitAt = []
+  i = 0, il = sourcePositions.length
+  j = 0, jl = destinationPositions.length
+  while(i < il && j < jl) {
+    // Test if the two values are equal taking into account the imprecision of floating point number
+    if (Math.abs(sourcePositions[i] - destinationPositions[j]) < 0.000001) {
+      i++
+      j++
+    } else if(sourcePositions[i] > destinationPositions[j]){
+      sourcePositionsToSplitAt.push(destinationPositions[j++])
+    } else {
+      destinationPositionsToSplitAt.push(sourcePositions[i++])
+    }
+  }
+  // If there are still some destination positions left, they all are not in the source and vice versa
+  sourcePositionsToSplitAt = sourcePositionsToSplitAt.concat(destinationPositions.slice(j))
+  destinationPositionsToSplitAt = destinationPositionsToSplitAt.concat(sourcePositions.slice(i))
+
+  // Split the source and the destination at the positions they don't have in common
+  cspSplitAtPositions(source, sourcePositions, sourcePositionsToSplitAt)
+  cspSplitAtPositions(destination, destinationPositions, destinationPositionsToSplitAt)
+
+
+  // Break paths so that corresponding subpaths have an equal number of segments
+  s = source, source = [], sourceSubpath = s[i = 0]
+  d = destination, destination = [], destinationSubpath = d[j = 0]
+  while (sourceSubpath && destinationSubpath) {
+    // Push REFERENCES to the current subpath arrays in their respective array
+    source.push(sourceSubpath)
+    destination.push(destinationSubpath)
+
+    il = sourceSubpath.length
+    jl = destinationSubpath.length
+
+    // If the current subpath of the source and the current subpath of the destination don't
+    // have the same length, that mean that the biggest of the two must be split in two
+    if(il > jl) {
+      lastSegPt = sourceSubpath[jl-1]
+      // Perform the split using splice that change the content of the array by removing elements and returning them in an array
+      sourceSubpath = sourceSubpath.splice(jl)
+      sourceSubpath.unshift(lastSegPt) // The last segment point is duplicated since these two segments must be joined together
+      destinationSubpath = d[++j] // This subpath has been accounted for, past to the next
+    } else if(il < jl) {
+      lastSegPt = destinationSubpath[il-1]
+      destinationSubpath = destinationSubpath.splice(il)
+      destinationSubpath.unshift(lastSegPt)
+      sourceSubpath = s[++i]
+    } else {
+      sourceSubpath = s[++i]
+      destinationSubpath = d[++j]
+    }
+  }
+
+  // Convert in path array and return
+  return [uncubicSuperPath(source), uncubicSuperPath(destination)]
+}
+
+
+
+
+
+
+// This function converts every segment of a path array into equivalent cubic Bezier curves
+// and return the results in a 3 dimensional array that have the following hierarchy:
+// Cubic super path:  [                                           ]
+// Segments:           [                                     ] ...
+// Segment points:      [SVG.Point, SVG.Point, SVG.Point] ...
+//
+// A segment point is a point with the two control points that are attached to it:
+// [First control point, Point, Second control point]
+//
+// If the passed path array cannot be converted in a cubic super path, this function return an empty array.
+function cubicSuperPath(pathArray) {
+  pathArray = new SVG.PathArray(pathArray)
+
+  var cubicSP = []
+    , subpath = null
+    , subpathStartPt = null
+    , lastPt = null
+    , lastCtrlPt = null
+    , i, il, cmd = null, params, lastCmd
+    , start, control, end
+    , arcSegPoints, segPt
+
+  for (i = 0, il = pathArray.value.length; i < il; i++) {
+    lastCmd = cmd
+    cmd = pathArray.value[i][0]
+    params = pathArray.value[i].slice(1)
+
+    switch (cmd) {
+      case 'M': // moveto
+        // Parameters: x y
+        if (lastPt) {
+          subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        }
+        subpath = []
+        cubicSP.push(subpath) // Push a reference to the current subpath array in the cubic super path array
+        subpathStartPt = new SVG.Point(params)
+        lastPt = subpathStartPt.clone()
+        lastCtrlPt = subpathStartPt.clone()
+        break
+
+      case 'L': // lineto
+        // Parameters: x y
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        lastPt = new SVG.Point(params)
+        lastCtrlPt = lastPt.clone()
+        break
+
+      case 'H': // horizontal lineto
+        // Parameters: x
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        lastPt = new SVG.Point(params[0], lastPt.y)
+        lastCtrlPt = lastPt.clone()
+        break
+
+      case 'V': // vertical lineto
+        // Parameters: y
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        lastPt = new SVG.Point(lastPt.x, params[0])
+        lastCtrlPt = lastPt.clone()
+        break
+
+      case 'C': // curveto
+        // Parameters: x1 y1 x2 y2 x y
+        subpath.push([lastCtrlPt, lastPt, new SVG.Point(params.slice(0,2))])
+        lastPt = new SVG.Point(params.slice(4,6))
+        lastCtrlPt = new SVG.Point(params.slice(2,4))
+        break
+
+      case 'S': // shorthand/smooth curveto
+        // Parameters: x2 y2 x y
+        // For this version of curveto, the first control point is the reflection of the second control point on the previous command relative to the current point
+        // If the previous command is not a curveto command, then the first control point is the same as the current point
+        if(lastCmd === 'C' || lastCmd === 'S') {
+          subpath.push([lastCtrlPt, lastPt, lastPt.times(2).minus(lastCtrlPt)])
+        } else {
+          subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        }
+        lastPt = new SVG.Point(params.slice(2,4))
+        lastCtrlPt = new SVG.Point(params.slice(0,2))
+        break
+
+      case 'Q': // quadratic Bezier curveto
+        // Parameters: x1 y1 x y
+        // For an explanation of the method used, see: https://pomax.github.io/bezierinfo/#reordering
+        start = lastPt
+        control = new SVG.Point(params.slice(0,2))
+        end = new SVG.Point(params.slice(2,4))
+
+        subpath.push([lastCtrlPt, start, start.times(1/3).plus(control.times(2/3))])
+        lastPt = end
+        lastCtrlPt = control.times(2/3).plus(end.times(1/3))
+        break
+
+      case 'T': // shorthand/smooth quadratic Bézier curveto
+        // Parameters: x y
+        // For this version of quadratic Bézier curveto, the control point is the reflection of the control point on the previous command relative to the current point
+        // If the previous command is not a quadratic Bézier curveto command, then the control point is the same as the current point
+        start = lastPt
+        if(lastCmd === 'Q' || lastCmd === 'T') {
+          control = start.times(2).minus(control)
+        } else {
+          control = start
+        }
+        end = new SVG.Point(params.slice(0,2))
+
+        subpath.push([lastCtrlPt, start, start.times(1/3).plus(control.times(2/3))])
+        lastPt = end
+        lastCtrlPt = control.times(2/3).plus(end.times(1/3))
+        break
+
+      case 'A': // elliptical arc
+        // Parameters: rx ry x-axis-rotation large-arc-flag sweep-flag x y
+        arcSegPoints = arcToPath(lastPt, params)
+        arcSegPoints[0][0] = lastCtrlPt
+        segPt = arcSegPoints.pop()
+        lastPt = segPt[1]
+        lastCtrlPt = segPt[0]
+        Array.prototype.push.apply(subpath, arcSegPoints)
+        break
+
+      case 'Z': // closepath
+        // Parameters: none
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        // Close the path only if it is not already closed
+        if(lastPt.x != subpathStartPt.x && lastPt.y != subpathStartPt.y) {
+          lastPt = subpathStartPt
+          lastCtrlPt = subpathStartPt.clone()
+        } else {
+          lastPt = null
+          lastCtrlPt = null
+        }
+        break
+    }
+  }
+
+  // Push final segment point if any
+  if(lastPt) {
+    subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+  }
+
+  return cubicSP
+}
+
+
+// This function convert a cubic super path into a path array
+function uncubicSuperPath (cubicSP) {
+  var i, il, j, jl, array = [], pathArray = new SVG.PathArray, subpath
+
+  for (i = 0, il = cubicSP.length; i < il; i++) {
+    subpath = cubicSP[i]
+
+    if (subpath.length) {
+      array.push(['M'].concat(subpath[0][1].toArray()))
+
+      for (j = 1, jl = subpath.length; j < jl; j++) {
+        array.push(['C'].concat(subpath[j-1][2].toArray(), subpath[j][0].toArray(), subpath[j][1].toArray()))
+      }
+    }
+  }
+
+  // Directly modify the value of a path array, this is done this way for performance
+  pathArray.value = array
+  return pathArray
+}
+
+// Convert an arc segment into equivalent cubic Bezier curves
+// Depending on the arc, up to 4 curves might be used to represent it since a
+// curve gives a good approximation for only a quarter of an ellipse
+// The curves are returned as an array of segment points:
+// [ [SVG.Point, SVG.Point, SVG.Point] ... ]
+function arcToPath(lastPt, params) {
+    // Parameters extraction, handle out-of-range parameters as specified in the SVG spec
+    // See: https://www.w3.org/TR/SVG11/implnote.html#ArcOutOfRangeParameters
+    var rx = Math.abs(params[0]), ry = Math.abs(params[1]), xAxisRotation = params[2] % 360
+      , largeArcFlag = params[3], sweepFlag = params[4], x2  = params[5], y2 = params[6]
+      , A = lastPt, B = new SVG.Point(x2, y2)
+      , primedCoord, lambda, mat, k, c, cSquare, t, O, OA, OB, tetaStart, tetaEnd
+      , deltaTeta, nbSectors, f, arcSegPoints, angle, sinAngle, cosAngle, pt, i, il
+
+    // Ensure radii are non-zero
+    if(rx === 0 || ry === 0 || (A.x === B.x && A.y === B.y)) {
+      // treat this arc as a straight line segment
+      return [[A, A.clone(), A.clone()], [B, B.clone(), B.clone()]]
+    }
+
+    // Ensure radii are large enough using the algorithm provided in the SVG spec
+    // See: https://www.w3.org/TR/SVG11/implnote.html#ArcCorrectionOutOfRangeRadii
+    primedCoord = A.minus(B).divide(2).transform(new SVG.Matrix().rotate(xAxisRotation))
+    lambda = (primedCoord.x * primedCoord.x) / (rx * rx) + (primedCoord.y * primedCoord.y) / (ry * ry)
+    if(lambda > 1) {
+      lambda = Math.sqrt(lambda)
+      rx = lambda*rx
+      ry = lambda*ry
+    }
+
+    // To simplify calculations, we make the arc part of a unit circle (rayon is 1) instead of an ellipse
+    mat = new SVG.Matrix().rotate(xAxisRotation).scale(1/rx, 1/ry).rotate(-xAxisRotation)
+    A = A.transform(mat)
+    B = B.transform(mat)
+
+    // Calculate the horizontal and vertical distance between the initial and final point of the arc
+    k = [B.x-A.x, B.y-A.y]
+
+    // Find the length of the chord formed by A and B
+    cSquare = k[0]*k[0] + k[1]*k[1]
+    c = Math.sqrt(cSquare)
+
+    // Calculate the ratios of the horizontal and vertical distance on the length of the chord
+    k[0] /= c
+    k[1] /= c
+
+    // Calculate the distance between the circle center and the chord midpoint
+    // using this formula: t = sqrt(r^2 - c^2 / 4)
+    // where t is the distance between the cirle center and the chord midpoint,
+    //       r is the rayon of the circle and c is the chord length
+    // From: http://www.ajdesigner.com/phpcircle/circle_segment_chord_t.php
+    // Because of the imprecision of floating point numbers, cSquare might end
+    // up being slightly above 4 which would result in a negative radicand
+    // To prevent that, a test is made before computing the square root
+    t = (cSquare < 4) ? Math.sqrt(1 - cSquare/4) : 0
+
+    // For most situations, there are actually two different ellipses that
+    // satisfy the constraints imposed by the points A and B, the radii rx and ry,
+    // and the xAxisRotation
+    // When the flags largeArcFlag and sweepFlag are equal, it means that the
+    // second ellipse is used as a solution
+    // See: https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
+    if(largeArcFlag === sweepFlag) {
+        t *= -1
+    }
+
+    // Calculate the coordinates of the center of the circle from the midpoint of the chord
+    // This is done by multiplying the ratios calculated previously by the distance between
+    // the circle center and the chord midpoint and using these values to go from the midpoint
+    // to the center of the circle
+    // The negative of the vertical distance ratio is used to modify the x coordinate while
+    // the horizontal distance ratio is used to modify the y coordinate
+    // That is because the center of the circle is perpendicular to the chord and perpendicular
+    // lines are negative reciprocals
+    O = new SVG.Point((B.x+A.x)/2 + t*-k[1], (B.y+A.y)/2 + t*k[0])
+    // Move the center of the circle at the origin
+    OA = A.minus(O)
+    OB = B.minus(O)
+
+    // Calculate the start and end angle
+    tetaStart = Math.acos(OA.x/OA.norm())
+    if (OA.y < 0) {
+      tetaStart *= -1
+    }
+    tetaEnd = Math.acos(OB.x/OB.norm())
+    if (OB.y < 0) {
+      tetaEnd *= -1
+    }
+
+    // If sweep-flag is '1', then the arc will be drawn in a "positive-angle" direction,
+    // make sure that the end angle is above the start angle
+    if (sweepFlag && tetaStart > tetaEnd) {
+      tetaEnd += 2*Math.PI
+    }
+    // If sweep-flag is '0', then the arc will be drawn in a "negative-angle" direction,
+    // make sure that the end angle is below the start angle
+    if (!sweepFlag && tetaStart < tetaEnd) {
+      tetaEnd -= 2*Math.PI
+    }
+
+    // Find the number of Bezier curves that are required to represent the arc
+    // A cubic Bezier curve gives a good enough approximation when representing at most a quarter of a circle
+    nbSectors = Math.ceil(Math.abs(tetaStart-tetaEnd) * 2/Math.PI)
+
+    // Calculate the coordinates of the points of all the Bezier curves required to represent the arc
+    // For an in-depth explanation of this part see: http://pomax.github.io/bezierinfo/#circles_cubic
+    arcSegPoints = []
+    angle = tetaStart
+    deltaTeta = (tetaEnd-tetaStart)/nbSectors
+    f = 4*Math.tan(deltaTeta/4)/3
+    for (i = 0; i <= nbSectors; i++) { // The <= is because a Bezier curve have a start and a endpoint
+      cosAngle = Math.cos(angle)
+      sinAngle = Math.sin(angle)
+
+      pt = O.plus(cosAngle, sinAngle)
+      arcSegPoints[i] = [pt.plus(+f*sinAngle, -f*cosAngle), pt, pt.plus(-f*sinAngle, +f*cosAngle)]
+
+      angle += deltaTeta
+    }
+
+    // Remove the first control point of the first segment point and remove the second control point of the last segment point
+    // These two control points are not used in the approximation of the arc, that is why they are removed
+    arcSegPoints[0][0] = arcSegPoints[0][1].clone()
+    arcSegPoints[arcSegPoints.length-1][2] = arcSegPoints[arcSegPoints.length-1][1].clone()
+
+    // Revert the transformation that was applied to make the arc part of a unit circle instead of an ellipse
+    mat = new SVG.Matrix().rotate(xAxisRotation).scale(rx, ry).rotate(-xAxisRotation)
+    for (i = 0, il = arcSegPoints.length; i < il; i++) {
+      arcSegPoints[i][0] = arcSegPoints[i][0].transform(mat)
+      arcSegPoints[i][1] = arcSegPoints[i][1].transform(mat)
+      arcSegPoints[i][2] = arcSegPoints[i][2].transform(mat)
+    }
+
+    return arcSegPoints
+}
+
+
+// Use de Casteljau's algorithm to split a cubic Bezier curve
+// For a description of the algorithm, see: https://pomax.github.io/bezierinfo/#decasteljau
+// Return an array of 3 segment points
+function cspSegSplit(segPt1, segPt2, t) {
+  segPt1 = [segPt1[0].clone(), segPt1[1].clone(), segPt1[2].clone()]
+  segPt2 = [segPt2[0].clone(), segPt2[1].clone(), segPt2[2].clone()]
+
+  var m1 = segPt1[1].morph(segPt1[2]).at(t)
+    , m2 = segPt1[2].morph(segPt2[0]).at(t)
+    , m3 = segPt2[0].morph(segPt2[1]).at(t)
+    , m4 = m1.morph(m2).at(t)
+    , m5 = m2.morph(m3).at(t)
+    , m = m4.morph(m5).at(t)
+
+  return [[segPt1[0], segPt1[1], m1], [m4, m, m5], [m3, segPt2[1], segPt2[2]]]
+}
+
+
+// Find the length of a cubic Bezier curve using the built-in method getTotalLength of SVGPathElement
+// For more info, see: https://www.w3.org/TR/SVG11/paths.html#InterfaceSVGPathElement
+function cspSegLength(segPt1, segPt2) {
+  var path = document.createElementNS(SVG.ns, "path")
+    , d = ['M', segPt1[1].toArray(), 'C', segPt1[2].toArray(), segPt2[0].toArray(), segPt2[1].toArray()].join(' ')
+
+  path.setAttribute('d', d)
+
+  return path.getTotalLength()
+}
+
+
+// Find the length of all the cubic Bezier curves of a cubic super path and return
+// the results in a 2 dimensional array that have the following hierarchy:
+// Cubic super path lengths:  [                ]
+// Segments lengths:           [          ] ...
+// Cubic Bezier curves length:  Number ...
+//
+// On the returned array, the property total is set to the sum of all the lengths
+function cspLengths(cubicSP) {
+  var total = 0
+    , subpath, lengths = [], lengthsSubpath, length
+    , i, il, j, jl
+
+  for (i = 0, il = cubicSP.length; i < il; i++) {
+    subpath = cubicSP[i]
+    lengthsSubpath = []
+    lengths[i] = lengthsSubpath // Save a reference to the current subpath lengths array in the cubic super path lengths array
+
+    for (j = 1, jl = subpath.length; j < jl; j++) {
+      length = cspSegLength(subpath[j-1], subpath[j])
+      lengthsSubpath[j-1] = length
+      total += length
+    }
+  }
+
+  lengths.total = total
+  return lengths
+}
+
+
+// Split a cubic Bezier curve at the given length ratio
+// Return an array of 3 segment points
+function cspSegSplitAtLengthRatio(segPt1, segPt2, lengthRatio) {
+  var t = 1.0
+    , tdiv = t
+    , currentLength = cspSegLength(segPt1, segPt2)
+    , targetLength = lengthRatio * currentLength
+    , diff = currentLength - targetLength
+    , split = cspSegSplit(segPt1, segPt2, t)
+    , maxNbLoops = 4096 // For not getting stuck in an infinite loop
+
+  while (Math.abs(diff) > 0.001 && maxNbLoops--) {
+    tdiv /= 2
+    t += (diff < 0) ? tdiv : -tdiv
+    split = cspSegSplit(segPt1, segPt2, t)
+    currentLength = cspSegLength(split[0], split[1])
+    diff = currentLength - targetLength
+  }
+
+  return split
+}
+
+
+
+// Find the position relative to the total length of the endpoint of all the cubic Bezier curves
+// of a cubic super path and return the results in a 1 dimensional array
+function cspPositions(cubicSP) {
+  var lengths = cspLengths(cubicSP), total = lengths.total
+    , pos = 0, positions = []
+    , i, il, j, jl
+
+  for (i = 0, il = lengths.length; i < il; i++) {
+    for (j = 0, jl = lengths[i].length; j < jl; j++) {
+      pos += lengths[i][j] / total
+      positions.push(pos)
+    }
+  }
+
+  return positions
+}
+
+// Split the passed cubic super path at the specified positions and return the results as a new cubic super path
+// For performance reasons, the positions of the passed cubic super path must also be provided
+function cspSplitAtPositions(cubicSP, positions, positionsToSplitAt){
+  var subpath, newSubpath
+    , accumNbPositions = 0, segPt, lengthRatio, split, pos, prevPos
+    , i, il, j, jl // indexes on the cubicSP array
+    , k = 0 // index on the positions array
+    , l = 0, ll = positionsToSplitAt.length
+
+  for (i = 0, il = cubicSP.length; i < il && l < ll; i++) {
+    subpath = cubicSP[i]
+    // The positions are only for the endpoints of the cubic Bezier curves, so
+    // a subpath need at least 2 segment points for a position to be on it
+    if(subpath.length < 2) {continue}
+    // Test if there are splits to be performed on the current subpath
+    if(positionsToSplitAt[l] < positions[accumNbPositions + subpath.length-2]) {
+      k = accumNbPositions
+      newSubpath = []
+      cubicSP[i] = newSubpath // Save a reference to the new current subpath array in the cubic super path array
+      pos = positions[k-1] || 0
+
+      // Recopy the content of the current subpath, performing splits where necessary
+      newSubpath.push(subpath[0])
+      for (j = 1, jl = subpath.length; j < jl; j++) {
+        prevPos = pos
+        pos = positions[k++]
+        segPt = subpath[j]
+
+        while(l < ll && positionsToSplitAt[l] < pos) {
+          lengthRatio = (positionsToSplitAt[l] - prevPos) / (pos - prevPos)
+          split = cspSegSplitAtLengthRatio(newSubpath[newSubpath.length-1], segPt, lengthRatio)
+          newSubpath[newSubpath.length-1] = split[0]
+          newSubpath.push(split[1])
+          segPt = split[2]
+          prevPos = positionsToSplitAt[l++]
+        }
+
+        newSubpath.push(segPt)
+      }
+    }
+
+    // -1 because positions are only for endpoints of Bezier curves
+    accumNbPositions += subpath.length - 1
+  }
+}
+
 // Add CustomEvent to IE9 and IE10
 if (typeof CustomEvent !== 'function') {
   // Code from: https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent
index 2a273bda7e3e4cee6cf0fcf1faf51e67447a79eb..ba28d7b9271c21d4c0a2601375f4018b8667025f 100644 (file)
@@ -1,2 +1,3 @@
-/*! svg.js v2.3.6 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function i(t,e){return t instanceof e}function n(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function s(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function r(t){return t.charAt(0).toUpperCase()+t.slice(1)}function a(t){return 4==t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function o(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function h(t,e,i){if(null==e||null==i){var n=t.bbox();null==e?e=n.width/n.height*i:null==i&&(i=n.height/n.width*e)}return{width:e,height:i}}function u(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function l(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function c(t){return t instanceof g.Matrix||(t=new g.Matrix(t)),t}function f(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function d(t){return t=t.replace(g.regex.whitespace,"").replace(g.regex.matrix,"").split(g.regex.matrixElements),l(g.utils.map(t,function(t){return parseFloat(t)}))}function p(t){for(var e=0,i=t.length,n="";e<i;e++)n+=t[e][0],null!=t[e][1]&&(n+=t[e][1],null!=t[e][2]&&(n+=" ",n+=t[e][2],null!=t[e][3]&&(n+=" ",n+=t[e][3],n+=" ",n+=t[e][4],null!=t[e][5]&&(n+=" ",n+=t[e][5],n+=" ",n+=t[e][6],null!=t[e][7]&&(n+=" ",n+=t[e][7])))));return n+" "}function m(t){for(var e=t.childNodes.length-1;e>=0;e--)t.childNodes[e]instanceof SVGElement&&m(t.childNodes[e]);return g.adopt(t).id(g.eid(t.nodeName))}function x(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function v(t){var e=t.toString().match(g.regex.reference);if(e)return e[1]}var g=this.SVG=function(t){if(g.supported)return t=new g.Doc(t),g.parser.draw||g.prepare(),t};if(g.ns="http://www.w3.org/2000/svg",g.xmlns="http://www.w3.org/2000/xmlns/",g.xlink="http://www.w3.org/1999/xlink",g.svgjs="http://svgjs.com/svgjs",g.supported=function(){return!!e.createElementNS&&!!e.createElementNS(g.ns,"svg").createSVGRect}(),!g.supported)return!1;g.did=1e3,g.eid=function(t){return"Svgjs"+r(t)+g.did++},g.create=function(t){var i=e.createElementNS(this.ns,t);return i.setAttribute("id",this.eid(t)),i},g.extend=function(){var t,e,i,n;for(t=[].slice.call(arguments),e=t.pop(),n=t.length-1;n>=0;n--)if(t[n])for(i in e)t[n].prototype[i]=e[i];g.Set&&g.Set.inherit&&g.Set.inherit()},g.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,g.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&g.extend(e,t.extend),t.construct&&g.extend(t.parent||g.Container,t.construct),e},g.adopt=function(t){if(!t)return null;if(t.instance)return t.instance;var e;return e="svg"==t.nodeName?t.parentNode instanceof SVGElement?new g.Nested:new g.Doc:"linearGradient"==t.nodeName?new g.Gradient("linear"):"radialGradient"==t.nodeName?new g.Gradient("radial"):g[r(t.nodeName)]?new(g[r(t.nodeName)]):new g.Element(t),e.type=t.nodeName,e.node=t,t.instance=e,e instanceof g.Doc&&e.namespace().defs(),e.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}),e},g.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new g.Doc(t):new g.Doc(e.documentElement).nested()).size(2,0);g.parser={body:t||e.documentElement,draw:i.style("opacity:0;position:fixed;left:100%;top:100%;overflow:hidden"),poly:i.polyline().node,path:i.path().node,native:g.create("svg")}},g.parser={native:g.create("svg")},e.addEventListener("DOMContentLoaded",function(){g.parser.draw||g.prepare()},!1),g.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,matrix:/matrix\(|\)/g,matrixElements:/,*\s+|,/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,negExp:/e\-/gi,comma:/,/g,hyphen:/\-/g,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,whitespaces:/\s+/,X:/X/g},g.utils={map:function(t,e){var i,n=t.length,s=[];for(i=0;i<n;i++)s.push(e(t[i]));return s},filter:function(t,e){var i,n=t.length,s=[];for(i=0;i<n;i++)e(t[i])&&s.push(t[i]);return s},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(t){return this.filter(t,function(t){return t instanceof SVGElement})}},g.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},g.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?g.regex.isRgb.test(t)?(e=g.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):g.regex.isHex.test(t)&&(e=g.regex.hex.exec(a(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},g.extend(g.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+o(this.r)+o(this.g)+o(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new g.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new g.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),g.Color.test=function(t){return t+="",g.regex.isHex.test(t)||g.regex.isRgb.test(t)},g.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},g.Color.isColor=function(t){return g.Color.isRgb(t)||g.Color.test(t)},g.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},g.extend(g.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.indexOf(this.value[t])==-1&&i.push(this.value[t]);return this.value=i},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new g.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:this.split(t)},split:function(t){return t.trim().split(/\s+/)},reverse:function(){return this.value.reverse(),this}}),g.PointArray=function(t,e){this.constructor.call(this,t,e||[[0,0]])},g.PointArray.prototype=new g.Array,g.extend(g.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.push(this.value[t].join(","));return i.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new g.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t))return t;t=t.trim().split(/\s+|,/),t.length%2!==0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([parseFloat(t[i]),parseFloat(t[i+1])]);return e},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x,this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y;return this},bbox:function(){return g.parser.poly.setAttribute("points",this.toString()),g.parser.poly.getBBox()}}),g.PathArray=function(t,e){this.constructor.call(this,t,e||[["M",0,0]])},g.PathArray.prototype=new g.Array,g.extend(g.PathArray,{toString:function(){return p(this.value)},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n,s=this.value.length-1;s>=0;s--)n=this.value[s][0],"M"==n||"L"==n||"T"==n?(this.value[s][1]+=t,this.value[s][2]+=e):"H"==n?this.value[s][1]+=t:"V"==n?this.value[s][1]+=e:"C"==n||"S"==n||"Q"==n?(this.value[s][1]+=t,this.value[s][2]+=e,this.value[s][3]+=t,this.value[s][4]+=e,"C"==n&&(this.value[s][5]+=t,this.value[s][6]+=e)):"A"==n&&(this.value[s][6]+=t,this.value[s][7]+=e);return this},size:function(t,e){var i,n,s=this.bbox();for(i=this.value.length-1;i>=0;i--)n=this.value[i][0],"M"==n||"L"==n||"T"==n?(this.value[i][1]=(this.value[i][1]-s.x)*t/s.width+s.x,this.value[i][2]=(this.value[i][2]-s.y)*e/s.height+s.y):"H"==n?this.value[i][1]=(this.value[i][1]-s.x)*t/s.width+s.x:"V"==n?this.value[i][1]=(this.value[i][1]-s.y)*e/s.height+s.y:"C"==n||"S"==n||"Q"==n?(this.value[i][1]=(this.value[i][1]-s.x)*t/s.width+s.x,this.value[i][2]=(this.value[i][2]-s.y)*e/s.height+s.y,this.value[i][3]=(this.value[i][3]-s.x)*t/s.width+s.x,this.value[i][4]=(this.value[i][4]-s.y)*e/s.height+s.y,"C"==n&&(this.value[i][5]=(this.value[i][5]-s.x)*t/s.width+s.x,this.value[i][6]=(this.value[i][6]-s.y)*e/s.height+s.y)):"A"==n&&(this.value[i][1]=this.value[i][1]*t/s.width,this.value[i][2]=this.value[i][2]*e/s.height,this.value[i][6]=(this.value[i][6]-s.x)*t/s.width+s.x,this.value[i][7]=(this.value[i][7]-s.y)*e/s.height+s.y);return this},parse:function(t){if(t instanceof g.PathArray)return t.valueOf();var e,i,n,s,r,a,o=0,h=0,u={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7};if("string"==typeof t){for(t=t.replace(g.regex.negExp,"X").replace(g.regex.pathLetters," $& ").replace(g.regex.hyphen," -").replace(g.regex.comma," ").replace(g.regex.X,"e-").trim().split(g.regex.whitespaces),e=t.length;--e;)if(t[e].indexOf(".")!=t[e].lastIndexOf(".")){var l=t[e].split("."),c=[l.shift(),l.shift()].join(".");t.splice.apply(t,[e,1].concat(c,l.map(function(t){return"."+t})))}}else t=t.reduce(function(t,e){return[].concat.apply(t,e)},[]);var a=[];do{for(g.regex.isPathLetter.test(t[0])?(s=t[0],t.shift()):"M"==s?s="L":"m"==s&&(s="l"),r=[s.toUpperCase()],e=0;e<u[r[0]];++e)r.push(parseFloat(t.shift()));s==r[0]?"M"==s||"L"==s||"C"==s||"Q"==s||"S"==s||"T"==s?(o=r[u[r[0]]-1],h=r[u[r[0]]]):"V"==s?h=r[1]:"H"==s?o=r[1]:"A"==s&&(o=r[6],h=r[7]):"m"==s||"l"==s||"c"==s||"s"==s||"q"==s||"t"==s?(r[1]+=o,r[2]+=h,null!=r[3]&&(r[3]+=o,r[4]+=h),null!=r[5]&&(r[5]+=o,r[6]+=h),o=r[u[r[0]]-1],h=r[u[r[0]]]):"v"==s?(r[1]+=h,h=r[1]):"h"==s?(r[1]+=o,o=r[1]):"a"==s&&(r[6]+=o,r[7]+=h,o=r[6],h=r[7]),"M"==r[0]&&(i=o,n=h),"Z"==r[0]&&(o=i,h=n),a.push(r)}while(t.length);return a},bbox:function(){return g.parser.path.setAttribute("d",this.toString()),g.parser.path.getBBox()}}),g.Number=g.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(g.regex.numberAndUnit),e&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5])):t instanceof g.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return new g.Number(this+new g.Number(t),this.unit)},minus:function(t){return this.plus(-new g.Number(t))},times:function(t){return new g.Number(this*new g.Number(t),this.unit)},divide:function(t){return new g.Number(this/new g.Number(t),this.unit)},to:function(t){var e=new g.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new g.Number(t),this},at:function(t){return this.destination?new g.Number(this.destination).minus(this).times(t).plus(this):this}}}),g.Element=g.invent({create:function(t){this._stroke=g.defaults.attrs.stroke,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this,this._stroke=t.getAttribute("stroke")||this._stroke)},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=h(this,t,e);return this.width(new g.Number(i.width)).height(new g.Number(i.height))},clone:function(t){var e=m(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return this.attr("id",t)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&t<i.x+i.width&&e<i.y+i.height},show:function(){return this.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(/\s+/)},hasClass:function(t){return this.classes().indexOf(t)!=-1},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!=t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return g.get(this.attr(t))},parent:function(t){var e=this;if(!e.node.parentNode)return null;if(e=g.adopt(e.node.parentNode),!t)return e;for(;e&&e.node instanceof SVGElement;){if("string"==typeof t?e.matches(t):e instanceof t)return e;e=g.adopt(e.node.parentNode)}},doc:function(){return this instanceof g.Doc?this:this.parent(g.Doc)},parents:function(t){var e=[],i=this;do{if(i=i.parent(t),!i||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return n(this.node,t)},native:function(){return this.node},svg:function(t){var i=e.createElement("svg");if(!(t&&this instanceof g.Parent))return i.appendChild(t=e.createElement("svg")),this.writeDataToDom(),t.appendChild(this.node.cloneNode(!0)),i.innerHTML.replace(/^<svg>/,"").replace(/<\/svg>$/,"");i.innerHTML="<svg>"+t.replace(/\n/,"").replace(/<(\w+)([^<]+?)\/>/g,"<$1$2></$1>")+"</svg>";for(var n=0,s=i.firstChild.childNodes.length;n<s;n++)this.node.appendChild(i.firstChild.firstChild);return this},writeDataToDom:function(){if(this.each||this.lines){var t=this.each?this:this.lines();t.each(function(){this.writeDataToDom()})}return this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return i(this,t)}}}),g.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return-Math.cos(t*Math.PI/2)+1}},g.morph=function(t){return function(e,i){return new g.MorphObj(e,i).at(t)}},g.Situation=g.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new g.Number(t.duration).valueOf(),this.delay=new g.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),g.FX=g.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new g.Situation({duration:t||1e3,delay:i||0,ease:g.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var e=new g.Situation({duration:t,delay:0,ease:g.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof g.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof g.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.situation&&this.situation.stop&&this.situation.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof g.Situation?this.startCurrent():this.situation.call(this)),this},initAnimations:function(){var t,e=this.situation;if(e.init)return this;for(t in e.animations)"viewbox"==t?e.animations[t]=this.target().viewbox().morph(e.animations[t]):(e.animations[t].value="plot"==t?this.target().array().value:this.target()[t](),e.animations[t].value.value&&(e.animations[t].value=e.animations[t].value.value),e.animations[t].relative&&(e.animations[t].destination.value=e.animations[t].destination.value+e.animations[t].value));for(t in e.attrs)if(e.attrs[t]instanceof g.Color){var i=new g.Color(this.target().attr(t));e.attrs[t].r=i.r,e.attrs[t].g=i.g,e.attrs[t].b=i.b}else e.attrs[t].value=this.target().attr(t);for(t in e.styles)e.styles[t].value=this.target().style(t);return e.initialTransformation=this.target().matrixify(),e.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){return this.active||this.start(),e&&this.clearQueue(),this.active=!1,t&&this.situation&&this.atEnd(),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return this.situation.loops===!0?this.at(this.situation.loop+1,!0):"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var i=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*i,this.situation.finish=this.situation.start+i,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var i=this.last();return i.loops=null==t||t,i.loop=0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return"undefined"==typeof t?e.reversed=!e.reversed:e.reversed=t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,g.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)})},afterAll:function(t){var e=function e(i){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,g.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)})},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,i){return this.last()[i||"animations"][t]=e,setTimeout(function(){this.start()}.bind(this),0),this},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),this.situation.loops!==!1){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),this.situation.loops===!0||i<this.situation.loops?(this.pos=e-i,n=this.situation.loop,this.situation.loop=i):(this.absPos=this.situation.loops,this.pos=1,n=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!=Boolean((this.situation.loop-n)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var s=this.situation.ease(this.pos);for(var r in this.situation.once)r>this.lastPos&&r<=s&&(this.situation.once[r].call(this.target(),this.pos,s),delete this.situation.once[r]);return this.active&&this.target().fire("during",{pos:this.pos,eased:s,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1==this.pos&&!this.situation.reversed||this.situation.reversed&&0==this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.target().off(".fx"),this.active=!1),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=s,this):this},eachAt:function(){var t,e,i=this,n=this.target(),s=this.situation;for(t in s.animations)e=[].concat(s.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),n[t].apply(n,e);for(t in s.attrs)e=[t].concat(s.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),n.attr.apply(n,e);for(t in s.styles)e=[t].concat(s.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(s.ease(i.pos),i.pos):t}),n.style.apply(n,e);if(s.transforms.length){for(e=s.initialTransformation,t=0,len=s.transforms.length;t<len;t++){var r=s.transforms[t];r instanceof g.Matrix?e=r.relative?e.multiply((new g.Matrix).morph(r).at(s.ease(this.pos))):e.morph(r).at(s.ease(this.pos)):(r.relative||r.undo(e.extract()),e=e.multiply(r.at(s.ease(this.pos))))}n.matrix(e)}return this},once:function(t,e,i){return i||(t=this.situation.ease(t)),this.situation.once[t]=e,this}},parent:g.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new g.FX(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new g.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),g.MorphObj=g.invent({create:function(t,e){return g.Color.isColor(e)?new g.Color(t).morph(e):g.regex.numberAndUnit.test(e)?new g.Number(t).morph(e):(this.value=0,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),g.extend(g.FX,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,new g.MorphObj(null,e),"attrs");return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.add(t,new g.MorphObj(null,e),"styles");return this},x:function(t,e){if(this.target()instanceof g.G)return this.transform({x:t},e),this;var i=(new g.Number).morph(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof g.G)return this.transform({y:t},e),this;var i=(new g.Number).morph(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",(new g.Number).morph(t))},cy:function(t){return this.add("cy",(new g.Number).morph(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof g.Text)this.attr("font-size",t);else{var i;t&&e||(i=this.target().bbox()),t||(t=i.width/i.height*e),e||(e=i.height/i.width*t),this.add("width",(new g.Number).morph(t)).add("height",(new g.Number).morph(e))}return this},plot:function(t){return this.add("plot",this.target().array().morph(t))},leading:function(t){return this.target().leading?this.add("leading",(new g.Number).morph(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof g.Container&&this.add("viewbox",new g.ViewBox(t,e,i,n)),this},update:function(t){if(this.target()instanceof g.Stop){if("number"==typeof t||t instanceof g.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),g.BBox=g.invent({create:function(t){if(t){var i;try{if(!e.documentElement.contains(t.node))throw new Exception("Element not in the dom");i=t.node.getBBox()}catch(e){if(t instanceof g.Shape){var n=t.clone(g.parser.draw).show();i=n.bbox(),n.remove()}else i={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=i.x,this.y=i.y,this.width=i.width,this.height=i.height}x(this)},parent:g.Element,construct:{bbox:function(){return new g.BBox(this)}}}),g.TBox=g.invent({create:function(t){if(t){var e=t.ctm().extract(),i=t.bbox();this.width=i.width*e.scaleX,this.height=i.height*e.scaleY,this.x=i.x+e.x,this.y=i.y+e.y}x(this)},parent:g.Element,construct:{tbox:function(){return new g.TBox(this)}}}),g.RBox=g.invent({create:function(e){if(e){var i=e.doc().parent(),n=e.node.getBoundingClientRect(),s=1;for(this.x=n.left,this.y=n.top,this.x-=i.offsetLeft,this.y-=i.offsetTop;i=i.offsetParent;)this.x-=i.offsetLeft,this.y-=i.offsetTop;for(i=e;i.parent&&(i=i.parent());)i.viewbox&&(s*=i.viewbox().zoom,this.x-=i.x()||0,this.y-=i.y()||0);this.width=n.width/=s,this.height=n.height/=s}x(this),this.x+=t.pageXOffset,this.y+=t.pageYOffset},parent:g.Element,construct:{rbox:function(){return new g.RBox(this)}}}),[g.BBox,g.TBox,g.RBox].forEach(function(t){g.extend(t,{merge:function(e){var i=new t;return i.x=Math.min(this.x,e.x),i.y=Math.min(this.y,e.y),i.width=Math.max(this.x+this.width,e.x+e.width)-i.x,i.height=Math.max(this.y+this.height,e.y+e.height)-i.y,x(i)}})}),g.Matrix=g.invent({create:function(t){var e,i=l([1,0,0,1,0,0]);for(t=t instanceof g.Element?t.matrixify():"string"==typeof t?d(t):6==arguments.length?l([].slice.call(arguments)):"object"==typeof t?t:i,e=w.length-1;e>=0;--e)this[w[e]]=t&&"number"==typeof t[w[e]]?t[w[e]]:i[w[e]]},extend:{extract:function(){var t=u(this,0,1),e=u(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new g.Matrix(this)}},clone:function(){return new g.Matrix(this)},morph:function(t){return this.destination=new g.Matrix(t),this},at:function(t){if(!this.destination)return this;var e=new g.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t});if(this.param&&this.param.to){var i={rotation:this.param.from.rotation+(this.param.to.rotation-this.param.from.rotation)*t,cx:this.param.from.cx,cy:this.param.from.cy};e=e.rotate((this.param.to.rotation-2*this.param.from.rotation)*t,i.cx,i.cy),e.param=i}return e},multiply:function(t){return new g.Matrix(this.native().multiply(c(t).native()))},inverse:function(){return new g.Matrix(this.native().inverse())},translate:function(t,e){return new g.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),this.around(i,n,new g.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=g.utils.radians(t),this.around(e,i,new g.Matrix(Math.cos(t),Math.sin(t),(-Math.sin(t)),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):this.scale(1,-1,0,e)},skew:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),t=g.utils.radians(t),e=g.utils.radians(e),this.around(i,n,new g.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,i){return this.skew(t,0,e,i)},skewY:function(t,e,i){return this.skew(0,t,e,i)},around:function(t,e,i){return this.multiply(new g.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new g.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=g.parser.native.createSVGMatrix(),e=w.length-1;e>=0;e--)t[w[e]]=this[w[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:g.Element,construct:{ctm:function(){return new g.Matrix(this.node.getCTM())},screenCTM:function(){return new g.Matrix(this.node.getScreenCTM())}}}),g.Point=g.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=e?{x:t,y:e}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new g.Point(this)},morph:function(t){return this.destination=new g.Point(t),this},at:function(t){if(!this.destination)return this;var e=new g.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=g.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new g.Point(this.native().matrixTransform(t.native()))}}}),g.extend(g.Element,{point:function(t,e){return new g.Point(t,e).transform(this.screenCTM().inverse())}}),g.extend(g.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=g.regex.isNumber.test(e[i].nodeValue)?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?g.defaults.attrs[t]:g.regex.isNumber.test(e)?parseFloat(e):e;"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),"fill"!=t&&"stroke"!=t||(g.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof g.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e);
-}))),"number"==typeof e?e=new g.Number(e):g.Color.isColor(e)?e=new g.Color(e):Array.isArray(e)?e=new g.Array(e):e instanceof g.Matrix&&e.param&&(this.param=e.param),"leading"==t?this.leading&&this.leading(e):"string"==typeof i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!=t&&"x"!=t||this.rebuild(t,e)}return this}}),g.extend(g.Element,{transform:function(t,e){var i,n=this;if("object"!=typeof t)return i=new g.Matrix(n).extract(),"string"==typeof t?i[t]:i;if(i=new g.Matrix(n),e=!!e||!!t.relative,null!=t.a)i=e?i.multiply(new g.Matrix(t)):new g.Matrix(t);else if(null!=t.rotation)f(t,n),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var s=i.extract();t.scaleX=1*t.scaleX/s.scaleX,t.scaleY=1*t.scaleY/s.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(f(t,n),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var s=i.extract();i=i.multiply((new g.Matrix).skew(s.skewX,s.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?i=i.flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),g.extend(g.FX,{transform:function(t,e){var i,n=this.target();return"object"!=typeof t?(i=new g.Matrix(n).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new g.Matrix(t):null!=t.rotation?(f(t,n),i=new g.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new g.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(f(t,n),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new g.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?i=(new g.Matrix).morph((new g.Matrix).flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset)):null==t.x&&null==t.y||(i=new g.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),setTimeout(function(){this.start()}.bind(this),0),this):this)}}),g.extend(g.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){var t=(this.attr("transform")||"").split(/\)\s*,?\s*/).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(g.regex.matrixElements).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(l(e[1])):t[e[0]].apply(t,e[1])},new g.Matrix);return t},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.rect(1,1),n=i.screenCTM().inverse();return i.remove(),this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),g.Transformation=g.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.create([].slice.call(arguments));if("object"==typeof t)for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[this.arguments[i]];if(Array.isArray(t))for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[i];this.inversed=!1,e===!0&&(this.inversed=!0)},extend:{at:function(t){for(var e=[],i=0,n=this.arguments.length;i<n;++i)e.push(this[this.arguments[i]]);var s=this._undo||new g.Matrix;return s=(new g.Matrix).morph(g.Matrix.prototype[this.method].apply(s,e)).at(t),this.inversed?s.inverse():s},undo:function(t){for(var e=0,i=this.arguments.length;e<i;++e)t[this.arguments[e]]="undefined"==typeof this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(g[r(this.method)])(t,(!0)).at(1),this}}}),g.Translate=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),g.Rotate=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new g.Matrix).rotate((new g.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){this._undo=t}}}),g.Scale=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),g.Skew=g.invent({parent:g.Matrix,inherit:g.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),g.extend(g.Element,{style:function(t,e){if(0==arguments.length)return this.node.style.cssText||"";if(arguments.length<2)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!g.regex.isCss.test(t))return this.node.style[s(t)];t=t.split(";");for(var i=0;i<t.length;i++)e=t[i].split(":"),this.style(e[0].replace(/\s+/g,""),e[1])}else this.node.style[s(t)]=null===e||g.regex.isBlank.test(e)?"":e;return this}}),g.Parent=g.invent({create:function(t){this.constructor.call(this,t)},inherit:g.Element,extend:{children:function(){return g.utils.map(g.utils.filterSVGElements(this.node.childNodes),function(t){return g.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return g.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,s=this.children();for(i=0,n=s.length;i<n;i++)s[i]instanceof g.Element&&t.apply(s[i],[i,s]),e&&s[i]instanceof g.Container&&s[i].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},defs:function(){return this.doc().defs()}}}),g.extend(g.Parent,{ungroup:function(t,e){return 0===e||this instanceof g.Defs?this:(t=t||(this instanceof g.Doc?this:this.parent(g.Parent)),e=e||1/0,this.each(function(){return this instanceof g.Defs?this:this instanceof g.Parent?this.ungroup(t,e-1):this.toParent(t)}),this.node.firstChild||this.remove(),this)},flatten:function(t,e){return this.ungroup(t,e)}}),g.Container=g.invent({create:function(t){this.constructor.call(this,t)},inherit:g.Parent}),g.ViewBox=g.invent({create:function(t){var e,i,n,s,r,a,o,h,u=[0,0,0,0],l=1,c=1,f=/[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi;if(t instanceof g.Element){for(o=t,h=t,a=(t.attr("viewBox")||"").match(f),r=t.bbox,n=new g.Number(t.width()),s=new g.Number(t.height());"%"==n.unit;)l*=n.value,n=new g.Number(o instanceof g.Doc?o.parent().offsetWidth:o.parent().width()),o=o.parent();for(;"%"==s.unit;)c*=s.value,s=new g.Number(h instanceof g.Doc?h.parent().offsetHeight:h.parent().height()),h=h.parent();this.x=0,this.y=0,this.width=n*l,this.height=s*c,this.zoom=1,a&&(e=parseFloat(a[0]),i=parseFloat(a[1]),n=parseFloat(a[2]),s=parseFloat(a[3]),this.zoom=this.width/this.height>n/s?this.height/s:this.width/n,this.x=e,this.y=i,this.width=n,this.height=s)}else t="string"==typeof t?t.match(f).map(function(t){return parseFloat(t)}):Array.isArray(t)?t:"object"==typeof t?[t.x,t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):u,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3]},extend:{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t){var t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments);return this.destination=new g.ViewBox(t),this},at:function(t){return this.destination?new g.ViewBox([this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t]):this}},parent:g.Container,construct:{viewbox:function(t){return 0==arguments.length?new g.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t))}}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){g.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),g.listeners=[],g.handlerMap=[],g.listenerId=0,g.on=function(t,e,i,n){var s=i.bind(n||t.instance||t),r=(g.handlerMap.indexOf(t)+1||g.handlerMap.push(t))-1,a=e.split(".")[0],o=e.split(".")[1]||"*";g.listeners[r]=g.listeners[r]||{},g.listeners[r][a]=g.listeners[r][a]||{},g.listeners[r][a][o]=g.listeners[r][a][o]||{},i._svgjsListenerId||(i._svgjsListenerId=++g.listenerId),g.listeners[r][a][o][i._svgjsListenerId]=s,t.addEventListener(a,s,!1)},g.off=function(t,e,i){var n=g.handlerMap.indexOf(t),s=e&&e.split(".")[0],r=e&&e.split(".")[1];if(n!=-1)if(i){if("function"==typeof i&&(i=i._svgjsListenerId),!i)return;g.listeners[n][s]&&g.listeners[n][s][r||"*"]&&(t.removeEventListener(s,g.listeners[n][s][r||"*"][i],!1),delete g.listeners[n][s][r||"*"][i])}else if(r&&s){if(g.listeners[n][s]&&g.listeners[n][s][r]){for(i in g.listeners[n][s][r])g.off(t,[s,r].join("."),i);delete g.listeners[n][s][r]}}else if(r)for(e in g.listeners[n])for(namespace in g.listeners[n][e])r===namespace&&g.off(t,[e,r].join("."));else if(s){if(g.listeners[n][s]){for(namespace in g.listeners[n][s])g.off(t,[s,namespace].join("."));delete g.listeners[n][s]}}else{for(e in g.listeners[n])g.off(t,e);delete g.listeners[n]}},g.extend(g.Element,{on:function(t,e,i){return g.on(this.node,t,e,i),this},off:function(t,e){return g.off(this.node,t,e),this},fire:function(t,e){return t instanceof Event?this.node.dispatchEvent(t):this.node.dispatchEvent(new b(t,{detail:e})),this}}),g.Defs=g.invent({create:"defs",inherit:g.Container}),g.G=g.invent({create:"g",inherit:g.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new g.G)}}}),g.extend(g.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof g.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof g.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),g.Mask=g.invent({create:function(){this.constructor.call(this,g.create("mask")),this.targets=[]},inherit:g.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return this.targets=[],this.parent().removeElement(this),this}},construct:{mask:function(){return this.defs().put(new g.Mask)}}}),g.extend(g.Element,{maskWith:function(t){return this.masker=t instanceof g.Mask?t:this.parent().mask().add(t),this.masker.targets.push(this),this.attr("mask",'url("#'+this.masker.attr("id")+'")')},unmask:function(){return delete this.masker,this.attr("mask",null)}}),g.ClipPath=g.invent({create:function(){this.constructor.call(this,g.create("clipPath")),this.targets=[]},inherit:g.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return this.targets=[],this.parent().removeElement(this),this}},construct:{clip:function(){return this.defs().put(new g.ClipPath)}}}),g.extend(g.Element,{clipWith:function(t){return this.clipper=t instanceof g.ClipPath?t:this.parent().clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),g.Gradient=g.invent({create:function(t){this.constructor.call(this,g.create(t+"Gradient")),this.type=t},inherit:g.Container,extend:{at:function(t,e,i){return this.put(new g.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),g.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),g.extend(g.Gradient,g.FX,{from:function(t,e){return"radial"==(this._target||this).type?this.attr({fx:new g.Number(t),fy:new g.Number(e)}):this.attr({x1:new g.Number(t),y1:new g.Number(e)})},to:function(t,e){return"radial"==(this._target||this).type?this.attr({cx:new g.Number(t),cy:new g.Number(e)}):this.attr({x2:new g.Number(t),y2:new g.Number(e)})}}),g.extend(g.Defs,{gradient:function(t,e){return this.put(new g.Gradient(t)).update(e)}}),g.Stop=g.invent({create:"stop",inherit:g.Element,extend:{update:function(t){return("number"==typeof t||t instanceof g.Number)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new g.Number(t.offset)),this}}}),g.Pattern=g.invent({create:"pattern",inherit:g.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),g.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),g.extend(g.Defs,{pattern:function(t,e,i){return this.put(new g.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),g.Doc=g.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,g.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:g.Container,extend:{namespace:function(){return this.attr({xmlns:g.ns,version:"1.1"}).attr("xmlns:xlink",g.xlink,g.xmlns).attr("xmlns:svgjs",g.svgjs,g.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=g.adopt(t):this._defs=new g.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},spof:function(t){var e=this.node.getScreenCTM();return e&&this.style("left",-e.e%1+"px").style("top",-e.f%1+"px"),this},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this}}}),g.Shape=g.invent({create:function(t){this.constructor.call(this,t)},inherit:g.Element}),g.Bare=g.invent({create:function(t,e){if(this.constructor.call(this,g.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:g.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),g.extend(g.Parent,{element:function(t,e){return this.put(new g.Bare(t,e))},symbol:function(){return this.defs().element("symbol",g.Container)}}),g.Use=g.invent({create:"use",inherit:g.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,g.xlink)}},construct:{use:function(t,e){return this.put(new g.Use).element(t,e)}}}),g.Rect=g.invent({create:"rect",inherit:g.Shape,construct:{rect:function(t,e){return this.put(new g.Rect).size(t,e)}}}),g.Circle=g.invent({create:"circle",inherit:g.Shape,construct:{circle:function(t){return this.put(new g.Circle).rx(new g.Number(t).divide(2)).move(0,0)}}}),g.extend(g.Circle,g.FX,{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),g.Ellipse=g.invent({create:"ellipse",inherit:g.Shape,construct:{ellipse:function(t,e){return this.put(new g.Ellipse).size(t,e).move(0,0)}}}),g.extend(g.Ellipse,g.Rect,g.FX,{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),g.extend(g.Circle,g.Ellipse,{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new g.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new g.Number(t).divide(2))},size:function(t,e){var i=h(this,t,e);return this.rx(new g.Number(i.width).divide(2)).ry(new g.Number(i.height).divide(2))}}),g.Line=g.invent({create:"line",inherit:g.Shape,extend:{array:function(){return new g.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return t="undefined"!=typeof e?{x1:t,y1:e,x2:i,y2:n}:new g.PointArray(t).toLine(),this.attr(t)},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var i=h(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return this.put(new g.Line).plot(t,e,i,n)}}}),g.Polyline=g.invent({create:"polyline",inherit:g.Shape,construct:{polyline:function(t){return this.put(new g.Polyline).plot(t)}}}),g.Polygon=g.invent({create:"polygon",inherit:g.Shape,construct:{polygon:function(t){return this.put(new g.Polygon).plot(t)}}}),g.extend(g.Polyline,g.Polygon,{array:function(){return this._array||(this._array=new g.PointArray(this.attr("points")))},plot:function(t){return this.attr("points",this._array=new g.PointArray(t))},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=h(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),g.extend(g.Line,g.Polyline,g.Polygon,{morphArray:g.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),g.Path=g.invent({create:"path",inherit:g.Shape,extend:{morphArray:g.PathArray,array:function(){return this._array||(this._array=new g.PathArray(this.attr("d")))},plot:function(t){return this.attr("d",this._array=new g.PathArray(t))},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var i=h(this,t,e);return this.attr("d",this.array().size(i.width,i.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new g.Path).plot(t)}}}),g.Image=g.invent({create:"image",inherit:g.Shape,extend:{load:function(t){if(!t)return this;var i=this,n=e.createElement("img");return n.onload=function(){var e=i.parent(g.Pattern);null!==e&&(0==i.width()&&0==i.height()&&i.size(n.width,n.height),e&&0==e.width()&&0==e.height()&&e.size(i.width(),i.height()),"function"==typeof i._loaded&&i._loaded.call(i,{width:n.width,height:n.height,ratio:n.width/n.height,url:t}))},n.onerror=function(t){"function"==typeof i._error&&i._error.call(i,t)},this.attr("href",n.src=this.src=t,g.xlink)},loaded:function(t){return this._loaded=t,this},error:function(t){return this._error=t,this}},construct:{image:function(t,e,i){return this.put(new g.Image).load(t).size(e||0,i||e||0)}}}),g.Text=g.invent({create:function(){this.constructor.call(this,g.create("text")),this.dom.leading=new g.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",g.defaults.attrs["font-family"])},inherit:g.Shape,extend:{x:function(t){return null==t?this.attr("x"):(this.textPath||this.lines().each(function(){this.dom.newLined&&this.x(t)}),this.attr("x",t))},y:function(t){var e=this.attr("y"),i="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-i:e:this.attr("y","number"==typeof t?t+i:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if("undefined"==typeof t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i<n;++i)0!=i&&3!=e[i].nodeType&&1==g.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var i=0,s=t.length;i<s;i++)this.tspan(t[i]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new g.Number(t),this.rebuild())},lines:function(){var t=(this.textPath&&this.textPath()||this).node,e=g.utils.map(g.utils.filterSVGElements(t.childNodes),function(t){return g.adopt(t)});return new g.Set(e)},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new g.Number(this.attr("font-size"));this.lines().each(function(){this.dom.newLined&&(this.textPath||this.attr("x",e.attr("x")),"\n"==this.text()?i+=n:(this.attr("dy",n+i),i=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new g.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new g.Text).text(t)},plain:function(t){return this.put(new g.Text).plain(t)}}}),g.Tspan=g.invent({create:"tspan",inherit:g.Shape,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(g.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),g.extend(g.Text,g.Tspan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,i=new g.Tspan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.text(t)},clear:function(){for(var t=(this.textPath&&this.textPath()||this).node;t.hasChildNodes();)t.removeChild(t.lastChild);return this},length:function(){return this.node.getComputedTextLength()}}),g.TextPath=g.invent({create:"textPath",inherit:g.Parent,parent:g.Text,construct:{path:function(t){for(var e=new g.TextPath,i=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+i,g.xlink),this},plot:function(t){var e=this.track();return e&&e.plot(t),this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return g.adopt(this.node.firstChild)}}}),g.Nested=g.invent({create:function(){this.constructor.call(this,g.create("svg")),this.style("overflow","visible")},inherit:g.Container,construct:{nested:function(){return this.put(new g.Nested)}}}),g.A=g.invent({create:"a",inherit:g.Container,extend:{to:function(t){return this.attr("href",t,g.xlink)},show:function(t){return this.attr("show",t,g.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new g.A).to(t)}}}),g.extend(g.Element,{linkTo:function(t){var e=new g.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),g.Marker=g.invent({create:"marker",inherit:g.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,i){return this.defs().marker(t,e,i)}}}),g.extend(g.Defs,{marker:function(t,e,i){return this.put(new g.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),g.extend(g.Line,g.Polyline,g.Polygon,g.Path,{marker:function(t,e,i,n){var s=["marker"];return"all"!=t&&s.push(t),s=s.join("-"),t=arguments[1]instanceof g.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(s,t)}});var y={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"==e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,i={};i[t]=function(i){if("undefined"==typeof i)return this;if("string"==typeof i||g.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=y[t].length-1;e>=0;e--)null!=i[y[t][e]]&&this.attr(y.prefix(t,y[t][e]),i[y[t][e]]);return this},g.extend(g.Element,g.FX,i)}),g.extend(g.Element,g.FX,{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({skew:t,cx:e,cy:i}):this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return this.transform({flip:t,offset:e})},matrix:function(t){return this.attr("transform",new g.Matrix(t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x((this instanceof g.FX?0:this.x())+t,!0)},dy:function(t){return this.y((this instanceof g.FX?0:this.y())+t,!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),g.extend(g.Rect,g.Ellipse,g.Circle,g.Gradient,g.FX,{radius:function(t,e){var i=(this._target||this).type;return"radial"==i||"circle"==i?this.attr("r",new g.Number(t)):this.rx(t).ry(null==e?t:e)}}),g.extend(g.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),g.extend(g.Parent,g.Text,g.FX,{font:function(t){for(var e in t)"leading"==e?this.leading(t[e]):"anchor"==e?this.attr("text-anchor",t[e]):"size"==e||"family"==e||"weight"==e||"stretch"==e||"variant"==e||"style"==e?this.attr("font-"+e,t[e]):this.attr(e,t[e]);return this}}),g.Set=g.invent({create:function(t){Array.isArray(t)?this.members=t:this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;t<e;t++)this.members.push(i[t]);return this},remove:function(t){var e=this.index(t);return e>-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e<i;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},length:function(){return this.members.length},has:function(t){return this.index(t)>=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},first:function(){return this.get(0)},last:function(){return this.get(this.members.length-1)},valueOf:function(){return this.members},bbox:function(){var t=new g.BBox;if(0==this.members.length)return t;var e=this.members[0].rbox();return t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height,this.each(function(){t=t.merge(this.rbox())}),t}},construct:{set:function(t){return new g.Set(t)}}}),g.FX.Set=g.invent({create:function(t){this.set=t}}),g.Set.inherit=function(){var t,e=[];for(var t in g.Shape.prototype)"function"==typeof g.Shape.prototype[t]&&"function"!=typeof g.Set.prototype[t]&&e.push(t);e.forEach(function(t){g.Set.prototype[t]=function(){for(var e=0,i=this.members.length;e<i;e++)this.members[e]&&"function"==typeof this.members[e][t]&&this.members[e][t].apply(this.members[e],arguments);return"animate"==t?this.fx||(this.fx=new g.FX.Set(this)):this}}),e=[];for(var t in g.FX.prototype)"function"==typeof g.FX.prototype[t]&&"function"!=typeof g.FX.Set.prototype[t]&&e.push(t);e.forEach(function(t){g.FX.Set.prototype[t]=function(){for(var e=0,i=this.set.members.length;e<i;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},g.extend(g.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),g.extend(g.Element,{remember:function(t,e){if("object"==typeof arguments[0])for(var e in t)this.remember(e,t[e]);else{if(1==arguments.length)return this.memory()[t];this.memory()[t]=e}return this},forget:function(){if(0==arguments.length)this._memory={};else for(var t=arguments.length-1;t>=0;t--)delete this.memory()[arguments[t]];return this},memory:function(){return this._memory||(this._memory={})}}),g.get=function(t){var i=e.getElementById(v(t)||t);return g.adopt(i)},g.select=function(t,i){return new g.Set(g.utils.map((i||e).querySelectorAll(t),function(t){return g.adopt(t)}))},g.extend(g.Parent,{select:function(t){return g.select(t,this.node)}});var w="abcdef".split("");if("function"!=typeof b){var b=function(t,i){i=i||{bubbles:!1,cancelable:!1,detail:void 0};var n=e.createEvent("CustomEvent");return n.initCustomEvent(t,i.bubbles,i.cancelable,i.detail),n};b.prototype=t.Event.prototype,t.CustomEvent=b}return function(e){for(var i=0,n=["moz","webkit"],s=0;s<n.length&&!t.requestAnimationFrame;++s)e.requestAnimationFrame=e[n[s]+"RequestAnimationFrame"],e.cancelAnimationFrame=e[n[s]+"CancelAnimationFrame"]||e[n[s]+"CancelRequestAnimationFrame"];e.requestAnimationFrame=e.requestAnimationFrame||function(t){var n=(new Date).getTime(),s=Math.max(0,16-(n-i)),r=e.setTimeout(function(){t(n+s)},s);return i=n+s,r},e.cancelAnimationFrame=e.cancelAnimationFrame||e.clearTimeout}(t),g});
\ No newline at end of file
+/*! svg.js v2.3.7 MIT*/;!function(t,e){"function"==typeof define&&define.amd?define(function(){return e(t,t.document)}):"object"==typeof exports?module.exports=t.document?e(t,t.document):function(t){return e(t,t.document)}:t.SVG=e(t,t.document)}("undefined"!=typeof window?window:this,function(t,e){function i(t,e){return t instanceof e}function n(t,e){return(t.matches||t.matchesSelector||t.msMatchesSelector||t.mozMatchesSelector||t.webkitMatchesSelector||t.oMatchesSelector).call(t,e)}function r(t){return t.toLowerCase().replace(/-(.)/g,function(t,e){return e.toUpperCase()})}function s(t){return t.charAt(0).toUpperCase()+t.slice(1)}function a(t){return 4==t.length?["#",t.substring(1,2),t.substring(1,2),t.substring(2,3),t.substring(2,3),t.substring(3,4),t.substring(3,4)].join(""):t}function o(t){var e=t.toString(16);return 1==e.length?"0"+e:e}function h(t,e,i){if(null==e||null==i){var n=t.bbox();null==e?e=n.width/n.height*i:null==i&&(i=n.height/n.width*e)}return{width:e,height:i}}function u(t,e,i){return{x:e*t.a+i*t.c+0,y:e*t.b+i*t.d+0}}function l(t){return{a:t[0],b:t[1],c:t[2],d:t[3],e:t[4],f:t[5]}}function c(t){return t instanceof A.Matrix||(t=new A.Matrix(t)),t}function f(t,e){t.cx=null==t.cx?e.bbox().cx:t.cx,t.cy=null==t.cy?e.bbox().cy:t.cy}function d(t){return t=t.replace(A.regex.whitespace,"").replace(A.regex.matrix,"").split(A.regex.matrixElements),l(A.utils.map(t,function(t){return parseFloat(t)}))}function p(t){for(var e=0,i=t.length,n="";e<i;e++)n+=t[e][0],null!=t[e][1]&&(n+=t[e][1],null!=t[e][2]&&(n+=" ",n+=t[e][2],null!=t[e][3]&&(n+=" ",n+=t[e][3],n+=" ",n+=t[e][4],null!=t[e][5]&&(n+=" ",n+=t[e][5],n+=" ",n+=t[e][6],null!=t[e][7]&&(n+=" ",n+=t[e][7])))));return n+" "}function m(t){for(var e=t.childNodes.length-1;e>=0;e--)t.childNodes[e]instanceof SVGElement&&m(t.childNodes[e]);return A.adopt(t).id(A.eid(t.nodeName))}function x(t){return null==t.x&&(t.x=0,t.y=0,t.width=0,t.height=0),t.w=t.width,t.h=t.height,t.x2=t.x+t.width,t.y2=t.y+t.height,t.cx=t.x+t.width/2,t.cy=t.y+t.height/2,t}function v(t){var e=t.toString().match(A.regex.reference);if(e)return e[1]}function y(t){t=new A.PathArray(t);var e,i,n,r,s,a,o,h,u,l=[],c=null,f=null,d=null,p=null,m=null;for(e=0,i=t.value.length;e<i;e++)switch(r=m,m=t.value[e][0],n=t.value[e].slice(1),m){case"M":d&&c.push([p,d,d.clone()]),c=[],l.push(c),f=new A.Point(n),d=f.clone(),p=f.clone();break;case"L":c.push([p,d,d.clone()]),d=new A.Point(n),p=d.clone();break;case"H":c.push([p,d,d.clone()]),d=new A.Point(n[0],d.y),p=d.clone();break;case"V":c.push([p,d,d.clone()]),d=new A.Point(d.x,n[0]),p=d.clone();break;case"C":c.push([p,d,new A.Point(n.slice(0,2))]),d=new A.Point(n.slice(4,6)),p=new A.Point(n.slice(2,4));break;case"S":"C"===r||"S"===r?c.push([p,d,d.times(2).minus(p)]):c.push([p,d,d.clone()]),d=new A.Point(n.slice(2,4)),p=new A.Point(n.slice(0,2));break;case"Q":s=d,a=new A.Point(n.slice(0,2)),o=new A.Point(n.slice(2,4)),c.push([p,s,s.times(1/3).plus(a.times(2/3))]),d=o,p=a.times(2/3).plus(o.times(1/3));break;case"T":s=d,a="Q"===r||"T"===r?s.times(2).minus(a):s,o=new A.Point(n.slice(0,2)),c.push([p,s,s.times(1/3).plus(a.times(2/3))]),d=o,p=a.times(2/3).plus(o.times(1/3));break;case"A":h=w(d,n),h[0][0]=p,u=h.pop(),d=u[1],p=u[0],Array.prototype.push.apply(c,h);break;case"Z":c.push([p,d,d.clone()]),d.x!=f.x&&d.y!=f.y?(d=f,p=f.clone()):(d=null,p=null)}return d&&c.push([p,d,d.clone()]),l}function g(t){var e,i,n,r,s,a=[],o=new A.PathArray;for(e=0,i=t.length;e<i;e++)if(s=t[e],s.length)for(a.push(["M"].concat(s[0][1].toArray())),n=1,r=s.length;n<r;n++)a.push(["C"].concat(s[n-1][2].toArray(),s[n][0].toArray(),s[n][1].toArray()));return o.value=a,o}function w(t,e){var i,n,r,s,a,o,h,u,l,c,f,d,p,m,x,v,y,g,w,b,M,P,C=Math.abs(e[0]),k=Math.abs(e[1]),N=e[2]%360,S=e[3],E=e[4],T=e[5],X=e[6],_=t,F=new A.Point(T,X);if(0===C||0===k||_.x===F.x&&_.y===F.y)return[[_,_.clone(),_.clone()],[F,F.clone(),F.clone()]];for(i=_.minus(F).divide(2).transform((new A.Matrix).rotate(N)),n=i.x*i.x/(C*C)+i.y*i.y/(k*k),n>1&&(n=Math.sqrt(n),C=n*C,k=n*k),r=(new A.Matrix).rotate(N).scale(1/C,1/k).rotate(-N),_=_.transform(r),F=F.transform(r),s=[F.x-_.x,F.y-_.y],o=s[0]*s[0]+s[1]*s[1],a=Math.sqrt(o),s[0]/=a,s[1]/=a,h=o<4?Math.sqrt(1-o/4):0,S===E&&(h*=-1),u=new A.Point((F.x+_.x)/2+h*-s[1],(F.y+_.y)/2+h*s[0]),l=_.minus(u),c=F.minus(u),f=Math.acos(l.x/l.norm()),l.y<0&&(f*=-1),d=Math.acos(c.x/c.norm()),c.y<0&&(d*=-1),E&&f>d&&(d+=2*Math.PI),!E&&f<d&&(d-=2*Math.PI),m=Math.ceil(2*Math.abs(f-d)/Math.PI),v=[],y=f,p=(d-f)/m,x=4*Math.tan(p/4)/3,M=0;M<=m;M++)w=Math.cos(y),g=Math.sin(y),b=u.plus(w,g),v[M]=[b.plus(+x*g,-x*w),b,b.plus(-x*g,+x*w)],y+=p;for(v[0][0]=v[0][1].clone(),v[v.length-1][2]=v[v.length-1][1].clone(),r=(new A.Matrix).rotate(N).scale(C,k).rotate(-N),M=0,P=v.length;M<P;M++)v[M][0]=v[M][0].transform(r),v[M][1]=v[M][1].transform(r),v[M][2]=v[M][2].transform(r);return v}function b(t,e,i){t=[t[0].clone(),t[1].clone(),t[2].clone()],e=[e[0].clone(),e[1].clone(),e[2].clone()];var n=t[1].morph(t[2]).at(i),r=t[2].morph(e[0]).at(i),s=e[0].morph(e[1]).at(i),a=n.morph(r).at(i),o=r.morph(s).at(i),h=a.morph(o).at(i);return[[t[0],t[1],n],[a,h,o],[s,e[1],e[2]]]}function M(t,i){var n=e.createElementNS(A.ns,"path"),r=["M",t[1].toArray(),"C",t[2].toArray(),i[0].toArray(),i[1].toArray()].join(" ");return n.setAttribute("d",r),n.getTotalLength()}function P(t){var e,i,n,r,s,a,o,h=0,u=[];for(r=0,s=t.length;r<s;r++)for(e=t[r],i=[],u[r]=i,a=1,o=e.length;a<o;a++)n=M(e[a-1],e[a]),i[a-1]=n,h+=n;return u.total=h,u}function C(t,e,i){for(var n=1,r=n,s=M(t,e),a=i*s,o=s-a,h=b(t,e,n),u=4096;Math.abs(o)>.001&&u--;)r/=2,n+=o<0?r:-r,h=b(t,e,n),s=M(h[0],h[1]),o=s-a;return h}function k(t){var e,i,n,r,s=P(t),a=s.total,o=0,h=[];for(e=0,i=s.length;e<i;e++)for(n=0,r=s[e].length;n<r;n++)o+=s[e][n]/a,h.push(o);return h}function N(t,e,i){var n,r,s,a,o,h,u,l,c,f,d,p=0,m=0,x=0,v=i.length;for(l=0,c=t.length;l<c&&x<v;l++)if(n=t[l],!(n.length<2)){if(i[x]<e[p+n.length-2])for(m=p,r=[],t[l]=r,h=e[m-1]||0,r.push(n[0]),f=1,d=n.length;f<d;f++){for(u=h,h=e[m++],s=n[f];x<v&&i[x]<h;)a=(i[x]-u)/(h-u),o=C(r[r.length-1],s,a),r[r.length-1]=o[0],r.push(o[1]),s=o[2],u=i[x++];r.push(s)}p+=n.length-1}}var A=this.SVG=function(t){if(A.supported)return t=new A.Doc(t),A.parser.draw||A.prepare(),t};if(A.ns="http://www.w3.org/2000/svg",A.xmlns="http://www.w3.org/2000/xmlns/",A.xlink="http://www.w3.org/1999/xlink",A.svgjs="http://svgjs.com/svgjs",A.supported=function(){return!!e.createElementNS&&!!e.createElementNS(A.ns,"svg").createSVGRect}(),!A.supported)return!1;A.did=1e3,A.eid=function(t){return"Svgjs"+s(t)+A.did++},A.create=function(t){var i=e.createElementNS(this.ns,t);return i.setAttribute("id",this.eid(t)),i},A.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];A.Set&&A.Set.inherit&&A.Set.inherit()},A.invent=function(t){var e="function"==typeof t.create?t.create:function(){this.constructor.call(this,A.create(t.create))};return t.inherit&&(e.prototype=new t.inherit),t.extend&&A.extend(e,t.extend),t.construct&&A.extend(t.parent||A.Container,t.construct),e},A.adopt=function(t){if(!t)return null;if(t.instance)return t.instance;var e;return e="svg"==t.nodeName?t.parentNode instanceof SVGElement?new A.Nested:new A.Doc:"linearGradient"==t.nodeName?new A.Gradient("linear"):"radialGradient"==t.nodeName?new A.Gradient("radial"):A[s(t.nodeName)]?new(A[s(t.nodeName)]):new A.Element(t),e.type=t.nodeName,e.node=t,t.instance=e,e instanceof A.Doc&&e.namespace().defs(),e.setData(JSON.parse(t.getAttribute("svgjs:data"))||{}),e},A.prepare=function(){var t=e.getElementsByTagName("body")[0],i=(t?new A.Doc(t):new A.Doc(e.documentElement).nested()).size(2,0);A.parser={body:t||e.documentElement,draw:i.style("opacity:0;position:fixed;left:100%;top:100%;overflow:hidden"),poly:i.polyline().node,path:i.path().node,native:A.create("svg")}},A.parser={native:A.create("svg")},e.addEventListener("DOMContentLoaded",function(){A.parser.draw||A.prepare()},!1),A.regex={numberAndUnit:/^([+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?)([a-z%]*)$/i,hex:/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i,rgb:/rgb\((\d+),(\d+),(\d+)\)/,reference:/#([a-z0-9\-_]+)/i,matrix:/matrix\(|\)/g,matrixElements:/,*\s+|,/,whitespace:/\s/g,isHex:/^#[a-f0-9]{3,6}$/i,isRgb:/^rgb\(/,isCss:/[^:]+:[^;]+;?/,isBlank:/^(\s+)?$/,isNumber:/^[+-]?(\d+(\.\d*)?|\.\d+)(e[+-]?\d+)?$/i,isPercent:/^-?[\d\.]+%$/,isImage:/\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i,negExp:/e\-/gi,comma:/,/g,hyphen:/\-/g,pathLetters:/[MLHVCSQTAZ]/gi,isPathLetter:/[MLHVCSQTAZ]/i,whitespaces:/\s+/,X:/X/g},A.utils={map:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)r.push(e(t[i]));return r},filter:function(t,e){var i,n=t.length,r=[];for(i=0;i<n;i++)e(t[i])&&r.push(t[i]);return r},radians:function(t){return t%360*Math.PI/180},degrees:function(t){return 180*t/Math.PI%360},filterSVGElements:function(t){return this.filter(t,function(t){return t instanceof SVGElement})}},A.defaults={attrs:{"fill-opacity":1,"stroke-opacity":1,"stroke-width":0,"stroke-linejoin":"miter","stroke-linecap":"butt",fill:"#000000",stroke:"#000000",opacity:1,x:0,y:0,cx:0,cy:0,width:0,height:0,r:0,rx:0,ry:0,offset:0,"stop-opacity":1,"stop-color":"#000000","font-size":16,"font-family":"Helvetica, Arial, sans-serif","text-anchor":"start"}},A.Color=function(t){var e;this.r=0,this.g=0,this.b=0,t&&("string"==typeof t?A.regex.isRgb.test(t)?(e=A.regex.rgb.exec(t.replace(/\s/g,"")),this.r=parseInt(e[1]),this.g=parseInt(e[2]),this.b=parseInt(e[3])):A.regex.isHex.test(t)&&(e=A.regex.hex.exec(a(t)),this.r=parseInt(e[1],16),this.g=parseInt(e[2],16),this.b=parseInt(e[3],16)):"object"==typeof t&&(this.r=t.r,this.g=t.g,this.b=t.b))},A.extend(A.Color,{toString:function(){return this.toHex()},toHex:function(){return"#"+o(this.r)+o(this.g)+o(this.b)},toRgb:function(){return"rgb("+[this.r,this.g,this.b].join()+")"},brightness:function(){return this.r/255*.3+this.g/255*.59+this.b/255*.11},morph:function(t){return this.destination=new A.Color(t),this},at:function(t){return this.destination?(t=t<0?0:t>1?1:t,new A.Color({r:~~(this.r+(this.destination.r-this.r)*t),g:~~(this.g+(this.destination.g-this.g)*t),b:~~(this.b+(this.destination.b-this.b)*t)})):this}}),A.Color.test=function(t){return t+="",A.regex.isHex.test(t)||A.regex.isRgb.test(t)},A.Color.isRgb=function(t){return t&&"number"==typeof t.r&&"number"==typeof t.g&&"number"==typeof t.b},A.Color.isColor=function(t){return A.Color.isRgb(t)||A.Color.test(t)},A.Array=function(t,e){t=(t||[]).valueOf(),0==t.length&&e&&(t=e.valueOf()),this.value=this.parse(t)},A.extend(A.Array,{morph:function(t){if(this.destination=this.parse(t),this.value.length!=this.destination.length){for(var e=this.value[this.value.length-1],i=this.destination[this.destination.length-1];this.value.length>this.destination.length;)this.destination.push(i);for(;this.value.length<this.destination.length;)this.value.push(e)}return this},settle:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.indexOf(this.value[t])==-1&&i.push(this.value[t]);return this.value=i},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push(this.value[e]+(this.destination[e]-this.value[e])*t);return new A.Array(n)},toString:function(){return this.value.join(" ")},valueOf:function(){return this.value},parse:function(t){return t=t.valueOf(),Array.isArray(t)?t:this.split(t)},split:function(t){return t.trim().split(/\s+/)},reverse:function(){return this.value.reverse(),this}}),A.PointArray=function(t,e){this.constructor.call(this,t,e||[[0,0]])},A.PointArray.prototype=new A.Array,A.extend(A.PointArray,{toString:function(){for(var t=0,e=this.value.length,i=[];t<e;t++)i.push(this.value[t].join(","));return i.join(" ")},toLine:function(){return{x1:this.value[0][0],y1:this.value[0][1],x2:this.value[1][0],y2:this.value[1][1]}},at:function(t){if(!this.destination)return this;for(var e=0,i=this.value.length,n=[];e<i;e++)n.push([this.value[e][0]+(this.destination[e][0]-this.value[e][0])*t,this.value[e][1]+(this.destination[e][1]-this.value[e][1])*t]);return new A.PointArray(n)},parse:function(t){var e=[];if(t=t.valueOf(),Array.isArray(t))return t;t=t.trim().split(/\s+|,/),t.length%2!==0&&t.pop();for(var i=0,n=t.length;i<n;i+=2)e.push([parseFloat(t[i]),parseFloat(t[i+1])]);return e},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n=this.value.length-1;n>=0;n--)this.value[n]=[this.value[n][0]+t,this.value[n][1]+e];return this},size:function(t,e){var i,n=this.bbox();for(i=this.value.length-1;i>=0;i--)this.value[i][0]=(this.value[i][0]-n.x)*t/n.width+n.x,this.value[i][1]=(this.value[i][1]-n.y)*e/n.height+n.y;return this},bbox:function(){return A.parser.poly.setAttribute("points",this.toString()),A.parser.poly.getBBox()}}),A.PathArray=function(t,e){this.constructor.call(this,t,e||[["M",0,0]])},A.PathArray.prototype=new A.Array,A.extend(A.PathArray,{toString:function(){return p(this.value)},move:function(t,e){var i=this.bbox();if(t-=i.x,e-=i.y,!isNaN(t)&&!isNaN(e))for(var n,r=this.value.length-1;r>=0;r--)n=this.value[r][0],"M"==n||"L"==n||"T"==n?(this.value[r][1]+=t,this.value[r][2]+=e):"H"==n?this.value[r][1]+=t:"V"==n?this.value[r][1]+=e:"C"==n||"S"==n||"Q"==n?(this.value[r][1]+=t,this.value[r][2]+=e,this.value[r][3]+=t,this.value[r][4]+=e,"C"==n&&(this.value[r][5]+=t,this.value[r][6]+=e)):"A"==n&&(this.value[r][6]+=t,this.value[r][7]+=e);return this},size:function(t,e){var i,n,r=this.bbox();for(i=this.value.length-1;i>=0;i--)n=this.value[i][0],"M"==n||"L"==n||"T"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y):"H"==n?this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x:"V"==n?this.value[i][1]=(this.value[i][1]-r.y)*e/r.height+r.y:"C"==n||"S"==n||"Q"==n?(this.value[i][1]=(this.value[i][1]-r.x)*t/r.width+r.x,this.value[i][2]=(this.value[i][2]-r.y)*e/r.height+r.y,this.value[i][3]=(this.value[i][3]-r.x)*t/r.width+r.x,this.value[i][4]=(this.value[i][4]-r.y)*e/r.height+r.y,"C"==n&&(this.value[i][5]=(this.value[i][5]-r.x)*t/r.width+r.x,this.value[i][6]=(this.value[i][6]-r.y)*e/r.height+r.y)):"A"==n&&(this.value[i][1]=this.value[i][1]*t/r.width,this.value[i][2]=this.value[i][2]*e/r.height,this.value[i][6]=(this.value[i][6]-r.x)*t/r.width+r.x,this.value[i][7]=(this.value[i][7]-r.y)*e/r.height+r.y);return this},haveSameCommands:function(t){var e,i,n;for(t=new A.PathArray(t),n=this.value.length===t.value.length,e=0,i=this.value.length;n&&e<i;e++)n=this.value[e][0]===t.value[e][0];return n},morph:function(t){var e;return this.destination=new A.PathArray(t),this.haveSameCommands(this.destination)?(this.sourceMorphable=this,this.destinationMorphable=this.destination):(e=A.utils.makePathsMorphable(this.value,this.destination),this.sourceMorphable=e[0],this.destinationMorphable=e[1]),this},at:function(t){if(1===t)return this.destination;if(0===t)return this;var e,i,n,r,s=this.sourceMorphable.value,a=this.destinationMorphable.value,o=[],h=new A.PathArray;for(e=0,i=s.length;e<i;e++){for(o[e]=[s[e][0]],n=1,r=s[e].length;n<r;n++)o[e][n]=s[e][n]+(a[e][n]-s[e][n])*t;"A"===o[e][0]&&(o[e][4]=+(0!=o[e][4]),o[e][5]=+(0!=o[e][5]))}return h.value=o,h},parse:function(t){if(t instanceof A.PathArray)return t.valueOf();var e,i,n,r,s,a,o=0,h=0,u={M:2,L:2,H:1,V:1,C:6,S:4,Q:4,T:2,A:7};if("string"==typeof t){for(t=t.replace(A.regex.negExp,"X").replace(A.regex.pathLetters," $& ").replace(A.regex.hyphen," -").replace(A.regex.comma," ").replace(A.regex.X,"e-").trim().split(A.regex.whitespaces),e=t.length;--e;)if(t[e].indexOf(".")!=t[e].lastIndexOf(".")){var l=t[e].split("."),c=[l.shift(),l.shift()].join(".");t.splice.apply(t,[e,1].concat(c,l.map(function(t){return"."+t})))}}else t=t.reduce(function(t,e){return[].concat.apply(t,e)},[]);var a=[];do{for(A.regex.isPathLetter.test(t[0])?(r=t[0],t.shift()):"M"==r?r="L":"m"==r&&(r="l"),s=[r.toUpperCase()],e=0;e<u[s[0]];++e)s.push(parseFloat(t.shift()));r==s[0]?"M"==r||"L"==r||"C"==r||"Q"==r||"S"==r||"T"==r?(o=s[u[s[0]]-1],h=s[u[s[0]]]):"V"==r?h=s[1]:"H"==r?o=s[1]:"A"==r&&(o=s[6],h=s[7]):"m"==r||"l"==r||"c"==r||"s"==r||"q"==r||"t"==r?(s[1]+=o,s[2]+=h,null!=s[3]&&(s[3]+=o,s[4]+=h),null!=s[5]&&(s[5]+=o,s[6]+=h),o=s[u[s[0]]-1],h=s[u[s[0]]]):"v"==r?(s[1]+=h,h=s[1]):"h"==r?(s[1]+=o,o=s[1]):"a"==r&&(s[6]+=o,s[7]+=h,o=s[6],h=s[7]),"M"==s[0]&&(i=o,n=h),"Z"==s[0]&&(o=i,h=n),a.push(s)}while(t.length);return a},bbox:function(){return A.parser.path.setAttribute("d",this.toString()),A.parser.path.getBBox()}}),A.Number=A.invent({create:function(t,e){this.value=0,this.unit=e||"","number"==typeof t?this.value=isNaN(t)?0:isFinite(t)?t:t<0?-3.4e38:3.4e38:"string"==typeof t?(e=t.match(A.regex.numberAndUnit),e&&(this.value=parseFloat(e[1]),"%"==e[5]?this.value/=100:"s"==e[5]&&(this.value*=1e3),this.unit=e[5])):t instanceof A.Number&&(this.value=t.valueOf(),this.unit=t.unit)},extend:{toString:function(){return("%"==this.unit?~~(1e8*this.value)/1e6:"s"==this.unit?this.value/1e3:this.value)+this.unit},toJSON:function(){return this.toString()},valueOf:function(){return this.value},plus:function(t){return new A.Number(this+new A.Number(t),this.unit)},minus:function(t){return this.plus(-new A.Number(t))},times:function(t){return new A.Number(this*new A.Number(t),this.unit)},divide:function(t){return new A.Number(this/new A.Number(t),this.unit)},to:function(t){var e=new A.Number(this);return"string"==typeof t&&(e.unit=t),e},morph:function(t){return this.destination=new A.Number(t),this},at:function(t){return this.destination?new A.Number(this.destination).minus(this).times(t).plus(this):this}}}),A.Element=A.invent({create:function(t){this._stroke=A.defaults.attrs.stroke,this.dom={},(this.node=t)&&(this.type=t.nodeName,this.node.instance=this,this._stroke=t.getAttribute("stroke")||this._stroke)},extend:{x:function(t){return this.attr("x",t)},y:function(t){return this.attr("y",t)},cx:function(t){return null==t?this.x()+this.width()/2:this.x(t-this.width()/2)},cy:function(t){return null==t?this.y()+this.height()/2:this.y(t-this.height()/2)},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},width:function(t){return this.attr("width",t)},height:function(t){return this.attr("height",t)},size:function(t,e){var i=h(this,t,e);return this.width(new A.Number(i.width)).height(new A.Number(i.height))},clone:function(t){var e=m(this.node.cloneNode(!0));return t?t.add(e):this.after(e),e},remove:function(){return this.parent()&&this.parent().removeElement(this),this},replace:function(t){return this.after(t).remove(),t},addTo:function(t){return t.put(this)},putIn:function(t){return t.add(this)},id:function(t){return this.attr("id",t)},inside:function(t,e){var i=this.bbox();return t>i.x&&e>i.y&&t<i.x+i.width&&e<i.y+i.height},show:function(){return this.style("display","")},hide:function(){return this.style("display","none")},visible:function(){return"none"!=this.style("display")},toString:function(){return this.attr("id")},classes:function(){var t=this.attr("class");return null==t?[]:t.trim().split(/\s+/)},hasClass:function(t){return this.classes().indexOf(t)!=-1},addClass:function(t){if(!this.hasClass(t)){var e=this.classes();e.push(t),this.attr("class",e.join(" "))}return this},removeClass:function(t){return this.hasClass(t)&&this.attr("class",this.classes().filter(function(e){return e!=t}).join(" ")),this},toggleClass:function(t){return this.hasClass(t)?this.removeClass(t):this.addClass(t)},reference:function(t){return A.get(this.attr(t))},parent:function(t){var e=this;if(!e.node.parentNode)return null;if(e=A.adopt(e.node.parentNode),!t)return e;for(;e&&e.node instanceof SVGElement;){if("string"==typeof t?e.matches(t):e instanceof t)return e;e=A.adopt(e.node.parentNode)}},doc:function(){return this instanceof A.Doc?this:this.parent(A.Doc)},parents:function(t){var e=[],i=this;do{if(i=i.parent(t),!i||!i.node)break;e.push(i)}while(i.parent);return e},matches:function(t){return n(this.node,t)},native:function(){return this.node},svg:function(t){var i=e.createElement("svg");if(!(t&&this instanceof A.Parent))return i.appendChild(t=e.createElement("svg")),this.writeDataToDom(),t.appendChild(this.node.cloneNode(!0)),i.innerHTML.replace(/^<svg>/,"").replace(/<\/svg>$/,"");i.innerHTML="<svg>"+t.replace(/\n/,"").replace(/<(\w+)([^<]+?)\/>/g,"<$1$2></$1>")+"</svg>";for(var n=0,r=i.firstChild.childNodes.length;n<r;n++)this.node.appendChild(i.firstChild.firstChild);return this},writeDataToDom:function(){if(this.each||this.lines){var t=this.each?this:this.lines();t.each(function(){this.writeDataToDom()})}return this.node.removeAttribute("svgjs:data"),Object.keys(this.dom).length&&this.node.setAttribute("svgjs:data",JSON.stringify(this.dom)),this},setData:function(t){return this.dom=t,this},is:function(t){return i(this,t)}}}),A.easing={"-":function(t){return t},"<>":function(t){return-Math.cos(t*Math.PI)/2+.5},">":function(t){return Math.sin(t*Math.PI/2)},"<":function(t){return-Math.cos(t*Math.PI/2)+1}},A.morph=function(t){return function(e,i){return new A.MorphObj(e,i).at(t)}},A.Situation=A.invent({create:function(t){this.init=!1,this.reversed=!1,this.reversing=!1,this.duration=new A.Number(t.duration).valueOf(),this.delay=new A.Number(t.delay).valueOf(),this.start=+new Date+this.delay,this.finish=this.start+this.duration,this.ease=t.ease,this.loop=0,this.loops=!1,this.animations={},this.attrs={},this.styles={},this.transforms=[],this.once={}}}),A.FX=A.invent({create:function(t){this._target=t,this.situations=[],this.active=!1,this.situation=null,this.paused=!1,this.lastPos=0,this.pos=0,this.absPos=0,this._speed=1},extend:{animate:function(t,e,i){"object"==typeof t&&(e=t.ease,i=t.delay,t=t.duration);var n=new A.Situation({duration:t||1e3,delay:i||0,ease:A.easing[e||"-"]||e});return this.queue(n),this},delay:function(t){var e=new A.Situation({duration:t,delay:0,ease:A.easing["-"]});return this.queue(e)},target:function(t){return t&&t instanceof A.Element?(this._target=t,this):this._target},timeToAbsPos:function(t){return(t-this.situation.start)/(this.situation.duration/this._speed)},absPosToTime:function(t){return this.situation.duration/this._speed*t+this.situation.start},startAnimFrame:function(){this.stopAnimFrame(),this.animationFrame=requestAnimationFrame(function(){this.step()}.bind(this))},stopAnimFrame:function(){cancelAnimationFrame(this.animationFrame)},start:function(){return!this.active&&this.situation&&(this.active=!0,this.startCurrent()),this},startCurrent:function(){return this.situation.start=+new Date+this.situation.delay/this._speed,this.situation.finish=this.situation.start+this.situation.duration/this._speed,this.initAnimations().step()},queue:function(t){return("function"==typeof t||t instanceof A.Situation)&&this.situations.push(t),this.situation||(this.situation=this.situations.shift()),this},dequeue:function(){return this.situation&&this.situation.stop&&this.situation.stop(),this.situation=this.situations.shift(),this.situation&&(this.situation instanceof A.Situation?this.startCurrent():this.situation.call(this)),this},initAnimations:function(){var t,e=this.situation;if(e.init)return this;for(t in e.animations)"viewbox"==t?e.animations[t]=this.target().viewbox().morph(e.animations[t]):(e.animations[t].value="plot"==t?this.target().array().value:this.target()[t](),e.animations[t].value.value&&(e.animations[t].value=e.animations[t].value.value),e.animations[t].relative&&(e.animations[t].destination.value=e.animations[t].destination.value+e.animations[t].value));for(t in e.attrs)if(e.attrs[t]instanceof A.Color){var i=new A.Color(this.target().attr(t));e.attrs[t].r=i.r,e.attrs[t].g=i.g,e.attrs[t].b=i.b}else e.attrs[t].value=this.target().attr(t);for(t in e.styles)e.styles[t].value=this.target().style(t);return e.initialTransformation=this.target().matrixify(),e.init=!0,this},clearQueue:function(){return this.situations=[],this},clearCurrent:function(){return this.situation=null,this},stop:function(t,e){return this.active||this.start(),e&&this.clearQueue(),this.active=!1,t&&this.situation&&this.atEnd(),this.stopAnimFrame(),this.clearCurrent()},reset:function(){if(this.situation){var t=this.situation;this.stop(),this.situation=t,this.atStart()}return this},finish:function(){for(this.stop(!0,!1);this.dequeue().situation&&this.stop(!0,!1););return this.clearQueue().clearCurrent(),this},atStart:function(){return this.at(0,!0)},atEnd:function(){return this.situation.loops===!0?this.at(this.situation.loop+1,!0):"number"==typeof this.situation.loops?this.at(this.situation.loops,!0):this.at(1,!0)},at:function(t,e){var i=this.situation.duration/this._speed;return this.absPos=t,e||(this.situation.reversed&&(this.absPos=1-this.absPos),this.absPos+=this.situation.loop),this.situation.start=+new Date-this.absPos*i,this.situation.finish=this.situation.start+i,this.step(!0)},speed:function(t){return 0===t?this.pause():t?(this._speed=t,this.at(this.absPos,!0)):this._speed},loop:function(t,e){var i=this.last();return i.loops=null==t||t,i.loop=0,e&&(i.reversing=!0),this},pause:function(){return this.paused=!0,this.stopAnimFrame(),this},play:function(){return this.paused?(this.paused=!1,this.at(this.absPos,!0)):this},reverse:function(t){var e=this.last();return"undefined"==typeof t?e.reversed=!e.reversed:e.reversed=t,this},progress:function(t){return t?this.situation.ease(this.pos):this.pos},after:function(t){var e=this.last(),i=function i(n){n.detail.situation==e&&(t.call(this,e),this.off("finished.fx",i))};return this.target().on("finished.fx",i),this},during:function(t){var e=this.last(),i=function(i){i.detail.situation==e&&t.call(this,i.detail.pos,A.morph(i.detail.pos),i.detail.eased,e)};return this.target().off("during.fx",i).on("during.fx",i),this.after(function(){this.off("during.fx",i)})},afterAll:function(t){var e=function e(i){t.call(this),this.off("allfinished.fx",e)};return this.target().off("allfinished.fx",e).on("allfinished.fx",e),this},duringAll:function(t){var e=function(e){t.call(this,e.detail.pos,A.morph(e.detail.pos),e.detail.eased,e.detail.situation)};return this.target().off("during.fx",e).on("during.fx",e),this.afterAll(function(){this.off("during.fx",e)})},last:function(){return this.situations.length?this.situations[this.situations.length-1]:this.situation},add:function(t,e,i){return this.last()[i||"animations"][t]=e,setTimeout(function(){this.start()}.bind(this),0),this},step:function(t){if(t||(this.absPos=this.timeToAbsPos(+new Date)),this.situation.loops!==!1){var e,i,n;e=Math.max(this.absPos,0),i=Math.floor(e),this.situation.loops===!0||i<this.situation.loops?(this.pos=e-i,n=this.situation.loop,this.situation.loop=i):(this.absPos=this.situation.loops,this.pos=1,n=this.situation.loop-1,this.situation.loop=this.situation.loops),this.situation.reversing&&(this.situation.reversed=this.situation.reversed!=Boolean((this.situation.loop-n)%2))}else this.absPos=Math.min(this.absPos,1),this.pos=this.absPos;this.pos<0&&(this.pos=0),this.situation.reversed&&(this.pos=1-this.pos);var r=this.situation.ease(this.pos);for(var s in this.situation.once)s>this.lastPos&&s<=r&&(this.situation.once[s].call(this.target(),this.pos,r),delete this.situation.once[s]);return this.active&&this.target().fire("during",{pos:this.pos,eased:r,fx:this,situation:this.situation}),this.situation?(this.eachAt(),1==this.pos&&!this.situation.reversed||this.situation.reversed&&0==this.pos?(this.stopAnimFrame(),this.target().fire("finished",{fx:this,situation:this.situation}),this.situations.length||(this.target().fire("allfinished"),this.target().off(".fx"),this.active=!1),this.active?this.dequeue():this.clearCurrent()):!this.paused&&this.active&&this.startAnimFrame(),this.lastPos=r,this):this},eachAt:function(){var t,e,i=this,n=this.target(),r=this.situation;for(t in r.animations)e=[].concat(r.animations[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(i.pos),i.pos):t}),n[t].apply(n,e);for(t in r.attrs)e=[t].concat(r.attrs[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(i.pos),i.pos):t}),n.attr.apply(n,e);for(t in r.styles)e=[t].concat(r.styles[t]).map(function(t){return"string"!=typeof t&&t.at?t.at(r.ease(i.pos),i.pos):t}),n.style.apply(n,e);if(r.transforms.length){for(e=r.initialTransformation,t=0,len=r.transforms.length;t<len;t++){var s=r.transforms[t];s instanceof A.Matrix?e=s.relative?e.multiply((new A.Matrix).morph(s).at(r.ease(this.pos))):e.morph(s).at(r.ease(this.pos)):(s.relative||s.undo(e.extract()),e=e.multiply(s.at(r.ease(this.pos))))}n.matrix(e)}return this},once:function(t,e,i){return i||(t=this.situation.ease(t)),this.situation.once[t]=e,this}},parent:A.Element,construct:{animate:function(t,e,i){return(this.fx||(this.fx=new A.FX(this))).animate(t,e,i)},delay:function(t){return(this.fx||(this.fx=new A.FX(this))).delay(t)},stop:function(t,e){return this.fx&&this.fx.stop(t,e),this},finish:function(){return this.fx&&this.fx.finish(),this},pause:function(){return this.fx&&this.fx.pause(),this},play:function(){return this.fx&&this.fx.play(),this},speed:function(t){if(this.fx){if(null==t)return this.fx.speed();this.fx.speed(t)}return this}}}),A.MorphObj=A.invent({create:function(t,e){return A.Color.isColor(e)?new A.Color(t).morph(e):A.regex.numberAndUnit.test(e)?new A.Number(t).morph(e):(this.value=0,void(this.destination=e))},extend:{at:function(t,e){return e<1?this.value:this.destination},valueOf:function(){return this.value}}}),A.extend(A.FX,{attr:function(t,e,i){if("object"==typeof t)for(var n in t)this.attr(n,t[n]);else this.add(t,new A.MorphObj(null,e),"attrs");return this},style:function(t,e){if("object"==typeof t)for(var i in t)this.style(i,t[i]);else this.add(t,new A.MorphObj(null,e),"styles");return this},x:function(t,e){if(this.target()instanceof A.G)return this.transform({x:t},e),this;var i=(new A.Number).morph(t);return i.relative=e,this.add("x",i)},y:function(t,e){if(this.target()instanceof A.G)return this.transform({y:t},e),this;var i=(new A.Number).morph(t);return i.relative=e,this.add("y",i)},cx:function(t){return this.add("cx",(new A.Number).morph(t))},cy:function(t){return this.add("cy",(new A.Number).morph(t))},move:function(t,e){return this.x(t).y(e)},center:function(t,e){return this.cx(t).cy(e)},size:function(t,e){if(this.target()instanceof A.Text)this.attr("font-size",t);else{var i;t&&e||(i=this.target().bbox()),t||(t=i.width/i.height*e),e||(e=i.height/i.width*t),this.add("width",(new A.Number).morph(t)).add("height",(new A.Number).morph(e))}return this},plot:function(t){return this.add("plot",this.target().array().morph(t))},leading:function(t){return this.target().leading?this.add("leading",(new A.Number).morph(t)):this},viewbox:function(t,e,i,n){return this.target()instanceof A.Container&&this.add("viewbox",new A.ViewBox(t,e,i,n)),this},update:function(t){if(this.target()instanceof A.Stop){if("number"==typeof t||t instanceof A.Number)return this.update({offset:arguments[0],color:arguments[1],opacity:arguments[2]});null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",t.offset)}return this}}),A.BBox=A.invent({create:function(t){if(t){var i;try{if(!e.documentElement.contains(t.node))throw new Exception("Element not in the dom");i=t.node.getBBox()}catch(e){if(t instanceof A.Shape){var n=t.clone(A.parser.draw).show();i=n.bbox(),n.remove()}else i={x:t.node.clientLeft,y:t.node.clientTop,width:t.node.clientWidth,height:t.node.clientHeight}}this.x=i.x,this.y=i.y,this.width=i.width,this.height=i.height}x(this)},parent:A.Element,construct:{bbox:function(){return new A.BBox(this)}}}),A.TBox=A.invent({create:function(t){if(t){var e=t.ctm().extract(),i=t.bbox();this.width=i.width*e.scaleX,this.height=i.height*e.scaleY,this.x=i.x+e.x,this.y=i.y+e.y}x(this)},parent:A.Element,construct:{tbox:function(){return new A.TBox(this)}}}),A.RBox=A.invent({create:function(e){if(e){var i=e.doc().parent(),n=e.node.getBoundingClientRect(),r=1;for(this.x=n.left,this.y=n.top,this.x-=i.offsetLeft,this.y-=i.offsetTop;i=i.offsetParent;)this.x-=i.offsetLeft,
+this.y-=i.offsetTop;for(i=e;i.parent&&(i=i.parent());)i.viewbox&&(r*=i.viewbox().zoom,this.x-=i.x()||0,this.y-=i.y()||0);this.width=n.width/=r,this.height=n.height/=r}x(this),this.x+=t.pageXOffset,this.y+=t.pageYOffset},parent:A.Element,construct:{rbox:function(){return new A.RBox(this)}}}),[A.BBox,A.TBox,A.RBox].forEach(function(t){A.extend(t,{merge:function(e){var i=new t;return i.x=Math.min(this.x,e.x),i.y=Math.min(this.y,e.y),i.width=Math.max(this.x+this.width,e.x+e.width)-i.x,i.height=Math.max(this.y+this.height,e.y+e.height)-i.y,x(i)}})}),A.Matrix=A.invent({create:function(t){var e,i=l([1,0,0,1,0,0]);for(t=t instanceof A.Element?t.matrixify():"string"==typeof t?d(t):6==arguments.length?l([].slice.call(arguments)):"object"==typeof t?t:i,e=E.length-1;e>=0;--e)this[E[e]]=t&&"number"==typeof t[E[e]]?t[E[e]]:i[E[e]]},extend:{extract:function(){var t=u(this,0,1),e=u(this,1,0),i=180/Math.PI*Math.atan2(t.y,t.x)-90;return{x:this.e,y:this.f,transformedX:(this.e*Math.cos(i*Math.PI/180)+this.f*Math.sin(i*Math.PI/180))/Math.sqrt(this.a*this.a+this.b*this.b),transformedY:(this.f*Math.cos(i*Math.PI/180)+this.e*Math.sin(-i*Math.PI/180))/Math.sqrt(this.c*this.c+this.d*this.d),skewX:-i,skewY:180/Math.PI*Math.atan2(e.y,e.x),scaleX:Math.sqrt(this.a*this.a+this.b*this.b),scaleY:Math.sqrt(this.c*this.c+this.d*this.d),rotation:i,a:this.a,b:this.b,c:this.c,d:this.d,e:this.e,f:this.f,matrix:new A.Matrix(this)}},clone:function(){return new A.Matrix(this)},morph:function(t){return this.destination=new A.Matrix(t),this},at:function(t){if(!this.destination)return this;var e=new A.Matrix({a:this.a+(this.destination.a-this.a)*t,b:this.b+(this.destination.b-this.b)*t,c:this.c+(this.destination.c-this.c)*t,d:this.d+(this.destination.d-this.d)*t,e:this.e+(this.destination.e-this.e)*t,f:this.f+(this.destination.f-this.f)*t});if(this.param&&this.param.to){var i={rotation:this.param.from.rotation+(this.param.to.rotation-this.param.from.rotation)*t,cx:this.param.from.cx,cy:this.param.from.cy};e=e.rotate((this.param.to.rotation-2*this.param.from.rotation)*t,i.cx,i.cy),e.param=i}return e},multiply:function(t){return new A.Matrix(this.native().multiply(c(t).native()))},inverse:function(){return new A.Matrix(this.native().inverse())},translate:function(t,e){return new A.Matrix(this.native().translate(t||0,e||0))},scale:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),this.around(i,n,new A.Matrix(t,0,0,e,0,0))},rotate:function(t,e,i){return t=A.utils.radians(t),this.around(e,i,new A.Matrix(Math.cos(t),Math.sin(t),(-Math.sin(t)),Math.cos(t),0,0))},flip:function(t,e){return"x"==t?this.scale(-1,1,e,0):this.scale(1,-1,0,e)},skew:function(t,e,i,n){return 1==arguments.length?e=t:3==arguments.length&&(n=i,i=e,e=t),t=A.utils.radians(t),e=A.utils.radians(e),this.around(i,n,new A.Matrix(1,Math.tan(e),Math.tan(t),1,0,0))},skewX:function(t,e,i){return this.skew(t,0,e,i)},skewY:function(t,e,i){return this.skew(0,t,e,i)},around:function(t,e,i){return this.multiply(new A.Matrix(1,0,0,1,t||0,e||0)).multiply(i).multiply(new A.Matrix(1,0,0,1,-t||0,-e||0))},native:function(){for(var t=A.parser.native.createSVGMatrix(),e=E.length-1;e>=0;e--)t[E[e]]=this[E[e]];return t},toString:function(){return"matrix("+this.a+","+this.b+","+this.c+","+this.d+","+this.e+","+this.f+")"}},parent:A.Element,construct:{ctm:function(){return new A.Matrix(this.node.getCTM())},screenCTM:function(){return new A.Matrix(this.node.getScreenCTM())}}}),A.Point=A.invent({create:function(t,e){var i,n={x:0,y:0};i=Array.isArray(t)?{x:t[0],y:t[1]}:"object"==typeof t?{x:t.x,y:t.y}:null!=t?{x:t,y:null!=e?e:t}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new A.Point(this)},morph:function(t,e){return this.destination=new A.Point(t,e),this},at:function(t){if(!this.destination)return this;var e=new A.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=A.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new A.Point(this.native().matrixTransform(t.native()))},toArray:function(){return[this.x,this.y]},plus:function(t,e){var i=new A.Point(t,e);return new A.Point(this.x+i.x,this.y+i.y)},minus:function(t,e){var i=new A.Point(t,e);return new A.Point(this.x-i.x,this.y-i.y)},times:function(t,e){var i=new A.Point(t,e);return new A.Point(this.x*i.x,this.y*i.y)},divide:function(t,e){var i=new A.Point(t,e);return new A.Point(this.x/i.x,this.y/i.y)},norm:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},distance:function(t,e){return this.minus(t,e).norm()}}}),A.extend(A.Element,{point:function(t,e){return new A.Point(t,e).transform(this.screenCTM().inverse())}}),A.extend(A.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes,i=e.length-1;i>=0;i--)t[e[i].nodeName]=A.regex.isNumber.test(e[i].nodeValue)?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?A.defaults.attrs[t]:A.regex.isNumber.test(e)?parseFloat(e):e;"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),"fill"!=t&&"stroke"!=t||(A.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof A.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new A.Number(e):A.Color.isColor(e)?e=new A.Color(e):Array.isArray(e)?e=new A.Array(e):e instanceof A.Matrix&&e.param&&(this.param=e.param),"leading"==t?this.leading&&this.leading(e):"string"==typeof i?this.node.setAttributeNS(i,t,e.toString()):this.node.setAttribute(t,e.toString()),!this.rebuild||"font-size"!=t&&"x"!=t||this.rebuild(t,e)}return this}}),A.extend(A.Element,{transform:function(t,e){var i,n=this;if("object"!=typeof t)return i=new A.Matrix(n).extract(),"string"==typeof t?i[t]:i;if(i=new A.Matrix(n),e=!!e||!!t.relative,null!=t.a)i=e?i.multiply(new A.Matrix(t)):new A.Matrix(t);else if(null!=t.rotation)f(t,n),i=e?i.rotate(t.rotation,t.cx,t.cy):i.rotate(t.rotation-i.extract().rotation,t.cx,t.cy);else if(null!=t.scale||null!=t.scaleX||null!=t.scaleY){if(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,!e){var r=i.extract();t.scaleX=1*t.scaleX/r.scaleX,t.scaleY=1*t.scaleY/r.scaleY}i=i.scale(t.scaleX,t.scaleY,t.cx,t.cy)}else if(null!=t.skew||null!=t.skewX||null!=t.skewY){if(f(t,n),t.skewX=null!=t.skew?t.skew:null!=t.skewX?t.skewX:0,t.skewY=null!=t.skew?t.skew:null!=t.skewY?t.skewY:0,!e){var r=i.extract();i=i.multiply((new A.Matrix).skew(r.skewX,r.skewY,t.cx,t.cy).inverse())}i=i.skew(t.skewX,t.skewY,t.cx,t.cy)}else t.flip?i=i.flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset):null==t.x&&null==t.y||(e?i=i.translate(t.x,t.y):(null!=t.x&&(i.e=t.x),null!=t.y&&(i.f=t.y)));return this.attr("transform",i)}}),A.extend(A.FX,{transform:function(t,e){var i,n=this.target();return"object"!=typeof t?(i=new A.Matrix(n).extract(),"string"==typeof t?i[t]:i):(e=!!e||!!t.relative,null!=t.a?i=new A.Matrix(t):null!=t.rotation?(f(t,n),i=new A.Rotate(t.rotation,t.cx,t.cy)):null!=t.scale||null!=t.scaleX||null!=t.scaleY?(f(t,n),t.scaleX=null!=t.scale?t.scale:null!=t.scaleX?t.scaleX:1,t.scaleY=null!=t.scale?t.scale:null!=t.scaleY?t.scaleY:1,i=new A.Scale(t.scaleX,t.scaleY,t.cx,t.cy)):null!=t.skewX||null!=t.skewY?(f(t,n),t.skewX=null!=t.skewX?t.skewX:0,t.skewY=null!=t.skewY?t.skewY:0,i=new A.Skew(t.skewX,t.skewY,t.cx,t.cy)):t.flip?i=(new A.Matrix).morph((new A.Matrix).flip(t.flip,null==t.offset?n.bbox()["c"+t.flip]:t.offset)):null==t.x&&null==t.y||(i=new A.Translate(t.x,t.y)),i?(i.relative=e,this.last().transforms.push(i),setTimeout(function(){this.start()}.bind(this),0),this):this)}}),A.extend(A.Element,{untransform:function(){return this.attr("transform",null)},matrixify:function(){var t=(this.attr("transform")||"").split(/\)\s*,?\s*/).slice(0,-1).map(function(t){var e=t.trim().split("(");return[e[0],e[1].split(A.regex.matrixElements).map(function(t){return parseFloat(t)})]}).reduce(function(t,e){return"matrix"==e[0]?t.multiply(l(e[1])):t[e[0]].apply(t,e[1])},new A.Matrix);return t},toParent:function(t){if(this==t)return this;var e=this.screenCTM(),i=t.rect(1,1),n=i.screenCTM().inverse();return i.remove(),this.addTo(t).untransform().transform(n.multiply(e)),this},toDoc:function(){return this.toParent(this.doc())}}),A.Transformation=A.invent({create:function(t,e){if(arguments.length>1&&"boolean"!=typeof e)return this.create([].slice.call(arguments));if("object"==typeof t)for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[this.arguments[i]];if(Array.isArray(t))for(var i=0,n=this.arguments.length;i<n;++i)this[this.arguments[i]]=t[i];this.inversed=!1,e===!0&&(this.inversed=!0)},extend:{at:function(t){for(var e=[],i=0,n=this.arguments.length;i<n;++i)e.push(this[this.arguments[i]]);var r=this._undo||new A.Matrix;return r=(new A.Matrix).morph(A.Matrix.prototype[this.method].apply(r,e)).at(t),this.inversed?r.inverse():r},undo:function(t){for(var e=0,i=this.arguments.length;e<i;++e)t[this.arguments[e]]="undefined"==typeof this[this.arguments[e]]?0:t[this.arguments[e]];return t.cx=this.cx,t.cy=this.cy,this._undo=new(A[s(this.method)])(t,(!0)).at(1),this}}}),A.Translate=A.invent({parent:A.Matrix,inherit:A.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["transformedX","transformedY"],method:"translate"}}),A.Rotate=A.invent({parent:A.Matrix,inherit:A.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["rotation","cx","cy"],method:"rotate",at:function(t){var e=(new A.Matrix).rotate((new A.Number).morph(this.rotation-(this._undo?this._undo.rotation:0)).at(t),this.cx,this.cy);return this.inversed?e.inverse():e},undo:function(t){this._undo=t}}}),A.Scale=A.invent({parent:A.Matrix,inherit:A.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["scaleX","scaleY","cx","cy"],method:"scale"}}),A.Skew=A.invent({parent:A.Matrix,inherit:A.Transformation,create:function(t,e){"object"==typeof t?this.constructor.call(this,t,e):this.constructor.call(this,[].slice.call(arguments))},extend:{arguments:["skewX","skewY","cx","cy"],method:"skew"}}),A.extend(A.Element,{style:function(t,e){if(0==arguments.length)return this.node.style.cssText||"";if(arguments.length<2)if("object"==typeof t)for(e in t)this.style(e,t[e]);else{if(!A.regex.isCss.test(t))return this.node.style[r(t)];t=t.split(";");for(var i=0;i<t.length;i++)e=t[i].split(":"),this.style(e[0].replace(/\s+/g,""),e[1])}else this.node.style[r(t)]=null===e||A.regex.isBlank.test(e)?"":e;return this}}),A.Parent=A.invent({create:function(t){this.constructor.call(this,t)},inherit:A.Element,extend:{children:function(){return A.utils.map(A.utils.filterSVGElements(this.node.childNodes),function(t){return A.adopt(t)})},add:function(t,e){return null==e?this.node.appendChild(t.node):t.node!=this.node.childNodes[e]&&this.node.insertBefore(t.node,this.node.childNodes[e]),this},put:function(t,e){return this.add(t,e),t},has:function(t){return this.index(t)>=0},index:function(t){return[].slice.call(this.node.childNodes).indexOf(t.node)},get:function(t){return A.adopt(this.node.childNodes[t])},first:function(){return this.get(0)},last:function(){return this.get(this.node.childNodes.length-1)},each:function(t,e){var i,n,r=this.children();for(i=0,n=r.length;i<n;i++)r[i]instanceof A.Element&&t.apply(r[i],[i,r]),e&&r[i]instanceof A.Container&&r[i].each(t,e);return this},removeElement:function(t){return this.node.removeChild(t.node),this},clear:function(){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return delete this._defs,this},defs:function(){return this.doc().defs()}}}),A.extend(A.Parent,{ungroup:function(t,e){return 0===e||this instanceof A.Defs?this:(t=t||(this instanceof A.Doc?this:this.parent(A.Parent)),e=e||1/0,this.each(function(){return this instanceof A.Defs?this:this instanceof A.Parent?this.ungroup(t,e-1):this.toParent(t)}),this.node.firstChild||this.remove(),this)},flatten:function(t,e){return this.ungroup(t,e)}}),A.Container=A.invent({create:function(t){this.constructor.call(this,t)},inherit:A.Parent}),A.ViewBox=A.invent({create:function(t){var e,i,n,r,s,a,o,h,u=[0,0,0,0],l=1,c=1,f=/[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[+-]?\d+)?/gi;if(t instanceof A.Element){for(o=t,h=t,a=(t.attr("viewBox")||"").match(f),s=t.bbox,n=new A.Number(t.width()),r=new A.Number(t.height());"%"==n.unit;)l*=n.value,n=new A.Number(o instanceof A.Doc?o.parent().offsetWidth:o.parent().width()),o=o.parent();for(;"%"==r.unit;)c*=r.value,r=new A.Number(h instanceof A.Doc?h.parent().offsetHeight:h.parent().height()),h=h.parent();this.x=0,this.y=0,this.width=n*l,this.height=r*c,this.zoom=1,a&&(e=parseFloat(a[0]),i=parseFloat(a[1]),n=parseFloat(a[2]),r=parseFloat(a[3]),this.zoom=this.width/this.height>n/r?this.height/r:this.width/n,this.x=e,this.y=i,this.width=n,this.height=r)}else t="string"==typeof t?t.match(f).map(function(t){return parseFloat(t)}):Array.isArray(t)?t:"object"==typeof t?[t.x,t.y,t.width,t.height]:4==arguments.length?[].slice.call(arguments):u,this.x=t[0],this.y=t[1],this.width=t[2],this.height=t[3]},extend:{toString:function(){return this.x+" "+this.y+" "+this.width+" "+this.height},morph:function(t){var t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments);return this.destination=new A.ViewBox(t),this},at:function(t){return this.destination?new A.ViewBox([this.x+(this.destination.x-this.x)*t,this.y+(this.destination.y-this.y)*t,this.width+(this.destination.width-this.width)*t,this.height+(this.destination.height-this.height)*t]):this}},parent:A.Container,construct:{viewbox:function(t){return 0==arguments.length?new A.ViewBox(this):(t=1==arguments.length?[t.x,t.y,t.width,t.height]:[].slice.call(arguments),this.attr("viewBox",t))}}}),["click","dblclick","mousedown","mouseup","mouseover","mouseout","mousemove","touchstart","touchmove","touchleave","touchend","touchcancel"].forEach(function(t){A.Element.prototype[t]=function(e){var i=this;return this.node["on"+t]="function"==typeof e?function(){return e.apply(i,arguments)}:null,this}}),A.listeners=[],A.handlerMap=[],A.listenerId=0,A.on=function(t,e,i,n){var r=i.bind(n||t.instance||t),s=(A.handlerMap.indexOf(t)+1||A.handlerMap.push(t))-1,a=e.split(".")[0],o=e.split(".")[1]||"*";A.listeners[s]=A.listeners[s]||{},A.listeners[s][a]=A.listeners[s][a]||{},A.listeners[s][a][o]=A.listeners[s][a][o]||{},i._svgjsListenerId||(i._svgjsListenerId=++A.listenerId),A.listeners[s][a][o][i._svgjsListenerId]=r,t.addEventListener(a,r,!1)},A.off=function(t,e,i){var n=A.handlerMap.indexOf(t),r=e&&e.split(".")[0],s=e&&e.split(".")[1];if(n!=-1)if(i){if("function"==typeof i&&(i=i._svgjsListenerId),!i)return;A.listeners[n][r]&&A.listeners[n][r][s||"*"]&&(t.removeEventListener(r,A.listeners[n][r][s||"*"][i],!1),delete A.listeners[n][r][s||"*"][i])}else if(s&&r){if(A.listeners[n][r]&&A.listeners[n][r][s]){for(i in A.listeners[n][r][s])A.off(t,[r,s].join("."),i);delete A.listeners[n][r][s]}}else if(s)for(e in A.listeners[n])for(namespace in A.listeners[n][e])s===namespace&&A.off(t,[e,s].join("."));else if(r){if(A.listeners[n][r]){for(namespace in A.listeners[n][r])A.off(t,[r,namespace].join("."));delete A.listeners[n][r]}}else{for(e in A.listeners[n])A.off(t,e);delete A.listeners[n]}},A.extend(A.Element,{on:function(t,e,i){return A.on(this.node,t,e,i),this},off:function(t,e){return A.off(this.node,t,e),this},fire:function(t,e){return t instanceof Event?this.node.dispatchEvent(t):this.node.dispatchEvent(new T(t,{detail:e})),this}}),A.Defs=A.invent({create:"defs",inherit:A.Container}),A.G=A.invent({create:"g",inherit:A.Container,extend:{x:function(t){return null==t?this.transform("x"):this.transform({x:t-this.x()},!0)},y:function(t){return null==t?this.transform("y"):this.transform({y:t-this.y()},!0)},cx:function(t){return null==t?this.gbox().cx:this.x(t-this.gbox().width/2)},cy:function(t){return null==t?this.gbox().cy:this.y(t-this.gbox().height/2)},gbox:function(){var t=this.bbox(),e=this.transform();return t.x+=e.x,t.x2+=e.x,t.cx+=e.x,t.y+=e.y,t.y2+=e.y,t.cy+=e.y,t}},construct:{group:function(){return this.put(new A.G)}}}),A.extend(A.Element,{siblings:function(){return this.parent().children()},position:function(){return this.parent().index(this)},next:function(){return this.siblings()[this.position()+1]},previous:function(){return this.siblings()[this.position()-1]},forward:function(){var t=this.position()+1,e=this.parent();return e.removeElement(this).add(this,t),e instanceof A.Doc&&e.node.appendChild(e.defs().node),this},backward:function(){var t=this.position();return t>0&&this.parent().removeElement(this).add(this,t-1),this},front:function(){var t=this.parent();return t.node.appendChild(this.node),t instanceof A.Doc&&t.node.appendChild(t.defs().node),this},back:function(){return this.position()>0&&this.parent().removeElement(this).add(this,0),this},before:function(t){t.remove();var e=this.position();return this.parent().add(t,e),this},after:function(t){t.remove();var e=this.position();return this.parent().add(t,e+1),this}}),A.Mask=A.invent({create:function(){this.constructor.call(this,A.create("mask")),this.targets=[]},inherit:A.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unmask();return this.targets=[],this.parent().removeElement(this),this}},construct:{mask:function(){return this.defs().put(new A.Mask)}}}),A.extend(A.Element,{maskWith:function(t){return this.masker=t instanceof A.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)}}),A.ClipPath=A.invent({create:function(){this.constructor.call(this,A.create("clipPath")),this.targets=[]},inherit:A.Container,extend:{remove:function(){for(var t=this.targets.length-1;t>=0;t--)this.targets[t]&&this.targets[t].unclip();return this.targets=[],this.parent().removeElement(this),this}},construct:{clip:function(){return this.defs().put(new A.ClipPath)}}}),A.extend(A.Element,{clipWith:function(t){return this.clipper=t instanceof A.ClipPath?t:this.parent().clip().add(t),this.clipper.targets.push(this),this.attr("clip-path",'url("#'+this.clipper.attr("id")+'")')},unclip:function(){return delete this.clipper,this.attr("clip-path",null)}}),A.Gradient=A.invent({create:function(t){this.constructor.call(this,A.create(t+"Gradient")),this.type=t},inherit:A.Container,extend:{at:function(t,e,i){return this.put(new A.Stop).update(t,e,i)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},fill:function(){return"url(#"+this.id()+")"},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="gradientTransform"),A.Container.prototype.attr.call(this,t,e,i)}},construct:{gradient:function(t,e){return this.defs().gradient(t,e)}}}),A.extend(A.Gradient,A.FX,{from:function(t,e){return"radial"==(this._target||this).type?this.attr({fx:new A.Number(t),fy:new A.Number(e)}):this.attr({x1:new A.Number(t),y1:new A.Number(e)})},to:function(t,e){return"radial"==(this._target||this).type?this.attr({cx:new A.Number(t),cy:new A.Number(e)}):this.attr({x2:new A.Number(t),y2:new A.Number(e)})}}),A.extend(A.Defs,{gradient:function(t,e){return this.put(new A.Gradient(t)).update(e)}}),A.Stop=A.invent({create:"stop",inherit:A.Element,extend:{update:function(t){return("number"==typeof t||t instanceof A.Number)&&(t={offset:arguments[0],color:arguments[1],opacity:arguments[2]}),null!=t.opacity&&this.attr("stop-opacity",t.opacity),null!=t.color&&this.attr("stop-color",t.color),null!=t.offset&&this.attr("offset",new A.Number(t.offset)),this}}}),A.Pattern=A.invent({create:"pattern",inherit:A.Container,extend:{fill:function(){return"url(#"+this.id()+")"},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return this.fill()},attr:function(t,e,i){return"transform"==t&&(t="patternTransform"),A.Container.prototype.attr.call(this,t,e,i)}},construct:{pattern:function(t,e,i){return this.defs().pattern(t,e,i)}}}),A.extend(A.Defs,{pattern:function(t,e,i){return this.put(new A.Pattern).update(i).attr({x:0,y:0,width:t,height:e,patternUnits:"userSpaceOnUse"})}}),A.Doc=A.invent({create:function(t){t&&(t="string"==typeof t?e.getElementById(t):t,"svg"==t.nodeName?this.constructor.call(this,t):(this.constructor.call(this,A.create("svg")),t.appendChild(this.node),this.size("100%","100%")),this.namespace().defs())},inherit:A.Container,extend:{namespace:function(){return this.attr({xmlns:A.ns,version:"1.1"}).attr("xmlns:xlink",A.xlink,A.xmlns).attr("xmlns:svgjs",A.svgjs,A.xmlns)},defs:function(){if(!this._defs){var t;(t=this.node.getElementsByTagName("defs")[0])?this._defs=A.adopt(t):this._defs=new A.Defs,this.node.appendChild(this._defs.node)}return this._defs},parent:function(){return"#document"==this.node.parentNode.nodeName?null:this.node.parentNode},spof:function(t){var e=this.node.getScreenCTM();return e&&this.style("left",-e.e%1+"px").style("top",-e.f%1+"px"),this},remove:function(){return this.parent()&&this.parent().removeChild(this.node),this}}}),A.Shape=A.invent({create:function(t){this.constructor.call(this,t)},inherit:A.Element}),A.Bare=A.invent({create:function(t,e){if(this.constructor.call(this,A.create(t)),e)for(var i in e.prototype)"function"==typeof e.prototype[i]&&(this[i]=e.prototype[i])},inherit:A.Element,extend:{words:function(t){for(;this.node.hasChildNodes();)this.node.removeChild(this.node.lastChild);return this.node.appendChild(e.createTextNode(t)),this}}}),A.extend(A.Parent,{element:function(t,e){return this.put(new A.Bare(t,e))},symbol:function(){return this.defs().element("symbol",A.Container)}}),A.Use=A.invent({create:"use",inherit:A.Shape,extend:{element:function(t,e){return this.attr("href",(e||"")+"#"+t,A.xlink)}},construct:{use:function(t,e){return this.put(new A.Use).element(t,e)}}}),A.Rect=A.invent({create:"rect",inherit:A.Shape,construct:{rect:function(t,e){return this.put(new A.Rect).size(t,e)}}}),A.Circle=A.invent({create:"circle",inherit:A.Shape,construct:{circle:function(t){return this.put(new A.Circle).rx(new A.Number(t).divide(2)).move(0,0)}}}),A.extend(A.Circle,A.FX,{rx:function(t){return this.attr("r",t)},ry:function(t){return this.rx(t)}}),A.Ellipse=A.invent({create:"ellipse",inherit:A.Shape,construct:{ellipse:function(t,e){return this.put(new A.Ellipse).size(t,e).move(0,0)}}}),A.extend(A.Ellipse,A.Rect,A.FX,{rx:function(t){return this.attr("rx",t)},ry:function(t){return this.attr("ry",t)}}),A.extend(A.Circle,A.Ellipse,{x:function(t){return null==t?this.cx()-this.rx():this.cx(t+this.rx())},y:function(t){return null==t?this.cy()-this.ry():this.cy(t+this.ry())},cx:function(t){return null==t?this.attr("cx"):this.attr("cx",t)},cy:function(t){return null==t?this.attr("cy"):this.attr("cy",t)},width:function(t){return null==t?2*this.rx():this.rx(new A.Number(t).divide(2))},height:function(t){return null==t?2*this.ry():this.ry(new A.Number(t).divide(2))},size:function(t,e){var i=h(this,t,e);return this.rx(new A.Number(i.width).divide(2)).ry(new A.Number(i.height).divide(2))}}),A.Line=A.invent({create:"line",inherit:A.Shape,extend:{array:function(){return new A.PointArray([[this.attr("x1"),this.attr("y1")],[this.attr("x2"),this.attr("y2")]])},plot:function(t,e,i,n){return t="undefined"!=typeof e?{x1:t,y1:e,x2:i,y2:n}:new A.PointArray(t).toLine(),this.attr(t)},move:function(t,e){return this.attr(this.array().move(t,e).toLine())},size:function(t,e){var i=h(this,t,e);return this.attr(this.array().size(i.width,i.height).toLine())}},construct:{line:function(t,e,i,n){return this.put(new A.Line).plot(t,e,i,n)}}}),A.Polyline=A.invent({create:"polyline",inherit:A.Shape,construct:{polyline:function(t){return this.put(new A.Polyline).plot(t)}}}),A.Polygon=A.invent({create:"polygon",inherit:A.Shape,construct:{polygon:function(t){return this.put(new A.Polygon).plot(t)}}}),A.extend(A.Polyline,A.Polygon,{array:function(){return this._array||(this._array=new A.PointArray(this.attr("points")))},plot:function(t){return this.attr("points",this._array=new A.PointArray(t))},move:function(t,e){return this.attr("points",this.array().move(t,e))},size:function(t,e){var i=h(this,t,e);return this.attr("points",this.array().size(i.width,i.height))}}),A.extend(A.Line,A.Polyline,A.Polygon,{morphArray:A.PointArray,x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},width:function(t){var e=this.bbox();return null==t?e.width:this.size(t,e.height)},height:function(t){var e=this.bbox();return null==t?e.height:this.size(e.width,t)}}),A.Path=A.invent({create:"path",inherit:A.Shape,extend:{morphArray:A.PathArray,array:function(){return this._array||(this._array=new A.PathArray(this.attr("d")))},plot:function(t){return this.attr("d",this._array=new A.PathArray(t))},move:function(t,e){return this.attr("d",this.array().move(t,e))},x:function(t){return null==t?this.bbox().x:this.move(t,this.bbox().y)},y:function(t){return null==t?this.bbox().y:this.move(this.bbox().x,t)},size:function(t,e){var i=h(this,t,e);return this.attr("d",this.array().size(i.width,i.height))},width:function(t){return null==t?this.bbox().width:this.size(t,this.bbox().height)},height:function(t){return null==t?this.bbox().height:this.size(this.bbox().width,t)}},construct:{path:function(t){return this.put(new A.Path).plot(t)}}}),A.Image=A.invent({create:"image",inherit:A.Shape,extend:{load:function(t){if(!t)return this;var i=this,n=e.createElement("img");return n.onload=function(){var e=i.parent(A.Pattern);null!==e&&(0==i.width()&&0==i.height()&&i.size(n.width,n.height),e&&0==e.width()&&0==e.height()&&e.size(i.width(),i.height()),"function"==typeof i._loaded&&i._loaded.call(i,{width:n.width,height:n.height,ratio:n.width/n.height,url:t}))},n.onerror=function(t){"function"==typeof i._error&&i._error.call(i,t)},this.attr("href",n.src=this.src=t,A.xlink)},loaded:function(t){return this._loaded=t,this},error:function(t){return this._error=t,this}},construct:{image:function(t,e,i){return this.put(new A.Image).load(t).size(e||0,i||e||0)}}}),A.Text=A.invent({create:function(){this.constructor.call(this,A.create("text")),this.dom.leading=new A.Number(1.3),this._rebuild=!0,this._build=!1,this.attr("font-family",A.defaults.attrs["font-family"])},inherit:A.Shape,extend:{x:function(t){return null==t?this.attr("x"):(this.textPath||this.lines().each(function(){this.dom.newLined&&this.x(t)}),this.attr("x",t))},y:function(t){var e=this.attr("y"),i="number"==typeof e?e-this.bbox().y:0;return null==t?"number"==typeof e?e-i:e:this.attr("y","number"==typeof t?t+i:t)},cx:function(t){return null==t?this.bbox().cx:this.x(t-this.bbox().width/2)},cy:function(t){return null==t?this.bbox().cy:this.y(t-this.bbox().height/2)},text:function(t){if("undefined"==typeof t){for(var t="",e=this.node.childNodes,i=0,n=e.length;i<n;++i)0!=i&&3!=e[i].nodeType&&1==A.adopt(e[i]).dom.newLined&&(t+="\n"),t+=e[i].textContent;return t}if(this.clear().build(!0),"function"==typeof t)t.call(this,this);else{t=t.split("\n");for(var i=0,r=t.length;i<r;i++)this.tspan(t[i]).newLine()}return this.build(!1).rebuild()},size:function(t){return this.attr("font-size",t).rebuild()},leading:function(t){return null==t?this.dom.leading:(this.dom.leading=new A.Number(t),this.rebuild())},lines:function(){var t=(this.textPath&&this.textPath()||this).node,e=A.utils.map(A.utils.filterSVGElements(t.childNodes),function(t){return A.adopt(t)});return new A.Set(e)},rebuild:function(t){if("boolean"==typeof t&&(this._rebuild=t),this._rebuild){var e=this,i=0,n=this.dom.leading*new A.Number(this.attr("font-size"));this.lines().each(function(){this.dom.newLined&&(this.textPath||this.attr("x",e.attr("x")),"\n"==this.text()?i+=n:(this.attr("dy",n+i),i=0))}),this.fire("rebuild")}return this},build:function(t){return this._build=!!t,this},setData:function(t){return this.dom=t,this.dom.leading=new A.Number(t.leading||1.3),this}},construct:{text:function(t){return this.put(new A.Text).text(t)},plain:function(t){return this.put(new A.Text).plain(t)}}}),A.Tspan=A.invent({create:"tspan",inherit:A.Shape,extend:{text:function(t){return null==t?this.node.textContent+(this.dom.newLined?"\n":""):("function"==typeof t?t.call(this,this):this.plain(t),this)},dx:function(t){return this.attr("dx",t)},dy:function(t){return this.attr("dy",t)},newLine:function(){var t=this.parent(A.Text);return this.dom.newLined=!0,this.dy(t.dom.leading*t.attr("font-size")).attr("x",t.x())}}}),A.extend(A.Text,A.Tspan,{plain:function(t){return this._build===!1&&this.clear(),this.node.appendChild(e.createTextNode(t)),this},tspan:function(t){var e=(this.textPath&&this.textPath()||this).node,i=new A.Tspan;return this._build===!1&&this.clear(),e.appendChild(i.node),i.text(t)},clear:function(){for(var t=(this.textPath&&this.textPath()||this).node;t.hasChildNodes();)t.removeChild(t.lastChild);return this},length:function(){return this.node.getComputedTextLength()}}),A.TextPath=A.invent({create:"textPath",inherit:A.Parent,parent:A.Text,construct:{path:function(t){for(var e=new A.TextPath,i=this.doc().defs().path(t);this.node.hasChildNodes();)e.node.appendChild(this.node.firstChild);return this.node.appendChild(e.node),e.attr("href","#"+i,A.xlink),this},plot:function(t){var e=this.track();return e&&e.plot(t),this},track:function(){var t=this.textPath();if(t)return t.reference("href")},textPath:function(){if(this.node.firstChild&&"textPath"==this.node.firstChild.nodeName)return A.adopt(this.node.firstChild)}}}),A.Nested=A.invent({create:function(){this.constructor.call(this,A.create("svg")),this.style("overflow","visible")},inherit:A.Container,construct:{nested:function(){return this.put(new A.Nested)}}}),A.A=A.invent({create:"a",inherit:A.Container,extend:{to:function(t){return this.attr("href",t,A.xlink)},show:function(t){return this.attr("show",t,A.xlink)},target:function(t){return this.attr("target",t)}},construct:{link:function(t){return this.put(new A.A).to(t)}}}),A.extend(A.Element,{linkTo:function(t){var e=new A.A;return"function"==typeof t?t.call(e,e):e.to(t),this.parent().put(e).put(this)}}),A.Marker=A.invent({create:"marker",inherit:A.Container,extend:{width:function(t){return this.attr("markerWidth",t)},height:function(t){return this.attr("markerHeight",t)},ref:function(t,e){return this.attr("refX",t).attr("refY",e)},update:function(t){return this.clear(),"function"==typeof t&&t.call(this,this),this},toString:function(){return"url(#"+this.id()+")"}},construct:{marker:function(t,e,i){return this.defs().marker(t,e,i)}}}),A.extend(A.Defs,{marker:function(t,e,i){return this.put(new A.Marker).size(t,e).ref(t/2,e/2).viewbox(0,0,t,e).attr("orient","auto").update(i)}}),A.extend(A.Line,A.Polyline,A.Polygon,A.Path,{marker:function(t,e,i,n){var r=["marker"];return"all"!=t&&r.push(t),r=r.join("-"),t=arguments[1]instanceof A.Marker?arguments[1]:this.doc().marker(e,i,n),this.attr(r,t)}});var S={stroke:["color","width","opacity","linecap","linejoin","miterlimit","dasharray","dashoffset"],fill:["color","opacity","rule"],prefix:function(t,e){return"color"==e?t:t+"-"+e}};["fill","stroke"].forEach(function(t){var e,i={};i[t]=function(i){if("undefined"==typeof i)return this;if("string"==typeof i||A.Color.isRgb(i)||i&&"function"==typeof i.fill)this.attr(t,i);else for(e=S[t].length-1;e>=0;e--)null!=i[S[t][e]]&&this.attr(S.prefix(t,S[t][e]),i[S[t][e]]);return this},A.extend(A.Element,A.FX,i)}),A.extend(A.Element,A.FX,{rotate:function(t,e,i){return this.transform({rotation:t,cx:e,cy:i})},skew:function(t,e,i,n){
+return 1==arguments.length||3==arguments.length?this.transform({skew:t,cx:e,cy:i}):this.transform({skewX:t,skewY:e,cx:i,cy:n})},scale:function(t,e,i,n){return 1==arguments.length||3==arguments.length?this.transform({scale:t,cx:e,cy:i}):this.transform({scaleX:t,scaleY:e,cx:i,cy:n})},translate:function(t,e){return this.transform({x:t,y:e})},flip:function(t,e){return this.transform({flip:t,offset:e})},matrix:function(t){return this.attr("transform",new A.Matrix(t))},opacity:function(t){return this.attr("opacity",t)},dx:function(t){return this.x((this instanceof A.FX?0:this.x())+t,!0)},dy:function(t){return this.y((this instanceof A.FX?0:this.y())+t,!0)},dmove:function(t,e){return this.dx(t).dy(e)}}),A.extend(A.Rect,A.Ellipse,A.Circle,A.Gradient,A.FX,{radius:function(t,e){var i=(this._target||this).type;return"radial"==i||"circle"==i?this.attr("r",new A.Number(t)):this.rx(t).ry(null==e?t:e)}}),A.extend(A.Path,{length:function(){return this.node.getTotalLength()},pointAt:function(t){return this.node.getPointAtLength(t)}}),A.extend(A.Parent,A.Text,A.FX,{font:function(t){for(var e in t)"leading"==e?this.leading(t[e]):"anchor"==e?this.attr("text-anchor",t[e]):"size"==e||"family"==e||"weight"==e||"stretch"==e||"variant"==e||"style"==e?this.attr("font-"+e,t[e]):this.attr(e,t[e]);return this}}),A.Set=A.invent({create:function(t){Array.isArray(t)?this.members=t:this.clear()},extend:{add:function(){var t,e,i=[].slice.call(arguments);for(t=0,e=i.length;t<e;t++)this.members.push(i[t]);return this},remove:function(t){var e=this.index(t);return e>-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e<i;e++)t.apply(this.members[e],[e,this.members]);return this},clear:function(){return this.members=[],this},length:function(){return this.members.length},has:function(t){return this.index(t)>=0},index:function(t){return this.members.indexOf(t)},get:function(t){return this.members[t]},first:function(){return this.get(0)},last:function(){return this.get(this.members.length-1)},valueOf:function(){return this.members},bbox:function(){var t=new A.BBox;if(0==this.members.length)return t;var e=this.members[0].rbox();return t.x=e.x,t.y=e.y,t.width=e.width,t.height=e.height,this.each(function(){t=t.merge(this.rbox())}),t}},construct:{set:function(t){return new A.Set(t)}}}),A.FX.Set=A.invent({create:function(t){this.set=t}}),A.Set.inherit=function(){var t,e=[];for(var t in A.Shape.prototype)"function"==typeof A.Shape.prototype[t]&&"function"!=typeof A.Set.prototype[t]&&e.push(t);e.forEach(function(t){A.Set.prototype[t]=function(){for(var e=0,i=this.members.length;e<i;e++)this.members[e]&&"function"==typeof this.members[e][t]&&this.members[e][t].apply(this.members[e],arguments);return"animate"==t?this.fx||(this.fx=new A.FX.Set(this)):this}}),e=[];for(var t in A.FX.prototype)"function"==typeof A.FX.prototype[t]&&"function"!=typeof A.FX.Set.prototype[t]&&e.push(t);e.forEach(function(t){A.FX.Set.prototype[t]=function(){for(var e=0,i=this.set.members.length;e<i;e++)this.set.members[e].fx[t].apply(this.set.members[e].fx,arguments);return this}})},A.extend(A.Element,{data:function(t,e,i){if("object"==typeof t)for(e in t)this.data(e,t[e]);else if(arguments.length<2)try{return JSON.parse(this.attr("data-"+t))}catch(e){return this.attr("data-"+t)}else this.attr("data-"+t,null===e?null:i===!0||"string"==typeof e||"number"==typeof e?e:JSON.stringify(e));return this}}),A.extend(A.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={})}}),A.get=function(t){var i=e.getElementById(v(t)||t);return A.adopt(i)},A.select=function(t,i){return new A.Set(A.utils.map((i||e).querySelectorAll(t),function(t){return A.adopt(t)}))},A.extend(A.Parent,{select:function(t){return A.select(t,this.node)}});var E="abcdef".split("");if(A.utils.makePathsMorphable=function(t,e){var i,n,r,s,a,o,h,u,l,c,f,d,p,m,x;for(i=y(t),s=y(e),n=k(i),a=k(s),r=[],o=[],h=0,u=n.length,l=0,c=a.length;h<u&&l<c;)Math.abs(n[h]-a[l])<1e-6?(h++,l++):n[h]>a[l]?r.push(a[l++]):o.push(n[h++]);for(r=r.concat(a.slice(l)),o=o.concat(n.slice(h)),N(i,n,r),N(s,a,o),f=i,i=[],p=f[h=0],d=s,s=[],m=d[l=0];p&&m;)i.push(p),s.push(m),u=p.length,c=m.length,u>c?(x=p[c-1],p=p.splice(c),p.unshift(x),m=d[++l]):u<c?(x=m[u-1],m=m.splice(u),m.unshift(x),p=f[++h]):(p=f[++h],m=d[++l]);return[g(i),g(s)]},"function"!=typeof T){var T=function(t,i){i=i||{bubbles:!1,cancelable:!1,detail:void 0};var n=e.createEvent("CustomEvent");return n.initCustomEvent(t,i.bubbles,i.cancelable,i.detail),n};T.prototype=t.Event.prototype,t.CustomEvent=T}return function(e){for(var i=0,n=["moz","webkit"],r=0;r<n.length&&!t.requestAnimationFrame;++r)e.requestAnimationFrame=e[n[r]+"RequestAnimationFrame"],e.cancelAnimationFrame=e[n[r]+"CancelAnimationFrame"]||e[n[r]+"CancelRequestAnimationFrame"];e.requestAnimationFrame=e.requestAnimationFrame||function(t){var n=(new Date).getTime(),r=Math.max(0,16-(n-i)),s=e.setTimeout(function(){t(n+r)},r);return i=n+r,s},e.cancelAnimationFrame=e.cancelAnimationFrame||e.clearTimeout}(t),A});
\ No newline at end of file
index 2bf1c097652599baec751fa44b4c8f0c14f4a18a..65ef6cca0c668186cb346fe42bef216a4dc7ac71 100644 (file)
@@ -80,6 +80,7 @@ var parts = [
 , 'src/memory.js'\r
 , 'src/selector.js'\r
 , 'src/helpers.js'\r
+, 'src/makepathsmorphable.js'\r
 , 'src/polyfill.js'\r
 ]\r
 \r
index 69ee8ad21e4ceaca388e88c9ad8b640739f2a8e1..e766d8543ffac82fdf818e2291142e0d01c5bdca 100644 (file)
@@ -113,4 +113,93 @@ describe('PathArray', function () {
     })
   })
 
-})
\ No newline at end of file
+  describe('haveSameCommands()', function() {
+    it('return true if the passed path array use the same commands', function() {
+      var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
+        , pathArray2 = new SVG.PathArray('m  -680, 527 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
+
+      expect(pathArray1.haveSameCommands(pathArray2)).toBe(true)
+    })
+    it('return false if the passed path array does not use the same commands', function() {
+      var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205   l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
+        , pathArray2 = new SVG.PathArray('m - 663, 521 c 147,178 118,-25 245,210 l -565,319 c 0,0 -134,-374 51,-251 185,122 268,-278 268,-278 z')
+
+      expect(pathArray1.haveSameCommands(pathArray2)).toBe(false)
+    })
+  })
+
+  describe('morph()', function() {
+    it('should set the attributes sourceMorphable to this path array and destinationMorphable to the passed path array when the passed path array have the same comands as this path array', function() {
+      var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
+        , pathArray2 = new SVG.PathArray('m  -680, 527 a 292,195 0 0 1 262,205 l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
+
+      pathArray1.morph(pathArray2)
+      expect(pathArray1.sourceMorphable).toEqual(pathArray1)
+      expect(pathArray1.destinationMorphable).toEqual(pathArray2)
+      expect(pathArray1.destination).toEqual(pathArray2)
+    })
+    it('should set the attributes sourceMorphable and destinationMorphable to path arrays that use the same commands when the passed path array do not use the same comands as this path array', function() {
+      var pathArray1 = new SVG.PathArray('m -1500,-478 a 292,195 0 0 1 262,205   l -565,319 c 0,0 -134,-374 51,-251 185,122 251,-273 251,-273 z')
+        , pathArray2 = new SVG.PathArray('m - 663, 521 c 147,178 118,-25 245,210 l -565,319 c 0,0 -134,-374 51,-251 185,122 268,-278 268,-278 z')
+
+      pathArray1.morph(pathArray2)
+      expect(pathArray1.sourceMorphable.haveSameCommands(pathArray1.destinationMorphable)).toBe(true)
+      expect(pathArray1.destination).toEqual(pathArray2)
+    })
+  })
+
+  describe('at()', function() {
+    it('should interpolate between sourceMorphable and destinationMorphable', function() {
+      var pathArray1 = new SVG.PathArray("M 19,73 C 19,73 31,45 29,30 26,9 48,24 48,24 l 0,13 c -17,-19 0,0 -29,35 z")
+        , pathArray2 = new SVG.PathArray("M 84,34 111,18 c 0,0 -29,16 -41,52")
+        , interpolatedPathArray = pathArray1.morph(pathArray2).at(0.5)
+        , sourceArray = pathArray1.sourceMorphable.value, destinationArray = pathArray1.destinationMorphable.value
+        , interpolatedArray = interpolatedPathArray.value
+        , i, il, j, jl
+
+      expect(destinationArray.length).toBe(sourceArray.length)
+      expect(interpolatedArray.length).toBe(sourceArray.length)
+
+      // For all the commands
+      for(i = 0, il = sourceArray.length; i < il; i++) {
+        expect(destinationArray[i].length).toBe(sourceArray[i].length)
+        expect(interpolatedArray[i].length).toBe(sourceArray[i].length)
+
+        // Expect the current command to be the same for all the arrays
+        expect(destinationArray[i][0]).toBe(sourceArray[i][0])
+        expect(interpolatedArray[i][0]).toBe(sourceArray[i][0])
+
+        // For all the parameters of the current command
+        for(j = 1, jl = sourceArray[i].length; j < jl; j++) {
+          expect(interpolatedArray[i][j]).toBe((sourceArray[i][j] + destinationArray[i][j]) / 2)
+        }
+      }
+    })
+    it('should interpolate flags and booleans as fractions between zero and one, with any non-zero value considered to be a value of one/true', function() {
+      // Only the Elliptical arc command use flags, it has the following form:
+      // A rx ry x-axis-rotation large-arc-flag sweep-flag x y
+      var pathArray1 = new SVG.PathArray('M  13 13 A 25 37 0 0 1  43 25')
+        , pathArray2 = new SVG.PathArray('M 101 55 A 25 37 0 1 0 130 67')
+        , interpolatedPathArray
+
+      pathArray1.morph(pathArray2)
+
+      // The interpolatedArray contain 2 commands: [['M', ...], ['A', ...]]
+      // Elliptical arc command in a path array followed by corresponding indexes:
+      // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
+      //   0    1   2        3                 4             5      6  7
+      interpolatedPathArray = pathArray1.at(0)
+      expect(interpolatedPathArray.value[1][4]).toBe(0)
+      expect(interpolatedPathArray.value[1][5]).toBe(1)
+
+      interpolatedPathArray = pathArray1.at(0.5)
+      expect(interpolatedPathArray.value[1][4]).toBe(1)
+      expect(interpolatedPathArray.value[1][5]).toBe(1)
+
+      interpolatedPathArray = pathArray1.at(1)
+      expect(interpolatedPathArray.value[1][4]).toBe(1)
+      expect(interpolatedPathArray.value[1][5]).toBe(0)
+    })
+  })
+
+})
diff --git a/spec/spec/makepathsmorphable.js b/spec/spec/makepathsmorphable.js
new file mode 100644 (file)
index 0000000..8a624a7
--- /dev/null
@@ -0,0 +1,225 @@
+describe('makePathsMorphable()', function(){
+  describe('when converting to cubic Bezier curves', function() {
+    describe('for an arc', function() {
+      it('should be able to convert it to cubic Bezier curves when the large-arc-flag and the sweep-flag are not set', function() {
+        var input = new SVG.PathArray('M 273 61 A 67 90 0 0 0 333 155')
+          , expected = new SVG.PathArray('M 273 61 C 271.2271728515625 108.77223205566406 297.5823059082031 150.06198120117188 333 155')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+      it('should be able to convert it to cubic Bezier curves when the sweep-flag is set', function() {
+        var input = new SVG.PathArray('M 273 215 A 67 90 0 0 1 333 309')
+          , expected = new SVG.PathArray('M 273 215 C 308.4176940917969 219.93800354003906 334.7728271484375 261.2277526855469 333 309')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+      it('should be able to convert it to cubic Bezier curves when the large-arc-flag is set', function() {
+        var input = new SVG.PathArray('M 273 419 A 67 90 0 1 0 333 513')
+          , expected = new SVG.PathArray('M 273 419 C 245.72036743164062 415.19659423828125 219.46961975097656 434.1106262207031 206.7387237548828 466.7421875 C 194.0078125 499.3737487792969 197.3677215576172 539.1329345703125 215.21971130371094 567.1010131835938 C 233.07171630859375 595.0692138671875 261.8105773925781 605.59814453125 287.7614440917969 593.6778564453125 C 313.71234130859375 581.7576293945312 331.6344909667969 549.7954711914062 333 513')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+      it('should be able to convert it to cubic Bezier curves when the large-arc-flag and the sweep-flag are set', function() {
+        var input = new SVG.PathArray('M 273 558 A 67 90 0 1 1 333 652')
+          , expected = new SVG.PathArray('M 273 558 C 274.3655090332031 521.20458984375 292.2876281738281 489.242431640625 318.238525390625 477.3221740722656 C 344.1894226074219 465.40191650390625 372.92828369140625 475.9308776855469 390.7802734375 503.8990173339844 C 408.63226318359375 531.8671264648438 411.9921875 571.6262817382812 399.26129150390625 604.2578735351562 C 386.5303649902344 636.889404296875 360.2796325683594 655.803466796875 333 652.0000610351562')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+      it('should be able to convert it to cubic Bezier curves when a x-axis-rotation is provided', function() {
+        var input = new SVG.PathArray('M 71 61 A 67 90 40 0 0 131 155')
+          , expected = new SVG.PathArray('M 71.00001525878906 61.00000762939453 C 59.933311462402344 86.95011138916016 60.439640045166016 113.46055603027344 72.35859680175781 132.13360595703125 C 84.2775650024414 150.806640625 106.13235473632812 159.32861328125 131.00001525878906 155.00001525878906')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+      it('should be able to convert it to cubic Bezier curves even when the radii are not large enough', function() {
+        var input = new SVG.PathArray('M 528 61 A 1 2 0 1 0 588 155')
+          , expected = new SVG.PathArray('M 528 61.000003814697266 C 515.0213012695312 94.1370849609375 517.9314575195312 142.04261779785156 534.5000610351562 168.00001525878906 C 551.0685424804688 193.95738220214844 575.0213012695312 188.1370849609375 588 155.00001525878906')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+    })
+
+    it('should be able to convert a line to a cubic Bezier curve', function() {
+      var input = new SVG.PathArray('M 98 753 L 543 515')
+        , expected = new SVG.PathArray('M 98 753 C 98 753 543 515 543 515')
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+
+    it('should be able to convert a horizontal line to a cubic Bezier curve', function() {
+      var input = new SVG.PathArray('M 104 220 H 367')
+        , expected = new SVG.PathArray('M 104 220 C 104 220 367 220 367 220')
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+
+    it('should be able to convert a vertical line to a cubic Bezier curve', function() {
+      var input = new SVG.PathArray('M 290 449 V 307')
+        , expected = new SVG.PathArray('M 290 449 C 290 449 290 307 290 307')
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+
+    it('should be able to convert a quadratic Bezier curve to a cubic Bezier curve', function() {
+      var input = new SVG.PathArray('M 98 457 Q 224 316 543 219')
+        , expected = new SVG.PathArray('M 98 457 C 181.99999999999997 363 330.3333333333333 283.66666666666663 543 219')
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+
+    it('should be able to convert a smooth quadratic Bezier curve to a cubic Bezier curve', function() {
+      var input = new SVG.PathArray('M 98 753 Q 224 612 543 515 T 723 800')
+        , expected = new SVG.PathArray('M 98 753 C 181.99999999999997 659 330.3333333333333 579.6666666666666 543 515 C 755.6666666666666 450.33333333333326 815.6666666666666 545.3333333333333 723 800')
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+
+    it('should convert a cubic Bezier curve to the same cubic Bezier curve', function() {
+      var input = new SVG.PathArray('M 66 350 C 304 -90 246 429 511 112')
+        , expected = input
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+
+    it('should be able to convert a smooth cubic Bezier curve to a cubic Bezier curve', function() {
+      var input = new SVG.PathArray('M 19 685 C 257 245 199 764 463 447 S 686 485 787 405')
+        , expected = new SVG.PathArray('M 19 685 C 257 245 199 764 463 447 C 727 130 686 485 787 405')
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+
+    describe('when the path end with a closepath command', function() {
+      it('should make a line between the starpoint and endpoint if they do not have the same coordinates', function() {
+        var input = new SVG.PathArray('M 147 225 L 281 90 C 281 90 558 157 217 252 Z')
+          , expected = new SVG.PathArray('M 147 225 C 147 225 281 90 281 90 C 281 90 558 157 217 252 C 217 252 147 225 147 225')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+      it('should not make a line between the starpoint and endpoint if they have the same coordinates', function() {
+        var input = new SVG.PathArray('M 187 473 C 187 473 428 313 424 432 C 420 550 187 473 187 473 Z')
+          , expected = new SVG.PathArray('M 187 473 C 187 473 428 313 424 432 C 420 550 187 473 187 473')
+
+        // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+        expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+      })
+    })
+
+    it('should be able to convert path that have subpaths', function() {
+      var input = new SVG.PathArray('M 205 246 C 205 246 64 232 392 356 C 520 404 385 324 385 324 M 220 224 A 117 87 0 0 1 331 234 A 117 87 0 0 1 379 310')
+        , expected = new SVG.PathArray('M 205 246 C 205 246 64 232 392 356 C 520 404 385 324 385 324 M 220.00001525878906 224.00001525878906 C 256.886474609375 213.12060546875 298.6747131347656 216.88531494140625 331.00006103515625 233.99998474121094 C 363.4692077636719 251.53590393066406 381.58673095703125 280.2220153808594 379.0000305175781 310')
+
+      // use input as the value for the two parameters so that the others parts of the algorithm don't interfere with the results of the conversion
+      expect(SVG.utils.makePathsMorphable(input, input)[0]).toEqual(expected)
+    })
+  })
+
+
+  it('should return two path arrays that use the same commands', function() {
+    var input1 = new SVG.PathArray('M 52 196 C 52 196 196 151 139 31 C 139 31 246 135 139 196')
+      , input2 = new SVG.PathArray('M 325 213 L 389 196 L 442 226 L 508 188')
+      , pathsMorphable = SVG.utils.makePathsMorphable(input1, input2)
+
+    expect(pathsMorphable[0].haveSameCommands(pathsMorphable[1])).toBe(true)
+  })
+
+  it('should return two path arrays that use only moveto and curveto commands', function() {
+    var input1 = new SVG.PathArray('M 73 96 L 104 66 L 91 88 M 69 24 A 63 29 0 0 1 130 27 A 63 29 0 0 1 156 52 C 66 61 69 24 69 24 Z')
+      , input2 = new SVG.PathArray('M 239 70 C 239 70 292 96 354 61 M 264 52 L 243 31 L 318 31 L 333 46 Z')
+      , pathsMorphable = SVG.utils.makePathsMorphable(input1, input2)
+      , i, il, j, jl, array
+
+    for(i = 0, il = pathsMorphable.length; i < il; i++) {
+      array = pathsMorphable[i].value
+      for(j = 0, jl = array.length; j < jl; j++) {
+        expect(array[j][0] === 'M' || array[j][0] === 'C').toBe(true)
+      }
+    }
+  })
+
+  it('should return two path arrays that have the same number of subpath as the passed path array that had the most', function() {
+     // input1 have one subpath
+    var input1 = new SVG.PathArray('M 40 125 L 108 35 C 108 35 96 120 133 126 C 67 126 40 125 40 125 Z')
+     // input2 have two subpath
+      , input2 = new SVG.PathArray('M 197 139 C 197 139 232 131 229 90 C 279 125 243 142 346 145 M 191 79 L 225 22 L 268 98 L 344 73')
+      , numberOfSubpath = 0, expectedNumberOfSubpath = 2
+      , pathsMorphable = SVG.utils.makePathsMorphable(input1, input2)
+      , i, il, j, jl, array
+
+    for(i = 0, il = pathsMorphable.length; i < il; i++) {
+      array = pathsMorphable[i].value
+      numberOfSubpath = 0
+      for(j = 0, jl = array.length; j < jl; j++) {
+        if(array[j][0] === 'M') {
+          numberOfSubpath++
+        }
+      }
+      expect(numberOfSubpath).toBe(expectedNumberOfSubpath)
+    }
+  })
+
+  describe('should return two path arrays that have segment points at the same position relative to the total length of their respective path', function(){
+    it('when the two passed path arrays have only one subpath', function(){
+      var input1 = new SVG.PathArray('M 52 196 C 52 196 196 151 139 31 C 139 31 246 135 139 196')
+        , input2 = new SVG.PathArray('M 325 213 L 389 196 L 442 226 L 508 188')
+        , expected1 = new SVG.PathArray('M 52 196 C 52 196 131.15503639355302 171.26405112701468 148.8625627168421 109.56584499288604 C 155.03864060691558 88.04658138682134 153.7396697998047 62.0308837890625 139 31 C 139 31 152.83611273037968 44.44818433606997 165.58209533253495 64.50917076455009 C 188.28137256170157 100.23571352270665 207.52320098876953 156.93537139892578 139 196')
+        , expected2 = new SVG.PathArray('M 325 213 C 325 213 389 196 389 196 C 389 196 408.3452686788514 206.95015208236873 423.66066663010764 215.61924526232508 C 433.6953197000548 221.29923756606877 442 226 442 226 C 442 226 508 188 508 188')
+        , pathsMorphable = SVG.utils.makePathsMorphable(input1, input2)
+
+        expect(pathsMorphable[0]).toEqual(expected1)
+        expect(pathsMorphable[1]).toEqual(expected2)
+    })
+
+    it('when one of the two passed path arrays have more then one subpath', function(){
+      var input1 = new SVG.PathArray('M 40 125 L 108 35 C 108 35 96 120 133 126 C 67 126 40 125 40 125 Z')
+       // input2 have more than one subpath
+        , input2 = new SVG.PathArray('M 197 139 C 197 139 232 131 229 90 C 279 125 243 142 346 145 M 191 79 L 225 22 L 268 98 L 344 73')
+        , expected1 = new SVG.PathArray('M 40 125 C 40 125 52.79324022307992 108.06777029298246 67.28167847620784 88.8918961344308 C 86.19626173004508 63.85788888670504 108 35 108 35 C 108 35 106.15418140310794 48.07454839465208 106.14249059903192 64.33001882474106 M 106.14249059903192 64.33001882474106 C 106.13151259113593 79.59438229998497 107.73782459669037 97.66360673509575 114.00847226966519 110.34563496202313 C 118.08668296727907 118.59358411812049 124.13779022684321 124.56288490165025 133 126 C 119.25033569335938 126 107.19329706928693 125.95659934147261 96.72038513043016 125.88788119064324 C 56.92209243844263 125.62674416438676 40 125 40 125')
+        , expected2 = new SVG.PathArray('M 197 139 C 197 139 232 131 229 90 C 270.5576934814453 119.09038543701172 252.7051460329676 135.74606928403955 304.63173695701465 142.26375161757144 C 315.18045033159433 143.58779699739534 328.60884857177734 144.49346160888672 346 145 M 191 79 C 191 79 225 22 225 22 C 225 22 233.41753200814128 36.87749843299389 242.8040255255205 53.467579998594374 C 254.63263889029622 74.37396641075611 268 98 268 98 C 268 98 344 73 344 73')
+        , pathsMorphable = SVG.utils.makePathsMorphable(input1, input2)
+
+        expect(pathsMorphable[0]).toEqual(expected1)
+        expect(pathsMorphable[1]).toEqual(expected2)
+    })
+
+    it('when the two passed path arrays have more then one subpath', function(){
+      var input1 = new SVG.PathArray('M 73 96 L 104 66 L 91 88 M 69 24 A 63 29 0 0 1 130 27 A 63 29 0 0 1 156 52 C 66 61 69 24 69 24 Z')
+        , input2 = new SVG.PathArray('M 239 70 C 239 70 292 96 354 61 M 264 52 L 243 31 L 318 31 L 333 46 Z')
+        , expected1 = new SVG.PathArray('M 73 96 C 73 96 104 66 104 66 C 104 66 91 88 91 88 M 69.00000762939453 24 C 79.7054945146665 21.904410892981105 91.26029182381859 21.247896750676198 102.41745719843816 21.96913231193544 M 102.41745719843816 21.96913231193544 C 111.20621436239367 22.537266241395347 119.74823784121546 23.96030449827539 127.43403682459561 26.208272013673316 C 128.30054227911958 26.461710350780116 129.15616464399147 26.725633997668268 130.00003051757812 27 C 147.31700134277344 32.76412582397461 157.10549926757812 42.1761589050293 156 52 C 147.66000366210938 52.83399963378906 140.1186079562176 53.27299250336364 133.2994220425104 53.3830248556465 C 126.57319294537638 53.49155728443149 120.5496180078558 53.28003662293028 115.1553879999344 52.81184480959273 C 67.00277496042524 48.632442154755466 69 24 69 24')
+        , expected2 = new SVG.PathArray('M 239 70 C 239 70 258.71147435647435 79.66977987298742 288.15472192097485 79.27674871180326 C 297.18432917449667 79.15621455482503 307.12922550607357 78.08925667452031 317.7015604164671 75.50671612921313 M 317.7015604164671 75.50671612921313 C 329.183864565392 72.70189427392025 341.4062637425959 68.10936724208295 354 61 M 264 52 C 264 52 243 31 243 31 C 243 31 244.13948627840728 31 246.1375515428337 31 C 253.8394970695019 31 274.29883165997177 31 291.42632264236624 31 C 305.90338310220073 31 318 31 318 31 C 318 31 333 46 333 46 C 333 46 264 52 264 52')
+        , pathsMorphable = SVG.utils.makePathsMorphable(input1, input2)
+
+        expect(pathsMorphable[0]).toEqual(expected1)
+        expect(pathsMorphable[1]).toEqual(expected2)
+    })
+  })
+
+  it('should not duplicate segment points because of the imprecise nature of floating point number', function() {
+    // The two inputs represent the same path but translated
+    var input1 = new SVG.PathArray('M 29.294424 49.280734 C 29.294424 49.280734 39.901025 -8.803036499999997 45.96194 17.460929000000004 C 52.022856 43.724895000000004 34.345186 69.988861 46.972093 75.039624 C 59.599 80.090387 21.213203 74.534548 35.860415 93.22237')
+      , input2 = new SVG.PathArray('M 98.994949 110.39496 C 98.994949 110.39496 109.60155 52.311192 115.66247000000001 78.575158 C 121.72338000000002 104.83912000000001 104.04571000000001 131.10309 116.67262000000001 136.15385 C 129.29953 141.20462 90.913728 135.64878000000002 105.56094000000002 154.3366')
+      , pathsMorphable = SVG.utils.makePathsMorphable(input1, input2)
+
+    // Since the two inputs represent the same path, the algorithm shouldn't
+    // add new segments points as the ones on the two passed path are already at
+    // the same position relative to the total length of their respective path
+    // But, because of imprecision introduced by floating point arithmetic,
+    // the segment points don't end up at the exact same position so the
+    // algorithm must take that into account when comparing their position
+    expect(pathsMorphable[0].haveSameCommands(input1)).toBe(true)
+    expect(pathsMorphable[1].haveSameCommands(input1)).toBe(true)
+  })
+})
index 3cd0bdcf66a18268ed8dc662bd487b78dc535747..7d3823c2c6eefacd890f8effe70bc075b3d3a3b5 100644 (file)
@@ -25,6 +25,15 @@ describe('Point', function() {
       })
     })
 
+    describe('with only x given', function() {
+      it('creates a point using the given value for both x and y', function() {
+        var point = new SVG.Point(7)
+
+        expect(point.x).toBe(7)
+        expect(point.y).toBe(7)
+      })
+    })
+
     describe('with array given', function() {
       it('creates a point from array', function() {
         var point = new SVG.Point([2,4])
@@ -51,7 +60,7 @@ describe('Point', function() {
         expect(point.y).toBe(4)
       })
     })
-    
+
     describe('with native SVGPoint given', function() {
       it('creates a point from native SVGPoint', function() {
         var point = new SVG.Point(new SVG.Point(2,4).native())
@@ -90,6 +99,14 @@ describe('Point', function() {
 
       expect(point1.destination).not.toBe(point2)
     })
+    it('allow passing the point by directly passing its coordinates', function() {
+      var point1 = new SVG.Point(1,1)
+        , point2 = new SVG.Point(2,2)
+
+      point1.morph(point2.x, point2.y)
+
+      expect(point1.destination).toEqual(point2)
+    })
   })
 
   describe('at()', function() {
@@ -117,4 +134,128 @@ describe('Point', function() {
     })
   })
 
-})
\ No newline at end of file
+  describe('toArray()', function() {
+    it('return an array of the x and y coordinates', function() {
+      var point = new SVG.Point(2,-13)
+      expect(point.toArray()).toEqual([point.x, point.y])
+    })
+  })
+
+  describe('plus()', function() {
+    it('perform an element-wise addition with the passed point', function() {
+      var point1 = new SVG.Point(4,3)
+        , point2 = new SVG.Point(2,5)
+        , point3 = point1.plus(point2)
+
+      expect(point3).toEqual(new SVG.Point(point1.x + point2.x, point1.y + point2.y))
+    })
+    it('allow passing the point by directly passing its coordinates', function() {
+      var point1 = new SVG.Point(4,3)
+      , point2 = new SVG.Point(2,5)
+      , point3 = point1.plus(point2.x, point2.y)
+
+      expect(point3).toEqual(new SVG.Point(point1.x + point2.x, point1.y + point2.y))
+    })
+    it('perform an element-wise addition with the passed number', function() {
+      var point1 = new SVG.Point(4,3)
+        , number = 6
+        , point2 = point1.plus(number)
+
+      expect(point2).toEqual(new SVG.Point(point1.x + number, point1.y + number))
+    })
+  })
+
+  describe('minus()', function() {
+    it('perform an element-wise subtraction with the passed point', function() {
+      var point1 = new SVG.Point(4,3)
+        , point2 = new SVG.Point(2,5)
+        , point3 = point1.minus(point2)
+
+      expect(point3).toEqual(new SVG.Point(point1.x - point2.x, point1.y - point2.y))
+    })
+    it('allow passing the point by directly passing its coordinates', function() {
+      var point1 = new SVG.Point(4,3)
+      , point2 = new SVG.Point(2,5)
+      , point3 = point1.minus(point2.x, point2.y)
+
+      expect(point3).toEqual(new SVG.Point(point1.x - point2.x, point1.y - point2.y))
+    })
+    it('perform an element-wise subtraction with the passed number', function() {
+      var point1 = new SVG.Point(4,3)
+        , number = 6
+        , point2 = point1.minus(number)
+
+      expect(point2).toEqual(new SVG.Point(point1.x - number, point1.y - number))
+    })
+  })
+
+  describe('times()', function() {
+    it('perform an element-wise multiplication with the passed point', function() {
+      var point1 = new SVG.Point(4,3)
+        , point2 = new SVG.Point(2,5)
+        , point3 = point1.times(point2)
+
+      expect(point3).toEqual(new SVG.Point(point1.x * point2.x, point1.y * point2.y))
+    })
+    it('allow passing the point by directly passing its coordinates', function() {
+      var point1 = new SVG.Point(4,3)
+      , point2 = new SVG.Point(2,5)
+      , point3 = point1.times(point2.x, point2.y)
+
+      expect(point3).toEqual(new SVG.Point(point1.x * point2.x, point1.y * point2.y))
+    })
+    it('perform an element-wise multiplication with the passed number', function() {
+      var point1 = new SVG.Point(4,3)
+        , number = 6
+        , point2 = point1.times(number)
+
+      expect(point2).toEqual(new SVG.Point(point1.x * number, point1.y * number))
+    })
+  })
+
+  describe('divide()', function() {
+    it('perform an element-wise division with the passed point', function() {
+      var point1 = new SVG.Point(4,3)
+        , point2 = new SVG.Point(2,5)
+        , point3 = point1.divide(point2)
+
+      expect(point3).toEqual(new SVG.Point(point1.x / point2.x, point1.y / point2.y))
+    })
+    it('allow passing the point by directly passing its coordinates', function() {
+      var point1 = new SVG.Point(4,3)
+      , point2 = new SVG.Point(2,5)
+      , point3 = point1.divide(point2.x, point2.y)
+
+      expect(point3).toEqual(new SVG.Point(point1.x / point2.x, point1.y / point2.y))
+    })
+    it('perform an element-wise division with the passed number', function() {
+      var point1 = new SVG.Point(4,3)
+        , number = 6
+        , point2 = point1.divide(number)
+
+      expect(point2).toEqual(new SVG.Point(point1.x / number, point1.y / number))
+    })
+  })
+
+  describe('norm()', function() {
+    it('calculate the Euclidean norm', function() {
+      var point = new SVG.Point(-2,12)
+      expect(point.norm()).toBe(Math.sqrt(point.x*point.x + point.y*point.y))
+    })
+  })
+
+  describe('distance()', function() {
+    it('calculate the distance to the passed point', function() {
+      var point1 = new SVG.Point(-6,-20)
+        , point2 = new SVG.Point(8,18)
+
+      expect(point1.distance(point2)).toBe(Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)))
+    })
+    it('allow passing the point by directly passing its coordinates', function() {
+      var point1 = new SVG.Point(-6,-20)
+        , point2 = new SVG.Point(8,18)
+
+      expect(point1.distance(point2.x, point2.y)).toBe(Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2)))
+    })
+  })
+})
diff --git a/src/makepathsmorphable.js b/src/makepathsmorphable.js
new file mode 100644 (file)
index 0000000..af0fc37
--- /dev/null
@@ -0,0 +1,536 @@
+// Take two path array that don't have the same commands (which mean that they
+// cannot be morphed in one another) and return 2 equivalent path array (meaning
+// that they produce the same shape as the passed path array) that have the
+// same commands (moveto and curveto)
+//
+// Algorithm used:
+// First, convert every path segment of the two passed paths into equivalent cubic Bezier curves.
+// Then, calculate the positions relative to the total length of the path of the endpoint of all those cubic Bezier curves.
+// After that, split the Bezier curves of the source at the positions that the destination have that are not common to the source and vice versa.
+// Finally, make the source and destination have the same number of subpaths.
+SVG.utils.makePathsMorphable = function (sourcePathArray, destinationPathArray) {
+  var source, sourcePositions, sourcePositionsToSplitAt
+    , destination, destinationPositions, destinationPositionsToSplitAt
+    , i, il, j, jl
+    , s, d
+    , sourceSubpath, destinationSubpath, lastSegPt
+
+  // Convert every path segments into equivalent cubic Bezier curves
+  source = cubicSuperPath(sourcePathArray)
+  destination = cubicSuperPath(destinationPathArray)
+
+  // The positions relative to the total length of the path is calculated for the endpoint of all those cubic bezier curves
+  sourcePositions = cspPositions(source)
+  destinationPositions = cspPositions(destination)
+
+  // Find the positions that the destination have that are not in the source and vice versa
+  sourcePositionsToSplitAt = []
+  destinationPositionsToSplitAt = []
+  i = 0, il = sourcePositions.length
+  j = 0, jl = destinationPositions.length
+  while(i < il && j < jl) {
+    // Test if the two values are equal taking into account the imprecision of floating point number
+    if (Math.abs(sourcePositions[i] - destinationPositions[j]) < 0.000001) {
+      i++
+      j++
+    } else if(sourcePositions[i] > destinationPositions[j]){
+      sourcePositionsToSplitAt.push(destinationPositions[j++])
+    } else {
+      destinationPositionsToSplitAt.push(sourcePositions[i++])
+    }
+  }
+  // If there are still some destination positions left, they all are not in the source and vice versa
+  sourcePositionsToSplitAt = sourcePositionsToSplitAt.concat(destinationPositions.slice(j))
+  destinationPositionsToSplitAt = destinationPositionsToSplitAt.concat(sourcePositions.slice(i))
+
+  // Split the source and the destination at the positions they don't have in common
+  cspSplitAtPositions(source, sourcePositions, sourcePositionsToSplitAt)
+  cspSplitAtPositions(destination, destinationPositions, destinationPositionsToSplitAt)
+
+
+  // Break paths so that corresponding subpaths have an equal number of segments
+  s = source, source = [], sourceSubpath = s[i = 0]
+  d = destination, destination = [], destinationSubpath = d[j = 0]
+  while (sourceSubpath && destinationSubpath) {
+    // Push REFERENCES to the current subpath arrays in their respective array
+    source.push(sourceSubpath)
+    destination.push(destinationSubpath)
+
+    il = sourceSubpath.length
+    jl = destinationSubpath.length
+
+    // If the current subpath of the source and the current subpath of the destination don't
+    // have the same length, that mean that the biggest of the two must be split in two
+    if(il > jl) {
+      lastSegPt = sourceSubpath[jl-1]
+      // Perform the split using splice that change the content of the array by removing elements and returning them in an array
+      sourceSubpath = sourceSubpath.splice(jl)
+      sourceSubpath.unshift(lastSegPt) // The last segment point is duplicated since these two segments must be joined together
+      destinationSubpath = d[++j] // This subpath has been accounted for, past to the next
+    } else if(il < jl) {
+      lastSegPt = destinationSubpath[il-1]
+      destinationSubpath = destinationSubpath.splice(il)
+      destinationSubpath.unshift(lastSegPt)
+      sourceSubpath = s[++i]
+    } else {
+      sourceSubpath = s[++i]
+      destinationSubpath = d[++j]
+    }
+  }
+
+  // Convert in path array and return
+  return [uncubicSuperPath(source), uncubicSuperPath(destination)]
+}
+
+
+
+
+
+
+// This function converts every segment of a path array into equivalent cubic Bezier curves
+// and return the results in a 3 dimensional array that have the following hierarchy:
+// Cubic super path:  [                                           ]
+// Segments:           [                                     ] ...
+// Segment points:      [SVG.Point, SVG.Point, SVG.Point] ...
+//
+// A segment point is a point with the two control points that are attached to it:
+// [First control point, Point, Second control point]
+//
+// If the passed path array cannot be converted in a cubic super path, this function return an empty array.
+function cubicSuperPath(pathArray) {
+  pathArray = new SVG.PathArray(pathArray)
+
+  var cubicSP = []
+    , subpath = null
+    , subpathStartPt = null
+    , lastPt = null
+    , lastCtrlPt = null
+    , i, il, cmd = null, params, lastCmd
+    , start, control, end
+    , arcSegPoints, segPt
+
+  for (i = 0, il = pathArray.value.length; i < il; i++) {
+    lastCmd = cmd
+    cmd = pathArray.value[i][0]
+    params = pathArray.value[i].slice(1)
+
+    switch (cmd) {
+      case 'M': // moveto
+        // Parameters: x y
+        if (lastPt) {
+          subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        }
+        subpath = []
+        cubicSP.push(subpath) // Push a reference to the current subpath array in the cubic super path array
+        subpathStartPt = new SVG.Point(params)
+        lastPt = subpathStartPt.clone()
+        lastCtrlPt = subpathStartPt.clone()
+        break
+
+      case 'L': // lineto
+        // Parameters: x y
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        lastPt = new SVG.Point(params)
+        lastCtrlPt = lastPt.clone()
+        break
+
+      case 'H': // horizontal lineto
+        // Parameters: x
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        lastPt = new SVG.Point(params[0], lastPt.y)
+        lastCtrlPt = lastPt.clone()
+        break
+
+      case 'V': // vertical lineto
+        // Parameters: y
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        lastPt = new SVG.Point(lastPt.x, params[0])
+        lastCtrlPt = lastPt.clone()
+        break
+
+      case 'C': // curveto
+        // Parameters: x1 y1 x2 y2 x y
+        subpath.push([lastCtrlPt, lastPt, new SVG.Point(params.slice(0,2))])
+        lastPt = new SVG.Point(params.slice(4,6))
+        lastCtrlPt = new SVG.Point(params.slice(2,4))
+        break
+
+      case 'S': // shorthand/smooth curveto
+        // Parameters: x2 y2 x y
+        // For this version of curveto, the first control point is the reflection of the second control point on the previous command relative to the current point
+        // If the previous command is not a curveto command, then the first control point is the same as the current point
+        if(lastCmd === 'C' || lastCmd === 'S') {
+          subpath.push([lastCtrlPt, lastPt, lastPt.times(2).minus(lastCtrlPt)])
+        } else {
+          subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        }
+        lastPt = new SVG.Point(params.slice(2,4))
+        lastCtrlPt = new SVG.Point(params.slice(0,2))
+        break
+
+      case 'Q': // quadratic Bezier curveto
+        // Parameters: x1 y1 x y
+        // For an explanation of the method used, see: https://pomax.github.io/bezierinfo/#reordering
+        start = lastPt
+        control = new SVG.Point(params.slice(0,2))
+        end = new SVG.Point(params.slice(2,4))
+
+        subpath.push([lastCtrlPt, start, start.times(1/3).plus(control.times(2/3))])
+        lastPt = end
+        lastCtrlPt = control.times(2/3).plus(end.times(1/3))
+        break
+
+      case 'T': // shorthand/smooth quadratic Bézier curveto
+        // Parameters: x y
+        // For this version of quadratic Bézier curveto, the control point is the reflection of the control point on the previous command relative to the current point
+        // If the previous command is not a quadratic Bézier curveto command, then the control point is the same as the current point
+        start = lastPt
+        if(lastCmd === 'Q' || lastCmd === 'T') {
+          control = start.times(2).minus(control)
+        } else {
+          control = start
+        }
+        end = new SVG.Point(params.slice(0,2))
+
+        subpath.push([lastCtrlPt, start, start.times(1/3).plus(control.times(2/3))])
+        lastPt = end
+        lastCtrlPt = control.times(2/3).plus(end.times(1/3))
+        break
+
+      case 'A': // elliptical arc
+        // Parameters: rx ry x-axis-rotation large-arc-flag sweep-flag x y
+        arcSegPoints = arcToPath(lastPt, params)
+        arcSegPoints[0][0] = lastCtrlPt
+        segPt = arcSegPoints.pop()
+        lastPt = segPt[1]
+        lastCtrlPt = segPt[0]
+        Array.prototype.push.apply(subpath, arcSegPoints)
+        break
+
+      case 'Z': // closepath
+        // Parameters: none
+        subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+        // Close the path only if it is not already closed
+        if(lastPt.x != subpathStartPt.x && lastPt.y != subpathStartPt.y) {
+          lastPt = subpathStartPt
+          lastCtrlPt = subpathStartPt.clone()
+        } else {
+          lastPt = null
+          lastCtrlPt = null
+        }
+        break
+    }
+  }
+
+  // Push final segment point if any
+  if(lastPt) {
+    subpath.push([lastCtrlPt, lastPt, lastPt.clone()])
+  }
+
+  return cubicSP
+}
+
+
+// This function convert a cubic super path into a path array
+function uncubicSuperPath (cubicSP) {
+  var i, il, j, jl, array = [], pathArray = new SVG.PathArray, subpath
+
+  for (i = 0, il = cubicSP.length; i < il; i++) {
+    subpath = cubicSP[i]
+
+    if (subpath.length) {
+      array.push(['M'].concat(subpath[0][1].toArray()))
+
+      for (j = 1, jl = subpath.length; j < jl; j++) {
+        array.push(['C'].concat(subpath[j-1][2].toArray(), subpath[j][0].toArray(), subpath[j][1].toArray()))
+      }
+    }
+  }
+
+  // Directly modify the value of a path array, this is done this way for performance
+  pathArray.value = array
+  return pathArray
+}
+
+// Convert an arc segment into equivalent cubic Bezier curves
+// Depending on the arc, up to 4 curves might be used to represent it since a
+// curve gives a good approximation for only a quarter of an ellipse
+// The curves are returned as an array of segment points:
+// [ [SVG.Point, SVG.Point, SVG.Point] ... ]
+function arcToPath(lastPt, params) {
+    // Parameters extraction, handle out-of-range parameters as specified in the SVG spec
+    // See: https://www.w3.org/TR/SVG11/implnote.html#ArcOutOfRangeParameters
+    var rx = Math.abs(params[0]), ry = Math.abs(params[1]), xAxisRotation = params[2] % 360
+      , largeArcFlag = params[3], sweepFlag = params[4], x2  = params[5], y2 = params[6]
+      , A = lastPt, B = new SVG.Point(x2, y2)
+      , primedCoord, lambda, mat, k, c, cSquare, t, O, OA, OB, tetaStart, tetaEnd
+      , deltaTeta, nbSectors, f, arcSegPoints, angle, sinAngle, cosAngle, pt, i, il
+
+    // Ensure radii are non-zero
+    if(rx === 0 || ry === 0 || (A.x === B.x && A.y === B.y)) {
+      // treat this arc as a straight line segment
+      return [[A, A.clone(), A.clone()], [B, B.clone(), B.clone()]]
+    }
+
+    // Ensure radii are large enough using the algorithm provided in the SVG spec
+    // See: https://www.w3.org/TR/SVG11/implnote.html#ArcCorrectionOutOfRangeRadii
+    primedCoord = A.minus(B).divide(2).transform(new SVG.Matrix().rotate(xAxisRotation))
+    lambda = (primedCoord.x * primedCoord.x) / (rx * rx) + (primedCoord.y * primedCoord.y) / (ry * ry)
+    if(lambda > 1) {
+      lambda = Math.sqrt(lambda)
+      rx = lambda*rx
+      ry = lambda*ry
+    }
+
+    // To simplify calculations, we make the arc part of a unit circle (rayon is 1) instead of an ellipse
+    mat = new SVG.Matrix().rotate(xAxisRotation).scale(1/rx, 1/ry).rotate(-xAxisRotation)
+    A = A.transform(mat)
+    B = B.transform(mat)
+
+    // Calculate the horizontal and vertical distance between the initial and final point of the arc
+    k = [B.x-A.x, B.y-A.y]
+
+    // Find the length of the chord formed by A and B
+    cSquare = k[0]*k[0] + k[1]*k[1]
+    c = Math.sqrt(cSquare)
+
+    // Calculate the ratios of the horizontal and vertical distance on the length of the chord
+    k[0] /= c
+    k[1] /= c
+
+    // Calculate the distance between the circle center and the chord midpoint
+    // using this formula: t = sqrt(r^2 - c^2 / 4)
+    // where t is the distance between the cirle center and the chord midpoint,
+    //       r is the rayon of the circle and c is the chord length
+    // From: http://www.ajdesigner.com/phpcircle/circle_segment_chord_t.php
+    // Because of the imprecision of floating point numbers, cSquare might end
+    // up being slightly above 4 which would result in a negative radicand
+    // To prevent that, a test is made before computing the square root
+    t = (cSquare < 4) ? Math.sqrt(1 - cSquare/4) : 0
+
+    // For most situations, there are actually two different ellipses that
+    // satisfy the constraints imposed by the points A and B, the radii rx and ry,
+    // and the xAxisRotation
+    // When the flags largeArcFlag and sweepFlag are equal, it means that the
+    // second ellipse is used as a solution
+    // See: https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands
+    if(largeArcFlag === sweepFlag) {
+        t *= -1
+    }
+
+    // Calculate the coordinates of the center of the circle from the midpoint of the chord
+    // This is done by multiplying the ratios calculated previously by the distance between
+    // the circle center and the chord midpoint and using these values to go from the midpoint
+    // to the center of the circle
+    // The negative of the vertical distance ratio is used to modify the x coordinate while
+    // the horizontal distance ratio is used to modify the y coordinate
+    // That is because the center of the circle is perpendicular to the chord and perpendicular
+    // lines are negative reciprocals
+    O = new SVG.Point((B.x+A.x)/2 + t*-k[1], (B.y+A.y)/2 + t*k[0])
+    // Move the center of the circle at the origin
+    OA = A.minus(O)
+    OB = B.minus(O)
+
+    // Calculate the start and end angle
+    tetaStart = Math.acos(OA.x/OA.norm())
+    if (OA.y < 0) {
+      tetaStart *= -1
+    }
+    tetaEnd = Math.acos(OB.x/OB.norm())
+    if (OB.y < 0) {
+      tetaEnd *= -1
+    }
+
+    // If sweep-flag is '1', then the arc will be drawn in a "positive-angle" direction,
+    // make sure that the end angle is above the start angle
+    if (sweepFlag && tetaStart > tetaEnd) {
+      tetaEnd += 2*Math.PI
+    }
+    // If sweep-flag is '0', then the arc will be drawn in a "negative-angle" direction,
+    // make sure that the end angle is below the start angle
+    if (!sweepFlag && tetaStart < tetaEnd) {
+      tetaEnd -= 2*Math.PI
+    }
+
+    // Find the number of Bezier curves that are required to represent the arc
+    // A cubic Bezier curve gives a good enough approximation when representing at most a quarter of a circle
+    nbSectors = Math.ceil(Math.abs(tetaStart-tetaEnd) * 2/Math.PI)
+
+    // Calculate the coordinates of the points of all the Bezier curves required to represent the arc
+    // For an in-depth explanation of this part see: http://pomax.github.io/bezierinfo/#circles_cubic
+    arcSegPoints = []
+    angle = tetaStart
+    deltaTeta = (tetaEnd-tetaStart)/nbSectors
+    f = 4*Math.tan(deltaTeta/4)/3
+    for (i = 0; i <= nbSectors; i++) { // The <= is because a Bezier curve have a start and a endpoint
+      cosAngle = Math.cos(angle)
+      sinAngle = Math.sin(angle)
+
+      pt = O.plus(cosAngle, sinAngle)
+      arcSegPoints[i] = [pt.plus(+f*sinAngle, -f*cosAngle), pt, pt.plus(-f*sinAngle, +f*cosAngle)]
+
+      angle += deltaTeta
+    }
+
+    // Remove the first control point of the first segment point and remove the second control point of the last segment point
+    // These two control points are not used in the approximation of the arc, that is why they are removed
+    arcSegPoints[0][0] = arcSegPoints[0][1].clone()
+    arcSegPoints[arcSegPoints.length-1][2] = arcSegPoints[arcSegPoints.length-1][1].clone()
+
+    // Revert the transformation that was applied to make the arc part of a unit circle instead of an ellipse
+    mat = new SVG.Matrix().rotate(xAxisRotation).scale(rx, ry).rotate(-xAxisRotation)
+    for (i = 0, il = arcSegPoints.length; i < il; i++) {
+      arcSegPoints[i][0] = arcSegPoints[i][0].transform(mat)
+      arcSegPoints[i][1] = arcSegPoints[i][1].transform(mat)
+      arcSegPoints[i][2] = arcSegPoints[i][2].transform(mat)
+    }
+
+    return arcSegPoints
+}
+
+
+// Use de Casteljau's algorithm to split a cubic Bezier curve
+// For a description of the algorithm, see: https://pomax.github.io/bezierinfo/#decasteljau
+// Return an array of 3 segment points
+function cspSegSplit(segPt1, segPt2, t) {
+  segPt1 = [segPt1[0].clone(), segPt1[1].clone(), segPt1[2].clone()]
+  segPt2 = [segPt2[0].clone(), segPt2[1].clone(), segPt2[2].clone()]
+
+  var m1 = segPt1[1].morph(segPt1[2]).at(t)
+    , m2 = segPt1[2].morph(segPt2[0]).at(t)
+    , m3 = segPt2[0].morph(segPt2[1]).at(t)
+    , m4 = m1.morph(m2).at(t)
+    , m5 = m2.morph(m3).at(t)
+    , m = m4.morph(m5).at(t)
+
+  return [[segPt1[0], segPt1[1], m1], [m4, m, m5], [m3, segPt2[1], segPt2[2]]]
+}
+
+
+// Find the length of a cubic Bezier curve using the built-in method getTotalLength of SVGPathElement
+// For more info, see: https://www.w3.org/TR/SVG11/paths.html#InterfaceSVGPathElement
+function cspSegLength(segPt1, segPt2) {
+  var path = document.createElementNS(SVG.ns, "path")
+    , d = ['M', segPt1[1].toArray(), 'C', segPt1[2].toArray(), segPt2[0].toArray(), segPt2[1].toArray()].join(' ')
+
+  path.setAttribute('d', d)
+
+  return path.getTotalLength()
+}
+
+
+// Find the length of all the cubic Bezier curves of a cubic super path and return
+// the results in a 2 dimensional array that have the following hierarchy:
+// Cubic super path lengths:  [                ]
+// Segments lengths:           [          ] ...
+// Cubic Bezier curves length:  Number ...
+//
+// On the returned array, the property total is set to the sum of all the lengths
+function cspLengths(cubicSP) {
+  var total = 0
+    , subpath, lengths = [], lengthsSubpath, length
+    , i, il, j, jl
+
+  for (i = 0, il = cubicSP.length; i < il; i++) {
+    subpath = cubicSP[i]
+    lengthsSubpath = []
+    lengths[i] = lengthsSubpath // Save a reference to the current subpath lengths array in the cubic super path lengths array
+
+    for (j = 1, jl = subpath.length; j < jl; j++) {
+      length = cspSegLength(subpath[j-1], subpath[j])
+      lengthsSubpath[j-1] = length
+      total += length
+    }
+  }
+
+  lengths.total = total
+  return lengths
+}
+
+
+// Split a cubic Bezier curve at the given length ratio
+// Return an array of 3 segment points
+function cspSegSplitAtLengthRatio(segPt1, segPt2, lengthRatio) {
+  var t = 1.0
+    , tdiv = t
+    , currentLength = cspSegLength(segPt1, segPt2)
+    , targetLength = lengthRatio * currentLength
+    , diff = currentLength - targetLength
+    , split = cspSegSplit(segPt1, segPt2, t)
+    , maxNbLoops = 4096 // For not getting stuck in an infinite loop
+
+  while (Math.abs(diff) > 0.001 && maxNbLoops--) {
+    tdiv /= 2
+    t += (diff < 0) ? tdiv : -tdiv
+    split = cspSegSplit(segPt1, segPt2, t)
+    currentLength = cspSegLength(split[0], split[1])
+    diff = currentLength - targetLength
+  }
+
+  return split
+}
+
+
+
+// Find the position relative to the total length of the endpoint of all the cubic Bezier curves
+// of a cubic super path and return the results in a 1 dimensional array
+function cspPositions(cubicSP) {
+  var lengths = cspLengths(cubicSP), total = lengths.total
+    , pos = 0, positions = []
+    , i, il, j, jl
+
+  for (i = 0, il = lengths.length; i < il; i++) {
+    for (j = 0, jl = lengths[i].length; j < jl; j++) {
+      pos += lengths[i][j] / total
+      positions.push(pos)
+    }
+  }
+
+  return positions
+}
+
+// Split the passed cubic super path at the specified positions and return the results as a new cubic super path
+// For performance reasons, the positions of the passed cubic super path must also be provided
+function cspSplitAtPositions(cubicSP, positions, positionsToSplitAt){
+  var subpath, newSubpath
+    , accumNbPositions = 0, segPt, lengthRatio, split, pos, prevPos
+    , i, il, j, jl // indexes on the cubicSP array
+    , k = 0 // index on the positions array
+    , l = 0, ll = positionsToSplitAt.length
+
+  for (i = 0, il = cubicSP.length; i < il && l < ll; i++) {
+    subpath = cubicSP[i]
+    // The positions are only for the endpoints of the cubic Bezier curves, so
+    // a subpath need at least 2 segment points for a position to be on it
+    if(subpath.length < 2) {continue}
+    // Test if there are splits to be performed on the current subpath
+    if(positionsToSplitAt[l] < positions[accumNbPositions + subpath.length-2]) {
+      k = accumNbPositions
+      newSubpath = []
+      cubicSP[i] = newSubpath // Save a reference to the new current subpath array in the cubic super path array
+      pos = positions[k-1] || 0
+
+      // Recopy the content of the current subpath, performing splits where necessary
+      newSubpath.push(subpath[0])
+      for (j = 1, jl = subpath.length; j < jl; j++) {
+        prevPos = pos
+        pos = positions[k++]
+        segPt = subpath[j]
+
+        while(l < ll && positionsToSplitAt[l] < pos) {
+          lengthRatio = (positionsToSplitAt[l] - prevPos) / (pos - prevPos)
+          split = cspSegSplitAtLengthRatio(newSubpath[newSubpath.length-1], segPt, lengthRatio)
+          newSubpath[newSubpath.length-1] = split[0]
+          newSubpath.push(split[1])
+          segPt = split[2]
+          prevPos = positionsToSplitAt[l++]
+        }
+
+        newSubpath.push(segPt)
+      }
+    }
+
+    // -1 because positions are only for endpoints of Bezier curves
+    accumNbPositions += subpath.length - 1
+  }
+}
index 90d0558b28a3c7775820d385e731e0180e25339a..c478b9ed7ba02517322a3085082e4c32d0f3ba8a 100644 (file)
@@ -100,6 +100,71 @@ SVG.extend(SVG.PathArray, {
 
     return this
   }
+  // Test if the passed path array use the same commands as this path array
+, haveSameCommands: function(pathArray) {
+    var i, il, haveSameCommands
+
+    pathArray = new SVG.PathArray(pathArray)
+
+    haveSameCommands = this.value.length === pathArray.value.length
+    for(i = 0, il = this.value.length; haveSameCommands && i < il; i++) {
+      haveSameCommands = this.value[i][0] === pathArray.value[i][0]
+    }
+
+    return haveSameCommands
+  }
+  // Make path array morphable
+, morph: function(pathArray) {
+    var pathsMorphable
+
+    this.destination = new SVG.PathArray(pathArray)
+
+    if(this.haveSameCommands(this.destination)) {
+      this.sourceMorphable = this
+      this.destinationMorphable = this.destination
+    } else {
+      pathsMorphable = SVG.utils.makePathsMorphable(this.value, this.destination)
+      this.sourceMorphable = pathsMorphable[0]
+      this.destinationMorphable = pathsMorphable[1]
+    }
+
+    return this
+  }
+  // Get morphed path array at given position
+, at: function(pos) {
+    if(pos === 1) {
+      return this.destination
+    } else if(pos === 0) {
+      return this
+    } else {
+      var sourceArray = this.sourceMorphable.value
+        , destinationArray = this.destinationMorphable.value
+        , array = [], pathArray = new SVG.PathArray()
+        , i, il, j, jl
+
+      // Animate has specified in the SVG spec
+      // See: https://www.w3.org/TR/SVG11/paths.html#PathElement
+      for (i = 0, il = sourceArray.length; i < il; i++) {
+        array[i] = [sourceArray[i][0]]
+        for(j=1, jl = sourceArray[i].length; j < jl; j++) {
+          array[i][j] = sourceArray[i][j] + (destinationArray[i][j] - sourceArray[i][j]) * pos
+        }
+        // For the two flags of the elliptical arc command, the SVG spec say:
+        // Flags and booleans are interpolated as fractions between zero and one, with any non-zero value considered to be a value of one/true
+        // Elliptical arc command as an array followed by corresponding indexes:
+        // ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y]
+        //   0    1   2        3                 4             5      6  7
+        if(array[i][0] === 'A') {
+          array[i][4] = +(array[i][4] != 0)
+          array[i][5] = +(array[i][5] != 0)
+        }
+      }
+
+      // Directly modify the value of a path array, this is done this way for performance
+      pathArray.value = array
+      return pathArray
+    }
+  }
   // Absolutize and parse path to array
 , parse: function(array) {
     // if it's already a patharray, no need to parse it
@@ -131,7 +196,7 @@ SVG.extend(SVG.PathArray, {
           array.splice.apply(array, [i, 1].concat(first, split.map(function(el){ return '.'+el }))) // add first and all other entries back to array
         }
       }
-        
+
     }else{
       array = array.reduce(function(prev, curr){
         return [].concat.apply(prev, curr)
@@ -240,4 +305,4 @@ SVG.extend(SVG.PathArray, {
     return SVG.parser.path.getBBox()
   }
 
-})
\ No newline at end of file
+})
index 8d1dae9c34b042d43b00e6bc1b8e3e441d0c29dd..226f4e04c972578cb879f61931bcefd58217d9ee 100644 (file)
@@ -2,15 +2,15 @@ SVG.Point = SVG.invent({
   // Initialize
   create: function(x,y) {
     var i, source, base = {x:0, y:0}
-    
+
     // ensure source as object
     source = Array.isArray(x) ?
       {x:x[0], y:x[1]} :
     typeof x === 'object' ?
       {x:x.x, y:x.y} :
-    y != null ?
-      {x:x, y:y} : base
-
+    x != null ?
+      {x:x, y:(y != null ? y : x)} : base // If y has no value, then x is used has its value
+                                          // This allow element-wise operations to be passed a single number
     // merge source
     this.x = source.x
     this.y = source.y
@@ -23,9 +23,9 @@ SVG.Point = SVG.invent({
       return new SVG.Point(this)
     }
     // Morph one point into another
-  , morph: function(point) {
+  , morph: function(x, y) {
       // store new destination
-      this.destination = new SVG.Point(point)
+      this.destination = new SVG.Point(x, y)
 
       return this
     }
@@ -57,7 +57,38 @@ SVG.Point = SVG.invent({
   , transform: function(matrix) {
       return new SVG.Point(this.native().matrixTransform(matrix.native()))
     }
-
+    // return an array of the x and y coordinates
+  , toArray: function() {
+      return [this.x, this.y]
+    }
+    // perform an element-wise addition with the passed point or number
+  , plus: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x + point.x, this.y + point.y)
+    }
+    // perform an element-wise subtraction with the passed point or number
+  , minus: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x - point.x, this.y - point.y)
+    }
+    // perform an element-wise multiplication with the passed point or number
+  , times: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x * point.x, this.y * point.y)
+    }
+    // perform an element-wise division with the passed point or number
+  , divide: function(x, y) {
+      var point = new SVG.Point(x, y)
+      return new SVG.Point(this.x / point.x, this.y / point.y)
+    }
+    // calculate the Euclidean norm
+  , norm: function() {
+      return Math.sqrt(this.x*this.x + this.y*this.y)
+    }
+    // calculate the distance to the passed point
+  , distance: function(x, y) {
+      return this.minus(x, y).norm()
+    }
   }
 
 })