From 0a2b7d186a620764d891ac701cf42b1a84f9e6d6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20T=C3=A9treault?= Date: Tue, 20 Dec 2016 21:33:18 -0500 Subject: [PATCH] Implement a more basic morph method for SVG.PathArray The method expect the paths to use the exact same commands. It will not attempt to modify them if they do not. Any more complex algorithm shall be provided as a plugin instead in order to keep the size of the library down. --- dist/svg.js | 644 ++------------------------------ dist/svg.min.js | 6 +- gulpfile.js | 3 +- spec/spec/array.js | 57 ++- spec/spec/makepathsmorphable.js | 225 ----------- spec/spec/point.js | 125 ------- src/makepathsmorphable.js | 536 -------------------------- src/patharray.js | 70 ++-- src/point.js | 35 +- 9 files changed, 96 insertions(+), 1605 deletions(-) delete mode 100644 spec/spec/makepathsmorphable.js delete mode 100644 src/makepathsmorphable.js diff --git a/dist/svg.js b/dist/svg.js index c693656..a9fbb9f 100644 --- a/dist/svg.js +++ b/dist/svg.js @@ -6,7 +6,7 @@ * @copyright Wout Fierens * @license MIT * -* BUILT: Sat Jan 14 2017 07:22:23 GMT+0100 (CET) +* BUILT: Sat Jan 14 2017 07:23:05 GMT+0100 (CET) */; (function(root, factory) { if (typeof define === 'function' && define.amd) { @@ -720,55 +720,47 @@ SVG.extend(SVG.PathArray, { } // Make path array morphable , morph: function(pathArray) { - var pathsMorphable - - this.destination = new SVG.PathArray(pathArray) + pathArray = new SVG.PathArray(pathArray) - if(this.haveSameCommands(this.destination)) { - this.sourceMorphable = this - this.destinationMorphable = this.destination + if(this.haveSameCommands(pathArray)) { + this.destination = pathArray } else { - pathsMorphable = SVG.utils.makePathsMorphable(this.value, this.destination) - this.sourceMorphable = pathsMorphable[0] - this.destinationMorphable = pathsMorphable[1] + this.destination = undefined } 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) - } - } + // make sure a destination is defined + if (!this.destination) return this - // Directly modify the value of a path array, this is done this way for performance - pathArray.value = array - return pathArray + var sourceArray = this.value + , destinationArray = this.destination.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) { @@ -2552,7 +2544,7 @@ SVG.Point = SVG.invent({ {x:x.x, y:x.y} : 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 @@ -2599,38 +2591,7 @@ 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() - } + } }) @@ -5463,543 +5424,6 @@ 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 diff --git a/dist/svg.min.js b/dist/svg.min.js index ba28d7b..ed45a29 100644 --- a/dist/svg.min.js +++ b/dist/svg.min.js @@ -1,3 +1,3 @@ -/*! 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=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;e1&&(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.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=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;i1?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=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&&ei.x&&e>i.y&&t/,"").replace(/<\/svg>$/,"");i.innerHTML=""+t.replace(/\n/,"").replace(/<(\w+)([^<]+?)\/>/g,"<$1$2>")+"";for(var n=0,r=i.firstChild.childNodes.length;n":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||ithis.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=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=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;in/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=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-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e=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=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;ha[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=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;i1?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=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},haveSameCommands:function(t){var e,i,n;for(t=new g.PathArray(t),n=this.value.length===t.value.length,e=0,i=this.value.length;n&&ei.x&&e>i.y&&t/,"").replace(/<\/svg>$/,"");i.innerHTML=""+t.replace(/\n/,"").replace(/<(\w+)([^<]+?)\/>/g,"<$1$2>")+"";for(var n=0,s=i.firstChild.childNodes.length;n":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||ithis.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=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!=t?{x:t,y:null!=e?e:t}:n,this.x=i.x,this.y=i.y},extend:{clone:function(){return new g.Point(this)},morph:function(t,e){return this.destination=new g.Point(t,e),this},at:function(t){if(!this.destination)return this;var e=new g.Point({x:this.x+(this.destination.x-this.x)*t,y:this.y+(this.destination.y-this.y)*t});return e},native:function(){var t=g.parser.native.createSVGPoint();return t.x=this.x,t.y=this.y,t},transform:function(t){return new g.Point(this.native().matrixTransform(t.native()))}}}),g.extend(g.Element,{point:function(t,e){return new g.Point(t,e).transform(this.screenCTM().inverse())}}),g.extend(g.Element,{attr:function(t,e,i){if(null==t){for(t={},e=this.node.attributes, +i=e.length-1;i>=0;i--)t[e[i].nodeName]=g.regex.isNumber.test(e[i].nodeValue)?parseFloat(e[i].nodeValue):e[i].nodeValue;return t}if("object"==typeof t)for(e in t)this.attr(e,t[e]);else if(null===e)this.node.removeAttribute(t);else{if(null==e)return e=this.node.getAttribute(t),null==e?g.defaults.attrs[t]:g.regex.isNumber.test(e)?parseFloat(e):e;"stroke-width"==t?this.attr("stroke",parseFloat(e)>0?this._stroke:null):"stroke"==t&&(this._stroke=e),"fill"!=t&&"stroke"!=t||(g.regex.isImage.test(e)&&(e=this.doc().defs().image(e,0,0)),e instanceof g.Image&&(e=this.doc().defs().pattern(0,0,function(){this.add(e)}))),"number"==typeof e?e=new g.Number(e):g.Color.isColor(e)?e=new g.Color(e):Array.isArray(e)?e=new g.Array(e):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=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;in/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=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-1&&this.members.splice(e,1),this},each:function(t){for(var e=0,i=this.members.length;e=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=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 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 - } -} diff --git a/src/patharray.js b/src/patharray.js index c478b9e..3077a95 100644 --- a/src/patharray.js +++ b/src/patharray.js @@ -115,55 +115,47 @@ SVG.extend(SVG.PathArray, { } // Make path array morphable , morph: function(pathArray) { - var pathsMorphable - - this.destination = new SVG.PathArray(pathArray) + pathArray = new SVG.PathArray(pathArray) - if(this.haveSameCommands(this.destination)) { - this.sourceMorphable = this - this.destinationMorphable = this.destination + if(this.haveSameCommands(pathArray)) { + this.destination = pathArray } else { - pathsMorphable = SVG.utils.makePathsMorphable(this.value, this.destination) - this.sourceMorphable = pathsMorphable[0] - this.destinationMorphable = pathsMorphable[1] + this.destination = undefined } 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) - } + // make sure a destination is defined + if (!this.destination) return this + + var sourceArray = this.value + , destinationArray = this.destination.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 } + + // 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) { diff --git a/src/point.js b/src/point.js index 226f4e0..3a54d43 100644 --- a/src/point.js +++ b/src/point.js @@ -10,7 +10,7 @@ SVG.Point = SVG.invent({ {x:x.x, y:x.y} : 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 @@ -57,38 +57,7 @@ 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() - } + } }) -- 2.39.5