master
Dmitry Baranovskiy 2014-03-07 10:45:24 +11:00
parent 5b3e509fb6
commit f09212b211
6 changed files with 262 additions and 85 deletions

View File

@ -1,6 +1,6 @@
{
"name": "Snap.svg",
"version": "0.1.1",
"version": "0.2.1",
"homepage": "http://snapsvg.io",
"authors": [
"Dmitry Baranovskiy <dmitry@baranovskiy.com>"

View File

@ -2,7 +2,7 @@
"name": "Snap.svg",
"repo": "adobe-webplatform/Snap.svg",
"description": "The JavaScript library for modern SVG graphics.",
"version": "0.1.1",
"version": "0.2.1",
"keywords": ["svg", "snap", "js", "javascript"],
"dependencies": {},
"development": {},

File diff suppressed because one or more lines are too long

138
dist/snap.svg.js vendored
View File

@ -14,7 +14,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
// build: 2014-01-13
// build: 2014-03-07
// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
@ -5292,7 +5292,74 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
};
}
function curveDim(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
// Returns bounding box of cubic bezier curve.
// Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
// Original version: NISHIO Hirokazu
// Modifications: https://github.com/timo22345
function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) {
var tvalues = [],
bounds = [[], []],
a, b, c, t, t1, t2, b2ac, sqrtb2ac;
for (var i = 0; i < 2; ++i) {
if (i == 0) {
b = 6 * x0 - 12 * x1 + 6 * x2;
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
c = 3 * x1 - 3 * x0;
} else {
b = 6 * y0 - 12 * y1 + 6 * y2;
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
c = 3 * y1 - 3 * y0;
}
if (abs(a) < 1e-12) {
if (abs(b) < 1e-12) {
continue;
}
t = -c / b;
if (0 < t && t < 1) {
tvalues.push(t);
}
continue;
}
b2ac = b * b - 4 * c * a;
sqrtb2ac = math.sqrt(b2ac);
if (b2ac < 0) {
continue;
}
t1 = (-b + sqrtb2ac) / (2 * a);
if (0 < t1 && t1 < 1) {
tvalues.push(t1);
}
t2 = (-b - sqrtb2ac) / (2 * a);
if (0 < t2 && t2 < 1) {
tvalues.push(t2);
}
}
var x, y, j = tvalues.length,
jlen = j,
mt;
while (j--) {
t = tvalues[j];
mt = 1 - t;
bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
}
bounds[0][jlen] = x0;
bounds[1][jlen] = y0;
bounds[0][jlen + 1] = x3;
bounds[1][jlen + 1] = y3;
bounds[0].length = bounds[1].length = jlen + 2;
return {
min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])},
max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])}
};
}
function curveDim2(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
c = p1x - c1x,
@ -5344,28 +5411,40 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
p2 = path2 && pathToAbsolute(path2),
attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
processPath = function (path, d) {
processPath = function (path, d, pcom) {
var nx, ny;
if (!path) {
return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
}
!(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);
!(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null);
switch (path[0]) {
case "M":
d.X = path[1];
d.Y = path[2];
break;
case "A":
path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
path = ["C"].concat(a2c[apply](0, [d.x, d.y].concat(path.slice(1))));
break;
case "S":
nx = d.x + (d.x - (d.bx || d.x));
ny = d.y + (d.y - (d.by || d.y));
if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
nx = d.x * 2 - d.bx; // And reflect the previous
ny = d.y * 2 - d.by; // command's control point relative to the current point.
}
else { // or some else or nothing
nx = d.x;
ny = d.y;
}
path = ["C", nx, ny].concat(path.slice(1));
break;
case "T":
d.qx = d.x + (d.x - (d.qx || d.x));
d.qy = d.y + (d.y - (d.qy || d.y));
if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
d.qx = d.x * 2 - d.qx; // And make a reflection similar
d.qy = d.y * 2 - d.qy; // to case "S".
}
else { // or something else or nothing
d.qx = d.x;
d.qy = d.y;
}
path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
break;
case "Q":
@ -5393,6 +5472,8 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
pp[i].shift();
var pi = pp[i];
while (pi.length) {
pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved
p2 && (pcoms2[i] = "A"); // the same as above
pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
}
pp.splice(i, 1);
@ -5408,12 +5489,41 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
a1.y = path1[i][2];
ii = mmax(p.length, p2 && p2.length || 0);
}
};
},
pcoms1 = [], // path commands of original path p
pcoms2 = [], // path commands of original path p2
pfirst = "", // temporary holder for original path command
pcom = ""; // holder for previous path command of original path
for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
p[i] = processPath(p[i], attrs);
fixArc(p, i);
p2 && (p2[i] = processPath(p2[i], attrs2));
p2 && fixArc(p2, i);
p[i] && (pfirst = p[i][0]); // save current path command
if (pfirst != "C") // C is not saved yet, because it may be result of conversion
{
pcoms1[i] = pfirst; // Save current path command
i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom
}
p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command
// which may produce multiple C:s
// so we have to make sure that C is also C in original path
fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
if (p2) { // the same procedures is done to p2
p2[i] && (pfirst = p2[i][0]);
if (pfirst != "C") {
pcoms2[i] = pfirst;
i && (pcom = pcoms2[i - 1]);
}
p2[i] = processPath(p2[i], attrs2, pcom);
if (pcoms2[i] != "A" && pfirst == "C") {
pcoms2[i] = "C";
}
fixArc(p2, i);
}
fixM(p, p2, attrs, attrs2, i);
fixM(p2, p, attrs2, attrs, i);
var seg = p[i],

View File

@ -11031,7 +11031,7 @@ prototypes). This allow you to extend anything you want.
<article id="Snap.path.getTotalLength">
<header>
<h3 class="dr-method">Snap.path.getTotalLength(path)<a href="#Snap.path.getTotalLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1076 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1076">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.getTotalLength(path)<a href="#Snap.path.getTotalLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1186 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1186">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.getTotalLength-extra"></div>
@ -11091,7 +11091,7 @@ prototypes). This allow you to extend anything you want.
<article id="Snap.path.getPointAtLength">
<header>
<h3 class="dr-method">Snap.path.getPointAtLength(path, length)<a href="#Snap.path.getPointAtLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1093 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1093">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.getPointAtLength(path, length)<a href="#Snap.path.getPointAtLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1203 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1203">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.getPointAtLength-extra"></div>
@ -11198,7 +11198,7 @@ prototypes). This allow you to extend anything you want.
<article id="Snap.path.getSubpath">
<header>
<h3 class="dr-method">Snap.path.getSubpath(path, from, to)<a href="#Snap.path.getSubpath" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1106 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1106">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.getSubpath(path, from, to)<a href="#Snap.path.getSubpath" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1216 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1216">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.getSubpath-extra"></div>
@ -11264,7 +11264,7 @@ prototypes). This allow you to extend anything you want.
<article id="Element.getTotalLength">
<header>
<h3 class="dr-method">Element.getTotalLength()<a href="#Element.getTotalLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1120 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1120">&#x27ad;</a></h3>
<h3 class="dr-method">Element.getTotalLength()<a href="#Element.getTotalLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1230 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1230">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Element.getTotalLength-extra"></div>
@ -11306,7 +11306,7 @@ prototypes). This allow you to extend anything you want.
<article id="Element.getPointAtLength">
<header>
<h3 class="dr-method">Element.getPointAtLength(length)<a href="#Element.getPointAtLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1141 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1141">&#x27ad;</a></h3>
<h3 class="dr-method">Element.getPointAtLength(length)<a href="#Element.getPointAtLength" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1251 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1251">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Element.getPointAtLength-extra"></div>
@ -11410,7 +11410,7 @@ prototypes). This allow you to extend anything you want.
<article id="Element.getSubpath">
<header>
<h3 class="dr-method">Element.getSubpath(from, to)<a href="#Element.getSubpath" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1156 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1156">&#x27ad;</a></h3>
<h3 class="dr-method">Element.getSubpath(from, to)<a href="#Element.getSubpath" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1266 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1266">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Element.getSubpath-extra"></div>
@ -11473,7 +11473,7 @@ prototypes). This allow you to extend anything you want.
<article id="Snap.path.findDotsAtSegment">
<header>
<h3 class="dr-method">Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t)<a href="#Snap.path.findDotsAtSegment" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1199 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1199">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t)<a href="#Snap.path.findDotsAtSegment" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1309 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1309">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.findDotsAtSegment-extra"></div>
@ -11698,7 +11698,7 @@ Finds dot coordinates on the given cubic beziér curve at the given t
<article id="Snap.path.bezierBBox">
<header>
<h3 class="dr-method">Snap.path.bezierBBox(…)<a href="#Snap.path.bezierBBox" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1227 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1227">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.bezierBBox(…)<a href="#Snap.path.bezierBBox" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1337 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1337">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.bezierBBox-extra"></div>
@ -11877,7 +11877,7 @@ Returns the bounding box of a given cubic beziér curve
<article id="Snap.path.isPointInsideBBox">
<header>
<h3 class="dr-method">Snap.path.isPointInsideBBox(bbox, x, y)<a href="#Snap.path.isPointInsideBBox" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1240 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1240">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.isPointInsideBBox(bbox, x, y)<a href="#Snap.path.isPointInsideBBox" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1350 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1350">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.isPointInsideBBox-extra"></div>
@ -11944,7 +11944,7 @@ Returns <code>true</code> if given point is inside bounding box
<article id="Snap.path.isBBoxIntersect">
<header>
<h3 class="dr-method">Snap.path.isBBoxIntersect(bbox1, bbox2)<a href="#Snap.path.isBBoxIntersect" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1252 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1252">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.isBBoxIntersect(bbox1, bbox2)<a href="#Snap.path.isBBoxIntersect" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1362 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1362">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.isBBoxIntersect-extra"></div>
@ -12008,7 +12008,7 @@ Returns <code>true</code> if two bounding boxes intersect
<article id="Snap.path.intersection">
<header>
<h3 class="dr-method">Snap.path.intersection(path1, path2)<a href="#Snap.path.intersection" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1276 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1276">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.intersection(path1, path2)<a href="#Snap.path.intersection" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1386 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1386">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.intersection-extra"></div>
@ -12164,7 +12164,7 @@ Finds intersections of two paths
<article id="Snap.path.isPointInside">
<header>
<h3 class="dr-method">Snap.path.isPointInside(path, x, y)<a href="#Snap.path.isPointInside" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1292 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1292">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.isPointInside(path, x, y)<a href="#Snap.path.isPointInside" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1402 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1402">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.isPointInside-extra"></div>
@ -12232,7 +12232,7 @@ Returns <code>true</code> if given point is inside a given closed path.
<article id="Snap.path.getBBox">
<header>
<h3 class="dr-method">Snap.path.getBBox(path)<a href="#Snap.path.getBBox" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1311 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1311">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.getBBox(path)<a href="#Snap.path.getBBox" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1421 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1421">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.getBBox-extra"></div>
@ -12361,7 +12361,7 @@ Returns the bounding box of a given path
<article id="Snap.path.toRelative">
<header>
<h3 class="dr-method">Snap.path.toRelative(path)<a href="#Snap.path.toRelative" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1323 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1323">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.toRelative(path)<a href="#Snap.path.toRelative" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1433 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1433">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.toRelative-extra"></div>
@ -12422,7 +12422,7 @@ Converts path coordinates into relative values
<article id="Snap.path.toAbsolute">
<header>
<h3 class="dr-method">Snap.path.toAbsolute(path)<a href="#Snap.path.toAbsolute" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1334 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1334">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.toAbsolute(path)<a href="#Snap.path.toAbsolute" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1444 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1444">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.toAbsolute-extra"></div>
@ -12483,7 +12483,7 @@ Converts path coordinates into absolute values
<article id="Snap.path.toCubic">
<header>
<h3 class="dr-method">Snap.path.toCubic(pathString)<a href="#Snap.path.toCubic" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1345 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1345">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.toCubic(pathString)<a href="#Snap.path.toCubic" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1455 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1455">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.toCubic-extra"></div>
@ -12544,7 +12544,7 @@ Converts path to a new path where all segments are cubic beziér curves
<article id="Snap.path.map">
<header>
<h3 class="dr-method">Snap.path.map(path, matrix)<a href="#Snap.path.map" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1355 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1355">&#x27ad;</a></h3>
<h3 class="dr-method">Snap.path.map(path, matrix)<a href="#Snap.path.map" title="Link to this section" class="dr-hash">&#x2693;</a><a class="dr-sourceline" title="Go to line 1465 in the source" href="https://github.com/adobe-webplatform/savage/blob/master/src/svg.js#1465">&#x27ad;</a></h3>
</header>
<section>
<div class="extra" id="Snap.path.map-extra"></div>

View File

@ -861,49 +861,73 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
};
}
function curveDim(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
c = p1x - c1x,
t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a,
t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a,
y = [p1y, p2y],
x = [p1x, p2x],
dot;
abs(t1) > "1e12" && (t1 = .5);
abs(t2) > "1e12" && (t2 = .5);
if (t1 > 0 && t1 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
x.push(dot.x);
y.push(dot.y);
// Returns bounding box of cubic bezier curve.
// Source: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
// Original version: NISHIO Hirokazu
// Modifications: https://github.com/timo22345
function curveDim(x0, y0, x1, y1, x2, y2, x3, y3) {
var tvalues = [],
bounds = [[], []],
a, b, c, t, t1, t2, b2ac, sqrtb2ac;
for (var i = 0; i < 2; ++i) {
if (i == 0) {
b = 6 * x0 - 12 * x1 + 6 * x2;
a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
c = 3 * x1 - 3 * x0;
} else {
b = 6 * y0 - 12 * y1 + 6 * y2;
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
c = 3 * y1 - 3 * y0;
}
if (t2 > 0 && t2 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
x.push(dot.x);
y.push(dot.y);
if (abs(a) < 1e-12) {
if (abs(b) < 1e-12) {
continue;
}
a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
c = p1y - c1y;
t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a;
t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a;
abs(t1) > "1e12" && (t1 = .5);
abs(t2) > "1e12" && (t2 = .5);
if (t1 > 0 && t1 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
x.push(dot.x);
y.push(dot.y);
t = -c / b;
if (0 < t && t < 1) {
tvalues.push(t);
}
if (t2 > 0 && t2 < 1) {
dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
x.push(dot.x);
y.push(dot.y);
continue;
}
b2ac = b * b - 4 * c * a;
sqrtb2ac = math.sqrt(b2ac);
if (b2ac < 0) {
continue;
}
t1 = (-b + sqrtb2ac) / (2 * a);
if (0 < t1 && t1 < 1) {
tvalues.push(t1);
}
t2 = (-b - sqrtb2ac) / (2 * a);
if (0 < t2 && t2 < 1) {
tvalues.push(t2);
}
}
var x, y, j = tvalues.length,
jlen = j,
mt;
while (j--) {
t = tvalues[j];
mt = 1 - t;
bounds[0][j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
bounds[1][j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
}
bounds[0][jlen] = x0;
bounds[1][jlen] = y0;
bounds[0][jlen + 1] = x3;
bounds[1][jlen + 1] = y3;
bounds[0].length = bounds[1].length = jlen + 2;
return {
min: {x: mmin.apply(0, x), y: mmin.apply(0, y)},
max: {x: mmax.apply(0, x), y: mmax.apply(0, y)}
min: {x: mmin.apply(0, bounds[0]), y: mmin.apply(0, bounds[1])},
max: {x: mmax.apply(0, bounds[0]), y: mmax.apply(0, bounds[1])}
};
}
function path2curve(path, path2) {
var pth = !path2 && paths(path);
if (!path2 && pth.curve) {
@ -913,28 +937,40 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
p2 = path2 && pathToAbsolute(path2),
attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
processPath = function (path, d) {
processPath = function (path, d, pcom) {
var nx, ny;
if (!path) {
return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
}
!(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);
!(path[0] in {T: 1, Q: 1}) && (d.qx = d.qy = null);
switch (path[0]) {
case "M":
d.X = path[1];
d.Y = path[2];
break;
case "A":
path = ["C"].concat(a2c.apply(0, [d.x, d.y].concat(path.slice(1))));
path = ["C"].concat(a2c[apply](0, [d.x, d.y].concat(path.slice(1))));
break;
case "S":
nx = d.x + (d.x - (d.bx || d.x));
ny = d.y + (d.y - (d.by || d.y));
if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S.
nx = d.x * 2 - d.bx; // And reflect the previous
ny = d.y * 2 - d.by; // command's control point relative to the current point.
}
else { // or some else or nothing
nx = d.x;
ny = d.y;
}
path = ["C", nx, ny].concat(path.slice(1));
break;
case "T":
d.qx = d.x + (d.x - (d.qx || d.x));
d.qy = d.y + (d.y - (d.qy || d.y));
if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T.
d.qx = d.x * 2 - d.qx; // And make a reflection similar
d.qy = d.y * 2 - d.qy; // to case "S".
}
else { // or something else or nothing
d.qx = d.x;
d.qy = d.y;
}
path = ["C"].concat(q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
break;
case "Q":
@ -962,6 +998,8 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
pp[i].shift();
var pi = pp[i];
while (pi.length) {
pcoms1[i] = "A"; // if created multiple C:s, their original seg is saved
p2 && (pcoms2[i] = "A"); // the same as above
pp.splice(i++, 0, ["C"].concat(pi.splice(0, 6)));
}
pp.splice(i, 1);
@ -977,12 +1015,41 @@ Snap.plugin(function (Snap, Element, Paper, glob) {
a1.y = path1[i][2];
ii = mmax(p.length, p2 && p2.length || 0);
}
};
},
pcoms1 = [], // path commands of original path p
pcoms2 = [], // path commands of original path p2
pfirst = "", // temporary holder for original path command
pcom = ""; // holder for previous path command of original path
for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) {
p[i] = processPath(p[i], attrs);
fixArc(p, i);
p2 && (p2[i] = processPath(p2[i], attrs2));
p2 && fixArc(p2, i);
p[i] && (pfirst = p[i][0]); // save current path command
if (pfirst != "C") // C is not saved yet, because it may be result of conversion
{
pcoms1[i] = pfirst; // Save current path command
i && ( pcom = pcoms1[i - 1]); // Get previous path command pcom
}
p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath
if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command
// which may produce multiple C:s
// so we have to make sure that C is also C in original path
fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1
if (p2) { // the same procedures is done to p2
p2[i] && (pfirst = p2[i][0]);
if (pfirst != "C") {
pcoms2[i] = pfirst;
i && (pcom = pcoms2[i - 1]);
}
p2[i] = processPath(p2[i], attrs2, pcom);
if (pcoms2[i] != "A" && pfirst == "C") {
pcoms2[i] = "C";
}
fixArc(p2, i);
}
fixM(p, p2, attrs, attrs2, i);
fixM(p2, p, attrs2, attrs, i);
var seg = p[i],