From 17c50a403b77c74835d1bce7b52ae0b3e14fbd3a Mon Sep 17 00:00:00 2001 From: Pomax Date: Sun, 6 Sep 2020 09:18:11 -0700 Subject: [PATCH] image regeneration --- docs/chapters/arcapproximation/arcs.js | 2 +- docs/chapters/canonical/canonical.js | 2 +- docs/chapters/canonical/interactive.js | 2 +- docs/chapters/catmullconv/catmull-rom.js | 4 +- docs/chapters/catmullconv/notes.txt | 2 +- docs/chapters/circles/arc-approximation.js | 6 +- .../circles_cubic/arc-approximation.js | 4 +- docs/chapters/control/lerp.js | 4 +- .../chapters/curveintersection/curve-curve.js | 2 +- docs/chapters/graduatedoffset/offsetting.js | 2 +- docs/chapters/intersections/curve-line.js | 2 +- docs/chapters/intersections/line-line.js | 2 +- docs/chapters/molding/molding.js | 2 +- docs/chapters/offsetting/offsetting.js | 4 +- docs/chapters/pointcurves/circle.js | 8 +- docs/chapters/shapes/boolean.js | 4 +- docs/chapters/shapes/paper-core.js | 14977 ---------------- docs/chapters/tracing/tracing.js | 2 +- ...g => da76341b841df1af8a39f797e85dfe3c.png} | Bin .../344346f09b6d5d7e3ddf91084ad50d46.png | Bin 26927 -> 0 bytes .../675217e6df3d75c86503dc2af623e14e.png | Bin 23395 -> 0 bytes .../83fe2473e20ea68b768765129ee44ae4.png | Bin 0 -> 27749 bytes .../c086e72bd8aaeab37436515ab251b2df.png | Bin 0 -> 24180 bytes ...g => aa46749b9469341d9249ca452390d875.png} | Bin ...g => 5801de8227960faa9bcbae578f78c2a3.png} | Bin ...g => da768b84c91262bab8ab36f895e8569b.png} | Bin ...g => 2cc2f0127510f2700656c2f894b36674.png} | Bin ...g => 3b627846198c0cb3c542fe13cb923029.png} | Bin ...g => 71d891b569460c79765670d3f49d2da9.png} | Bin ...g => 9540ecc84c3fc63a07f5372ab031c99e.png} | Bin ...g => 17bf62e05a1fc3387b0c210f2decff45.png} | Bin ...g => 8cc724d5343c65685d88c92b2d069a2a.png} | Bin ...g => 4a762fb56468c342c72756a76d134f05.png} | Bin ...g => 7003a384ec371217af2b225ae65872e7.png} | Bin ...g => cab1799841eedd1dcd1cd81b6045f40f.png} | Bin ...g => 834af194de17a5eb2c1920773ab904e3.png} | Bin ...g => aefb177e5532a9f995b9d88e85582c68.png} | Bin ...g => cdf7515d133cbf41ffbaea8c488e0924.png} | Bin ...g => 1ad78f9f9d001278c491b0f2be5cc8ea.png} | Bin ...g => 768094c3c47d3888cf81e7a1d20d2eab.png} | Bin ...g => 43875f6ad588bfd04cdb65b591a62052.png} | Bin ...g => 75f7b5b31e98444e13f17e5c3e5b7322.png} | Bin ...g => 81b5d76a31fec09719eb7b00c2c82200.png} | Bin ...g => 09cfa54ec3709d54efdce78832e42367.png} | Bin docs/index.html | 46 +- docs/ja-JP/index.html | 46 +- .../lib/perform-code-surgery.js | 2 +- docs/zh-CN/index.html | 46 +- 48 files changed, 97 insertions(+), 15074 deletions(-) delete mode 100644 docs/chapters/shapes/paper-core.js rename docs/images/chapters/arcapproximation/{6f30b487d0cb60a4caeed4a199c48253.png => da76341b841df1af8a39f797e85dfe3c.png} (100%) delete mode 100644 docs/images/chapters/canonical/344346f09b6d5d7e3ddf91084ad50d46.png delete mode 100644 docs/images/chapters/canonical/675217e6df3d75c86503dc2af623e14e.png create mode 100644 docs/images/chapters/canonical/83fe2473e20ea68b768765129ee44ae4.png create mode 100644 docs/images/chapters/canonical/c086e72bd8aaeab37436515ab251b2df.png rename docs/images/chapters/catmullconv/{a6289e403f079730b7546ab94176d42f.png => aa46749b9469341d9249ca452390d875.png} (100%) rename docs/images/chapters/circles/{6b6d06464219b8b0a046cfd99fe571d1.png => 5801de8227960faa9bcbae578f78c2a3.png} (100%) rename docs/images/chapters/circles_cubic/{9c6b58f84913ca69f930a19ade6baf53.png => da768b84c91262bab8ab36f895e8569b.png} (100%) rename docs/images/chapters/control/{882ae425daeb3f449e5a4d649b8425e7.png => 2cc2f0127510f2700656c2f894b36674.png} (100%) rename docs/images/chapters/control/{2c5b710606f31ed8830397ad2a77d16e.png => 3b627846198c0cb3c542fe13cb923029.png} (100%) rename docs/images/chapters/control/{c7cebd1c54c120c3a9513062e562f3a6.png => 71d891b569460c79765670d3f49d2da9.png} (100%) rename docs/images/chapters/curveintersection/{914e097fe4341697e05b6fd328cc4c91.png => 9540ecc84c3fc63a07f5372ab031c99e.png} (100%) rename docs/images/chapters/graduatedoffset/{99ff5ed1aec246be4490cc617c629138.png => 17bf62e05a1fc3387b0c210f2decff45.png} (100%) rename docs/images/chapters/graduatedoffset/{204745d093e479adaf1fc6fbba0d9d41.png => 8cc724d5343c65685d88c92b2d069a2a.png} (100%) rename docs/images/chapters/intersections/{dc26a6063dadc31d242f1c1c8f38bb5e.png => 4a762fb56468c342c72756a76d134f05.png} (100%) rename docs/images/chapters/intersections/{594c2df534a1736c03cd3a96ff4a9913.png => 7003a384ec371217af2b225ae65872e7.png} (100%) rename docs/images/chapters/intersections/{61876a2bd727df377619c5ad34ce86be.png => cab1799841eedd1dcd1cd81b6045f40f.png} (100%) rename docs/images/chapters/molding/{502de5e21415ee75ab5d2cffbc921a77.png => 834af194de17a5eb2c1920773ab904e3.png} (100%) rename docs/images/chapters/molding/{9a214cd85a1f0857b1b57db5e9c37b9c.png => aefb177e5532a9f995b9d88e85582c68.png} (100%) rename docs/images/chapters/molding/{610251fd14e24cd1378590de87ce2a74.png => cdf7515d133cbf41ffbaea8c488e0924.png} (100%) rename docs/images/chapters/offsetting/{953485135c6d856ae1327fd47e55c920.png => 1ad78f9f9d001278c491b0f2be5cc8ea.png} (100%) rename docs/images/chapters/offsetting/{91cd824148a388762d27e40fabb34e0d.png => 768094c3c47d3888cf81e7a1d20d2eab.png} (100%) rename docs/images/chapters/pointcurves/{173ea31517a72a927d561f121f0677db.png => 43875f6ad588bfd04cdb65b591a62052.png} (100%) rename docs/images/chapters/pointcurves/{8d045d352f5017b65e60620b92d7ae29.png => 75f7b5b31e98444e13f17e5c3e5b7322.png} (100%) rename docs/images/chapters/shapes/{46b3f87fa3aa9b54b688fbdfbe9ffb5e.png => 81b5d76a31fec09719eb7b00c2c82200.png} (100%) rename docs/images/chapters/tracing/{133bf9d02801a3149c9ddb8b313e6797.png => 09cfa54ec3709d54efdce78832e42367.png} (100%) diff --git a/docs/chapters/arcapproximation/arcs.js b/docs/chapters/arcapproximation/arcs.js index 607ecf8f..4e0f078b 100644 --- a/docs/chapters/arcapproximation/arcs.js +++ b/docs/chapters/arcapproximation/arcs.js @@ -17,7 +17,7 @@ draw() { // See "arc.js" for the code required to find arcs on the curve. let arcs = curve.arcs(this.error); arcs.forEach(a => { - setColor( randomColor(0.3) ); + setColor(randomColor(0.3)); arc( a.x, a.y, a.r, a.s, a.e, a.x, a.y diff --git a/docs/chapters/canonical/canonical.js b/docs/chapters/canonical/canonical.js index 378d3757..52b94ada 100644 --- a/docs/chapters/canonical/canonical.js +++ b/docs/chapters/canonical/canonical.js @@ -83,7 +83,7 @@ loopFunction0(x) { } loopFunction1(x) { - return { x, y: ( sqrt(3) * sqrt(4*x - x*x) - x) / 2 }; + return { x, y: (sqrt(3) * sqrt(4*x - x*x) - x) / 2 }; } diff --git a/docs/chapters/canonical/interactive.js b/docs/chapters/canonical/interactive.js index 195bbf69..aef669f4 100644 --- a/docs/chapters/canonical/interactive.js +++ b/docs/chapters/canonical/interactive.js @@ -150,7 +150,7 @@ loopFunction0(x) { } loopFunction1(x) { - return { x, y: ( sqrt(3) * sqrt(4*x - x*x) - x) / 2 }; + return { x, y: (sqrt(3) * sqrt(4*x - x*x) - x) / 2 }; } diff --git a/docs/chapters/catmullconv/catmull-rom.js b/docs/chapters/catmullconv/catmull-rom.js index ff59dcbb..e377fa72 100644 --- a/docs/chapters/catmullconv/catmull-rom.js +++ b/docs/chapters/catmullconv/catmull-rom.js @@ -39,7 +39,7 @@ draw() { noLineDash(); points.forEach(p => { - setColor( randomColor() ); + setColor(randomColor()); circle(p.x, p.y, 3); }); } @@ -56,7 +56,7 @@ dragSegment(p0, p1, p2, p3) { }; noFill(); - setStroke( randomColor() ); + setStroke(randomColor() ); start(); this.addCoordinate(0, p1, p2, m1, m2); diff --git a/docs/chapters/catmullconv/notes.txt b/docs/chapters/catmullconv/notes.txt index 3312534d..a1a6a79e 100644 --- a/docs/chapters/catmullconv/notes.txt +++ b/docs/chapters/catmullconv/notes.txt @@ -97,7 +97,7 @@ dragSegment(p0, p1, p2, p3) { }; noFill(); - setStroke( randomColor() ); + setStroke(randomColor() ); start(); this.markCoordinate(0, p1,p2,tangent1,tangent2); diff --git a/docs/chapters/circles/arc-approximation.js b/docs/chapters/circles/arc-approximation.js index e01f484e..8faeef3a 100644 --- a/docs/chapters/circles/arc-approximation.js +++ b/docs/chapters/circles/arc-approximation.js @@ -39,12 +39,12 @@ draw() { updateCurve(a) { let angle = -a; - let b = ( cos(angle) - 1 ) / sin(angle); + let b = (cos(angle) - 1 ) / sin(angle); // new control point curve.points[1] = { - x: w/2 + r * ( cos(angle) - b * sin(angle) ), - y: w/2 + r * ( sin(angle) + b * cos(angle) ) + x: w/2 + r * (cos(angle) - b * sin(angle) ), + y: w/2 + r * (sin(angle) + b * cos(angle) ) }; // new endpoint diff --git a/docs/chapters/circles_cubic/arc-approximation.js b/docs/chapters/circles_cubic/arc-approximation.js index 00758c68..f78d49be 100644 --- a/docs/chapters/circles_cubic/arc-approximation.js +++ b/docs/chapters/circles_cubic/arc-approximation.js @@ -78,8 +78,8 @@ getRealCurve(S, E, angle) { const f = 4/3 * tan(angle/4); const C1 = { x: w/2 + r, y: h/2 + r * f }; const C2 = { - x: w/2 + r * ( cos(angle) + f * sin(angle) ), - y: h/2 + r * ( sin(angle) - f * cos(angle) ) + x: w/2 + r * (cos(angle) + f * sin(angle)), + y: h/2 + r * (sin(angle) - f * cos(angle)) }; return new Bezier(this, [S, C1, C2, E]); } diff --git a/docs/chapters/control/lerp.js b/docs/chapters/control/lerp.js index aa8ab297..030aecfa 100644 --- a/docs/chapters/control/lerp.js +++ b/docs/chapters/control/lerp.js @@ -43,12 +43,12 @@ draw() { noFill(); this.s.forEach((s,i) => { - setStroke( randomColor(0.2)); + setStroke(randomColor(0.2)); line( i/(this.s.length-1) * this.width, 0, i/(this.s.length-1) * this.width, this.height ) - setStroke( randomColor(1.0, false )); + setStroke(randomColor(1.0, false )); drawShape(s); }) diff --git a/docs/chapters/curveintersection/curve-curve.js b/docs/chapters/curveintersection/curve-curve.js index ccb1184c..4a95ebeb 100644 --- a/docs/chapters/curveintersection/curve-curve.js +++ b/docs/chapters/curveintersection/curve-curve.js @@ -95,7 +95,7 @@ drawIteration() { pair.forEach(b => { let curve = new Bezier(this, b.points); curve.drawCurve(); - curve.drawBoundingBox( randomColor() ); + curve.drawBoundingBox(randomColor()); }) }); diff --git a/docs/chapters/graduatedoffset/offsetting.js b/docs/chapters/graduatedoffset/offsetting.js index af18fe6c..ca471707 100644 --- a/docs/chapters/graduatedoffset/offsetting.js +++ b/docs/chapters/graduatedoffset/offsetting.js @@ -21,7 +21,7 @@ draw() { }; drawCurve(c) { - setStroke( randomColor() ); + setStroke(randomColor() ); start() c.getLUT(16).forEach(p => vertex(p.x, p.y)); end(); diff --git a/docs/chapters/intersections/curve-line.js b/docs/chapters/intersections/curve-line.js index d81095ac..cb7425e6 100644 --- a/docs/chapters/intersections/curve-line.js +++ b/docs/chapters/intersections/curve-line.js @@ -47,7 +47,7 @@ draw() { drawLine(p1, p2) { setStroke(`black`); line(p1.x, p1.y, p2.x, p2.y); - setStroke( randomColor() ); + setStroke(randomColor() ); circle(p1.x, p1.y, 3); circle(p2.x, p2.y, 3); } diff --git a/docs/chapters/intersections/line-line.js b/docs/chapters/intersections/line-line.js index eb022550..5af4f836 100644 --- a/docs/chapters/intersections/line-line.js +++ b/docs/chapters/intersections/line-line.js @@ -39,7 +39,7 @@ draw() { drawLine(p1, p2) { setColor(`black`); line(p1.x, p1.y, p2.x, p2.y); - setStroke( randomColor() ); + setStroke(randomColor() ); circle(p1.x, p1.y, 2); circle(p2.x, p2.y, 2); } diff --git a/docs/chapters/molding/molding.js b/docs/chapters/molding/molding.js index 152bf018..461796b3 100644 --- a/docs/chapters/molding/molding.js +++ b/docs/chapters/molding/molding.js @@ -168,7 +168,7 @@ getIdealisedCurve(p1, p2, p3) { d2 = dist(p3.x, p3.y, p2.x, p2.y), t = d1 / (d1 + d2), { A, B, C, S, E } = Bezier.getABC(3, p1, p2, p3, t), - angle = ( atan2(E.y-S.y, E.x-S.x) - atan2(B.y-S.y, B.x-S.x) + TAU ) % TAU, + angle = (atan2(E.y-S.y, E.x-S.x) - atan2(B.y-S.y, B.x-S.x) + TAU) % TAU, bc = (angle < 0 || angle > PI ? -1 : 1) * dist(S.x, S.y, E.x, E.y)/3, de1 = t * bc, de2 = (1-t) * bc, diff --git a/docs/chapters/offsetting/offsetting.js b/docs/chapters/offsetting/offsetting.js index 1bb7f5fe..506c1d6e 100644 --- a/docs/chapters/offsetting/offsetting.js +++ b/docs/chapters/offsetting/offsetting.js @@ -19,7 +19,7 @@ draw() { var reduced = this.reduce(curve); reduced.forEach(c => { - setStroke( randomColor() ); + setStroke(randomColor() ); this.drawCurve(c); circle(c.points[0].x, c.points[0].y, 2); }); @@ -93,7 +93,7 @@ reduce(curve) { segment = p1.split(t1, t2); if (!segment.simple()) { t2 -= step; - if ( abs(t1 - t2) < step) { + if (abs(t1 - t2) < step) { // we can never form a reduction return []; } diff --git a/docs/chapters/pointcurves/circle.js b/docs/chapters/pointcurves/circle.js index a1efa103..dd885005 100644 --- a/docs/chapters/pointcurves/circle.js +++ b/docs/chapters/pointcurves/circle.js @@ -102,17 +102,17 @@ caclulateCenter(p1, p2, p3) { } showChords(p1, p2, p3, c) { - setStroke( randomColor() ); + setStroke(randomColor() ); line(p1.x, p1.y, p2.x, p2.y); let m1 = { x: (p1.x+p2.x)/2, y: (p1.y+p2.y)/2 }; line(m1.x, m1.y, c.x + (c.x-m1.x)/2, c.y + (c.y-m1.y)/2); - setStroke( randomColor() ); + setStroke(randomColor() ); line(p3.x, p3.y, p2.x, p2.y); let m2 = { x: (p3.x+p2.x)/2, y: (p3.y+p2.y)/2 }; line(m2.x, m2.y, c.x + (c.x-m2.x)/2, c.y + (c.y-m2.y)/2); - setStroke( randomColor() ); + setStroke(randomColor() ); line(p3.x, p3.y, p1.x, p1.y); let m3 = { x: (p3.x+p1.x)/2, y: (p3.y+p1.y)/2 }; line(m3.x, m3.y, c.x + (c.x-m3.x)/2, c.y + (c.y-m3.y)/2); @@ -131,7 +131,7 @@ showCurve(p1, p2, p3, c) { // Check which length we need to use for our e1-e2 segment, // corrected for whether B is "above" or "below" the baseline: - const angle = ( atan2(E.y-S.y, E.x-S.x) - atan2(B.y-S.y, B.x-S.x) + TAU ) % TAU, + const angle = (atan2(E.y-S.y, E.x-S.x) - atan2(B.y-S.y, B.x-S.x) + TAU) % TAU, bc = (angle < 0 || angle > PI ? -1 : 1) * dist(S.x, S.y, E.x, E.y)/3, de1 = t * bc, de2 = (1-t) * bc; diff --git a/docs/chapters/shapes/boolean.js b/docs/chapters/shapes/boolean.js index 41d56d58..2858d479 100644 --- a/docs/chapters/shapes/boolean.js +++ b/docs/chapters/shapes/boolean.js @@ -58,7 +58,7 @@ draw() { drawSegment(segment) { - setStroke( randomColor(0.2) ); + setStroke(randomColor(0.2) ); start() segment.getLUT(16).forEach(p => vertex(p.x, p.y)) end(); @@ -78,7 +78,7 @@ drawBoolean(s1, s2) { ti = ti.map(s => s.split(`/`).map(parseFloat)); // remove "near enough to be considered duplicate" t pairs for(let i=ti.length-1; i>0; i--) { - if ( abs(ti[i][0] - ti[i-1][0]) < 0.01 && abs(ti[i][1] - ti[i-1][1]) < 0.01) { + if (abs(ti[i][0] - ti[i-1][0]) < 0.01 && abs(ti[i][1] - ti[i-1][1]) < 0.01) { ti.splice(i,1); } } diff --git a/docs/chapters/shapes/paper-core.js b/docs/chapters/shapes/paper-core.js deleted file mode 100644 index 2e25cf8c..00000000 --- a/docs/chapters/shapes/paper-core.js +++ /dev/null @@ -1,14977 +0,0 @@ -/*! - * Paper.js v0.11.8 - The Swiss Army Knife of Vector Graphics Scripting. - * http://paperjs.org/ - * - * Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey - * http://scratchdisk.com/ & http://jonathanpuckey.com/ - * - * Distributed under the MIT license. See LICENSE file for details. - * - * All rights reserved. - * - * Date: Wed Oct 17 17:00:54 2018 +0200 - * - *** - * - * Straps.js - Class inheritance library with support for bean-style accessors - * - * Copyright (c) 2006 - 2016 Juerg Lehni - * http://scratchdisk.com/ - * - * Distributed under the MIT license. - * - *** - * - * Acorn.js - * http://marijnhaverbeke.nl/acorn/ - * - * Acorn is a tiny, fast JavaScript parser written in JavaScript, - * created by Marijn Haverbeke and released under an MIT license. - * - */ - -var paper = function(self, undefined) { - -self = self || require('./node/self.js'); -var window = self.window, - document = self.document; - -var Base = new function() { - var hidden = /^(statics|enumerable|beans|preserve)$/, - array = [], - slice = array.slice, - create = Object.create, - describe = Object.getOwnPropertyDescriptor, - define = Object.defineProperty, - - forEach = array.forEach || function(iter, bind) { - for (var i = 0, l = this.length; i < l; i++) { - iter.call(bind, this[i], i, this); - } - }, - - forIn = function(iter, bind) { - for (var i in this) { - if (this.hasOwnProperty(i)) - iter.call(bind, this[i], i, this); - } - }, - - set = Object.assign || function(dst) { - for (var i = 1, l = arguments.length; i < l; i++) { - var src = arguments[i]; - for (var key in src) { - if (src.hasOwnProperty(key)) - dst[key] = src[key]; - } - } - return dst; - }, - - each = function(obj, iter, bind) { - if (obj) { - var desc = describe(obj, 'length'); - (desc && typeof desc.value === 'number' ? forEach : forIn) - .call(obj, iter, bind = bind || obj); - } - return bind; - }; - - function inject(dest, src, enumerable, beans, preserve) { - var beansNames = {}; - - function field(name, val) { - val = val || (val = describe(src, name)) - && (val.get ? val : val.value); - if (typeof val === 'string' && val[0] === '#') - val = dest[val.substring(1)] || val; - var isFunc = typeof val === 'function', - res = val, - prev = preserve || isFunc && !val.base - ? (val && val.get ? name in dest : dest[name]) - : null, - bean; - if (!preserve || !prev) { - if (isFunc && prev) - val.base = prev; - if (isFunc && beans !== false - && (bean = name.match(/^([gs]et|is)(([A-Z])(.*))$/))) - beansNames[bean[3].toLowerCase() + bean[4]] = bean[2]; - if (!res || isFunc || !res.get || typeof res.get !== 'function' - || !Base.isPlainObject(res)) { - res = { value: res, writable: true }; - } - if ((describe(dest, name) - || { configurable: true }).configurable) { - res.configurable = true; - res.enumerable = enumerable != null ? enumerable : !bean; - } - define(dest, name, res); - } - } - if (src) { - for (var name in src) { - if (src.hasOwnProperty(name) && !hidden.test(name)) - field(name); - } - for (var name in beansNames) { - var part = beansNames[name], - set = dest['set' + part], - get = dest['get' + part] || set && dest['is' + part]; - if (get && (beans === true || get.length === 0)) - field(name, { get: get, set: set }); - } - } - return dest; - } - - function Base() { - for (var i = 0, l = arguments.length; i < l; i++) { - var src = arguments[i]; - if (src) - set(this, src); - } - return this; - } - - return inject(Base, { - inject: function(src) { - if (src) { - var statics = src.statics === true ? src : src.statics, - beans = src.beans, - preserve = src.preserve; - if (statics !== src) - inject(this.prototype, src, src.enumerable, beans, preserve); - inject(this, statics, null, beans, preserve); - } - for (var i = 1, l = arguments.length; i < l; i++) - this.inject(arguments[i]); - return this; - }, - - extend: function() { - var base = this, - ctor, - proto; - for (var i = 0, obj, l = arguments.length; - i < l && !(ctor && proto); i++) { - obj = arguments[i]; - ctor = ctor || obj.initialize; - proto = proto || obj.prototype; - } - ctor = ctor || function() { - base.apply(this, arguments); - }; - proto = ctor.prototype = proto || create(this.prototype); - define(proto, 'constructor', - { value: ctor, writable: true, configurable: true }); - inject(ctor, this); - if (arguments.length) - this.inject.apply(ctor, arguments); - ctor.base = base; - return ctor; - } - }).inject({ - enumerable: false, - - initialize: Base, - - set: Base, - - inject: function() { - for (var i = 0, l = arguments.length; i < l; i++) { - var src = arguments[i]; - if (src) { - inject(this, src, src.enumerable, src.beans, src.preserve); - } - } - return this; - }, - - extend: function() { - var res = create(this); - return res.inject.apply(res, arguments); - }, - - each: function(iter, bind) { - return each(this, iter, bind); - }, - - clone: function() { - return new this.constructor(this); - }, - - statics: { - set: set, - each: each, - create: create, - define: define, - describe: describe, - - clone: function(obj) { - return set(new obj.constructor(), obj); - }, - - isPlainObject: function(obj) { - var ctor = obj != null && obj.constructor; - return ctor && (ctor === Object || ctor === Base - || ctor.name === 'Object'); - }, - - pick: function(a, b) { - return a !== undefined ? a : b; - }, - - slice: function(list, begin, end) { - return slice.call(list, begin, end); - } - } - }); -}; - -if (typeof module !== 'undefined') - module.exports = Base; - -Base.inject({ - enumerable: false, - - toString: function() { - return this._id != null - ? (this._class || 'Object') + (this._name - ? " '" + this._name + "'" - : ' @' + this._id) - : '{ ' + Base.each(this, function(value, key) { - if (!/^_/.test(key)) { - var type = typeof value; - this.push(key + ': ' + (type === 'number' - ? Formatter.instance.number(value) - : type === 'string' ? "'" + value + "'" : value)); - } - }, []).join(', ') + ' }'; - }, - - getClassName: function() { - return this._class || ''; - }, - - importJSON: function(json) { - return Base.importJSON(json, this); - }, - - exportJSON: function(options) { - return Base.exportJSON(this, options); - }, - - toJSON: function() { - return Base.serialize(this); - }, - - set: function(props, exclude) { - if (props) - Base.filter(this, props, exclude, this._prioritize); - return this; - } -}, { - -beans: false, -statics: { - exports: {}, - - extend: function extend() { - var res = extend.base.apply(this, arguments), - name = res.prototype._class; - if (name && !Base.exports[name]) - Base.exports[name] = res; - return res; - }, - - equals: function(obj1, obj2) { - if (obj1 === obj2) - return true; - if (obj1 && obj1.equals) - return obj1.equals(obj2); - if (obj2 && obj2.equals) - return obj2.equals(obj1); - if (obj1 && obj2 - && typeof obj1 === 'object' && typeof obj2 === 'object') { - if (Array.isArray(obj1) && Array.isArray(obj2)) { - var length = obj1.length; - if (length !== obj2.length) - return false; - while (length--) { - if (!Base.equals(obj1[length], obj2[length])) - return false; - } - } else { - var keys = Object.keys(obj1), - length = keys.length; - if (length !== Object.keys(obj2).length) - return false; - while (length--) { - var key = keys[length]; - if (!(obj2.hasOwnProperty(key) - && Base.equals(obj1[key], obj2[key]))) - return false; - } - } - return true; - } - return false; - }, - - read: function(list, start, options, amount) { - if (this === Base) { - var value = this.peek(list, start); - list.__index++; - return value; - } - var proto = this.prototype, - readIndex = proto._readIndex, - begin = start || readIndex && list.__index || 0, - length = list.length, - obj = list[begin]; - amount = amount || length - begin; - if (obj instanceof this - || options && options.readNull && obj == null && amount <= 1) { - if (readIndex) - list.__index = begin + 1; - return obj && options && options.clone ? obj.clone() : obj; - } - obj = Base.create(proto); - if (readIndex) - obj.__read = true; - obj = obj.initialize.apply(obj, begin > 0 || begin + amount < length - ? Base.slice(list, begin, begin + amount) - : list) || obj; - if (readIndex) { - list.__index = begin + obj.__read; - var filtered = obj.__filtered; - if (filtered) { - list.__filtered = filtered; - obj.__filtered = undefined; - } - obj.__read = undefined; - } - return obj; - }, - - peek: function(list, start) { - return list[list.__index = start || list.__index || 0]; - }, - - remain: function(list) { - return list.length - (list.__index || 0); - }, - - readList: function(list, start, options, amount) { - var res = [], - entry, - begin = start || 0, - end = amount ? begin + amount : list.length; - for (var i = begin; i < end; i++) { - res.push(Array.isArray(entry = list[i]) - ? this.read(entry, 0, options) - : this.read(list, i, options, 1)); - } - return res; - }, - - readNamed: function(list, name, start, options, amount) { - var value = this.getNamed(list, name), - hasObject = value !== undefined; - if (hasObject) { - var filtered = list.__filtered; - if (!filtered) { - filtered = list.__filtered = Base.create(list[0]); - filtered.__unfiltered = list[0]; - } - filtered[name] = undefined; - } - var l = hasObject ? [value] : list, - res = this.read(l, start, options, amount); - return res; - }, - - getNamed: function(list, name) { - var arg = list[0]; - if (list._hasObject === undefined) - list._hasObject = list.length === 1 && Base.isPlainObject(arg); - if (list._hasObject) - return name ? arg[name] : list.__filtered || arg; - }, - - hasNamed: function(list, name) { - return !!this.getNamed(list, name); - }, - - filter: function(dest, source, exclude, prioritize) { - var processed; - - function handleKey(key) { - if (!(exclude && key in exclude) && - !(processed && key in processed)) { - var value = source[key]; - if (value !== undefined) - dest[key] = value; - } - } - - if (prioritize) { - var keys = {}; - for (var i = 0, key, l = prioritize.length; i < l; i++) { - if ((key = prioritize[i]) in source) { - handleKey(key); - keys[key] = true; - } - } - processed = keys; - } - - Object.keys(source.__unfiltered || source).forEach(handleKey); - return dest; - }, - - isPlainValue: function(obj, asString) { - return Base.isPlainObject(obj) || Array.isArray(obj) - || asString && typeof obj === 'string'; - }, - - serialize: function(obj, options, compact, dictionary) { - options = options || {}; - - var isRoot = !dictionary, - res; - if (isRoot) { - options.formatter = new Formatter(options.precision); - dictionary = { - length: 0, - definitions: {}, - references: {}, - add: function(item, create) { - var id = '#' + item._id, - ref = this.references[id]; - if (!ref) { - this.length++; - var res = create.call(item), - name = item._class; - if (name && res[0] !== name) - res.unshift(name); - this.definitions[id] = res; - ref = this.references[id] = [id]; - } - return ref; - } - }; - } - if (obj && obj._serialize) { - res = obj._serialize(options, dictionary); - var name = obj._class; - if (name && !obj._compactSerialize && (isRoot || !compact) - && res[0] !== name) { - res.unshift(name); - } - } else if (Array.isArray(obj)) { - res = []; - for (var i = 0, l = obj.length; i < l; i++) - res[i] = Base.serialize(obj[i], options, compact, dictionary); - } else if (Base.isPlainObject(obj)) { - res = {}; - var keys = Object.keys(obj); - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - res[key] = Base.serialize(obj[key], options, compact, - dictionary); - } - } else if (typeof obj === 'number') { - res = options.formatter.number(obj, options.precision); - } else { - res = obj; - } - return isRoot && dictionary.length > 0 - ? [['dictionary', dictionary.definitions], res] - : res; - }, - - deserialize: function(json, create, _data, _setDictionary, _isRoot) { - var res = json, - isFirst = !_data, - hasDictionary = isFirst && json && json.length - && json[0][0] === 'dictionary'; - _data = _data || {}; - if (Array.isArray(json)) { - var type = json[0], - isDictionary = type === 'dictionary'; - if (json.length == 1 && /^#/.test(type)) { - return _data.dictionary[type]; - } - type = Base.exports[type]; - res = []; - for (var i = type ? 1 : 0, l = json.length; i < l; i++) { - res.push(Base.deserialize(json[i], create, _data, - isDictionary, hasDictionary)); - } - if (type) { - var args = res; - if (create) { - res = create(type, args, isFirst || _isRoot); - } else { - res = new type(args); - } - } - } else if (Base.isPlainObject(json)) { - res = {}; - if (_setDictionary) - _data.dictionary = res; - for (var key in json) - res[key] = Base.deserialize(json[key], create, _data); - } - return hasDictionary ? res[1] : res; - }, - - exportJSON: function(obj, options) { - var json = Base.serialize(obj, options); - return options && options.asString == false - ? json - : JSON.stringify(json); - }, - - importJSON: function(json, target) { - return Base.deserialize( - typeof json === 'string' ? JSON.parse(json) : json, - function(ctor, args, isRoot) { - var useTarget = isRoot && target - && target.constructor === ctor, - obj = useTarget ? target - : Base.create(ctor.prototype); - if (args.length === 1 && obj instanceof Item - && (useTarget || !(obj instanceof Layer))) { - var arg = args[0]; - if (Base.isPlainObject(arg)) - arg.insert = false; - } - (useTarget ? obj.set : ctor).apply(obj, args); - if (useTarget) - target = null; - return obj; - }); - }, - - push: function(list, items) { - var itemsLength = items.length; - if (itemsLength < 4096) { - list.push.apply(list, items); - } else { - var startLength = list.length; - list.length += itemsLength; - for (var i = 0; i < itemsLength; i++) { - list[startLength + i] = items[i]; - } - } - return list; - }, - - splice: function(list, items, index, remove) { - var amount = items && items.length, - append = index === undefined; - index = append ? list.length : index; - if (index > list.length) - index = list.length; - for (var i = 0; i < amount; i++) - items[i]._index = index + i; - if (append) { - Base.push(list, items); - return []; - } else { - var args = [index, remove]; - if (items) - Base.push(args, items); - var removed = list.splice.apply(list, args); - for (var i = 0, l = removed.length; i < l; i++) - removed[i]._index = undefined; - for (var i = index + amount, l = list.length; i < l; i++) - list[i]._index = i; - return removed; - } - }, - - capitalize: function(str) { - return str.replace(/\b[a-z]/g, function(match) { - return match.toUpperCase(); - }); - }, - - camelize: function(str) { - return str.replace(/-(.)/g, function(match, chr) { - return chr.toUpperCase(); - }); - }, - - hyphenate: function(str) { - return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); - } -}}); - -var Emitter = { - on: function(type, func) { - if (typeof type !== 'string') { - Base.each(type, function(value, key) { - this.on(key, value); - }, this); - } else { - var types = this._eventTypes, - entry = types && types[type], - handlers = this._callbacks = this._callbacks || {}; - handlers = handlers[type] = handlers[type] || []; - if (handlers.indexOf(func) === -1) { - handlers.push(func); - if (entry && entry.install && handlers.length === 1) - entry.install.call(this, type); - } - } - return this; - }, - - off: function(type, func) { - if (typeof type !== 'string') { - Base.each(type, function(value, key) { - this.off(key, value); - }, this); - return; - } - var types = this._eventTypes, - entry = types && types[type], - handlers = this._callbacks && this._callbacks[type], - index; - if (handlers) { - if (!func || (index = handlers.indexOf(func)) !== -1 - && handlers.length === 1) { - if (entry && entry.uninstall) - entry.uninstall.call(this, type); - delete this._callbacks[type]; - } else if (index !== -1) { - handlers.splice(index, 1); - } - } - return this; - }, - - once: function(type, func) { - return this.on(type, function() { - func.apply(this, arguments); - this.off(type, func); - }); - }, - - emit: function(type, event) { - var handlers = this._callbacks && this._callbacks[type]; - if (!handlers) - return false; - var args = Base.slice(arguments, 1), - setTarget = event && event.target && !event.currentTarget; - handlers = handlers.slice(); - if (setTarget) - event.currentTarget = this; - for (var i = 0, l = handlers.length; i < l; i++) { - if (handlers[i].apply(this, args) == false) { - if (event && event.stop) - event.stop(); - break; - } - } - if (setTarget) - delete event.currentTarget; - return true; - }, - - responds: function(type) { - return !!(this._callbacks && this._callbacks[type]); - }, - - attach: '#on', - detach: '#off', - fire: '#emit', - - _installEvents: function(install) { - var types = this._eventTypes, - handlers = this._callbacks, - key = install ? 'install' : 'uninstall'; - if (types) { - for (var type in handlers) { - if (handlers[type].length > 0) { - var entry = types[type], - func = entry && entry[key]; - if (func) - func.call(this, type); - } - } - } - }, - - statics: { - inject: function inject(src) { - var events = src._events; - if (events) { - var types = {}; - Base.each(events, function(entry, key) { - var isString = typeof entry === 'string', - name = isString ? entry : key, - part = Base.capitalize(name), - type = name.substring(2).toLowerCase(); - types[type] = isString ? {} : entry; - name = '_' + name; - src['get' + part] = function() { - return this[name]; - }; - src['set' + part] = function(func) { - var prev = this[name]; - if (prev) - this.off(type, prev); - if (func) - this.on(type, func); - this[name] = func; - }; - }); - src._eventTypes = types; - } - return inject.base.apply(this, arguments); - } - } -}; - -var PaperScope = Base.extend({ - _class: 'PaperScope', - - initialize: function PaperScope() { - paper = this; - this.settings = new Base({ - applyMatrix: true, - insertItems: true, - handleSize: 4, - hitTolerance: 0 - }); - this.project = null; - this.projects = []; - this.tools = []; - this._id = PaperScope._id++; - PaperScope._scopes[this._id] = this; - var proto = PaperScope.prototype; - if (!this.support) { - var ctx = CanvasProvider.getContext(1, 1) || {}; - proto.support = { - nativeDash: 'setLineDash' in ctx || 'mozDash' in ctx, - nativeBlendModes: BlendMode.nativeModes - }; - CanvasProvider.release(ctx); - } - if (!this.agent) { - var user = self.navigator.userAgent.toLowerCase(), - os = (/(darwin|win|mac|linux|freebsd|sunos)/.exec(user)||[])[0], - platform = os === 'darwin' ? 'mac' : os, - agent = proto.agent = proto.browser = { platform: platform }; - if (platform) - agent[platform] = true; - user.replace( - /(opera|chrome|safari|webkit|firefox|msie|trident|atom|node)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g, - function(match, n, v1, v2, rv) { - if (!agent.chrome) { - var v = n === 'opera' ? v2 : - /^(node|trident)$/.test(n) ? rv : v1; - agent.version = v; - agent.versionNumber = parseFloat(v); - n = n === 'trident' ? 'msie' : n; - agent.name = n; - agent[n] = true; - } - } - ); - if (agent.chrome) - delete agent.webkit; - if (agent.atom) - delete agent.chrome; - } - }, - - version: "0.11.8", - - getView: function() { - var project = this.project; - return project && project._view; - }, - - getPaper: function() { - return this; - }, - - execute: function(code, options) { - }, - - install: function(scope) { - var that = this; - Base.each(['project', 'view', 'tool'], function(key) { - Base.define(scope, key, { - configurable: true, - get: function() { - return that[key]; - } - }); - }); - for (var key in this) - if (!/^_/.test(key) && this[key]) - scope[key] = this[key]; - }, - - setup: function(element) { - paper = this; - this.project = new Project(element); - return this; - }, - - createCanvas: function(width, height) { - return CanvasProvider.getCanvas(width, height); - }, - - activate: function() { - paper = this; - }, - - clear: function() { - var projects = this.projects, - tools = this.tools; - for (var i = projects.length - 1; i >= 0; i--) - projects[i].remove(); - for (var i = tools.length - 1; i >= 0; i--) - tools[i].remove(); - }, - - remove: function() { - this.clear(); - delete PaperScope._scopes[this._id]; - }, - - statics: new function() { - function handleAttribute(name) { - name += 'Attribute'; - return function(el, attr) { - return el[name](attr) || el[name]('data-paper-' + attr); - }; - } - - return { - _scopes: {}, - _id: 0, - - get: function(id) { - return this._scopes[id] || null; - }, - - getAttribute: handleAttribute('get'), - hasAttribute: handleAttribute('has') - }; - } -}); - -var PaperScopeItem = Base.extend(Emitter, { - - initialize: function(activate) { - this._scope = paper; - this._index = this._scope[this._list].push(this) - 1; - if (activate || !this._scope[this._reference]) - this.activate(); - }, - - activate: function() { - if (!this._scope) - return false; - var prev = this._scope[this._reference]; - if (prev && prev !== this) - prev.emit('deactivate'); - this._scope[this._reference] = this; - this.emit('activate', prev); - return true; - }, - - isActive: function() { - return this._scope[this._reference] === this; - }, - - remove: function() { - if (this._index == null) - return false; - Base.splice(this._scope[this._list], null, this._index, 1); - if (this._scope[this._reference] == this) - this._scope[this._reference] = null; - this._scope = null; - return true; - }, - - getView: function() { - return this._scope.getView(); - } -}); - -var Formatter = Base.extend({ - initialize: function(precision) { - this.precision = Base.pick(precision, 5); - this.multiplier = Math.pow(10, this.precision); - }, - - number: function(val) { - return this.precision < 16 - ? Math.round(val * this.multiplier) / this.multiplier : val; - }, - - pair: function(val1, val2, separator) { - return this.number(val1) + (separator || ',') + this.number(val2); - }, - - point: function(val, separator) { - return this.number(val.x) + (separator || ',') + this.number(val.y); - }, - - size: function(val, separator) { - return this.number(val.width) + (separator || ',') - + this.number(val.height); - }, - - rectangle: function(val, separator) { - return this.point(val, separator) + (separator || ',') - + this.size(val, separator); - } -}); - -Formatter.instance = new Formatter(); - -var Numerical = new function() { - - var abscissas = [ - [ 0.5773502691896257645091488], - [0,0.7745966692414833770358531], - [ 0.3399810435848562648026658,0.8611363115940525752239465], - [0,0.5384693101056830910363144,0.9061798459386639927976269], - [ 0.2386191860831969086305017,0.6612093864662645136613996,0.9324695142031520278123016], - [0,0.4058451513773971669066064,0.7415311855993944398638648,0.9491079123427585245261897], - [ 0.1834346424956498049394761,0.5255324099163289858177390,0.7966664774136267395915539,0.9602898564975362316835609], - [0,0.3242534234038089290385380,0.6133714327005903973087020,0.8360311073266357942994298,0.9681602395076260898355762], - [ 0.1488743389816312108848260,0.4333953941292471907992659,0.6794095682990244062343274,0.8650633666889845107320967,0.9739065285171717200779640], - [0,0.2695431559523449723315320,0.5190961292068118159257257,0.7301520055740493240934163,0.8870625997680952990751578,0.9782286581460569928039380], - [ 0.1252334085114689154724414,0.3678314989981801937526915,0.5873179542866174472967024,0.7699026741943046870368938,0.9041172563704748566784659,0.9815606342467192506905491], - [0,0.2304583159551347940655281,0.4484927510364468528779129,0.6423493394403402206439846,0.8015780907333099127942065,0.9175983992229779652065478,0.9841830547185881494728294], - [ 0.1080549487073436620662447,0.3191123689278897604356718,0.5152486363581540919652907,0.6872929048116854701480198,0.8272013150697649931897947,0.9284348836635735173363911,0.9862838086968123388415973], - [0,0.2011940939974345223006283,0.3941513470775633698972074,0.5709721726085388475372267,0.7244177313601700474161861,0.8482065834104272162006483,0.9372733924007059043077589,0.9879925180204854284895657], - [ 0.0950125098376374401853193,0.2816035507792589132304605,0.4580167776572273863424194,0.6178762444026437484466718,0.7554044083550030338951012,0.8656312023878317438804679,0.9445750230732325760779884,0.9894009349916499325961542] - ]; - - var weights = [ - [1], - [0.8888888888888888888888889,0.5555555555555555555555556], - [0.6521451548625461426269361,0.3478548451374538573730639], - [0.5688888888888888888888889,0.4786286704993664680412915,0.2369268850561890875142640], - [0.4679139345726910473898703,0.3607615730481386075698335,0.1713244923791703450402961], - [0.4179591836734693877551020,0.3818300505051189449503698,0.2797053914892766679014678,0.1294849661688696932706114], - [0.3626837833783619829651504,0.3137066458778872873379622,0.2223810344533744705443560,0.1012285362903762591525314], - [0.3302393550012597631645251,0.3123470770400028400686304,0.2606106964029354623187429,0.1806481606948574040584720,0.0812743883615744119718922], - [0.2955242247147528701738930,0.2692667193099963550912269,0.2190863625159820439955349,0.1494513491505805931457763,0.0666713443086881375935688], - [0.2729250867779006307144835,0.2628045445102466621806889,0.2331937645919904799185237,0.1862902109277342514260976,0.1255803694649046246346943,0.0556685671161736664827537], - [0.2491470458134027850005624,0.2334925365383548087608499,0.2031674267230659217490645,0.1600783285433462263346525,0.1069393259953184309602547,0.0471753363865118271946160], - [0.2325515532308739101945895,0.2262831802628972384120902,0.2078160475368885023125232,0.1781459807619457382800467,0.1388735102197872384636018,0.0921214998377284479144218,0.0404840047653158795200216], - [0.2152638534631577901958764,0.2051984637212956039659241,0.1855383974779378137417166,0.1572031671581935345696019,0.1215185706879031846894148,0.0801580871597602098056333,0.0351194603317518630318329], - [0.2025782419255612728806202,0.1984314853271115764561183,0.1861610000155622110268006,0.1662692058169939335532009,0.1395706779261543144478048,0.1071592204671719350118695,0.0703660474881081247092674,0.0307532419961172683546284], - [0.1894506104550684962853967,0.1826034150449235888667637,0.1691565193950025381893121,0.1495959888165767320815017,0.1246289712555338720524763,0.0951585116824927848099251,0.0622535239386478928628438,0.0271524594117540948517806] - ]; - - var abs = Math.abs, - sqrt = Math.sqrt, - pow = Math.pow, - log2 = Math.log2 || function(x) { - return Math.log(x) * Math.LOG2E; - }, - EPSILON = 1e-12, - MACHINE_EPSILON = 1.12e-16; - - function clamp(value, min, max) { - return value < min ? min : value > max ? max : value; - } - - function getDiscriminant(a, b, c) { - function split(v) { - var x = v * 134217729, - y = v - x, - hi = y + x, - lo = v - hi; - return [hi, lo]; - } - - var D = b * b - a * c, - E = b * b + a * c; - if (abs(D) * 3 < E) { - var ad = split(a), - bd = split(b), - cd = split(c), - p = b * b, - dp = (bd[0] * bd[0] - p + 2 * bd[0] * bd[1]) + bd[1] * bd[1], - q = a * c, - dq = (ad[0] * cd[0] - q + ad[0] * cd[1] + ad[1] * cd[0]) - + ad[1] * cd[1]; - D = (p - q) + (dp - dq); - } - return D; - } - - function getNormalizationFactor() { - var norm = Math.max.apply(Math, arguments); - return norm && (norm < 1e-8 || norm > 1e8) - ? pow(2, -Math.round(log2(norm))) - : 0; - } - - return { - EPSILON: EPSILON, - MACHINE_EPSILON: MACHINE_EPSILON, - CURVETIME_EPSILON: 1e-8, - GEOMETRIC_EPSILON: 1e-7, - TRIGONOMETRIC_EPSILON: 1e-8, - KAPPA: 4 * (sqrt(2) - 1) / 3, - - isZero: function(val) { - return val >= -EPSILON && val <= EPSILON; - }, - - clamp: clamp, - - integrate: function(f, a, b, n) { - var x = abscissas[n - 2], - w = weights[n - 2], - A = (b - a) * 0.5, - B = A + a, - i = 0, - m = (n + 1) >> 1, - sum = n & 1 ? w[i++] * f(B) : 0; - while (i < m) { - var Ax = A * x[i]; - sum += w[i++] * (f(B + Ax) + f(B - Ax)); - } - return A * sum; - }, - - findRoot: function(f, df, x, a, b, n, tolerance) { - for (var i = 0; i < n; i++) { - var fx = f(x), - dx = fx / df(x), - nx = x - dx; - if (abs(dx) < tolerance) { - x = nx; - break; - } - if (fx > 0) { - b = x; - x = nx <= a ? (a + b) * 0.5 : nx; - } else { - a = x; - x = nx >= b ? (a + b) * 0.5 : nx; - } - } - return clamp(x, a, b); - }, - - solveQuadratic: function(a, b, c, roots, min, max) { - var x1, x2 = Infinity; - if (abs(a) < EPSILON) { - if (abs(b) < EPSILON) - return abs(c) < EPSILON ? -1 : 0; - x1 = -c / b; - } else { - b *= -0.5; - var D = getDiscriminant(a, b, c); - if (D && abs(D) < MACHINE_EPSILON) { - var f = getNormalizationFactor(abs(a), abs(b), abs(c)); - if (f) { - a *= f; - b *= f; - c *= f; - D = getDiscriminant(a, b, c); - } - } - if (D >= -MACHINE_EPSILON) { - var Q = D < 0 ? 0 : sqrt(D), - R = b + (b < 0 ? -Q : Q); - if (R === 0) { - x1 = c / a; - x2 = -x1; - } else { - x1 = R / a; - x2 = c / R; - } - } - } - var count = 0, - boundless = min == null, - minB = min - EPSILON, - maxB = max + EPSILON; - if (isFinite(x1) && (boundless || x1 > minB && x1 < maxB)) - roots[count++] = boundless ? x1 : clamp(x1, min, max); - if (x2 !== x1 - && isFinite(x2) && (boundless || x2 > minB && x2 < maxB)) - roots[count++] = boundless ? x2 : clamp(x2, min, max); - return count; - }, - - solveCubic: function(a, b, c, d, roots, min, max) { - var f = getNormalizationFactor(abs(a), abs(b), abs(c), abs(d)), - x, b1, c2, qd, q; - if (f) { - a *= f; - b *= f; - c *= f; - d *= f; - } - - function evaluate(x0) { - x = x0; - var tmp = a * x; - b1 = tmp + b; - c2 = b1 * x + c; - qd = (tmp + b1) * x + c2; - q = c2 * x + d; - } - - if (abs(a) < EPSILON) { - a = b; - b1 = c; - c2 = d; - x = Infinity; - } else if (abs(d) < EPSILON) { - b1 = b; - c2 = c; - x = 0; - } else { - evaluate(-(b / a) / 3); - var t = q / a, - r = pow(abs(t), 1/3), - s = t < 0 ? -1 : 1, - td = -qd / a, - rd = td > 0 ? 1.324717957244746 * Math.max(r, sqrt(td)) : r, - x0 = x - s * rd; - if (x0 !== x) { - do { - evaluate(x0); - x0 = qd === 0 ? x : x - q / qd / (1 + MACHINE_EPSILON); - } while (s * x0 > s * x); - if (abs(a) * x * x > abs(d / x)) { - c2 = -d / x; - b1 = (c2 - c) / x; - } - } - } - var count = Numerical.solveQuadratic(a, b1, c2, roots, min, max), - boundless = min == null; - if (isFinite(x) && (count === 0 - || count > 0 && x !== roots[0] && x !== roots[1]) - && (boundless || x > min - EPSILON && x < max + EPSILON)) - roots[count++] = boundless ? x : clamp(x, min, max); - return count; - } - }; -}; - -var UID = { - _id: 1, - _pools: {}, - - get: function(name) { - if (name) { - var pool = this._pools[name]; - if (!pool) - pool = this._pools[name] = { _id: 1 }; - return pool._id++; - } else { - return this._id++; - } - } -}; - -var Point = Base.extend({ - _class: 'Point', - _readIndex: true, - - initialize: function Point(arg0, arg1) { - var type = typeof arg0, - reading = this.__read, - read = 0; - if (type === 'number') { - var hasY = typeof arg1 === 'number'; - this._set(arg0, hasY ? arg1 : arg0); - if (reading) - read = hasY ? 2 : 1; - } else if (type === 'undefined' || arg0 === null) { - this._set(0, 0); - if (reading) - read = arg0 === null ? 1 : 0; - } else { - var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0; - read = 1; - if (Array.isArray(obj)) { - this._set(+obj[0], +(obj.length > 1 ? obj[1] : obj[0])); - } else if ('x' in obj) { - this._set(obj.x || 0, obj.y || 0); - } else if ('width' in obj) { - this._set(obj.width || 0, obj.height || 0); - } else if ('angle' in obj) { - this._set(obj.length || 0, 0); - this.setAngle(obj.angle || 0); - } else { - this._set(0, 0); - read = 0; - } - } - if (reading) - this.__read = read; - return this; - }, - - set: '#initialize', - - _set: function(x, y) { - this.x = x; - this.y = y; - return this; - }, - - equals: function(point) { - return this === point || point - && (this.x === point.x && this.y === point.y - || Array.isArray(point) - && this.x === point[0] && this.y === point[1]) - || false; - }, - - clone: function() { - return new Point(this.x, this.y); - }, - - toString: function() { - var f = Formatter.instance; - return '{ x: ' + f.number(this.x) + ', y: ' + f.number(this.y) + ' }'; - }, - - _serialize: function(options) { - var f = options.formatter; - return [f.number(this.x), f.number(this.y)]; - }, - - getLength: function() { - return Math.sqrt(this.x * this.x + this.y * this.y); - }, - - setLength: function(length) { - if (this.isZero()) { - var angle = this._angle || 0; - this._set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } else { - var scale = length / this.getLength(); - if (Numerical.isZero(scale)) - this.getAngle(); - this._set( - this.x * scale, - this.y * scale - ); - } - }, - getAngle: function() { - return this.getAngleInRadians.apply(this, arguments) * 180 / Math.PI; - }, - - setAngle: function(angle) { - this.setAngleInRadians.call(this, angle * Math.PI / 180); - }, - - getAngleInDegrees: '#getAngle', - setAngleInDegrees: '#setAngle', - - getAngleInRadians: function() { - if (!arguments.length) { - return this.isZero() - ? this._angle || 0 - : this._angle = Math.atan2(this.y, this.x); - } else { - var point = Point.read(arguments), - div = this.getLength() * point.getLength(); - if (Numerical.isZero(div)) { - return NaN; - } else { - var a = this.dot(point) / div; - return Math.acos(a < -1 ? -1 : a > 1 ? 1 : a); - } - } - }, - - setAngleInRadians: function(angle) { - this._angle = angle; - if (!this.isZero()) { - var length = this.getLength(); - this._set( - Math.cos(angle) * length, - Math.sin(angle) * length - ); - } - }, - - getQuadrant: function() { - return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3; - } -}, { - beans: false, - - getDirectedAngle: function() { - var point = Point.read(arguments); - return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI; - }, - - getDistance: function() { - var point = Point.read(arguments), - x = point.x - this.x, - y = point.y - this.y, - d = x * x + y * y, - squared = Base.read(arguments); - return squared ? d : Math.sqrt(d); - }, - - normalize: function(length) { - if (length === undefined) - length = 1; - var current = this.getLength(), - scale = current !== 0 ? length / current : 0, - point = new Point(this.x * scale, this.y * scale); - if (scale >= 0) - point._angle = this._angle; - return point; - }, - - rotate: function(angle, center) { - if (angle === 0) - return this.clone(); - angle = angle * Math.PI / 180; - var point = center ? this.subtract(center) : this, - sin = Math.sin(angle), - cos = Math.cos(angle); - point = new Point( - point.x * cos - point.y * sin, - point.x * sin + point.y * cos - ); - return center ? point.add(center) : point; - }, - - transform: function(matrix) { - return matrix ? matrix._transformPoint(this) : this; - }, - - add: function() { - var point = Point.read(arguments); - return new Point(this.x + point.x, this.y + point.y); - }, - - subtract: function() { - var point = Point.read(arguments); - return new Point(this.x - point.x, this.y - point.y); - }, - - multiply: function() { - var point = Point.read(arguments); - return new Point(this.x * point.x, this.y * point.y); - }, - - divide: function() { - var point = Point.read(arguments); - return new Point(this.x / point.x, this.y / point.y); - }, - - modulo: function() { - var point = Point.read(arguments); - return new Point(this.x % point.x, this.y % point.y); - }, - - negate: function() { - return new Point(-this.x, -this.y); - }, - - isInside: function() { - return Rectangle.read(arguments).contains(this); - }, - - isClose: function() { - var point = Point.read(arguments), - tolerance = Base.read(arguments); - return this.getDistance(point) <= tolerance; - }, - - isCollinear: function() { - var point = Point.read(arguments); - return Point.isCollinear(this.x, this.y, point.x, point.y); - }, - - isColinear: '#isCollinear', - - isOrthogonal: function() { - var point = Point.read(arguments); - return Point.isOrthogonal(this.x, this.y, point.x, point.y); - }, - - isZero: function() { - var isZero = Numerical.isZero; - return isZero(this.x) && isZero(this.y); - }, - - isNaN: function() { - return isNaN(this.x) || isNaN(this.y); - }, - - isInQuadrant: function(q) { - return this.x * (q > 1 && q < 4 ? -1 : 1) >= 0 - && this.y * (q > 2 ? -1 : 1) >= 0; - }, - - dot: function() { - var point = Point.read(arguments); - return this.x * point.x + this.y * point.y; - }, - - cross: function() { - var point = Point.read(arguments); - return this.x * point.y - this.y * point.x; - }, - - project: function() { - var point = Point.read(arguments), - scale = point.isZero() ? 0 : this.dot(point) / point.dot(point); - return new Point( - point.x * scale, - point.y * scale - ); - }, - - statics: { - min: function() { - var point1 = Point.read(arguments), - point2 = Point.read(arguments); - return new Point( - Math.min(point1.x, point2.x), - Math.min(point1.y, point2.y) - ); - }, - - max: function() { - var point1 = Point.read(arguments), - point2 = Point.read(arguments); - return new Point( - Math.max(point1.x, point2.x), - Math.max(point1.y, point2.y) - ); - }, - - random: function() { - return new Point(Math.random(), Math.random()); - }, - - isCollinear: function(x1, y1, x2, y2) { - return Math.abs(x1 * y2 - y1 * x2) - <= Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)) - * 1e-8; - }, - - isOrthogonal: function(x1, y1, x2, y2) { - return Math.abs(x1 * x2 + y1 * y2) - <= Math.sqrt((x1 * x1 + y1 * y1) * (x2 * x2 + y2 * y2)) - * 1e-8; - } - } -}, Base.each(['round', 'ceil', 'floor', 'abs'], function(key) { - var op = Math[key]; - this[key] = function() { - return new Point(op(this.x), op(this.y)); - }; -}, {})); - -var LinkedPoint = Point.extend({ - initialize: function Point(x, y, owner, setter) { - this._x = x; - this._y = y; - this._owner = owner; - this._setter = setter; - }, - - _set: function(x, y, _dontNotify) { - this._x = x; - this._y = y; - if (!_dontNotify) - this._owner[this._setter](this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner[this._setter](this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner[this._setter](this); - }, - - isSelected: function() { - return !!(this._owner._selection & this._getSelection()); - }, - - setSelected: function(selected) { - this._owner._changeSelection(this._getSelection(), selected); - }, - - _getSelection: function() { - return this._setter === 'setPosition' ? 4 : 0; - } -}); - -var Size = Base.extend({ - _class: 'Size', - _readIndex: true, - - initialize: function Size(arg0, arg1) { - var type = typeof arg0, - reading = this.__read, - read = 0; - if (type === 'number') { - var hasHeight = typeof arg1 === 'number'; - this._set(arg0, hasHeight ? arg1 : arg0); - if (reading) - read = hasHeight ? 2 : 1; - } else if (type === 'undefined' || arg0 === null) { - this._set(0, 0); - if (reading) - read = arg0 === null ? 1 : 0; - } else { - var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0; - read = 1; - if (Array.isArray(obj)) { - this._set(+obj[0], +(obj.length > 1 ? obj[1] : obj[0])); - } else if ('width' in obj) { - this._set(obj.width || 0, obj.height || 0); - } else if ('x' in obj) { - this._set(obj.x || 0, obj.y || 0); - } else { - this._set(0, 0); - read = 0; - } - } - if (reading) - this.__read = read; - return this; - }, - - set: '#initialize', - - _set: function(width, height) { - this.width = width; - this.height = height; - return this; - }, - - equals: function(size) { - return size === this || size && (this.width === size.width - && this.height === size.height - || Array.isArray(size) && this.width === size[0] - && this.height === size[1]) || false; - }, - - clone: function() { - return new Size(this.width, this.height); - }, - - toString: function() { - var f = Formatter.instance; - return '{ width: ' + f.number(this.width) - + ', height: ' + f.number(this.height) + ' }'; - }, - - _serialize: function(options) { - var f = options.formatter; - return [f.number(this.width), - f.number(this.height)]; - }, - - add: function() { - var size = Size.read(arguments); - return new Size(this.width + size.width, this.height + size.height); - }, - - subtract: function() { - var size = Size.read(arguments); - return new Size(this.width - size.width, this.height - size.height); - }, - - multiply: function() { - var size = Size.read(arguments); - return new Size(this.width * size.width, this.height * size.height); - }, - - divide: function() { - var size = Size.read(arguments); - return new Size(this.width / size.width, this.height / size.height); - }, - - modulo: function() { - var size = Size.read(arguments); - return new Size(this.width % size.width, this.height % size.height); - }, - - negate: function() { - return new Size(-this.width, -this.height); - }, - - isZero: function() { - var isZero = Numerical.isZero; - return isZero(this.width) && isZero(this.height); - }, - - isNaN: function() { - return isNaN(this.width) || isNaN(this.height); - }, - - statics: { - min: function(size1, size2) { - return new Size( - Math.min(size1.width, size2.width), - Math.min(size1.height, size2.height)); - }, - - max: function(size1, size2) { - return new Size( - Math.max(size1.width, size2.width), - Math.max(size1.height, size2.height)); - }, - - random: function() { - return new Size(Math.random(), Math.random()); - } - } -}, Base.each(['round', 'ceil', 'floor', 'abs'], function(key) { - var op = Math[key]; - this[key] = function() { - return new Size(op(this.width), op(this.height)); - }; -}, {})); - -var LinkedSize = Size.extend({ - initialize: function Size(width, height, owner, setter) { - this._width = width; - this._height = height; - this._owner = owner; - this._setter = setter; - }, - - _set: function(width, height, _dontNotify) { - this._width = width; - this._height = height; - if (!_dontNotify) - this._owner[this._setter](this); - return this; - }, - - getWidth: function() { - return this._width; - }, - - setWidth: function(width) { - this._width = width; - this._owner[this._setter](this); - }, - - getHeight: function() { - return this._height; - }, - - setHeight: function(height) { - this._height = height; - this._owner[this._setter](this); - } -}); - -var Rectangle = Base.extend({ - _class: 'Rectangle', - _readIndex: true, - beans: true, - - initialize: function Rectangle(arg0, arg1, arg2, arg3) { - var type = typeof arg0, - read; - if (type === 'number') { - this._set(arg0, arg1, arg2, arg3); - read = 4; - } else if (type === 'undefined' || arg0 === null) { - this._set(0, 0, 0, 0); - read = arg0 === null ? 1 : 0; - } else if (arguments.length === 1) { - if (Array.isArray(arg0)) { - this._set.apply(this, arg0); - read = 1; - } else if (arg0.x !== undefined || arg0.width !== undefined) { - this._set(arg0.x || 0, arg0.y || 0, - arg0.width || 0, arg0.height || 0); - read = 1; - } else if (arg0.from === undefined && arg0.to === undefined) { - this._set(0, 0, 0, 0); - Base.filter(this, arg0); - read = 1; - } - } - if (read === undefined) { - var frm = Point.readNamed(arguments, 'from'), - next = Base.peek(arguments), - x = frm.x, - y = frm.y, - width, - height; - if (next && next.x !== undefined - || Base.hasNamed(arguments, 'to')) { - var to = Point.readNamed(arguments, 'to'); - width = to.x - x; - height = to.y - y; - if (width < 0) { - x = to.x; - width = -width; - } - if (height < 0) { - y = to.y; - height = -height; - } - } else { - var size = Size.read(arguments); - width = size.width; - height = size.height; - } - this._set(x, y, width, height); - read = arguments.__index; - var filtered = arguments.__filtered; - if (filtered) - this.__filtered = filtered; - } - if (this.__read) - this.__read = read; - return this; - }, - - set: '#initialize', - - _set: function(x, y, width, height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - return this; - }, - - clone: function() { - return new Rectangle(this.x, this.y, this.width, this.height); - }, - - equals: function(rect) { - var rt = Base.isPlainValue(rect) - ? Rectangle.read(arguments) - : rect; - return rt === this - || rt && this.x === rt.x && this.y === rt.y - && this.width === rt.width && this.height === rt.height - || false; - }, - - toString: function() { - var f = Formatter.instance; - return '{ x: ' + f.number(this.x) - + ', y: ' + f.number(this.y) - + ', width: ' + f.number(this.width) - + ', height: ' + f.number(this.height) - + ' }'; - }, - - _serialize: function(options) { - var f = options.formatter; - return [f.number(this.x), - f.number(this.y), - f.number(this.width), - f.number(this.height)]; - }, - - getPoint: function(_dontLink) { - var ctor = _dontLink ? Point : LinkedPoint; - return new ctor(this.x, this.y, this, 'setPoint'); - }, - - setPoint: function() { - var point = Point.read(arguments); - this.x = point.x; - this.y = point.y; - }, - - getSize: function(_dontLink) { - var ctor = _dontLink ? Size : LinkedSize; - return new ctor(this.width, this.height, this, 'setSize'); - }, - - _fw: 1, - _fh: 1, - - setSize: function() { - var size = Size.read(arguments), - sx = this._sx, - sy = this._sy, - w = size.width, - h = size.height; - if (sx) { - this.x += (this.width - w) * sx; - } - if (sy) { - this.y += (this.height - h) * sy; - } - this.width = w; - this.height = h; - this._fw = this._fh = 1; - }, - - getLeft: function() { - return this.x; - }, - - setLeft: function(left) { - if (!this._fw) { - var amount = left - this.x; - this.width -= this._sx === 0.5 ? amount * 2 : amount; - } - this.x = left; - this._sx = this._fw = 0; - }, - - getTop: function() { - return this.y; - }, - - setTop: function(top) { - if (!this._fh) { - var amount = top - this.y; - this.height -= this._sy === 0.5 ? amount * 2 : amount; - } - this.y = top; - this._sy = this._fh = 0; - }, - - getRight: function() { - return this.x + this.width; - }, - - setRight: function(right) { - if (!this._fw) { - var amount = right - this.x; - this.width = this._sx === 0.5 ? amount * 2 : amount; - } - this.x = right - this.width; - this._sx = 1; - this._fw = 0; - }, - - getBottom: function() { - return this.y + this.height; - }, - - setBottom: function(bottom) { - if (!this._fh) { - var amount = bottom - this.y; - this.height = this._sy === 0.5 ? amount * 2 : amount; - } - this.y = bottom - this.height; - this._sy = 1; - this._fh = 0; - }, - - getCenterX: function() { - return this.x + this.width / 2; - }, - - setCenterX: function(x) { - if (this._fw || this._sx === 0.5) { - this.x = x - this.width / 2; - } else { - if (this._sx) { - this.x += (x - this.x) * 2 * this._sx; - } - this.width = (x - this.x) * 2; - } - this._sx = 0.5; - this._fw = 0; - }, - - getCenterY: function() { - return this.y + this.height / 2; - }, - - setCenterY: function(y) { - if (this._fh || this._sy === 0.5) { - this.y = y - this.height / 2; - } else { - if (this._sy) { - this.y += (y - this.y) * 2 * this._sy; - } - this.height = (y - this.y) * 2; - } - this._sy = 0.5; - this._fh = 0; - }, - - getCenter: function(_dontLink) { - var ctor = _dontLink ? Point : LinkedPoint; - return new ctor(this.getCenterX(), this.getCenterY(), this, 'setCenter'); - }, - - setCenter: function() { - var point = Point.read(arguments); - this.setCenterX(point.x); - this.setCenterY(point.y); - return this; - }, - - getArea: function() { - return this.width * this.height; - }, - - isEmpty: function() { - return this.width === 0 || this.height === 0; - }, - - contains: function(arg) { - return arg && arg.width !== undefined - || (Array.isArray(arg) ? arg : arguments).length === 4 - ? this._containsRectangle(Rectangle.read(arguments)) - : this._containsPoint(Point.read(arguments)); - }, - - _containsPoint: function(point) { - var x = point.x, - y = point.y; - return x >= this.x && y >= this.y - && x <= this.x + this.width - && y <= this.y + this.height; - }, - - _containsRectangle: function(rect) { - var x = rect.x, - y = rect.y; - return x >= this.x && y >= this.y - && x + rect.width <= this.x + this.width - && y + rect.height <= this.y + this.height; - }, - - intersects: function() { - var rect = Rectangle.read(arguments), - epsilon = Base.read(arguments) || 0; - return rect.x + rect.width > this.x - epsilon - && rect.y + rect.height > this.y - epsilon - && rect.x < this.x + this.width + epsilon - && rect.y < this.y + this.height + epsilon; - }, - - intersect: function() { - var rect = Rectangle.read(arguments), - x1 = Math.max(this.x, rect.x), - y1 = Math.max(this.y, rect.y), - x2 = Math.min(this.x + this.width, rect.x + rect.width), - y2 = Math.min(this.y + this.height, rect.y + rect.height); - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - }, - - unite: function() { - var rect = Rectangle.read(arguments), - x1 = Math.min(this.x, rect.x), - y1 = Math.min(this.y, rect.y), - x2 = Math.max(this.x + this.width, rect.x + rect.width), - y2 = Math.max(this.y + this.height, rect.y + rect.height); - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - }, - - include: function() { - var point = Point.read(arguments); - var x1 = Math.min(this.x, point.x), - y1 = Math.min(this.y, point.y), - x2 = Math.max(this.x + this.width, point.x), - y2 = Math.max(this.y + this.height, point.y); - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - }, - - expand: function() { - var amount = Size.read(arguments), - hor = amount.width, - ver = amount.height; - return new Rectangle(this.x - hor / 2, this.y - ver / 2, - this.width + hor, this.height + ver); - }, - - scale: function(hor, ver) { - return this.expand(this.width * hor - this.width, - this.height * (ver === undefined ? hor : ver) - this.height); - } -}, Base.each([ - ['Top', 'Left'], ['Top', 'Right'], - ['Bottom', 'Left'], ['Bottom', 'Right'], - ['Left', 'Center'], ['Top', 'Center'], - ['Right', 'Center'], ['Bottom', 'Center'] - ], - function(parts, index) { - var part = parts.join(''), - xFirst = /^[RL]/.test(part); - if (index >= 4) - parts[1] += xFirst ? 'Y' : 'X'; - var x = parts[xFirst ? 0 : 1], - y = parts[xFirst ? 1 : 0], - getX = 'get' + x, - getY = 'get' + y, - setX = 'set' + x, - setY = 'set' + y, - get = 'get' + part, - set = 'set' + part; - this[get] = function(_dontLink) { - var ctor = _dontLink ? Point : LinkedPoint; - return new ctor(this[getX](), this[getY](), this, set); - }; - this[set] = function() { - var point = Point.read(arguments); - this[setX](point.x); - this[setY](point.y); - }; - }, { - beans: true - } -)); - -var LinkedRectangle = Rectangle.extend({ - initialize: function Rectangle(x, y, width, height, owner, setter) { - this._set(x, y, width, height, true); - this._owner = owner; - this._setter = setter; - }, - - _set: function(x, y, width, height, _dontNotify) { - this._x = x; - this._y = y; - this._width = width; - this._height = height; - if (!_dontNotify) - this._owner[this._setter](this); - return this; - } -}, -new function() { - var proto = Rectangle.prototype; - - return Base.each(['x', 'y', 'width', 'height'], function(key) { - var part = Base.capitalize(key), - internal = '_' + key; - this['get' + part] = function() { - return this[internal]; - }; - - this['set' + part] = function(value) { - this[internal] = value; - if (!this._dontNotify) - this._owner[this._setter](this); - }; - }, Base.each(['Point', 'Size', 'Center', - 'Left', 'Top', 'Right', 'Bottom', 'CenterX', 'CenterY', - 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter'], - function(key) { - var name = 'set' + key; - this[name] = function() { - this._dontNotify = true; - proto[name].apply(this, arguments); - this._dontNotify = false; - this._owner[this._setter](this); - }; - }, { - isSelected: function() { - return !!(this._owner._selection & 2); - }, - - setSelected: function(selected) { - var owner = this._owner; - if (owner._changeSelection) { - owner._changeSelection(2, selected); - } - } - }) - ); -}); - -var Matrix = Base.extend({ - _class: 'Matrix', - - initialize: function Matrix(arg, _dontNotify) { - var count = arguments.length, - ok = true; - if (count >= 6) { - this._set.apply(this, arguments); - } else if (count === 1 || count === 2) { - if (arg instanceof Matrix) { - this._set(arg._a, arg._b, arg._c, arg._d, arg._tx, arg._ty, - _dontNotify); - } else if (Array.isArray(arg)) { - this._set.apply(this, - _dontNotify ? arg.concat([_dontNotify]) : arg); - } else { - ok = false; - } - } else if (!count) { - this.reset(); - } else { - ok = false; - } - if (!ok) { - throw new Error('Unsupported matrix parameters'); - } - return this; - }, - - set: '#initialize', - - _set: function(a, b, c, d, tx, ty, _dontNotify) { - this._a = a; - this._b = b; - this._c = c; - this._d = d; - this._tx = tx; - this._ty = ty; - if (!_dontNotify) - this._changed(); - return this; - }, - - _serialize: function(options, dictionary) { - return Base.serialize(this.getValues(), options, true, dictionary); - }, - - _changed: function() { - var owner = this._owner; - if (owner) { - if (owner._applyMatrix) { - owner.transform(null, true); - } else { - owner._changed(25); - } - } - }, - - clone: function() { - return new Matrix(this._a, this._b, this._c, this._d, - this._tx, this._ty); - }, - - equals: function(mx) { - return mx === this || mx && this._a === mx._a && this._b === mx._b - && this._c === mx._c && this._d === mx._d - && this._tx === mx._tx && this._ty === mx._ty; - }, - - toString: function() { - var f = Formatter.instance; - return '[[' + [f.number(this._a), f.number(this._c), - f.number(this._tx)].join(', ') + '], [' - + [f.number(this._b), f.number(this._d), - f.number(this._ty)].join(', ') + ']]'; - }, - - reset: function(_dontNotify) { - this._a = this._d = 1; - this._b = this._c = this._tx = this._ty = 0; - if (!_dontNotify) - this._changed(); - return this; - }, - - apply: function(recursively, _setApplyMatrix) { - var owner = this._owner; - if (owner) { - owner.transform(null, true, Base.pick(recursively, true), - _setApplyMatrix); - return this.isIdentity(); - } - return false; - }, - - translate: function() { - var point = Point.read(arguments), - x = point.x, - y = point.y; - this._tx += x * this._a + y * this._c; - this._ty += x * this._b + y * this._d; - this._changed(); - return this; - }, - - scale: function() { - var scale = Point.read(arguments), - center = Point.read(arguments, 0, { readNull: true }); - if (center) - this.translate(center); - this._a *= scale.x; - this._b *= scale.x; - this._c *= scale.y; - this._d *= scale.y; - if (center) - this.translate(center.negate()); - this._changed(); - return this; - }, - - rotate: function(angle ) { - angle *= Math.PI / 180; - var center = Point.read(arguments, 1), - x = center.x, - y = center.y, - cos = Math.cos(angle), - sin = Math.sin(angle), - tx = x - x * cos + y * sin, - ty = y - x * sin - y * cos, - a = this._a, - b = this._b, - c = this._c, - d = this._d; - this._a = cos * a + sin * c; - this._b = cos * b + sin * d; - this._c = -sin * a + cos * c; - this._d = -sin * b + cos * d; - this._tx += tx * a + ty * c; - this._ty += tx * b + ty * d; - this._changed(); - return this; - }, - - shear: function() { - var shear = Point.read(arguments), - center = Point.read(arguments, 0, { readNull: true }); - if (center) - this.translate(center); - var a = this._a, - b = this._b; - this._a += shear.y * this._c; - this._b += shear.y * this._d; - this._c += shear.x * a; - this._d += shear.x * b; - if (center) - this.translate(center.negate()); - this._changed(); - return this; - }, - - skew: function() { - var skew = Point.read(arguments), - center = Point.read(arguments, 0, { readNull: true }), - toRadians = Math.PI / 180, - shear = new Point(Math.tan(skew.x * toRadians), - Math.tan(skew.y * toRadians)); - return this.shear(shear, center); - }, - - append: function(mx, _dontNotify) { - if (mx) { - var a1 = this._a, - b1 = this._b, - c1 = this._c, - d1 = this._d, - a2 = mx._a, - b2 = mx._c, - c2 = mx._b, - d2 = mx._d, - tx2 = mx._tx, - ty2 = mx._ty; - this._a = a2 * a1 + c2 * c1; - this._c = b2 * a1 + d2 * c1; - this._b = a2 * b1 + c2 * d1; - this._d = b2 * b1 + d2 * d1; - this._tx += tx2 * a1 + ty2 * c1; - this._ty += tx2 * b1 + ty2 * d1; - if (!_dontNotify) - this._changed(); - } - return this; - }, - - prepend: function(mx, _dontNotify) { - if (mx) { - var a1 = this._a, - b1 = this._b, - c1 = this._c, - d1 = this._d, - tx1 = this._tx, - ty1 = this._ty, - a2 = mx._a, - b2 = mx._c, - c2 = mx._b, - d2 = mx._d, - tx2 = mx._tx, - ty2 = mx._ty; - this._a = a2 * a1 + b2 * b1; - this._c = a2 * c1 + b2 * d1; - this._b = c2 * a1 + d2 * b1; - this._d = c2 * c1 + d2 * d1; - this._tx = a2 * tx1 + b2 * ty1 + tx2; - this._ty = c2 * tx1 + d2 * ty1 + ty2; - if (!_dontNotify) - this._changed(); - } - return this; - }, - - appended: function(mx) { - return this.clone().append(mx); - }, - - prepended: function(mx) { - return this.clone().prepend(mx); - }, - - invert: function() { - var a = this._a, - b = this._b, - c = this._c, - d = this._d, - tx = this._tx, - ty = this._ty, - det = a * d - b * c, - res = null; - if (det && !isNaN(det) && isFinite(tx) && isFinite(ty)) { - this._a = d / det; - this._b = -b / det; - this._c = -c / det; - this._d = a / det; - this._tx = (c * ty - d * tx) / det; - this._ty = (b * tx - a * ty) / det; - res = this; - } - return res; - }, - - inverted: function() { - return this.clone().invert(); - }, - - concatenate: '#append', - preConcatenate: '#prepend', - chain: '#appended', - - _shiftless: function() { - return new Matrix(this._a, this._b, this._c, this._d, 0, 0); - }, - - _orNullIfIdentity: function() { - return this.isIdentity() ? null : this; - }, - - isIdentity: function() { - return this._a === 1 && this._b === 0 && this._c === 0 && this._d === 1 - && this._tx === 0 && this._ty === 0; - }, - - isInvertible: function() { - var det = this._a * this._d - this._c * this._b; - return det && !isNaN(det) && isFinite(this._tx) && isFinite(this._ty); - }, - - isSingular: function() { - return !this.isInvertible(); - }, - - transform: function( src, dst, count) { - return arguments.length < 3 - ? this._transformPoint(Point.read(arguments)) - : this._transformCoordinates(src, dst, count); - }, - - _transformPoint: function(point, dest, _dontNotify) { - var x = point.x, - y = point.y; - if (!dest) - dest = new Point(); - return dest._set( - x * this._a + y * this._c + this._tx, - x * this._b + y * this._d + this._ty, - _dontNotify); - }, - - _transformCoordinates: function(src, dst, count) { - for (var i = 0, max = 2 * count; i < max; i += 2) { - var x = src[i], - y = src[i + 1]; - dst[i] = x * this._a + y * this._c + this._tx; - dst[i + 1] = x * this._b + y * this._d + this._ty; - } - return dst; - }, - - _transformCorners: function(rect) { - var x1 = rect.x, - y1 = rect.y, - x2 = x1 + rect.width, - y2 = y1 + rect.height, - coords = [ x1, y1, x2, y1, x2, y2, x1, y2 ]; - return this._transformCoordinates(coords, coords, 4); - }, - - _transformBounds: function(bounds, dest, _dontNotify) { - var coords = this._transformCorners(bounds), - min = coords.slice(0, 2), - max = min.slice(); - for (var i = 2; i < 8; i++) { - var val = coords[i], - j = i & 1; - if (val < min[j]) { - min[j] = val; - } else if (val > max[j]) { - max[j] = val; - } - } - if (!dest) - dest = new Rectangle(); - return dest._set(min[0], min[1], max[0] - min[0], max[1] - min[1], - _dontNotify); - }, - - inverseTransform: function() { - return this._inverseTransform(Point.read(arguments)); - }, - - _inverseTransform: function(point, dest, _dontNotify) { - var a = this._a, - b = this._b, - c = this._c, - d = this._d, - tx = this._tx, - ty = this._ty, - det = a * d - b * c, - res = null; - if (det && !isNaN(det) && isFinite(tx) && isFinite(ty)) { - var x = point.x - this._tx, - y = point.y - this._ty; - if (!dest) - dest = new Point(); - res = dest._set( - (x * d - y * c) / det, - (y * a - x * b) / det, - _dontNotify); - } - return res; - }, - - decompose: function() { - var a = this._a, - b = this._b, - c = this._c, - d = this._d, - det = a * d - b * c, - sqrt = Math.sqrt, - atan2 = Math.atan2, - degrees = 180 / Math.PI, - rotate, - scale, - skew; - if (a !== 0 || b !== 0) { - var r = sqrt(a * a + b * b); - rotate = Math.acos(a / r) * (b > 0 ? 1 : -1); - scale = [r, det / r]; - skew = [atan2(a * c + b * d, r * r), 0]; - } else if (c !== 0 || d !== 0) { - var s = sqrt(c * c + d * d); - rotate = Math.asin(c / s) * (d > 0 ? 1 : -1); - scale = [det / s, s]; - skew = [0, atan2(a * c + b * d, s * s)]; - } else { - rotate = 0; - skew = scale = [0, 0]; - } - return { - translation: this.getTranslation(), - rotation: rotate * degrees, - scaling: new Point(scale), - skewing: new Point(skew[0] * degrees, skew[1] * degrees) - }; - }, - - getValues: function() { - return [ this._a, this._b, this._c, this._d, this._tx, this._ty ]; - }, - - getTranslation: function() { - return new Point(this._tx, this._ty); - }, - - getScaling: function() { - return (this.decompose() || {}).scaling; - }, - - getRotation: function() { - return (this.decompose() || {}).rotation; - }, - - applyToContext: function(ctx) { - if (!this.isIdentity()) { - ctx.transform(this._a, this._b, this._c, this._d, - this._tx, this._ty); - } - } -}, Base.each(['a', 'b', 'c', 'd', 'tx', 'ty'], function(key) { - var part = Base.capitalize(key), - prop = '_' + key; - this['get' + part] = function() { - return this[prop]; - }; - this['set' + part] = function(value) { - this[prop] = value; - this._changed(); - }; -}, {})); - -var Line = Base.extend({ - _class: 'Line', - - initialize: function Line(arg0, arg1, arg2, arg3, arg4) { - var asVector = false; - if (arguments.length >= 4) { - this._px = arg0; - this._py = arg1; - this._vx = arg2; - this._vy = arg3; - asVector = arg4; - } else { - this._px = arg0.x; - this._py = arg0.y; - this._vx = arg1.x; - this._vy = arg1.y; - asVector = arg2; - } - if (!asVector) { - this._vx -= this._px; - this._vy -= this._py; - } - }, - - getPoint: function() { - return new Point(this._px, this._py); - }, - - getVector: function() { - return new Point(this._vx, this._vy); - }, - - getLength: function() { - return this.getVector().getLength(); - }, - - intersect: function(line, isInfinite) { - return Line.intersect( - this._px, this._py, this._vx, this._vy, - line._px, line._py, line._vx, line._vy, - true, isInfinite); - }, - - getSide: function(point, isInfinite) { - return Line.getSide( - this._px, this._py, this._vx, this._vy, - point.x, point.y, true, isInfinite); - }, - - getDistance: function(point) { - return Math.abs(this.getSignedDistance(point)); - }, - - getSignedDistance: function(point) { - return Line.getSignedDistance(this._px, this._py, this._vx, this._vy, - point.x, point.y, true); - }, - - isCollinear: function(line) { - return Point.isCollinear(this._vx, this._vy, line._vx, line._vy); - }, - - isOrthogonal: function(line) { - return Point.isOrthogonal(this._vx, this._vy, line._vx, line._vy); - }, - - statics: { - intersect: function(p1x, p1y, v1x, v1y, p2x, p2y, v2x, v2y, asVector, - isInfinite) { - if (!asVector) { - v1x -= p1x; - v1y -= p1y; - v2x -= p2x; - v2y -= p2y; - } - var cross = v1x * v2y - v1y * v2x; - if (!Numerical.isZero(cross)) { - var dx = p1x - p2x, - dy = p1y - p2y, - u1 = (v2x * dy - v2y * dx) / cross, - u2 = (v1x * dy - v1y * dx) / cross, - epsilon = 1e-12, - uMin = -epsilon, - uMax = 1 + epsilon; - if (isInfinite - || uMin < u1 && u1 < uMax && uMin < u2 && u2 < uMax) { - if (!isInfinite) { - u1 = u1 <= 0 ? 0 : u1 >= 1 ? 1 : u1; - } - return new Point( - p1x + u1 * v1x, - p1y + u1 * v1y); - } - } - }, - - getSide: function(px, py, vx, vy, x, y, asVector, isInfinite) { - if (!asVector) { - vx -= px; - vy -= py; - } - var v2x = x - px, - v2y = y - py, - ccw = v2x * vy - v2y * vx; - if (!isInfinite && Numerical.isZero(ccw)) { - ccw = (v2x * vx + v2x * vx) / (vx * vx + vy * vy); - if (ccw >= 0 && ccw <= 1) - ccw = 0; - } - return ccw < 0 ? -1 : ccw > 0 ? 1 : 0; - }, - - getSignedDistance: function(px, py, vx, vy, x, y, asVector) { - if (!asVector) { - vx -= px; - vy -= py; - } - return vx === 0 ? vy > 0 ? x - px : px - x - : vy === 0 ? vx < 0 ? y - py : py - y - : ((x-px) * vy - (y-py) * vx) / Math.sqrt(vx * vx + vy * vy); - }, - - getDistance: function(px, py, vx, vy, x, y, asVector) { - return Math.abs( - Line.getSignedDistance(px, py, vx, vy, x, y, asVector)); - } - } -}); - -var Project = PaperScopeItem.extend({ - _class: 'Project', - _list: 'projects', - _reference: 'project', - _compactSerialize: true, - - initialize: function Project(element) { - PaperScopeItem.call(this, true); - this._children = []; - this._namedChildren = {}; - this._activeLayer = null; - this._currentStyle = new Style(null, null, this); - this._view = View.create(this, - element || CanvasProvider.getCanvas(1, 1)); - this._selectionItems = {}; - this._selectionCount = 0; - this._updateVersion = 0; - }, - - _serialize: function(options, dictionary) { - return Base.serialize(this._children, options, true, dictionary); - }, - - _changed: function(flags, item) { - if (flags & 1) { - var view = this._view; - if (view) { - view._needsUpdate = true; - if (!view._requested && view._autoUpdate) - view.requestUpdate(); - } - } - var changes = this._changes; - if (changes && item) { - var changesById = this._changesById, - id = item._id, - entry = changesById[id]; - if (entry) { - entry.flags |= flags; - } else { - changes.push(changesById[id] = { item: item, flags: flags }); - } - } - }, - - clear: function() { - var children = this._children; - for (var i = children.length - 1; i >= 0; i--) - children[i].remove(); - }, - - isEmpty: function() { - return !this._children.length; - }, - - remove: function remove() { - if (!remove.base.call(this)) - return false; - if (this._view) - this._view.remove(); - return true; - }, - - getView: function() { - return this._view; - }, - - getCurrentStyle: function() { - return this._currentStyle; - }, - - setCurrentStyle: function(style) { - this._currentStyle.set(style); - }, - - getIndex: function() { - return this._index; - }, - - getOptions: function() { - return this._scope.settings; - }, - - getLayers: function() { - return this._children; - }, - - getActiveLayer: function() { - return this._activeLayer || new Layer({ project: this, insert: true }); - }, - - getSymbolDefinitions: function() { - var definitions = [], - ids = {}; - this.getItems({ - class: SymbolItem, - match: function(item) { - var definition = item._definition, - id = definition._id; - if (!ids[id]) { - ids[id] = true; - definitions.push(definition); - } - return false; - } - }); - return definitions; - }, - - getSymbols: 'getSymbolDefinitions', - - getSelectedItems: function() { - var selectionItems = this._selectionItems, - items = []; - for (var id in selectionItems) { - var item = selectionItems[id], - selection = item._selection; - if ((selection & 1) && item.isInserted()) { - items.push(item); - } else if (!selection) { - this._updateSelection(item); - } - } - return items; - }, - - _updateSelection: function(item) { - var id = item._id, - selectionItems = this._selectionItems; - if (item._selection) { - if (selectionItems[id] !== item) { - this._selectionCount++; - selectionItems[id] = item; - } - } else if (selectionItems[id] === item) { - this._selectionCount--; - delete selectionItems[id]; - } - }, - - selectAll: function() { - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) - children[i].setFullySelected(true); - }, - - deselectAll: function() { - var selectionItems = this._selectionItems; - for (var i in selectionItems) - selectionItems[i].setFullySelected(false); - }, - - addLayer: function(layer) { - return this.insertLayer(undefined, layer); - }, - - insertLayer: function(index, layer) { - if (layer instanceof Layer) { - layer._remove(false, true); - Base.splice(this._children, [layer], index, 0); - layer._setProject(this, true); - var name = layer._name; - if (name) - layer.setName(name); - if (this._changes) - layer._changed(5); - if (!this._activeLayer) - this._activeLayer = layer; - } else { - layer = null; - } - return layer; - }, - - _insertItem: function(index, item, _created) { - item = this.insertLayer(index, item) - || (this._activeLayer || this._insertItem(undefined, - new Layer(Item.NO_INSERT), true)) - .insertChild(index, item); - if (_created && item.activate) - item.activate(); - return item; - }, - - getItems: function(options) { - return Item._getItems(this, options); - }, - - getItem: function(options) { - return Item._getItems(this, options, null, null, true)[0] || null; - }, - - importJSON: function(json) { - this.activate(); - var layer = this._activeLayer; - return Base.importJSON(json, layer && layer.isEmpty() && layer); - }, - - removeOn: function(type) { - var sets = this._removeSets; - if (sets) { - if (type === 'mouseup') - sets.mousedrag = null; - var set = sets[type]; - if (set) { - for (var id in set) { - var item = set[id]; - for (var key in sets) { - var other = sets[key]; - if (other && other != set) - delete other[item._id]; - } - item.remove(); - } - sets[type] = null; - } - } - }, - - draw: function(ctx, matrix, pixelRatio) { - this._updateVersion++; - ctx.save(); - matrix.applyToContext(ctx); - var children = this._children, - param = new Base({ - offset: new Point(0, 0), - pixelRatio: pixelRatio, - viewMatrix: matrix.isIdentity() ? null : matrix, - matrices: [new Matrix()], - updateMatrix: true - }); - for (var i = 0, l = children.length; i < l; i++) { - children[i].draw(ctx, param); - } - ctx.restore(); - - if (this._selectionCount > 0) { - ctx.save(); - ctx.strokeWidth = 1; - var items = this._selectionItems, - size = this._scope.settings.handleSize, - version = this._updateVersion; - for (var id in items) { - items[id]._drawSelection(ctx, matrix, size, items, version); - } - ctx.restore(); - } - } -}); - -var Item = Base.extend(Emitter, { - statics: { - extend: function extend(src) { - if (src._serializeFields) - src._serializeFields = Base.set({}, - this.prototype._serializeFields, src._serializeFields); - return extend.base.apply(this, arguments); - }, - - NO_INSERT: { insert: false } - }, - - _class: 'Item', - _name: null, - _applyMatrix: true, - _canApplyMatrix: true, - _canScaleStroke: false, - _pivot: null, - _visible: true, - _blendMode: 'normal', - _opacity: 1, - _locked: false, - _guide: false, - _clipMask: false, - _selection: 0, - _selectBounds: true, - _selectChildren: false, - _serializeFields: { - name: null, - applyMatrix: null, - matrix: new Matrix(), - pivot: null, - visible: true, - blendMode: 'normal', - opacity: 1, - locked: false, - guide: false, - clipMask: false, - selected: false, - data: {} - }, - _prioritize: ['applyMatrix'] -}, -new function() { - var handlers = ['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onClick', - 'onDoubleClick', 'onMouseMove', 'onMouseEnter', 'onMouseLeave']; - return Base.each(handlers, - function(name) { - this._events[name] = { - install: function(type) { - this.getView()._countItemEvent(type, 1); - }, - - uninstall: function(type) { - this.getView()._countItemEvent(type, -1); - } - }; - }, { - _events: { - onFrame: { - install: function() { - this.getView()._animateItem(this, true); - }, - - uninstall: function() { - this.getView()._animateItem(this, false); - } - }, - - onLoad: {}, - onError: {} - }, - statics: { - _itemHandlers: handlers - } - } - ); -}, { - initialize: function Item() { - }, - - _initialize: function(props, point) { - var hasProps = props && Base.isPlainObject(props), - internal = hasProps && props.internal === true, - matrix = this._matrix = new Matrix(), - project = hasProps && props.project || paper.project, - settings = paper.settings; - this._id = internal ? null : UID.get(); - this._parent = this._index = null; - this._applyMatrix = this._canApplyMatrix && settings.applyMatrix; - if (point) - matrix.translate(point); - matrix._owner = this; - this._style = new Style(project._currentStyle, this, project); - if (internal || hasProps && props.insert == false - || !settings.insertItems && !(hasProps && props.insert === true)) { - this._setProject(project); - } else { - (hasProps && props.parent || project) - ._insertItem(undefined, this, true); - } - if (hasProps && props !== Item.NO_INSERT) { - this.set(props, { - internal: true, insert: true, project: true, parent: true - }); - } - return hasProps; - }, - - _serialize: function(options, dictionary) { - var props = {}, - that = this; - - function serialize(fields) { - for (var key in fields) { - var value = that[key]; - if (!Base.equals(value, key === 'leading' - ? fields.fontSize * 1.2 : fields[key])) { - props[key] = Base.serialize(value, options, - key !== 'data', dictionary); - } - } - } - - serialize(this._serializeFields); - if (!(this instanceof Group)) - serialize(this._style._defaults); - return [ this._class, props ]; - }, - - _changed: function(flags) { - var symbol = this._symbol, - cacheParent = this._parent || symbol, - project = this._project; - if (flags & 8) { - this._bounds = this._position = this._decomposed = undefined; - } - if (flags & 16) { - this._globalMatrix = undefined; - } - if (cacheParent - && (flags & 72)) { - Item._clearBoundsCache(cacheParent); - } - if (flags & 2) { - Item._clearBoundsCache(this); - } - if (project) - project._changed(flags, this); - if (symbol) - symbol._changed(flags); - }, - - getId: function() { - return this._id; - }, - - getName: function() { - return this._name; - }, - - setName: function(name) { - - if (this._name) - this._removeNamed(); - if (name === (+name) + '') - throw new Error( - 'Names consisting only of numbers are not supported.'); - var owner = this._getOwner(); - if (name && owner) { - var children = owner._children, - namedChildren = owner._namedChildren; - (namedChildren[name] = namedChildren[name] || []).push(this); - if (!(name in children)) - children[name] = this; - } - this._name = name || undefined; - this._changed(256); - }, - - getStyle: function() { - return this._style; - }, - - setStyle: function(style) { - this.getStyle().set(style); - } -}, Base.each(['locked', 'visible', 'blendMode', 'opacity', 'guide'], - function(name) { - var part = Base.capitalize(name), - key = '_' + name, - flags = { - locked: 256, - visible: 265 - }; - this['get' + part] = function() { - return this[key]; - }; - this['set' + part] = function(value) { - if (value != this[key]) { - this[key] = value; - this._changed(flags[name] || 257); - } - }; - }, -{}), { - beans: true, - - getSelection: function() { - return this._selection; - }, - - setSelection: function(selection) { - if (selection !== this._selection) { - this._selection = selection; - var project = this._project; - if (project) { - project._updateSelection(this); - this._changed(257); - } - } - }, - - _changeSelection: function(flag, selected) { - var selection = this._selection; - this.setSelection(selected ? selection | flag : selection & ~flag); - }, - - isSelected: function() { - if (this._selectChildren) { - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) - if (children[i].isSelected()) - return true; - } - return !!(this._selection & 1); - }, - - setSelected: function(selected) { - if (this._selectChildren) { - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) - children[i].setSelected(selected); - } - this._changeSelection(1, selected); - }, - - isFullySelected: function() { - var children = this._children, - selected = !!(this._selection & 1); - if (children && selected) { - for (var i = 0, l = children.length; i < l; i++) - if (!children[i].isFullySelected()) - return false; - return true; - } - return selected; - }, - - setFullySelected: function(selected) { - var children = this._children; - if (children) { - for (var i = 0, l = children.length; i < l; i++) - children[i].setFullySelected(selected); - } - this._changeSelection(1, selected); - }, - - isClipMask: function() { - return this._clipMask; - }, - - setClipMask: function(clipMask) { - if (this._clipMask != (clipMask = !!clipMask)) { - this._clipMask = clipMask; - if (clipMask) { - this.setFillColor(null); - this.setStrokeColor(null); - } - this._changed(257); - if (this._parent) - this._parent._changed(2048); - } - }, - - getData: function() { - if (!this._data) - this._data = {}; - return this._data; - }, - - setData: function(data) { - this._data = data; - }, - - getPosition: function(_dontLink) { - var ctor = _dontLink ? Point : LinkedPoint; - var position = this._position || - (this._position = this._getPositionFromBounds()); - return new ctor(position.x, position.y, this, 'setPosition'); - }, - - setPosition: function() { - this.translate(Point.read(arguments).subtract(this.getPosition(true))); - }, - - _getPositionFromBounds: function(bounds) { - return this._pivot - ? this._matrix._transformPoint(this._pivot) - : (bounds || this.getBounds()).getCenter(true); - }, - - getPivot: function() { - var pivot = this._pivot; - return pivot - ? new LinkedPoint(pivot.x, pivot.y, this, 'setPivot') - : null; - }, - - setPivot: function() { - this._pivot = Point.read(arguments, 0, { clone: true, readNull: true }); - this._position = undefined; - } -}, Base.each({ - getStrokeBounds: { stroke: true }, - getHandleBounds: { handle: true }, - getInternalBounds: { internal: true } - }, - function(options, key) { - this[key] = function(matrix) { - return this.getBounds(matrix, options); - }; - }, -{ - beans: true, - - getBounds: function(matrix, options) { - var hasMatrix = options || matrix instanceof Matrix, - opts = Base.set({}, hasMatrix ? options : matrix, - this._boundsOptions); - if (!opts.stroke || this.getStrokeScaling()) - opts.cacheItem = this; - var rect = this._getCachedBounds(hasMatrix && matrix, opts).rect; - return !arguments.length - ? new LinkedRectangle(rect.x, rect.y, rect.width, rect.height, - this, 'setBounds') - : rect; - }, - - setBounds: function() { - var rect = Rectangle.read(arguments), - bounds = this.getBounds(), - _matrix = this._matrix, - matrix = new Matrix(), - center = rect.getCenter(); - matrix.translate(center); - if (rect.width != bounds.width || rect.height != bounds.height) { - if (!_matrix.isInvertible()) { - _matrix.set(_matrix._backup - || new Matrix().translate(_matrix.getTranslation())); - bounds = this.getBounds(); - } - matrix.scale( - bounds.width !== 0 ? rect.width / bounds.width : 0, - bounds.height !== 0 ? rect.height / bounds.height : 0); - } - center = bounds.getCenter(); - matrix.translate(-center.x, -center.y); - this.transform(matrix); - }, - - _getBounds: function(matrix, options) { - var children = this._children; - if (!children || !children.length) - return new Rectangle(); - Item._updateBoundsCache(this, options.cacheItem); - return Item._getBounds(children, matrix, options); - }, - - _getBoundsCacheKey: function(options, internal) { - return [ - options.stroke ? 1 : 0, - options.handle ? 1 : 0, - internal ? 1 : 0 - ].join(''); - }, - - _getCachedBounds: function(matrix, options, noInternal) { - matrix = matrix && matrix._orNullIfIdentity(); - var internal = options.internal && !noInternal, - cacheItem = options.cacheItem, - _matrix = internal ? null : this._matrix._orNullIfIdentity(), - cacheKey = cacheItem && (!matrix || matrix.equals(_matrix)) - && this._getBoundsCacheKey(options, internal), - bounds = this._bounds; - Item._updateBoundsCache(this._parent || this._symbol, cacheItem); - if (cacheKey && bounds && cacheKey in bounds) { - var cached = bounds[cacheKey]; - return { - rect: cached.rect.clone(), - nonscaling: cached.nonscaling - }; - } - var res = this._getBounds(matrix || _matrix, options), - rect = res.rect || res, - style = this._style, - nonscaling = res.nonscaling || style.hasStroke() - && !style.getStrokeScaling(); - if (cacheKey) { - if (!bounds) { - this._bounds = bounds = {}; - } - var cached = bounds[cacheKey] = { - rect: rect.clone(), - nonscaling: nonscaling, - internal: internal - }; - } - return { - rect: rect, - nonscaling: nonscaling - }; - }, - - _getStrokeMatrix: function(matrix, options) { - var parent = this.getStrokeScaling() ? null - : options && options.internal ? this - : this._parent || this._symbol && this._symbol._item, - mx = parent ? parent.getViewMatrix().invert() : matrix; - return mx && mx._shiftless(); - }, - - statics: { - _updateBoundsCache: function(parent, item) { - if (parent && item) { - var id = item._id, - ref = parent._boundsCache = parent._boundsCache || { - ids: {}, - list: [] - }; - if (!ref.ids[id]) { - ref.list.push(item); - ref.ids[id] = item; - } - } - }, - - _clearBoundsCache: function(item) { - var cache = item._boundsCache; - if (cache) { - item._bounds = item._position = item._boundsCache = undefined; - for (var i = 0, list = cache.list, l = list.length; i < l; i++){ - var other = list[i]; - if (other !== item) { - other._bounds = other._position = undefined; - if (other._boundsCache) - Item._clearBoundsCache(other); - } - } - } - }, - - _getBounds: function(items, matrix, options) { - var x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2, - nonscaling = false; - options = options || {}; - for (var i = 0, l = items.length; i < l; i++) { - var item = items[i]; - if (item._visible && !item.isEmpty()) { - var bounds = item._getCachedBounds( - matrix && matrix.appended(item._matrix), options, true), - rect = bounds.rect; - x1 = Math.min(rect.x, x1); - y1 = Math.min(rect.y, y1); - x2 = Math.max(rect.x + rect.width, x2); - y2 = Math.max(rect.y + rect.height, y2); - if (bounds.nonscaling) - nonscaling = true; - } - } - return { - rect: isFinite(x1) - ? new Rectangle(x1, y1, x2 - x1, y2 - y1) - : new Rectangle(), - nonscaling: nonscaling - }; - } - } - -}), { - beans: true, - - _decompose: function() { - return this._applyMatrix - ? null - : this._decomposed || (this._decomposed = this._matrix.decompose()); - }, - - getRotation: function() { - var decomposed = this._decompose(); - return decomposed ? decomposed.rotation : 0; - }, - - setRotation: function(rotation) { - var current = this.getRotation(); - if (current != null && rotation != null) { - var decomposed = this._decomposed; - this.rotate(rotation - current); - if (decomposed) { - decomposed.rotation = rotation; - this._decomposed = decomposed; - } - } - }, - - getScaling: function() { - var decomposed = this._decompose(), - s = decomposed && decomposed.scaling; - return new LinkedPoint(s ? s.x : 1, s ? s.y : 1, this, 'setScaling'); - }, - - setScaling: function() { - var current = this.getScaling(), - scaling = Point.read(arguments, 0, { clone: true, readNull: true }); - if (current && scaling && !current.equals(scaling)) { - var rotation = this.getRotation(), - decomposed = this._decomposed, - matrix = new Matrix(), - center = this.getPosition(true); - matrix.translate(center); - if (rotation) - matrix.rotate(rotation); - matrix.scale(scaling.x / current.x, scaling.y / current.y); - if (rotation) - matrix.rotate(-rotation); - matrix.translate(center.negate()); - this.transform(matrix); - if (decomposed) { - decomposed.scaling = scaling; - this._decomposed = decomposed; - } - } - }, - - getMatrix: function() { - return this._matrix; - }, - - setMatrix: function() { - var matrix = this._matrix; - matrix.initialize.apply(matrix, arguments); - }, - - getGlobalMatrix: function(_dontClone) { - var matrix = this._globalMatrix; - if (matrix) { - var parent = this._parent; - var parents = []; - while (parent) { - if (!parent._globalMatrix) { - matrix = null; - for (var i = 0, l = parents.length; i < l; i++) { - parents[i]._globalMatrix = null; - } - break; - } - parents.push(parent); - parent = parent._parent; - } - } - if (!matrix) { - matrix = this._globalMatrix = this._matrix.clone(); - var parent = this._parent; - if (parent) - matrix.prepend(parent.getGlobalMatrix(true)); - } - return _dontClone ? matrix : matrix.clone(); - }, - - getViewMatrix: function() { - return this.getGlobalMatrix().prepend(this.getView()._matrix); - }, - - getApplyMatrix: function() { - return this._applyMatrix; - }, - - setApplyMatrix: function(apply) { - if (this._applyMatrix = this._canApplyMatrix && !!apply) - this.transform(null, true); - }, - - getTransformContent: '#getApplyMatrix', - setTransformContent: '#setApplyMatrix', -}, { - getProject: function() { - return this._project; - }, - - _setProject: function(project, installEvents) { - if (this._project !== project) { - if (this._project) - this._installEvents(false); - this._project = project; - var children = this._children; - for (var i = 0, l = children && children.length; i < l; i++) - children[i]._setProject(project); - installEvents = true; - } - if (installEvents) - this._installEvents(true); - }, - - getView: function() { - return this._project._view; - }, - - _installEvents: function _installEvents(install) { - _installEvents.base.call(this, install); - var children = this._children; - for (var i = 0, l = children && children.length; i < l; i++) - children[i]._installEvents(install); - }, - - getLayer: function() { - var parent = this; - while (parent = parent._parent) { - if (parent instanceof Layer) - return parent; - } - return null; - }, - - getParent: function() { - return this._parent; - }, - - setParent: function(item) { - return item.addChild(this); - }, - - _getOwner: '#getParent', - - getChildren: function() { - return this._children; - }, - - setChildren: function(items) { - this.removeChildren(); - this.addChildren(items); - }, - - getFirstChild: function() { - return this._children && this._children[0] || null; - }, - - getLastChild: function() { - return this._children && this._children[this._children.length - 1] - || null; - }, - - getNextSibling: function() { - var owner = this._getOwner(); - return owner && owner._children[this._index + 1] || null; - }, - - getPreviousSibling: function() { - var owner = this._getOwner(); - return owner && owner._children[this._index - 1] || null; - }, - - getIndex: function() { - return this._index; - }, - - equals: function(item) { - return item === this || item && this._class === item._class - && this._style.equals(item._style) - && this._matrix.equals(item._matrix) - && this._locked === item._locked - && this._visible === item._visible - && this._blendMode === item._blendMode - && this._opacity === item._opacity - && this._clipMask === item._clipMask - && this._guide === item._guide - && this._equals(item) - || false; - }, - - _equals: function(item) { - return Base.equals(this._children, item._children); - }, - - clone: function(options) { - var copy = new this.constructor(Item.NO_INSERT), - children = this._children, - insert = Base.pick(options ? options.insert : undefined, - options === undefined || options === true), - deep = Base.pick(options ? options.deep : undefined, true); - if (children) - copy.copyAttributes(this); - if (!children || deep) - copy.copyContent(this); - if (!children) - copy.copyAttributes(this); - if (insert) - copy.insertAbove(this); - var name = this._name, - parent = this._parent; - if (name && parent) { - var children = parent._children, - orig = name, - i = 1; - while (children[name]) - name = orig + ' ' + (i++); - if (name !== orig) - copy.setName(name); - } - return copy; - }, - - copyContent: function(source) { - var children = source._children; - for (var i = 0, l = children && children.length; i < l; i++) { - this.addChild(children[i].clone(false), true); - } - }, - - copyAttributes: function(source, excludeMatrix) { - this.setStyle(source._style); - var keys = ['_locked', '_visible', '_blendMode', '_opacity', - '_clipMask', '_guide']; - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - if (source.hasOwnProperty(key)) - this[key] = source[key]; - } - if (!excludeMatrix) - this._matrix.set(source._matrix, true); - this.setApplyMatrix(source._applyMatrix); - this.setPivot(source._pivot); - this.setSelection(source._selection); - var data = source._data, - name = source._name; - this._data = data ? Base.clone(data) : null; - if (name) - this.setName(name); - }, - - rasterize: function(resolution, insert) { - var bounds = this.getStrokeBounds(), - scale = (resolution || this.getView().getResolution()) / 72, - topLeft = bounds.getTopLeft().floor(), - bottomRight = bounds.getBottomRight().ceil(), - size = new Size(bottomRight.subtract(topLeft)), - raster = new Raster(Item.NO_INSERT); - if (!size.isZero()) { - var canvas = CanvasProvider.getCanvas(size.multiply(scale)), - ctx = canvas.getContext('2d'), - matrix = new Matrix().scale(scale).translate(topLeft.negate()); - ctx.save(); - matrix.applyToContext(ctx); - this.draw(ctx, new Base({ matrices: [matrix] })); - ctx.restore(); - raster.setCanvas(canvas); - } - raster.transform(new Matrix().translate(topLeft.add(size.divide(2))) - .scale(1 / scale)); - if (insert === undefined || insert) - raster.insertAbove(this); - return raster; - }, - - contains: function() { - return !!this._contains( - this._matrix._inverseTransform(Point.read(arguments))); - }, - - _contains: function(point) { - var children = this._children; - if (children) { - for (var i = children.length - 1; i >= 0; i--) { - if (children[i].contains(point)) - return true; - } - return false; - } - return point.isInside(this.getInternalBounds()); - }, - - isInside: function() { - return Rectangle.read(arguments).contains(this.getBounds()); - }, - - _asPathItem: function() { - return new Path.Rectangle({ - rectangle: this.getInternalBounds(), - matrix: this._matrix, - insert: false, - }); - }, - - intersects: function(item, _matrix) { - if (!(item instanceof Item)) - return false; - return this._asPathItem().getIntersections(item._asPathItem(), null, - _matrix, true).length > 0; - } -}, -new function() { - function hitTest() { - return this._hitTest( - Point.read(arguments), - HitResult.getOptions(arguments)); - } - - function hitTestAll() { - var point = Point.read(arguments), - options = HitResult.getOptions(arguments), - all = []; - this._hitTest(point, Base.set({ all: all }, options)); - return all; - } - - function hitTestChildren(point, options, viewMatrix, _exclude) { - var children = this._children; - if (children) { - for (var i = children.length - 1; i >= 0; i--) { - var child = children[i]; - var res = child !== _exclude && child._hitTest(point, options, - viewMatrix); - if (res && !options.all) - return res; - } - } - return null; - } - - Project.inject({ - hitTest: hitTest, - hitTestAll: hitTestAll, - _hitTest: hitTestChildren - }); - - return { - hitTest: hitTest, - hitTestAll: hitTestAll, - _hitTestChildren: hitTestChildren, - }; -}, { - - _hitTest: function(point, options, parentViewMatrix) { - if (this._locked || !this._visible || this._guide && !options.guides - || this.isEmpty()) { - return null; - } - - var matrix = this._matrix, - viewMatrix = parentViewMatrix - ? parentViewMatrix.appended(matrix) - : this.getGlobalMatrix().prepend(this.getView()._matrix), - tolerance = Math.max(options.tolerance, 1e-12), - tolerancePadding = options._tolerancePadding = new Size( - Path._getStrokePadding(tolerance, - matrix._shiftless().invert())); - point = matrix._inverseTransform(point); - if (!point || !this._children && - !this.getBounds({ internal: true, stroke: true, handle: true }) - .expand(tolerancePadding.multiply(2))._containsPoint(point)) { - return null; - } - - var checkSelf = !(options.guides && !this._guide - || options.selected && !this.isSelected() - || options.type && options.type !== Base.hyphenate(this._class) - || options.class && !(this instanceof options.class)), - match = options.match, - that = this, - bounds, - res; - - function filter(hit) { - if (hit && match && !match(hit)) - hit = null; - if (hit && options.all) - options.all.push(hit); - return hit; - } - - function checkPoint(type, part) { - var pt = part ? bounds['get' + part]() : that.getPosition(); - if (point.subtract(pt).divide(tolerancePadding).length <= 1) { - return new HitResult(type, that, { - name: part ? Base.hyphenate(part) : type, - point: pt - }); - } - } - - var checkPosition = options.position, - checkCenter = options.center, - checkBounds = options.bounds; - if (checkSelf && this._parent - && (checkPosition || checkCenter || checkBounds)) { - if (checkCenter || checkBounds) { - bounds = this.getInternalBounds(); - } - res = checkPosition && checkPoint('position') || - checkCenter && checkPoint('center', 'Center'); - if (!res && checkBounds) { - var points = [ - 'TopLeft', 'TopRight', 'BottomLeft', 'BottomRight', - 'LeftCenter', 'TopCenter', 'RightCenter', 'BottomCenter' - ]; - for (var i = 0; i < 8 && !res; i++) { - res = checkPoint('bounds', points[i]); - } - } - res = filter(res); - } - - if (!res) { - res = this._hitTestChildren(point, options, viewMatrix) - || checkSelf - && filter(this._hitTestSelf(point, options, viewMatrix, - this.getStrokeScaling() ? null - : viewMatrix._shiftless().invert())) - || null; - } - if (res && res.point) { - res.point = matrix.transform(res.point); - } - return res; - }, - - _hitTestSelf: function(point, options) { - if (options.fill && this.hasFill() && this._contains(point)) - return new HitResult('fill', this); - }, - - matches: function(name, compare) { - function matchObject(obj1, obj2) { - for (var i in obj1) { - if (obj1.hasOwnProperty(i)) { - var val1 = obj1[i], - val2 = obj2[i]; - if (Base.isPlainObject(val1) && Base.isPlainObject(val2)) { - if (!matchObject(val1, val2)) - return false; - } else if (!Base.equals(val1, val2)) { - return false; - } - } - } - return true; - } - var type = typeof name; - if (type === 'object') { - for (var key in name) { - if (name.hasOwnProperty(key) && !this.matches(key, name[key])) - return false; - } - return true; - } else if (type === 'function') { - return name(this); - } else if (name === 'match') { - return compare(this); - } else { - var value = /^(empty|editable)$/.test(name) - ? this['is' + Base.capitalize(name)]() - : name === 'type' - ? Base.hyphenate(this._class) - : this[name]; - if (name === 'class') { - if (typeof compare === 'function') - return this instanceof compare; - value = this._class; - } - if (typeof compare === 'function') { - return !!compare(value); - } else if (compare) { - if (compare.test) { - return compare.test(value); - } else if (Base.isPlainObject(compare)) { - return matchObject(compare, value); - } - } - return Base.equals(value, compare); - } - }, - - getItems: function(options) { - return Item._getItems(this, options, this._matrix); - }, - - getItem: function(options) { - return Item._getItems(this, options, this._matrix, null, true)[0] - || null; - }, - - statics: { - _getItems: function _getItems(item, options, matrix, param, firstOnly) { - if (!param) { - var obj = typeof options === 'object' && options, - overlapping = obj && obj.overlapping, - inside = obj && obj.inside, - bounds = overlapping || inside, - rect = bounds && Rectangle.read([bounds]); - param = { - items: [], - recursive: obj && obj.recursive !== false, - inside: !!inside, - overlapping: !!overlapping, - rect: rect, - path: overlapping && new Path.Rectangle({ - rectangle: rect, - insert: false - }) - }; - if (obj) { - options = Base.filter({}, options, { - recursive: true, inside: true, overlapping: true - }); - } - } - var children = item._children, - items = param.items, - rect = param.rect; - matrix = rect && (matrix || new Matrix()); - for (var i = 0, l = children && children.length; i < l; i++) { - var child = children[i], - childMatrix = matrix && matrix.appended(child._matrix), - add = true; - if (rect) { - var bounds = child.getBounds(childMatrix); - if (!rect.intersects(bounds)) - continue; - if (!(rect.contains(bounds) - || param.overlapping && (bounds.contains(rect) - || param.path.intersects(child, childMatrix)))) - add = false; - } - if (add && child.matches(options)) { - items.push(child); - if (firstOnly) - break; - } - if (param.recursive !== false) { - _getItems(child, options, childMatrix, param, firstOnly); - } - if (firstOnly && items.length > 0) - break; - } - return items; - } - } -}, { - - importJSON: function(json) { - var res = Base.importJSON(json, this); - return res !== this ? this.addChild(res) : res; - }, - - addChild: function(item) { - return this.insertChild(undefined, item); - }, - - insertChild: function(index, item) { - var res = item ? this.insertChildren(index, [item]) : null; - return res && res[0]; - }, - - addChildren: function(items) { - return this.insertChildren(this._children.length, items); - }, - - insertChildren: function(index, items) { - var children = this._children; - if (children && items && items.length > 0) { - items = Base.slice(items); - var inserted = {}; - for (var i = items.length - 1; i >= 0; i--) { - var item = items[i], - id = item && item._id; - if (!item || inserted[id]) { - items.splice(i, 1); - } else { - item._remove(false, true); - inserted[id] = true; - } - } - Base.splice(children, items, index, 0); - var project = this._project, - notifySelf = project._changes; - for (var i = 0, l = items.length; i < l; i++) { - var item = items[i], - name = item._name; - item._parent = this; - item._setProject(project, true); - if (name) - item.setName(name); - if (notifySelf) - item._changed(5); - } - this._changed(11); - } else { - items = null; - } - return items; - }, - - _insertItem: '#insertChild', - - _insertAt: function(item, offset) { - var owner = item && item._getOwner(), - res = item !== this && owner ? this : null; - if (res) { - res._remove(false, true); - owner._insertItem(item._index + offset, res); - } - return res; - }, - - insertAbove: function(item) { - return this._insertAt(item, 1); - }, - - insertBelow: function(item) { - return this._insertAt(item, 0); - }, - - sendToBack: function() { - var owner = this._getOwner(); - return owner ? owner._insertItem(0, this) : null; - }, - - bringToFront: function() { - var owner = this._getOwner(); - return owner ? owner._insertItem(undefined, this) : null; - }, - - appendTop: '#addChild', - - appendBottom: function(item) { - return this.insertChild(0, item); - }, - - moveAbove: '#insertAbove', - - moveBelow: '#insertBelow', - - addTo: function(owner) { - return owner._insertItem(undefined, this); - }, - - copyTo: function(owner) { - return this.clone(false).addTo(owner); - }, - - reduce: function(options) { - var children = this._children; - if (children && children.length === 1) { - var child = children[0].reduce(options); - if (this._parent) { - child.insertAbove(this); - this.remove(); - } else { - child.remove(); - } - return child; - } - return this; - }, - - _removeNamed: function() { - var owner = this._getOwner(); - if (owner) { - var children = owner._children, - namedChildren = owner._namedChildren, - name = this._name, - namedArray = namedChildren[name], - index = namedArray ? namedArray.indexOf(this) : -1; - if (index !== -1) { - if (children[name] == this) - delete children[name]; - namedArray.splice(index, 1); - if (namedArray.length) { - children[name] = namedArray[0]; - } else { - delete namedChildren[name]; - } - } - } - }, - - _remove: function(notifySelf, notifyParent) { - var owner = this._getOwner(), - project = this._project, - index = this._index; - if (this._style) - this._style._dispose(); - if (owner) { - if (this._name) - this._removeNamed(); - if (index != null) { - if (project._activeLayer === this) - project._activeLayer = this.getNextSibling() - || this.getPreviousSibling(); - Base.splice(owner._children, null, index, 1); - } - this._installEvents(false); - if (notifySelf && project._changes) - this._changed(5); - if (notifyParent) - owner._changed(11, this); - this._parent = null; - return true; - } - return false; - }, - - remove: function() { - return this._remove(true, true); - }, - - replaceWith: function(item) { - var ok = item && item.insertBelow(this); - if (ok) - this.remove(); - return ok; - }, - - removeChildren: function(start, end) { - if (!this._children) - return null; - start = start || 0; - end = Base.pick(end, this._children.length); - var removed = Base.splice(this._children, null, start, end - start); - for (var i = removed.length - 1; i >= 0; i--) { - removed[i]._remove(true, false); - } - if (removed.length > 0) - this._changed(11); - return removed; - }, - - clear: '#removeChildren', - - reverseChildren: function() { - if (this._children) { - this._children.reverse(); - for (var i = 0, l = this._children.length; i < l; i++) - this._children[i]._index = i; - this._changed(11); - } - }, - - isEmpty: function() { - var children = this._children; - return !children || !children.length; - }, - - isEditable: function() { - var item = this; - while (item) { - if (!item._visible || item._locked) - return false; - item = item._parent; - } - return true; - }, - - hasFill: function() { - return this.getStyle().hasFill(); - }, - - hasStroke: function() { - return this.getStyle().hasStroke(); - }, - - hasShadow: function() { - return this.getStyle().hasShadow(); - }, - - _getOrder: function(item) { - function getList(item) { - var list = []; - do { - list.unshift(item); - } while (item = item._parent); - return list; - } - var list1 = getList(this), - list2 = getList(item); - for (var i = 0, l = Math.min(list1.length, list2.length); i < l; i++) { - if (list1[i] != list2[i]) { - return list1[i]._index < list2[i]._index ? 1 : -1; - } - } - return 0; - }, - - hasChildren: function() { - return this._children && this._children.length > 0; - }, - - isInserted: function() { - return this._parent ? this._parent.isInserted() : false; - }, - - isAbove: function(item) { - return this._getOrder(item) === -1; - }, - - isBelow: function(item) { - return this._getOrder(item) === 1; - }, - - isParent: function(item) { - return this._parent === item; - }, - - isChild: function(item) { - return item && item._parent === this; - }, - - isDescendant: function(item) { - var parent = this; - while (parent = parent._parent) { - if (parent === item) - return true; - } - return false; - }, - - isAncestor: function(item) { - return item ? item.isDescendant(this) : false; - }, - - isSibling: function(item) { - return this._parent === item._parent; - }, - - isGroupedWith: function(item) { - var parent = this._parent; - while (parent) { - if (parent._parent - && /^(Group|Layer|CompoundPath)$/.test(parent._class) - && item.isDescendant(parent)) - return true; - parent = parent._parent; - } - return false; - }, - -}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) { - var rotate = key === 'rotate'; - this[key] = function() { - var value = (rotate ? Base : Point).read(arguments), - center = Point.read(arguments, 0, { readNull: true }); - return this.transform(new Matrix()[key](value, - center || this.getPosition(true))); - }; -}, { - translate: function() { - var mx = new Matrix(); - return this.transform(mx.translate.apply(mx, arguments)); - }, - - transform: function(matrix, _applyMatrix, _applyRecursively, - _setApplyMatrix) { - var _matrix = this._matrix, - transformMatrix = matrix && !matrix.isIdentity(), - applyMatrix = (_applyMatrix || this._applyMatrix) - && ((!_matrix.isIdentity() || transformMatrix) - || _applyMatrix && _applyRecursively && this._children); - if (!transformMatrix && !applyMatrix) - return this; - if (transformMatrix) { - if (!matrix.isInvertible() && _matrix.isInvertible()) - _matrix._backup = _matrix.getValues(); - _matrix.prepend(matrix, true); - var style = this._style, - fillColor = style.getFillColor(true), - strokeColor = style.getStrokeColor(true); - if (fillColor) - fillColor.transform(matrix); - if (strokeColor) - strokeColor.transform(matrix); - } - if (applyMatrix && (applyMatrix = this._transformContent(_matrix, - _applyRecursively, _setApplyMatrix))) { - var pivot = this._pivot; - if (pivot) - _matrix._transformPoint(pivot, pivot, true); - _matrix.reset(true); - if (_setApplyMatrix && this._canApplyMatrix) - this._applyMatrix = true; - } - var bounds = this._bounds, - position = this._position; - if (transformMatrix || applyMatrix) { - this._changed(25); - } - var decomp = transformMatrix && bounds && matrix.decompose(); - if (decomp && decomp.skewing.isZero() && decomp.rotation % 90 === 0) { - for (var key in bounds) { - var cache = bounds[key]; - if (cache.nonscaling) { - delete bounds[key]; - } else if (applyMatrix || !cache.internal) { - var rect = cache.rect; - matrix._transformBounds(rect, rect); - } - } - this._bounds = bounds; - var cached = bounds[this._getBoundsCacheKey( - this._boundsOptions || {})]; - if (cached) { - this._position = this._getPositionFromBounds(cached.rect); - } - } else if (transformMatrix && position && this._pivot) { - this._position = matrix._transformPoint(position, position); - } - return this; - }, - - _transformContent: function(matrix, applyRecursively, setApplyMatrix) { - var children = this._children; - if (children) { - for (var i = 0, l = children.length; i < l; i++) - children[i].transform(matrix, true, applyRecursively, - setApplyMatrix); - return true; - } - }, - - globalToLocal: function() { - return this.getGlobalMatrix(true)._inverseTransform( - Point.read(arguments)); - }, - - localToGlobal: function() { - return this.getGlobalMatrix(true)._transformPoint( - Point.read(arguments)); - }, - - parentToLocal: function() { - return this._matrix._inverseTransform(Point.read(arguments)); - }, - - localToParent: function() { - return this._matrix._transformPoint(Point.read(arguments)); - }, - - fitBounds: function(rectangle, fill) { - rectangle = Rectangle.read(arguments); - var bounds = this.getBounds(), - itemRatio = bounds.height / bounds.width, - rectRatio = rectangle.height / rectangle.width, - scale = (fill ? itemRatio > rectRatio : itemRatio < rectRatio) - ? rectangle.width / bounds.width - : rectangle.height / bounds.height, - newBounds = new Rectangle(new Point(), - new Size(bounds.width * scale, bounds.height * scale)); - newBounds.setCenter(rectangle.getCenter()); - this.setBounds(newBounds); - } -}), { - - _setStyles: function(ctx, param, viewMatrix) { - var style = this._style, - matrix = this._matrix; - if (style.hasFill()) { - ctx.fillStyle = style.getFillColor().toCanvasStyle(ctx, matrix); - } - if (style.hasStroke()) { - ctx.strokeStyle = style.getStrokeColor().toCanvasStyle(ctx, matrix); - ctx.lineWidth = style.getStrokeWidth(); - var strokeJoin = style.getStrokeJoin(), - strokeCap = style.getStrokeCap(), - miterLimit = style.getMiterLimit(); - if (strokeJoin) - ctx.lineJoin = strokeJoin; - if (strokeCap) - ctx.lineCap = strokeCap; - if (miterLimit) - ctx.miterLimit = miterLimit; - if (paper.support.nativeDash) { - var dashArray = style.getDashArray(), - dashOffset = style.getDashOffset(); - if (dashArray && dashArray.length) { - if ('setLineDash' in ctx) { - ctx.setLineDash(dashArray); - ctx.lineDashOffset = dashOffset; - } else { - ctx.mozDash = dashArray; - ctx.mozDashOffset = dashOffset; - } - } - } - } - if (style.hasShadow()) { - var pixelRatio = param.pixelRatio || 1, - mx = viewMatrix._shiftless().prepend( - new Matrix().scale(pixelRatio, pixelRatio)), - blur = mx.transform(new Point(style.getShadowBlur(), 0)), - offset = mx.transform(this.getShadowOffset()); - ctx.shadowColor = style.getShadowColor().toCanvasStyle(ctx); - ctx.shadowBlur = blur.getLength(); - ctx.shadowOffsetX = offset.x; - ctx.shadowOffsetY = offset.y; - } - }, - - draw: function(ctx, param, parentStrokeMatrix) { - var updateVersion = this._updateVersion = this._project._updateVersion; - if (!this._visible || this._opacity === 0) - return; - var matrices = param.matrices, - viewMatrix = param.viewMatrix, - matrix = this._matrix, - globalMatrix = matrices[matrices.length - 1].appended(matrix); - if (!globalMatrix.isInvertible()) - return; - - viewMatrix = viewMatrix ? viewMatrix.appended(globalMatrix) - : globalMatrix; - - matrices.push(globalMatrix); - if (param.updateMatrix) { - this._globalMatrix = globalMatrix; - } - - var blendMode = this._blendMode, - opacity = this._opacity, - normalBlend = blendMode === 'normal', - nativeBlend = BlendMode.nativeModes[blendMode], - direct = normalBlend && opacity === 1 - || param.dontStart - || param.clip - || (nativeBlend || normalBlend && opacity < 1) - && this._canComposite(), - pixelRatio = param.pixelRatio || 1, - mainCtx, itemOffset, prevOffset; - if (!direct) { - var bounds = this.getStrokeBounds(viewMatrix); - if (!bounds.width || !bounds.height) { - matrices.pop(); - return; - } - prevOffset = param.offset; - itemOffset = param.offset = bounds.getTopLeft().floor(); - mainCtx = ctx; - ctx = CanvasProvider.getContext(bounds.getSize().ceil().add(1) - .multiply(pixelRatio)); - if (pixelRatio !== 1) - ctx.scale(pixelRatio, pixelRatio); - } - ctx.save(); - var strokeMatrix = parentStrokeMatrix - ? parentStrokeMatrix.appended(matrix) - : this._canScaleStroke && !this.getStrokeScaling(true) - && viewMatrix, - clip = !direct && param.clipItem, - transform = !strokeMatrix || clip; - if (direct) { - ctx.globalAlpha = opacity; - if (nativeBlend) - ctx.globalCompositeOperation = blendMode; - } else if (transform) { - ctx.translate(-itemOffset.x, -itemOffset.y); - } - if (transform) { - (direct ? matrix : viewMatrix).applyToContext(ctx); - } - if (clip) { - param.clipItem.draw(ctx, param.extend({ clip: true })); - } - if (strokeMatrix) { - ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); - var offset = param.offset; - if (offset) - ctx.translate(-offset.x, -offset.y); - } - this._draw(ctx, param, viewMatrix, strokeMatrix); - ctx.restore(); - matrices.pop(); - if (param.clip && !param.dontFinish) - ctx.clip(); - if (!direct) { - BlendMode.process(blendMode, ctx, mainCtx, opacity, - itemOffset.subtract(prevOffset).multiply(pixelRatio)); - CanvasProvider.release(ctx); - param.offset = prevOffset; - } - }, - - _isUpdated: function(updateVersion) { - var parent = this._parent; - if (parent instanceof CompoundPath) - return parent._isUpdated(updateVersion); - var updated = this._updateVersion === updateVersion; - if (!updated && parent && parent._visible - && parent._isUpdated(updateVersion)) { - this._updateVersion = updateVersion; - updated = true; - } - return updated; - }, - - _drawSelection: function(ctx, matrix, size, selectionItems, updateVersion) { - var selection = this._selection, - itemSelected = selection & 1, - boundsSelected = selection & 2 - || itemSelected && this._selectBounds, - positionSelected = selection & 4; - if (!this._drawSelected) - itemSelected = false; - if ((itemSelected || boundsSelected || positionSelected) - && this._isUpdated(updateVersion)) { - var layer, - color = this.getSelectedColor(true) || (layer = this.getLayer()) - && layer.getSelectedColor(true), - mx = matrix.appended(this.getGlobalMatrix(true)), - half = size / 2; - ctx.strokeStyle = ctx.fillStyle = color - ? color.toCanvasStyle(ctx) : '#009dec'; - if (itemSelected) - this._drawSelected(ctx, mx, selectionItems); - if (positionSelected) { - var pos = this.getPosition(true), - parent = this._parent, - point = parent ? parent.localToGlobal(pos) : pos, - x = point.x, - y = point.y; - ctx.beginPath(); - ctx.arc(x, y, half, 0, Math.PI * 2, true); - ctx.stroke(); - var deltas = [[0, -1], [1, 0], [0, 1], [-1, 0]], - start = half, - end = size + 1; - for (var i = 0; i < 4; i++) { - var delta = deltas[i], - dx = delta[0], - dy = delta[1]; - ctx.moveTo(x + dx * start, y + dy * start); - ctx.lineTo(x + dx * end, y + dy * end); - ctx.stroke(); - } - } - if (boundsSelected) { - var coords = mx._transformCorners(this.getInternalBounds()); - ctx.beginPath(); - for (var i = 0; i < 8; i++) { - ctx[!i ? 'moveTo' : 'lineTo'](coords[i], coords[++i]); - } - ctx.closePath(); - ctx.stroke(); - for (var i = 0; i < 8; i++) { - ctx.fillRect(coords[i] - half, coords[++i] - half, - size, size); - } - } - } - }, - - _canComposite: function() { - return false; - } -}, Base.each(['down', 'drag', 'up', 'move'], function(key) { - this['removeOn' + Base.capitalize(key)] = function() { - var hash = {}; - hash[key] = true; - return this.removeOn(hash); - }; -}, { - - removeOn: function(obj) { - for (var name in obj) { - if (obj[name]) { - var key = 'mouse' + name, - project = this._project, - sets = project._removeSets = project._removeSets || {}; - sets[key] = sets[key] || {}; - sets[key][this._id] = this; - } - } - return this; - } -})); - -var Group = Item.extend({ - _class: 'Group', - _selectBounds: false, - _selectChildren: true, - _serializeFields: { - children: [] - }, - - initialize: function Group(arg) { - this._children = []; - this._namedChildren = {}; - if (!this._initialize(arg)) - this.addChildren(Array.isArray(arg) ? arg : arguments); - }, - - _changed: function _changed(flags) { - _changed.base.call(this, flags); - if (flags & 2050) { - this._clipItem = undefined; - } - }, - - _getClipItem: function() { - var clipItem = this._clipItem; - if (clipItem === undefined) { - clipItem = null; - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) { - if (children[i]._clipMask) { - clipItem = children[i]; - break; - } - } - this._clipItem = clipItem; - } - return clipItem; - }, - - isClipped: function() { - return !!this._getClipItem(); - }, - - setClipped: function(clipped) { - var child = this.getFirstChild(); - if (child) - child.setClipMask(clipped); - }, - - _getBounds: function _getBounds(matrix, options) { - var clipItem = this._getClipItem(); - return clipItem - ? clipItem._getCachedBounds( - matrix && matrix.appended(clipItem._matrix), - Base.set({}, options, { stroke: false })) - : _getBounds.base.call(this, matrix, options); - }, - - _hitTestChildren: function _hitTestChildren(point, options, viewMatrix) { - var clipItem = this._getClipItem(); - return (!clipItem || clipItem.contains(point)) - && _hitTestChildren.base.call(this, point, options, viewMatrix, - clipItem); - }, - - _draw: function(ctx, param) { - var clip = param.clip, - clipItem = !clip && this._getClipItem(); - param = param.extend({ clipItem: clipItem, clip: false }); - if (clip) { - ctx.beginPath(); - param.dontStart = param.dontFinish = true; - } else if (clipItem) { - clipItem.draw(ctx, param.extend({ clip: true })); - } - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) { - var item = children[i]; - if (item !== clipItem) - item.draw(ctx, param); - } - } -}); - -var Layer = Group.extend({ - _class: 'Layer', - - initialize: function Layer() { - Group.apply(this, arguments); - }, - - _getOwner: function() { - return this._parent || this._index != null && this._project; - }, - - isInserted: function isInserted() { - return this._parent ? isInserted.base.call(this) : this._index != null; - }, - - activate: function() { - this._project._activeLayer = this; - }, - - _hitTestSelf: function() { - } -}); - -var Shape = Item.extend({ - _class: 'Shape', - _applyMatrix: false, - _canApplyMatrix: false, - _canScaleStroke: true, - _serializeFields: { - type: null, - size: null, - radius: null - }, - - initialize: function Shape(props, point) { - this._initialize(props, point); - }, - - _equals: function(item) { - return this._type === item._type - && this._size.equals(item._size) - && Base.equals(this._radius, item._radius); - }, - - copyContent: function(source) { - this.setType(source._type); - this.setSize(source._size); - this.setRadius(source._radius); - }, - - getType: function() { - return this._type; - }, - - setType: function(type) { - this._type = type; - }, - - getShape: '#getType', - setShape: '#setType', - - getSize: function() { - var size = this._size; - return new LinkedSize(size.width, size.height, this, 'setSize'); - }, - - setSize: function() { - var size = Size.read(arguments); - if (!this._size) { - this._size = size.clone(); - } else if (!this._size.equals(size)) { - var type = this._type, - width = size.width, - height = size.height; - if (type === 'rectangle') { - this._radius.set(Size.min(this._radius, size.divide(2))); - } else if (type === 'circle') { - width = height = (width + height) / 2; - this._radius = width / 2; - } else if (type === 'ellipse') { - this._radius._set(width / 2, height / 2); - } - this._size._set(width, height); - this._changed(9); - } - }, - - getRadius: function() { - var rad = this._radius; - return this._type === 'circle' - ? rad - : new LinkedSize(rad.width, rad.height, this, 'setRadius'); - }, - - setRadius: function(radius) { - var type = this._type; - if (type === 'circle') { - if (radius === this._radius) - return; - var size = radius * 2; - this._radius = radius; - this._size._set(size, size); - } else { - radius = Size.read(arguments); - if (!this._radius) { - this._radius = radius.clone(); - } else { - if (this._radius.equals(radius)) - return; - this._radius.set(radius); - if (type === 'rectangle') { - var size = Size.max(this._size, radius.multiply(2)); - this._size.set(size); - } else if (type === 'ellipse') { - this._size._set(radius.width * 2, radius.height * 2); - } - } - } - this._changed(9); - }, - - isEmpty: function() { - return false; - }, - - toPath: function(insert) { - var path = new Path[Base.capitalize(this._type)]({ - center: new Point(), - size: this._size, - radius: this._radius, - insert: false - }); - path.copyAttributes(this); - if (paper.settings.applyMatrix) - path.setApplyMatrix(true); - if (insert === undefined || insert) - path.insertAbove(this); - return path; - }, - - toShape: '#clone', - - _asPathItem: function() { - return this.toPath(false); - }, - - _draw: function(ctx, param, viewMatrix, strokeMatrix) { - var style = this._style, - hasFill = style.hasFill(), - hasStroke = style.hasStroke(), - dontPaint = param.dontFinish || param.clip, - untransformed = !strokeMatrix; - if (hasFill || hasStroke || dontPaint) { - var type = this._type, - radius = this._radius, - isCircle = type === 'circle'; - if (!param.dontStart) - ctx.beginPath(); - if (untransformed && isCircle) { - ctx.arc(0, 0, radius, 0, Math.PI * 2, true); - } else { - var rx = isCircle ? radius : radius.width, - ry = isCircle ? radius : radius.height, - size = this._size, - width = size.width, - height = size.height; - if (untransformed && type === 'rectangle' && rx === 0 && ry === 0) { - ctx.rect(-width / 2, -height / 2, width, height); - } else { - var x = width / 2, - y = height / 2, - kappa = 1 - 0.5522847498307936, - cx = rx * kappa, - cy = ry * kappa, - c = [ - -x, -y + ry, - -x, -y + cy, - -x + cx, -y, - -x + rx, -y, - x - rx, -y, - x - cx, -y, - x, -y + cy, - x, -y + ry, - x, y - ry, - x, y - cy, - x - cx, y, - x - rx, y, - -x + rx, y, - -x + cx, y, - -x, y - cy, - -x, y - ry - ]; - if (strokeMatrix) - strokeMatrix.transform(c, c, 32); - ctx.moveTo(c[0], c[1]); - ctx.bezierCurveTo(c[2], c[3], c[4], c[5], c[6], c[7]); - if (x !== rx) - ctx.lineTo(c[8], c[9]); - ctx.bezierCurveTo(c[10], c[11], c[12], c[13], c[14], c[15]); - if (y !== ry) - ctx.lineTo(c[16], c[17]); - ctx.bezierCurveTo(c[18], c[19], c[20], c[21], c[22], c[23]); - if (x !== rx) - ctx.lineTo(c[24], c[25]); - ctx.bezierCurveTo(c[26], c[27], c[28], c[29], c[30], c[31]); - } - } - ctx.closePath(); - } - if (!dontPaint && (hasFill || hasStroke)) { - this._setStyles(ctx, param, viewMatrix); - if (hasFill) { - ctx.fill(style.getFillRule()); - ctx.shadowColor = 'rgba(0,0,0,0)'; - } - if (hasStroke) - ctx.stroke(); - } - }, - - _canComposite: function() { - return !(this.hasFill() && this.hasStroke()); - }, - - _getBounds: function(matrix, options) { - var rect = new Rectangle(this._size).setCenter(0, 0), - style = this._style, - strokeWidth = options.stroke && style.hasStroke() - && style.getStrokeWidth(); - if (matrix) - rect = matrix._transformBounds(rect); - return strokeWidth - ? rect.expand(Path._getStrokePadding(strokeWidth, - this._getStrokeMatrix(matrix, options))) - : rect; - } -}, -new function() { - function getCornerCenter(that, point, expand) { - var radius = that._radius; - if (!radius.isZero()) { - var halfSize = that._size.divide(2); - for (var q = 1; q <= 4; q++) { - var dir = new Point(q > 1 && q < 4 ? -1 : 1, q > 2 ? -1 : 1), - corner = dir.multiply(halfSize), - center = corner.subtract(dir.multiply(radius)), - rect = new Rectangle( - expand ? corner.add(dir.multiply(expand)) : corner, - center); - if (rect.contains(point)) - return { point: center, quadrant: q }; - } - } - } - - function isOnEllipseStroke(point, radius, padding, quadrant) { - var vector = point.divide(radius); - return (!quadrant || vector.isInQuadrant(quadrant)) && - vector.subtract(vector.normalize()).multiply(radius) - .divide(padding).length <= 1; - } - - return { - _contains: function _contains(point) { - if (this._type === 'rectangle') { - var center = getCornerCenter(this, point); - return center - ? point.subtract(center.point).divide(this._radius) - .getLength() <= 1 - : _contains.base.call(this, point); - } else { - return point.divide(this.size).getLength() <= 0.5; - } - }, - - _hitTestSelf: function _hitTestSelf(point, options, viewMatrix, - strokeMatrix) { - var hit = false, - style = this._style, - hitStroke = options.stroke && style.hasStroke(), - hitFill = options.fill && style.hasFill(); - if (hitStroke || hitFill) { - var type = this._type, - radius = this._radius, - strokeRadius = hitStroke ? style.getStrokeWidth() / 2 : 0, - strokePadding = options._tolerancePadding.add( - Path._getStrokePadding(strokeRadius, - !style.getStrokeScaling() && strokeMatrix)); - if (type === 'rectangle') { - var padding = strokePadding.multiply(2), - center = getCornerCenter(this, point, padding); - if (center) { - hit = isOnEllipseStroke(point.subtract(center.point), - radius, strokePadding, center.quadrant); - } else { - var rect = new Rectangle(this._size).setCenter(0, 0), - outer = rect.expand(padding), - inner = rect.expand(padding.negate()); - hit = outer._containsPoint(point) - && !inner._containsPoint(point); - } - } else { - hit = isOnEllipseStroke(point, radius, strokePadding); - } - } - return hit ? new HitResult(hitStroke ? 'stroke' : 'fill', this) - : _hitTestSelf.base.apply(this, arguments); - } - }; -}, { - -statics: new function() { - function createShape(type, point, size, radius, args) { - var item = new Shape(Base.getNamed(args), point); - item._type = type; - item._size = size; - item._radius = radius; - return item; - } - - return { - Circle: function() { - var center = Point.readNamed(arguments, 'center'), - radius = Base.readNamed(arguments, 'radius'); - return createShape('circle', center, new Size(radius * 2), radius, - arguments); - }, - - Rectangle: function() { - var rect = Rectangle.readNamed(arguments, 'rectangle'), - radius = Size.min(Size.readNamed(arguments, 'radius'), - rect.getSize(true).divide(2)); - return createShape('rectangle', rect.getCenter(true), - rect.getSize(true), radius, arguments); - }, - - Ellipse: function() { - var ellipse = Shape._readEllipse(arguments), - radius = ellipse.radius; - return createShape('ellipse', ellipse.center, radius.multiply(2), - radius, arguments); - }, - - _readEllipse: function(args) { - var center, - radius; - if (Base.hasNamed(args, 'radius')) { - center = Point.readNamed(args, 'center'); - radius = Size.readNamed(args, 'radius'); - } else { - var rect = Rectangle.readNamed(args, 'rectangle'); - center = rect.getCenter(true); - radius = rect.getSize(true).divide(2); - } - return { center: center, radius: radius }; - } - }; -}}); - -var Raster = Item.extend({ - _class: 'Raster', - _applyMatrix: false, - _canApplyMatrix: false, - _boundsOptions: { stroke: false, handle: false }, - _serializeFields: { - crossOrigin: null, - source: null - }, - _prioritize: ['crossOrigin'], - _smoothing: true, - - initialize: function Raster(object, position) { - if (!this._initialize(object, - position !== undefined && Point.read(arguments, 1))) { - var image = typeof object === 'string' - ? document.getElementById(object) : object; - if (image) { - this.setImage(image); - } else { - this.setSource(object); - } - } - if (!this._size) { - this._size = new Size(); - this._loaded = false; - } - }, - - _equals: function(item) { - return this.getSource() === item.getSource(); - }, - - copyContent: function(source) { - var image = source._image, - canvas = source._canvas; - if (image) { - this._setImage(image); - } else if (canvas) { - var copyCanvas = CanvasProvider.getCanvas(source._size); - copyCanvas.getContext('2d').drawImage(canvas, 0, 0); - this._setImage(copyCanvas); - } - this._crossOrigin = source._crossOrigin; - }, - - getSize: function() { - var size = this._size; - return new LinkedSize(size ? size.width : 0, size ? size.height : 0, - this, 'setSize'); - }, - - setSize: function() { - var size = Size.read(arguments); - if (!size.equals(this._size)) { - if (size.width > 0 && size.height > 0) { - var element = this.getElement(); - this._setImage(CanvasProvider.getCanvas(size)); - if (element) - this.getContext(true).drawImage(element, 0, 0, - size.width, size.height); - } else { - if (this._canvas) - CanvasProvider.release(this._canvas); - this._size = size.clone(); - } - } - }, - - getWidth: function() { - return this._size ? this._size.width : 0; - }, - - setWidth: function(width) { - this.setSize(width, this.getHeight()); - }, - - getHeight: function() { - return this._size ? this._size.height : 0; - }, - - setHeight: function(height) { - this.setSize(this.getWidth(), height); - }, - - getLoaded: function() { - return this._loaded; - }, - - isEmpty: function() { - var size = this._size; - return !size || size.width === 0 && size.height === 0; - }, - - getResolution: function() { - var matrix = this._matrix, - orig = new Point(0, 0).transform(matrix), - u = new Point(1, 0).transform(matrix).subtract(orig), - v = new Point(0, 1).transform(matrix).subtract(orig); - return new Size( - 72 / u.getLength(), - 72 / v.getLength() - ); - }, - - getPpi: '#getResolution', - - getImage: function() { - return this._image; - }, - - setImage: function(image) { - var that = this; - - function emit(event) { - var view = that.getView(), - type = event && event.type || 'load'; - if (view && that.responds(type)) { - paper = view._scope; - that.emit(type, new Event(event)); - } - } - - this._setImage(image); - if (this._loaded) { - setTimeout(emit, 0); - } else if (image) { - DomEvent.add(image, { - load: function(event) { - that._setImage(image); - emit(event); - }, - error: emit - }); - } - }, - - _setImage: function(image) { - if (this._canvas) - CanvasProvider.release(this._canvas); - if (image && image.getContext) { - this._image = null; - this._canvas = image; - this._loaded = true; - } else { - this._image = image; - this._canvas = null; - this._loaded = !!(image && image.src && image.complete); - } - this._size = new Size( - image ? image.naturalWidth || image.width : 0, - image ? image.naturalHeight || image.height : 0); - this._context = null; - this._changed(1033); - }, - - getCanvas: function() { - if (!this._canvas) { - var ctx = CanvasProvider.getContext(this._size); - try { - if (this._image) - ctx.drawImage(this._image, 0, 0); - this._canvas = ctx.canvas; - } catch (e) { - CanvasProvider.release(ctx); - } - } - return this._canvas; - }, - - setCanvas: '#setImage', - - getContext: function(modify) { - if (!this._context) - this._context = this.getCanvas().getContext('2d'); - if (modify) { - this._image = null; - this._changed(1025); - } - return this._context; - }, - - setContext: function(context) { - this._context = context; - }, - - getSource: function() { - var image = this._image; - return image && image.src || this.toDataURL(); - }, - - setSource: function(src) { - var image = new self.Image(), - crossOrigin = this._crossOrigin; - if (crossOrigin) - image.crossOrigin = crossOrigin; - image.src = src; - this.setImage(image); - }, - - getCrossOrigin: function() { - var image = this._image; - return image && image.crossOrigin || this._crossOrigin || ''; - }, - - setCrossOrigin: function(crossOrigin) { - this._crossOrigin = crossOrigin; - var image = this._image; - if (image) - image.crossOrigin = crossOrigin; - }, - - getSmoothing: function() { - return this._smoothing; - }, - - setSmoothing: function(smoothing) { - this._smoothing = smoothing; - this._changed(257); - }, - - getElement: function() { - return this._canvas || this._loaded && this._image; - } -}, { - beans: false, - - getSubCanvas: function() { - var rect = Rectangle.read(arguments), - ctx = CanvasProvider.getContext(rect.getSize()); - ctx.drawImage(this.getCanvas(), rect.x, rect.y, - rect.width, rect.height, 0, 0, rect.width, rect.height); - return ctx.canvas; - }, - - getSubRaster: function() { - var rect = Rectangle.read(arguments), - raster = new Raster(Item.NO_INSERT); - raster._setImage(this.getSubCanvas(rect)); - raster.translate(rect.getCenter().subtract(this.getSize().divide(2))); - raster._matrix.prepend(this._matrix); - raster.insertAbove(this); - return raster; - }, - - toDataURL: function() { - var image = this._image, - src = image && image.src; - if (/^data:/.test(src)) - return src; - var canvas = this.getCanvas(); - return canvas ? canvas.toDataURL.apply(canvas, arguments) : null; - }, - - drawImage: function(image ) { - var point = Point.read(arguments, 1); - this.getContext(true).drawImage(image, point.x, point.y); - }, - - getAverageColor: function(object) { - var bounds, path; - if (!object) { - bounds = this.getBounds(); - } else if (object instanceof PathItem) { - path = object; - bounds = object.getBounds(); - } else if (typeof object === 'object') { - if ('width' in object) { - bounds = new Rectangle(object); - } else if ('x' in object) { - bounds = new Rectangle(object.x - 0.5, object.y - 0.5, 1, 1); - } - } - if (!bounds) - return null; - var sampleSize = 32, - width = Math.min(bounds.width, sampleSize), - height = Math.min(bounds.height, sampleSize); - var ctx = Raster._sampleContext; - if (!ctx) { - ctx = Raster._sampleContext = CanvasProvider.getContext( - new Size(sampleSize)); - } else { - ctx.clearRect(0, 0, sampleSize + 1, sampleSize + 1); - } - ctx.save(); - var matrix = new Matrix() - .scale(width / bounds.width, height / bounds.height) - .translate(-bounds.x, -bounds.y); - matrix.applyToContext(ctx); - if (path) - path.draw(ctx, new Base({ clip: true, matrices: [matrix] })); - this._matrix.applyToContext(ctx); - var element = this.getElement(), - size = this._size; - if (element) - ctx.drawImage(element, -size.width / 2, -size.height / 2); - ctx.restore(); - var pixels = ctx.getImageData(0.5, 0.5, Math.ceil(width), - Math.ceil(height)).data, - channels = [0, 0, 0], - total = 0; - for (var i = 0, l = pixels.length; i < l; i += 4) { - var alpha = pixels[i + 3]; - total += alpha; - alpha /= 255; - channels[0] += pixels[i] * alpha; - channels[1] += pixels[i + 1] * alpha; - channels[2] += pixels[i + 2] * alpha; - } - for (var i = 0; i < 3; i++) - channels[i] /= total; - return total ? Color.read(channels) : null; - }, - - getPixel: function() { - var point = Point.read(arguments); - var data = this.getContext().getImageData(point.x, point.y, 1, 1).data; - return new Color('rgb', [data[0] / 255, data[1] / 255, data[2] / 255], - data[3] / 255); - }, - - setPixel: function() { - var point = Point.read(arguments), - color = Color.read(arguments), - components = color._convert('rgb'), - alpha = color._alpha, - ctx = this.getContext(true), - imageData = ctx.createImageData(1, 1), - data = imageData.data; - data[0] = components[0] * 255; - data[1] = components[1] * 255; - data[2] = components[2] * 255; - data[3] = alpha != null ? alpha * 255 : 255; - ctx.putImageData(imageData, point.x, point.y); - }, - - createImageData: function() { - var size = Size.read(arguments); - return this.getContext().createImageData(size.width, size.height); - }, - - getImageData: function() { - var rect = Rectangle.read(arguments); - if (rect.isEmpty()) - rect = new Rectangle(this._size); - return this.getContext().getImageData(rect.x, rect.y, - rect.width, rect.height); - }, - - setImageData: function(data ) { - var point = Point.read(arguments, 1); - this.getContext(true).putImageData(data, point.x, point.y); - }, - - _getBounds: function(matrix, options) { - var rect = new Rectangle(this._size).setCenter(0, 0); - return matrix ? matrix._transformBounds(rect) : rect; - }, - - _hitTestSelf: function(point) { - if (this._contains(point)) { - var that = this; - return new HitResult('pixel', that, { - offset: point.add(that._size.divide(2)).round(), - color: { - get: function() { - return that.getPixel(this.offset); - } - } - }); - } - }, - - _draw: function(ctx, param, viewMatrix) { - var element = this.getElement(); - if (element) { - ctx.globalAlpha = this._opacity; - - this._setStyles(ctx, param, viewMatrix); - - DomElement.setPrefixed( - ctx, 'imageSmoothingEnabled', this._smoothing - ); - - ctx.drawImage(element, - -this._size.width / 2, -this._size.height / 2); - } - }, - - _canComposite: function() { - return true; - } -}); - -var SymbolItem = Item.extend({ - _class: 'SymbolItem', - _applyMatrix: false, - _canApplyMatrix: false, - _boundsOptions: { stroke: true }, - _serializeFields: { - symbol: null - }, - - initialize: function SymbolItem(arg0, arg1) { - if (!this._initialize(arg0, - arg1 !== undefined && Point.read(arguments, 1))) - this.setDefinition(arg0 instanceof SymbolDefinition ? - arg0 : new SymbolDefinition(arg0)); - }, - - _equals: function(item) { - return this._definition === item._definition; - }, - - copyContent: function(source) { - this.setDefinition(source._definition); - }, - - getDefinition: function() { - return this._definition; - }, - - setDefinition: function(definition) { - this._definition = definition; - this._changed(9); - }, - - getSymbol: '#getDefinition', - setSymbol: '#setDefinition', - - isEmpty: function() { - return this._definition._item.isEmpty(); - }, - - _getBounds: function(matrix, options) { - var item = this._definition._item; - return item._getCachedBounds(item._matrix.prepended(matrix), options); - }, - - _hitTestSelf: function(point, options, viewMatrix) { - var res = this._definition._item._hitTest(point, options, viewMatrix); - if (res) - res.item = this; - return res; - }, - - _draw: function(ctx, param) { - this._definition._item.draw(ctx, param); - } - -}); - -var SymbolDefinition = Base.extend({ - _class: 'SymbolDefinition', - - initialize: function SymbolDefinition(item, dontCenter) { - this._id = UID.get(); - this.project = paper.project; - if (item) - this.setItem(item, dontCenter); - }, - - _serialize: function(options, dictionary) { - return dictionary.add(this, function() { - return Base.serialize([this._class, this._item], - options, false, dictionary); - }); - }, - - _changed: function(flags) { - if (flags & 8) - Item._clearBoundsCache(this); - if (flags & 1) - this.project._changed(flags); - }, - - getItem: function() { - return this._item; - }, - - setItem: function(item, _dontCenter) { - if (item._symbol) - item = item.clone(); - if (this._item) - this._item._symbol = null; - this._item = item; - item.remove(); - item.setSelected(false); - if (!_dontCenter) - item.setPosition(new Point()); - item._symbol = this; - this._changed(9); - }, - - getDefinition: '#getItem', - setDefinition: '#setItem', - - place: function(position) { - return new SymbolItem(this, position); - }, - - clone: function() { - return new SymbolDefinition(this._item.clone(false)); - }, - - equals: function(symbol) { - return symbol === this - || symbol && this._item.equals(symbol._item) - || false; - } -}); - -var HitResult = Base.extend({ - _class: 'HitResult', - - initialize: function HitResult(type, item, values) { - this.type = type; - this.item = item; - if (values) - this.inject(values); - }, - - statics: { - getOptions: function(args) { - var options = args && Base.read(args); - return Base.set({ - type: null, - tolerance: paper.settings.hitTolerance, - fill: !options, - stroke: !options, - segments: !options, - handles: false, - ends: false, - position: false, - center: false, - bounds: false, - guides: false, - selected: false - }, options); - } - } -}); - -var Segment = Base.extend({ - _class: 'Segment', - beans: true, - _selection: 0, - - initialize: function Segment(arg0, arg1, arg2, arg3, arg4, arg5) { - var count = arguments.length, - point, handleIn, handleOut, selection; - if (count > 0) { - if (arg0 == null || typeof arg0 === 'object') { - if (count === 1 && arg0 && 'point' in arg0) { - point = arg0.point; - handleIn = arg0.handleIn; - handleOut = arg0.handleOut; - selection = arg0.selection; - } else { - point = arg0; - handleIn = arg1; - handleOut = arg2; - selection = arg3; - } - } else { - point = [ arg0, arg1 ]; - handleIn = arg2 !== undefined ? [ arg2, arg3 ] : null; - handleOut = arg4 !== undefined ? [ arg4, arg5 ] : null; - } - } - new SegmentPoint(point, this, '_point'); - new SegmentPoint(handleIn, this, '_handleIn'); - new SegmentPoint(handleOut, this, '_handleOut'); - if (selection) - this.setSelection(selection); - }, - - _serialize: function(options, dictionary) { - var point = this._point, - selection = this._selection, - obj = selection || this.hasHandles() - ? [point, this._handleIn, this._handleOut] - : point; - if (selection) - obj.push(selection); - return Base.serialize(obj, options, true, dictionary); - }, - - _changed: function(point) { - var path = this._path; - if (!path) - return; - var curves = path._curves, - index = this._index, - curve; - if (curves) { - if ((!point || point === this._point || point === this._handleIn) - && (curve = index > 0 ? curves[index - 1] : path._closed - ? curves[curves.length - 1] : null)) - curve._changed(); - if ((!point || point === this._point || point === this._handleOut) - && (curve = curves[index])) - curve._changed(); - } - path._changed(41); - }, - - getPoint: function() { - return this._point; - }, - - setPoint: function() { - this._point.set(Point.read(arguments)); - }, - - getHandleIn: function() { - return this._handleIn; - }, - - setHandleIn: function() { - this._handleIn.set(Point.read(arguments)); - }, - - getHandleOut: function() { - return this._handleOut; - }, - - setHandleOut: function() { - this._handleOut.set(Point.read(arguments)); - }, - - hasHandles: function() { - return !this._handleIn.isZero() || !this._handleOut.isZero(); - }, - - isSmooth: function() { - var handleIn = this._handleIn, - handleOut = this._handleOut; - return !handleIn.isZero() && !handleOut.isZero() - && handleIn.isCollinear(handleOut); - }, - - clearHandles: function() { - this._handleIn._set(0, 0); - this._handleOut._set(0, 0); - }, - - getSelection: function() { - return this._selection; - }, - - setSelection: function(selection) { - var oldSelection = this._selection, - path = this._path; - this._selection = selection = selection || 0; - if (path && selection !== oldSelection) { - path._updateSelection(this, oldSelection, selection); - path._changed(257); - } - }, - - _changeSelection: function(flag, selected) { - var selection = this._selection; - this.setSelection(selected ? selection | flag : selection & ~flag); - }, - - isSelected: function() { - return !!(this._selection & 7); - }, - - setSelected: function(selected) { - this._changeSelection(7, selected); - }, - - getIndex: function() { - return this._index !== undefined ? this._index : null; - }, - - getPath: function() { - return this._path || null; - }, - - getCurve: function() { - var path = this._path, - index = this._index; - if (path) { - if (index > 0 && !path._closed - && index === path._segments.length - 1) - index--; - return path.getCurves()[index] || null; - } - return null; - }, - - getLocation: function() { - var curve = this.getCurve(); - return curve - ? new CurveLocation(curve, this === curve._segment1 ? 0 : 1) - : null; - }, - - getNext: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index + 1] - || this._path._closed && segments[0]) || null; - }, - - smooth: function(options, _first, _last) { - var opts = options || {}, - type = opts.type, - factor = opts.factor, - prev = this.getPrevious(), - next = this.getNext(), - p0 = (prev || this)._point, - p1 = this._point, - p2 = (next || this)._point, - d1 = p0.getDistance(p1), - d2 = p1.getDistance(p2); - if (!type || type === 'catmull-rom') { - var a = factor === undefined ? 0.5 : factor, - d1_a = Math.pow(d1, a), - d1_2a = d1_a * d1_a, - d2_a = Math.pow(d2, a), - d2_2a = d2_a * d2_a; - if (!_first && prev) { - var A = 2 * d2_2a + 3 * d2_a * d1_a + d1_2a, - N = 3 * d2_a * (d2_a + d1_a); - this.setHandleIn(N !== 0 - ? new Point( - (d2_2a * p0._x + A * p1._x - d1_2a * p2._x) / N - p1._x, - (d2_2a * p0._y + A * p1._y - d1_2a * p2._y) / N - p1._y) - : new Point()); - } - if (!_last && next) { - var A = 2 * d1_2a + 3 * d1_a * d2_a + d2_2a, - N = 3 * d1_a * (d1_a + d2_a); - this.setHandleOut(N !== 0 - ? new Point( - (d1_2a * p2._x + A * p1._x - d2_2a * p0._x) / N - p1._x, - (d1_2a * p2._y + A * p1._y - d2_2a * p0._y) / N - p1._y) - : new Point()); - } - } else if (type === 'geometric') { - if (prev && next) { - var vector = p0.subtract(p2), - t = factor === undefined ? 0.4 : factor, - k = t * d1 / (d1 + d2); - if (!_first) - this.setHandleIn(vector.multiply(k)); - if (!_last) - this.setHandleOut(vector.multiply(k - t)); - } - } else { - throw new Error('Smoothing method \'' + type + '\' not supported.'); - } - }, - - getPrevious: function() { - var segments = this._path && this._path._segments; - return segments && (segments[this._index - 1] - || this._path._closed && segments[segments.length - 1]) || null; - }, - - isFirst: function() { - return !this._index; - }, - - isLast: function() { - var path = this._path; - return path && this._index === path._segments.length - 1 || false; - }, - - reverse: function() { - var handleIn = this._handleIn, - handleOut = this._handleOut, - tmp = handleIn.clone(); - handleIn.set(handleOut); - handleOut.set(tmp); - }, - - reversed: function() { - return new Segment(this._point, this._handleOut, this._handleIn); - }, - - remove: function() { - return this._path ? !!this._path.removeSegment(this._index) : false; - }, - - clone: function() { - return new Segment(this._point, this._handleIn, this._handleOut); - }, - - equals: function(segment) { - return segment === this || segment && this._class === segment._class - && this._point.equals(segment._point) - && this._handleIn.equals(segment._handleIn) - && this._handleOut.equals(segment._handleOut) - || false; - }, - - toString: function() { - var parts = [ 'point: ' + this._point ]; - if (!this._handleIn.isZero()) - parts.push('handleIn: ' + this._handleIn); - if (!this._handleOut.isZero()) - parts.push('handleOut: ' + this._handleOut); - return '{ ' + parts.join(', ') + ' }'; - }, - - transform: function(matrix) { - this._transformCoordinates(matrix, new Array(6), true); - this._changed(); - }, - - interpolate: function(from, to, factor) { - var u = 1 - factor, - v = factor, - point1 = from._point, - point2 = to._point, - handleIn1 = from._handleIn, - handleIn2 = to._handleIn, - handleOut2 = to._handleOut, - handleOut1 = from._handleOut; - this._point._set( - u * point1._x + v * point2._x, - u * point1._y + v * point2._y, true); - this._handleIn._set( - u * handleIn1._x + v * handleIn2._x, - u * handleIn1._y + v * handleIn2._y, true); - this._handleOut._set( - u * handleOut1._x + v * handleOut2._x, - u * handleOut1._y + v * handleOut2._y, true); - this._changed(); - }, - - _transformCoordinates: function(matrix, coords, change) { - var point = this._point, - handleIn = !change || !this._handleIn.isZero() - ? this._handleIn : null, - handleOut = !change || !this._handleOut.isZero() - ? this._handleOut : null, - x = point._x, - y = point._y, - i = 2; - coords[0] = x; - coords[1] = y; - if (handleIn) { - coords[i++] = handleIn._x + x; - coords[i++] = handleIn._y + y; - } - if (handleOut) { - coords[i++] = handleOut._x + x; - coords[i++] = handleOut._y + y; - } - if (matrix) { - matrix._transformCoordinates(coords, coords, i / 2); - x = coords[0]; - y = coords[1]; - if (change) { - point._x = x; - point._y = y; - i = 2; - if (handleIn) { - handleIn._x = coords[i++] - x; - handleIn._y = coords[i++] - y; - } - if (handleOut) { - handleOut._x = coords[i++] - x; - handleOut._y = coords[i++] - y; - } - } else { - if (!handleIn) { - coords[i++] = x; - coords[i++] = y; - } - if (!handleOut) { - coords[i++] = x; - coords[i++] = y; - } - } - } - return coords; - } -}); - -var SegmentPoint = Point.extend({ - initialize: function SegmentPoint(point, owner, key) { - var x, y, - selected; - if (!point) { - x = y = 0; - } else if ((x = point[0]) !== undefined) { - y = point[1]; - } else { - var pt = point; - if ((x = pt.x) === undefined) { - pt = Point.read(arguments); - x = pt.x; - } - y = pt.y; - selected = pt.selected; - } - this._x = x; - this._y = y; - this._owner = owner; - owner[key] = this; - if (selected) - this.setSelected(true); - }, - - _set: function(x, y) { - this._x = x; - this._y = y; - this._owner._changed(this); - return this; - }, - - getX: function() { - return this._x; - }, - - setX: function(x) { - this._x = x; - this._owner._changed(this); - }, - - getY: function() { - return this._y; - }, - - setY: function(y) { - this._y = y; - this._owner._changed(this); - }, - - isZero: function() { - var isZero = Numerical.isZero; - return isZero(this._x) && isZero(this._y); - }, - - isSelected: function() { - return !!(this._owner._selection & this._getSelection()); - }, - - setSelected: function(selected) { - this._owner._changeSelection(this._getSelection(), selected); - }, - - _getSelection: function() { - var owner = this._owner; - return this === owner._point ? 1 - : this === owner._handleIn ? 2 - : this === owner._handleOut ? 4 - : 0; - } -}); - -var Curve = Base.extend({ - _class: 'Curve', - beans: true, - - initialize: function Curve(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { - var count = arguments.length, - seg1, seg2, - point1, point2, - handle1, handle2; - if (count === 3) { - this._path = arg0; - seg1 = arg1; - seg2 = arg2; - } else if (!count) { - seg1 = new Segment(); - seg2 = new Segment(); - } else if (count === 1) { - if ('segment1' in arg0) { - seg1 = new Segment(arg0.segment1); - seg2 = new Segment(arg0.segment2); - } else if ('point1' in arg0) { - point1 = arg0.point1; - handle1 = arg0.handle1; - handle2 = arg0.handle2; - point2 = arg0.point2; - } else if (Array.isArray(arg0)) { - point1 = [arg0[0], arg0[1]]; - point2 = [arg0[6], arg0[7]]; - handle1 = [arg0[2] - arg0[0], arg0[3] - arg0[1]]; - handle2 = [arg0[4] - arg0[6], arg0[5] - arg0[7]]; - } - } else if (count === 2) { - seg1 = new Segment(arg0); - seg2 = new Segment(arg1); - } else if (count === 4) { - point1 = arg0; - handle1 = arg1; - handle2 = arg2; - point2 = arg3; - } else if (count === 8) { - point1 = [arg0, arg1]; - point2 = [arg6, arg7]; - handle1 = [arg2 - arg0, arg3 - arg1]; - handle2 = [arg4 - arg6, arg5 - arg7]; - } - this._segment1 = seg1 || new Segment(point1, null, handle1); - this._segment2 = seg2 || new Segment(point2, handle2, null); - }, - - _serialize: function(options, dictionary) { - return Base.serialize(this.hasHandles() - ? [this.getPoint1(), this.getHandle1(), this.getHandle2(), - this.getPoint2()] - : [this.getPoint1(), this.getPoint2()], - options, true, dictionary); - }, - - _changed: function() { - this._length = this._bounds = undefined; - }, - - clone: function() { - return new Curve(this._segment1, this._segment2); - }, - - toString: function() { - var parts = [ 'point1: ' + this._segment1._point ]; - if (!this._segment1._handleOut.isZero()) - parts.push('handle1: ' + this._segment1._handleOut); - if (!this._segment2._handleIn.isZero()) - parts.push('handle2: ' + this._segment2._handleIn); - parts.push('point2: ' + this._segment2._point); - return '{ ' + parts.join(', ') + ' }'; - }, - - classify: function() { - return Curve.classify(this.getValues()); - }, - - remove: function() { - var removed = false; - if (this._path) { - var segment2 = this._segment2, - handleOut = segment2._handleOut; - removed = segment2.remove(); - if (removed) - this._segment1._handleOut.set(handleOut); - } - return removed; - }, - - getPoint1: function() { - return this._segment1._point; - }, - - setPoint1: function() { - this._segment1._point.set(Point.read(arguments)); - }, - - getPoint2: function() { - return this._segment2._point; - }, - - setPoint2: function() { - this._segment2._point.set(Point.read(arguments)); - }, - - getHandle1: function() { - return this._segment1._handleOut; - }, - - setHandle1: function() { - this._segment1._handleOut.set(Point.read(arguments)); - }, - - getHandle2: function() { - return this._segment2._handleIn; - }, - - setHandle2: function() { - this._segment2._handleIn.set(Point.read(arguments)); - }, - - getSegment1: function() { - return this._segment1; - }, - - getSegment2: function() { - return this._segment2; - }, - - getPath: function() { - return this._path; - }, - - getIndex: function() { - return this._segment1._index; - }, - - getNext: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index + 1] - || this._path._closed && curves[0]) || null; - }, - - getPrevious: function() { - var curves = this._path && this._path._curves; - return curves && (curves[this._segment1._index - 1] - || this._path._closed && curves[curves.length - 1]) || null; - }, - - isFirst: function() { - return !this._segment1._index; - }, - - isLast: function() { - var path = this._path; - return path && this._segment1._index === path._curves.length - 1 - || false; - }, - - isSelected: function() { - return this.getPoint1().isSelected() - && this.getHandle1().isSelected() - && this.getHandle2().isSelected() - && this.getPoint2().isSelected(); - }, - - setSelected: function(selected) { - this.getPoint1().setSelected(selected); - this.getHandle1().setSelected(selected); - this.getHandle2().setSelected(selected); - this.getPoint2().setSelected(selected); - }, - - getValues: function(matrix) { - return Curve.getValues(this._segment1, this._segment2, matrix); - }, - - getPoints: function() { - var coords = this.getValues(), - points = []; - for (var i = 0; i < 8; i += 2) - points.push(new Point(coords[i], coords[i + 1])); - return points; - } -}, { - getLength: function() { - if (this._length == null) - this._length = Curve.getLength(this.getValues(), 0, 1); - return this._length; - }, - - getArea: function() { - return Curve.getArea(this.getValues()); - }, - - getLine: function() { - return new Line(this._segment1._point, this._segment2._point); - }, - - getPart: function(from, to) { - return new Curve(Curve.getPart(this.getValues(), from, to)); - }, - - getPartLength: function(from, to) { - return Curve.getLength(this.getValues(), from, to); - }, - - divideAt: function(location) { - return this.divideAtTime(location && location.curve === this - ? location.time : this.getTimeAt(location)); - }, - - divideAtTime: function(time, _setHandles) { - var tMin = 1e-8, - tMax = 1 - tMin, - res = null; - if (time >= tMin && time <= tMax) { - var parts = Curve.subdivide(this.getValues(), time), - left = parts[0], - right = parts[1], - setHandles = _setHandles || this.hasHandles(), - seg1 = this._segment1, - seg2 = this._segment2, - path = this._path; - if (setHandles) { - seg1._handleOut._set(left[2] - left[0], left[3] - left[1]); - seg2._handleIn._set(right[4] - right[6],right[5] - right[7]); - } - var x = left[6], y = left[7], - segment = new Segment(new Point(x, y), - setHandles && new Point(left[4] - x, left[5] - y), - setHandles && new Point(right[2] - x, right[3] - y)); - if (path) { - path.insert(seg1._index + 1, segment); - res = this.getNext(); - } else { - this._segment2 = segment; - this._changed(); - res = new Curve(segment, seg2); - } - } - return res; - }, - - splitAt: function(location) { - var path = this._path; - return path ? path.splitAt(location) : null; - }, - - splitAtTime: function(time) { - return this.splitAt(this.getLocationAtTime(time)); - }, - - divide: function(offset, isTime) { - return this.divideAtTime(offset === undefined ? 0.5 : isTime ? offset - : this.getTimeAt(offset)); - }, - - split: function(offset, isTime) { - return this.splitAtTime(offset === undefined ? 0.5 : isTime ? offset - : this.getTimeAt(offset)); - }, - - reversed: function() { - return new Curve(this._segment2.reversed(), this._segment1.reversed()); - }, - - clearHandles: function() { - this._segment1._handleOut._set(0, 0); - this._segment2._handleIn._set(0, 0); - }, - -statics: { - getValues: function(segment1, segment2, matrix, straight) { - var p1 = segment1._point, - h1 = segment1._handleOut, - h2 = segment2._handleIn, - p2 = segment2._point, - x1 = p1.x, y1 = p1.y, - x2 = p2.x, y2 = p2.y, - values = straight - ? [ x1, y1, x1, y1, x2, y2, x2, y2 ] - : [ - x1, y1, - x1 + h1._x, y1 + h1._y, - x2 + h2._x, y2 + h2._y, - x2, y2 - ]; - if (matrix) - matrix._transformCoordinates(values, values, 4); - return values; - }, - - subdivide: function(v, t) { - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7]; - if (t === undefined) - t = 0.5; - var u = 1 - t, - x4 = u * x0 + t * x1, y4 = u * y0 + t * y1, - x5 = u * x1 + t * x2, y5 = u * y1 + t * y2, - x6 = u * x2 + t * x3, y6 = u * y2 + t * y3, - x7 = u * x4 + t * x5, y7 = u * y4 + t * y5, - x8 = u * x5 + t * x6, y8 = u * y5 + t * y6, - x9 = u * x7 + t * x8, y9 = u * y7 + t * y8; - return [ - [x0, y0, x4, y4, x7, y7, x9, y9], - [x9, y9, x8, y8, x6, y6, x3, y3] - ]; - }, - - getMonoCurves: function(v, dir) { - var curves = [], - io = dir ? 0 : 1, - o0 = v[io + 0], - o1 = v[io + 2], - o2 = v[io + 4], - o3 = v[io + 6]; - if ((o0 >= o1) === (o1 >= o2) && (o1 >= o2) === (o2 >= o3) - || Curve.isStraight(v)) { - curves.push(v); - } else { - var a = 3 * (o1 - o2) - o0 + o3, - b = 2 * (o0 + o2) - 4 * o1, - c = o1 - o0, - tMin = 1e-8, - tMax = 1 - tMin, - roots = [], - n = Numerical.solveQuadratic(a, b, c, roots, tMin, tMax); - if (!n) { - curves.push(v); - } else { - roots.sort(); - var t = roots[0], - parts = Curve.subdivide(v, t); - curves.push(parts[0]); - if (n > 1) { - t = (roots[1] - t) / (1 - t); - parts = Curve.subdivide(parts[1], t); - curves.push(parts[0]); - } - curves.push(parts[1]); - } - } - return curves; - }, - - solveCubic: function (v, coord, val, roots, min, max) { - var v0 = v[coord], - v1 = v[coord + 2], - v2 = v[coord + 4], - v3 = v[coord + 6], - res = 0; - if ( !(v0 < val && v3 < val && v1 < val && v2 < val || - v0 > val && v3 > val && v1 > val && v2 > val)) { - var c = 3 * (v1 - v0), - b = 3 * (v2 - v1) - c, - a = v3 - v0 - c - b; - res = Numerical.solveCubic(a, b, c, v0 - val, roots, min, max); - } - return res; - }, - - getTimeOf: function(v, point) { - var p0 = new Point(v[0], v[1]), - p3 = new Point(v[6], v[7]), - epsilon = 1e-12, - geomEpsilon = 1e-7, - t = point.isClose(p0, epsilon) ? 0 - : point.isClose(p3, epsilon) ? 1 - : null; - if (t === null) { - var coords = [point.x, point.y], - roots = []; - for (var c = 0; c < 2; c++) { - var count = Curve.solveCubic(v, c, coords[c], roots, 0, 1); - for (var i = 0; i < count; i++) { - var u = roots[i]; - if (point.isClose(Curve.getPoint(v, u), geomEpsilon)) - return u; - } - } - } - return point.isClose(p0, geomEpsilon) ? 0 - : point.isClose(p3, geomEpsilon) ? 1 - : null; - }, - - getNearestTime: function(v, point) { - if (Curve.isStraight(v)) { - var x0 = v[0], y0 = v[1], - x3 = v[6], y3 = v[7], - vx = x3 - x0, vy = y3 - y0, - det = vx * vx + vy * vy; - if (det === 0) - return 0; - var u = ((point.x - x0) * vx + (point.y - y0) * vy) / det; - return u < 1e-12 ? 0 - : u > 0.999999999999 ? 1 - : Curve.getTimeOf(v, - new Point(x0 + u * vx, y0 + u * vy)); - } - - var count = 100, - minDist = Infinity, - minT = 0; - - function refine(t) { - if (t >= 0 && t <= 1) { - var dist = point.getDistance(Curve.getPoint(v, t), true); - if (dist < minDist) { - minDist = dist; - minT = t; - return true; - } - } - } - - for (var i = 0; i <= count; i++) - refine(i / count); - - var step = 1 / (count * 2); - while (step > 1e-8) { - if (!refine(minT - step) && !refine(minT + step)) - step /= 2; - } - return minT; - }, - - getPart: function(v, from, to) { - var flip = from > to; - if (flip) { - var tmp = from; - from = to; - to = tmp; - } - if (from > 0) - v = Curve.subdivide(v, from)[1]; - if (to < 1) - v = Curve.subdivide(v, (to - from) / (1 - from))[0]; - return flip - ? [v[6], v[7], v[4], v[5], v[2], v[3], v[0], v[1]] - : v; - }, - - isFlatEnough: function(v, flatness) { - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7], - ux = 3 * x1 - 2 * x0 - x3, - uy = 3 * y1 - 2 * y0 - y3, - vx = 3 * x2 - 2 * x3 - x0, - vy = 3 * y2 - 2 * y3 - y0; - return Math.max(ux * ux, vx * vx) + Math.max(uy * uy, vy * vy) - <= 16 * flatness * flatness; - }, - - getArea: function(v) { - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7]; - return 3 * ((y3 - y0) * (x1 + x2) - (x3 - x0) * (y1 + y2) - + y1 * (x0 - x2) - x1 * (y0 - y2) - + y3 * (x2 + x0 / 3) - x3 * (y2 + y0 / 3)) / 20; - }, - - getBounds: function(v) { - var min = v.slice(0, 2), - max = min.slice(), - roots = [0, 0]; - for (var i = 0; i < 2; i++) - Curve._addBounds(v[i], v[i + 2], v[i + 4], v[i + 6], - i, 0, min, max, roots); - return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]); - }, - - _addBounds: function(v0, v1, v2, v3, coord, padding, min, max, roots) { - function add(value, padding) { - var left = value - padding, - right = value + padding; - if (left < min[coord]) - min[coord] = left; - if (right > max[coord]) - max[coord] = right; - } - - padding /= 2; - var minPad = min[coord] - padding, - maxPad = max[coord] + padding; - if ( v0 < minPad || v1 < minPad || v2 < minPad || v3 < minPad || - v0 > maxPad || v1 > maxPad || v2 > maxPad || v3 > maxPad) { - if (v1 < v0 != v1 < v3 && v2 < v0 != v2 < v3) { - add(v0, padding); - add(v3, padding); - } else { - var a = 3 * (v1 - v2) - v0 + v3, - b = 2 * (v0 + v2) - 4 * v1, - c = v1 - v0, - count = Numerical.solveQuadratic(a, b, c, roots), - tMin = 1e-8, - tMax = 1 - tMin; - add(v3, 0); - for (var i = 0; i < count; i++) { - var t = roots[i], - u = 1 - t; - if (tMin <= t && t <= tMax) - add(u * u * u * v0 - + 3 * u * u * t * v1 - + 3 * u * t * t * v2 - + t * t * t * v3, - padding); - } - } - } - } -}}, Base.each( - ['getBounds', 'getStrokeBounds', 'getHandleBounds'], - function(name) { - this[name] = function() { - if (!this._bounds) - this._bounds = {}; - var bounds = this._bounds[name]; - if (!bounds) { - bounds = this._bounds[name] = Path[name]( - [this._segment1, this._segment2], false, this._path); - } - return bounds.clone(); - }; - }, -{ - -}), Base.each({ - isStraight: function(p1, h1, h2, p2) { - if (h1.isZero() && h2.isZero()) { - return true; - } else { - var v = p2.subtract(p1); - if (v.isZero()) { - return false; - } else if (v.isCollinear(h1) && v.isCollinear(h2)) { - var l = new Line(p1, p2), - epsilon = 1e-7; - if (l.getDistance(p1.add(h1)) < epsilon && - l.getDistance(p2.add(h2)) < epsilon) { - var div = v.dot(v), - s1 = v.dot(h1) / div, - s2 = v.dot(h2) / div; - return s1 >= 0 && s1 <= 1 && s2 <= 0 && s2 >= -1; - } - } - } - return false; - }, - - isLinear: function(p1, h1, h2, p2) { - var third = p2.subtract(p1).divide(3); - return h1.equals(third) && h2.negate().equals(third); - } -}, function(test, name) { - this[name] = function(epsilon) { - var seg1 = this._segment1, - seg2 = this._segment2; - return test(seg1._point, seg1._handleOut, seg2._handleIn, seg2._point, - epsilon); - }; - - this.statics[name] = function(v, epsilon) { - var x0 = v[0], y0 = v[1], - x3 = v[6], y3 = v[7]; - return test( - new Point(x0, y0), - new Point(v[2] - x0, v[3] - y0), - new Point(v[4] - x3, v[5] - y3), - new Point(x3, y3), epsilon); - }; -}, { - statics: {}, - - hasHandles: function() { - return !this._segment1._handleOut.isZero() - || !this._segment2._handleIn.isZero(); - }, - - hasLength: function(epsilon) { - return (!this.getPoint1().equals(this.getPoint2()) || this.hasHandles()) - && this.getLength() > (epsilon || 0); - }, - - isCollinear: function(curve) { - return curve && this.isStraight() && curve.isStraight() - && this.getLine().isCollinear(curve.getLine()); - }, - - isHorizontal: function() { - return this.isStraight() && Math.abs(this.getTangentAtTime(0.5).y) - < 1e-8; - }, - - isVertical: function() { - return this.isStraight() && Math.abs(this.getTangentAtTime(0.5).x) - < 1e-8; - } -}), { - beans: false, - - getLocationAt: function(offset, _isTime) { - return this.getLocationAtTime( - _isTime ? offset : this.getTimeAt(offset)); - }, - - getLocationAtTime: function(t) { - return t != null && t >= 0 && t <= 1 - ? new CurveLocation(this, t) - : null; - }, - - getTimeAt: function(offset, start) { - return Curve.getTimeAt(this.getValues(), offset, start); - }, - - getParameterAt: '#getTimeAt', - - getTimesWithTangent: function () { - var tangent = Point.read(arguments); - return tangent.isZero() - ? [] - : Curve.getTimesWithTangent(this.getValues(), tangent); - }, - - getOffsetAtTime: function(t) { - return this.getPartLength(0, t); - }, - - getLocationOf: function() { - return this.getLocationAtTime(this.getTimeOf(Point.read(arguments))); - }, - - getOffsetOf: function() { - var loc = this.getLocationOf.apply(this, arguments); - return loc ? loc.getOffset() : null; - }, - - getTimeOf: function() { - return Curve.getTimeOf(this.getValues(), Point.read(arguments)); - }, - - getParameterOf: '#getTimeOf', - - getNearestLocation: function() { - var point = Point.read(arguments), - values = this.getValues(), - t = Curve.getNearestTime(values, point), - pt = Curve.getPoint(values, t); - return new CurveLocation(this, t, pt, null, point.getDistance(pt)); - }, - - getNearestPoint: function() { - var loc = this.getNearestLocation.apply(this, arguments); - return loc ? loc.getPoint() : loc; - } - -}, -new function() { - var methods = ['getPoint', 'getTangent', 'getNormal', 'getWeightedTangent', - 'getWeightedNormal', 'getCurvature']; - return Base.each(methods, - function(name) { - this[name + 'At'] = function(location, _isTime) { - var values = this.getValues(); - return Curve[name](values, _isTime ? location - : Curve.getTimeAt(values, location)); - }; - - this[name + 'AtTime'] = function(time) { - return Curve[name](this.getValues(), time); - }; - }, { - statics: { - _evaluateMethods: methods - } - } - ); -}, -new function() { - - function getLengthIntegrand(v) { - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7], - - ax = 9 * (x1 - x2) + 3 * (x3 - x0), - bx = 6 * (x0 + x2) - 12 * x1, - cx = 3 * (x1 - x0), - - ay = 9 * (y1 - y2) + 3 * (y3 - y0), - by = 6 * (y0 + y2) - 12 * y1, - cy = 3 * (y1 - y0); - - return function(t) { - var dx = (ax * t + bx) * t + cx, - dy = (ay * t + by) * t + cy; - return Math.sqrt(dx * dx + dy * dy); - }; - } - - function getIterations(a, b) { - return Math.max(2, Math.min(16, Math.ceil(Math.abs(b - a) * 32))); - } - - function evaluate(v, t, type, normalized) { - if (t == null || t < 0 || t > 1) - return null; - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7], - isZero = Numerical.isZero; - if (isZero(x1 - x0) && isZero(y1 - y0)) { - x1 = x0; - y1 = y0; - } - if (isZero(x2 - x3) && isZero(y2 - y3)) { - x2 = x3; - y2 = y3; - } - var cx = 3 * (x1 - x0), - bx = 3 * (x2 - x1) - cx, - ax = x3 - x0 - cx - bx, - cy = 3 * (y1 - y0), - by = 3 * (y2 - y1) - cy, - ay = y3 - y0 - cy - by, - x, y; - if (type === 0) { - x = t === 0 ? x0 : t === 1 ? x3 - : ((ax * t + bx) * t + cx) * t + x0; - y = t === 0 ? y0 : t === 1 ? y3 - : ((ay * t + by) * t + cy) * t + y0; - } else { - var tMin = 1e-8, - tMax = 1 - tMin; - if (t < tMin) { - x = cx; - y = cy; - } else if (t > tMax) { - x = 3 * (x3 - x2); - y = 3 * (y3 - y2); - } else { - x = (3 * ax * t + 2 * bx) * t + cx; - y = (3 * ay * t + 2 * by) * t + cy; - } - if (normalized) { - if (x === 0 && y === 0 && (t < tMin || t > tMax)) { - x = x2 - x1; - y = y2 - y1; - } - var len = Math.sqrt(x * x + y * y); - if (len) { - x /= len; - y /= len; - } - } - if (type === 3) { - var x2 = 6 * ax * t + 2 * bx, - y2 = 6 * ay * t + 2 * by, - d = Math.pow(x * x + y * y, 3 / 2); - x = d !== 0 ? (x * y2 - y * x2) / d : 0; - y = 0; - } - } - return type === 2 ? new Point(y, -x) : new Point(x, y); - } - - return { statics: { - - classify: function(v) { - - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7], - a1 = x0 * (y3 - y2) + y0 * (x2 - x3) + x3 * y2 - y3 * x2, - a2 = x1 * (y0 - y3) + y1 * (x3 - x0) + x0 * y3 - y0 * x3, - a3 = x2 * (y1 - y0) + y2 * (x0 - x1) + x1 * y0 - y1 * x0, - d3 = 3 * a3, - d2 = d3 - a2, - d1 = d2 - a2 + a1, - l = Math.sqrt(d1 * d1 + d2 * d2 + d3 * d3), - s = l !== 0 ? 1 / l : 0, - isZero = Numerical.isZero, - serpentine = 'serpentine'; - d1 *= s; - d2 *= s; - d3 *= s; - - function type(type, t1, t2) { - var hasRoots = t1 !== undefined, - t1Ok = hasRoots && t1 > 0 && t1 < 1, - t2Ok = hasRoots && t2 > 0 && t2 < 1; - if (hasRoots && (!(t1Ok || t2Ok) - || type === 'loop' && !(t1Ok && t2Ok))) { - type = 'arch'; - t1Ok = t2Ok = false; - } - return { - type: type, - roots: t1Ok || t2Ok - ? t1Ok && t2Ok - ? t1 < t2 ? [t1, t2] : [t2, t1] - : [t1Ok ? t1 : t2] - : null - }; - } - - if (isZero(d1)) { - return isZero(d2) - ? type(isZero(d3) ? 'line' : 'quadratic') - : type(serpentine, d3 / (3 * d2)); - } - var d = 3 * d2 * d2 - 4 * d1 * d3; - if (isZero(d)) { - return type('cusp', d2 / (2 * d1)); - } - var f1 = d > 0 ? Math.sqrt(d / 3) : Math.sqrt(-d), - f2 = 2 * d1; - return type(d > 0 ? serpentine : 'loop', - (d2 + f1) / f2, - (d2 - f1) / f2); - }, - - getLength: function(v, a, b, ds) { - if (a === undefined) - a = 0; - if (b === undefined) - b = 1; - if (Curve.isStraight(v)) { - var c = v; - if (b < 1) { - c = Curve.subdivide(c, b)[0]; - a /= b; - } - if (a > 0) { - c = Curve.subdivide(c, a)[1]; - } - var dx = c[6] - c[0], - dy = c[7] - c[1]; - return Math.sqrt(dx * dx + dy * dy); - } - return Numerical.integrate(ds || getLengthIntegrand(v), a, b, - getIterations(a, b)); - }, - - getTimeAt: function(v, offset, start) { - if (start === undefined) - start = offset < 0 ? 1 : 0; - if (offset === 0) - return start; - var abs = Math.abs, - epsilon = 1e-12, - forward = offset > 0, - a = forward ? start : 0, - b = forward ? 1 : start, - ds = getLengthIntegrand(v), - rangeLength = Curve.getLength(v, a, b, ds), - diff = abs(offset) - rangeLength; - if (abs(diff) < epsilon) { - return forward ? b : a; - } else if (diff > epsilon) { - return null; - } - var guess = offset / rangeLength, - length = 0; - function f(t) { - length += Numerical.integrate(ds, start, t, - getIterations(start, t)); - start = t; - return length - offset; - } - return Numerical.findRoot(f, ds, start + guess, a, b, 32, - 1e-12); - }, - - getPoint: function(v, t) { - return evaluate(v, t, 0, false); - }, - - getTangent: function(v, t) { - return evaluate(v, t, 1, true); - }, - - getWeightedTangent: function(v, t) { - return evaluate(v, t, 1, false); - }, - - getNormal: function(v, t) { - return evaluate(v, t, 2, true); - }, - - getWeightedNormal: function(v, t) { - return evaluate(v, t, 2, false); - }, - - getCurvature: function(v, t) { - return evaluate(v, t, 3, false).x; - }, - - getPeaks: function(v) { - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7], - ax = -x0 + 3 * x1 - 3 * x2 + x3, - bx = 3 * x0 - 6 * x1 + 3 * x2, - cx = -3 * x0 + 3 * x1, - ay = -y0 + 3 * y1 - 3 * y2 + y3, - by = 3 * y0 - 6 * y1 + 3 * y2, - cy = -3 * y0 + 3 * y1, - tMin = 1e-8, - tMax = 1 - tMin, - roots = []; - Numerical.solveCubic( - 9 * (ax * ax + ay * ay), - 9 * (ax * bx + by * ay), - 2 * (bx * bx + by * by) + 3 * (cx * ax + cy * ay), - (cx * bx + by * cy), - roots, tMin, tMax); - return roots.sort(); - } - }}; -}, -new function() { - - function addLocation(locations, include, c1, t1, c2, t2, overlap) { - var excludeStart = !overlap && c1.getPrevious() === c2, - excludeEnd = !overlap && c1 !== c2 && c1.getNext() === c2, - tMin = 1e-8, - tMax = 1 - tMin; - if (t1 !== null && t1 >= (excludeStart ? tMin : 0) && - t1 <= (excludeEnd ? tMax : 1)) { - if (t2 !== null && t2 >= (excludeEnd ? tMin : 0) && - t2 <= (excludeStart ? tMax : 1)) { - var loc1 = new CurveLocation(c1, t1, null, overlap), - loc2 = new CurveLocation(c2, t2, null, overlap); - loc1._intersection = loc2; - loc2._intersection = loc1; - if (!include || include(loc1)) { - CurveLocation.insert(locations, loc1, true); - } - } - } - } - - function addCurveIntersections(v1, v2, c1, c2, locations, include, flip, - recursion, calls, tMin, tMax, uMin, uMax) { - if (++calls >= 4096 || ++recursion >= 40) - return calls; - var fatLineEpsilon = 1e-9, - q0x = v2[0], q0y = v2[1], q3x = v2[6], q3y = v2[7], - getSignedDistance = Line.getSignedDistance, - d1 = getSignedDistance(q0x, q0y, q3x, q3y, v2[2], v2[3]), - d2 = getSignedDistance(q0x, q0y, q3x, q3y, v2[4], v2[5]), - factor = d1 * d2 > 0 ? 3 / 4 : 4 / 9, - dMin = factor * Math.min(0, d1, d2), - dMax = factor * Math.max(0, d1, d2), - dp0 = getSignedDistance(q0x, q0y, q3x, q3y, v1[0], v1[1]), - dp1 = getSignedDistance(q0x, q0y, q3x, q3y, v1[2], v1[3]), - dp2 = getSignedDistance(q0x, q0y, q3x, q3y, v1[4], v1[5]), - dp3 = getSignedDistance(q0x, q0y, q3x, q3y, v1[6], v1[7]), - hull = getConvexHull(dp0, dp1, dp2, dp3), - top = hull[0], - bottom = hull[1], - tMinClip, - tMaxClip; - if (d1 === 0 && d2 === 0 - && dp0 === 0 && dp1 === 0 && dp2 === 0 && dp3 === 0 - || (tMinClip = clipConvexHull(top, bottom, dMin, dMax)) == null - || (tMaxClip = clipConvexHull(top.reverse(), bottom.reverse(), - dMin, dMax)) == null) - return calls; - var tMinNew = tMin + (tMax - tMin) * tMinClip, - tMaxNew = tMin + (tMax - tMin) * tMaxClip; - if (Math.max(uMax - uMin, tMaxNew - tMinNew) < fatLineEpsilon) { - var t = (tMinNew + tMaxNew) / 2, - u = (uMin + uMax) / 2; - addLocation(locations, include, - flip ? c2 : c1, flip ? u : t, - flip ? c1 : c2, flip ? t : u); - } else { - v1 = Curve.getPart(v1, tMinClip, tMaxClip); - if (tMaxClip - tMinClip > 0.8) { - if (tMaxNew - tMinNew > uMax - uMin) { - var parts = Curve.subdivide(v1, 0.5), - t = (tMinNew + tMaxNew) / 2; - calls = addCurveIntersections( - v2, parts[0], c2, c1, locations, include, !flip, - recursion, calls, uMin, uMax, tMinNew, t); - calls = addCurveIntersections( - v2, parts[1], c2, c1, locations, include, !flip, - recursion, calls, uMin, uMax, t, tMaxNew); - } else { - var parts = Curve.subdivide(v2, 0.5), - u = (uMin + uMax) / 2; - calls = addCurveIntersections( - parts[0], v1, c2, c1, locations, include, !flip, - recursion, calls, uMin, u, tMinNew, tMaxNew); - calls = addCurveIntersections( - parts[1], v1, c2, c1, locations, include, !flip, - recursion, calls, u, uMax, tMinNew, tMaxNew); - } - } else { - if (uMax - uMin >= fatLineEpsilon) { - calls = addCurveIntersections( - v2, v1, c2, c1, locations, include, !flip, - recursion, calls, uMin, uMax, tMinNew, tMaxNew); - } else { - calls = addCurveIntersections( - v1, v2, c1, c2, locations, include, flip, - recursion, calls, tMinNew, tMaxNew, uMin, uMax); - } - } - } - return calls; - } - - function getConvexHull(dq0, dq1, dq2, dq3) { - var p0 = [ 0, dq0 ], - p1 = [ 1 / 3, dq1 ], - p2 = [ 2 / 3, dq2 ], - p3 = [ 1, dq3 ], - dist1 = dq1 - (2 * dq0 + dq3) / 3, - dist2 = dq2 - (dq0 + 2 * dq3) / 3, - hull; - if (dist1 * dist2 < 0) { - hull = [[p0, p1, p3], [p0, p2, p3]]; - } else { - var distRatio = dist1 / dist2; - hull = [ - distRatio >= 2 ? [p0, p1, p3] - : distRatio <= 0.5 ? [p0, p2, p3] - : [p0, p1, p2, p3], - [p0, p3] - ]; - } - return (dist1 || dist2) < 0 ? hull.reverse() : hull; - } - - function clipConvexHull(hullTop, hullBottom, dMin, dMax) { - if (hullTop[0][1] < dMin) { - return clipConvexHullPart(hullTop, true, dMin); - } else if (hullBottom[0][1] > dMax) { - return clipConvexHullPart(hullBottom, false, dMax); - } else { - return hullTop[0][0]; - } - } - - function clipConvexHullPart(part, top, threshold) { - var px = part[0][0], - py = part[0][1]; - for (var i = 1, l = part.length; i < l; i++) { - var qx = part[i][0], - qy = part[i][1]; - if (top ? qy >= threshold : qy <= threshold) { - return qy === threshold ? qx - : px + (threshold - py) * (qx - px) / (qy - py); - } - px = qx; - py = qy; - } - return null; - } - - function getCurveLineIntersections(v, px, py, vx, vy) { - var isZero = Numerical.isZero; - if (isZero(vx) && isZero(vy)) { - var t = Curve.getTimeOf(v, new Point(px, py)); - return t === null ? [] : [t]; - } - var angle = Math.atan2(-vy, vx), - sin = Math.sin(angle), - cos = Math.cos(angle), - rv = [], - roots = []; - for (var i = 0; i < 8; i += 2) { - var x = v[i] - px, - y = v[i + 1] - py; - rv.push( - x * cos - y * sin, - x * sin + y * cos); - } - Curve.solveCubic(rv, 1, 0, roots, 0, 1); - return roots; - } - - function addCurveLineIntersections(v1, v2, c1, c2, locations, include, - flip) { - var x1 = v2[0], y1 = v2[1], - x2 = v2[6], y2 = v2[7], - roots = getCurveLineIntersections(v1, x1, y1, x2 - x1, y2 - y1); - for (var i = 0, l = roots.length; i < l; i++) { - var t1 = roots[i], - p1 = Curve.getPoint(v1, t1), - t2 = Curve.getTimeOf(v2, p1); - if (t2 !== null) { - addLocation(locations, include, - flip ? c2 : c1, flip ? t2 : t1, - flip ? c1 : c2, flip ? t1 : t2); - } - } - } - - function addLineIntersection(v1, v2, c1, c2, locations, include) { - var pt = Line.intersect( - v1[0], v1[1], v1[6], v1[7], - v2[0], v2[1], v2[6], v2[7]); - if (pt) { - addLocation(locations, include, - c1, Curve.getTimeOf(v1, pt), - c2, Curve.getTimeOf(v2, pt)); - } - } - - function getCurveIntersections(v1, v2, c1, c2, locations, include) { - var epsilon = 1e-12, - min = Math.min, - max = Math.max; - - if (max(v1[0], v1[2], v1[4], v1[6]) + epsilon > - min(v2[0], v2[2], v2[4], v2[6]) && - min(v1[0], v1[2], v1[4], v1[6]) - epsilon < - max(v2[0], v2[2], v2[4], v2[6]) && - max(v1[1], v1[3], v1[5], v1[7]) + epsilon > - min(v2[1], v2[3], v2[5], v2[7]) && - min(v1[1], v1[3], v1[5], v1[7]) - epsilon < - max(v2[1], v2[3], v2[5], v2[7])) { - var overlaps = getOverlaps(v1, v2); - if (overlaps) { - for (var i = 0; i < 2; i++) { - var overlap = overlaps[i]; - addLocation(locations, include, - c1, overlap[0], - c2, overlap[1], true); - } - } else { - var straight1 = Curve.isStraight(v1), - straight2 = Curve.isStraight(v2), - straight = straight1 && straight2, - flip = straight1 && !straight2, - before = locations.length; - (straight - ? addLineIntersection - : straight1 || straight2 - ? addCurveLineIntersections - : addCurveIntersections)( - flip ? v2 : v1, flip ? v1 : v2, - flip ? c2 : c1, flip ? c1 : c2, - locations, include, flip, - 0, 0, 0, 1, 0, 1); - if (!straight || locations.length === before) { - for (var i = 0; i < 4; i++) { - var t1 = i >> 1, - t2 = i & 1, - i1 = t1 * 6, - i2 = t2 * 6, - p1 = new Point(v1[i1], v1[i1 + 1]), - p2 = new Point(v2[i2], v2[i2 + 1]); - if (p1.isClose(p2, epsilon)) { - addLocation(locations, include, - c1, t1, - c2, t2); - } - } - } - } - } - return locations; - } - - function getLoopIntersection(v1, c1, locations, include) { - var info = Curve.classify(v1); - if (info.type === 'loop') { - var roots = info.roots; - addLocation(locations, include, - c1, roots[0], - c1, roots[1]); - } - return locations; - } - - function getIntersections(curves1, curves2, include, matrix1, matrix2, - _returnFirst) { - var self = !curves2; - if (self) - curves2 = curves1; - var length1 = curves1.length, - length2 = curves2.length, - values2 = [], - arrays = [], - locations, - current; - for (var i = 0; i < length2; i++) - values2[i] = curves2[i].getValues(matrix2); - for (var i = 0; i < length1; i++) { - var curve1 = curves1[i], - values1 = self ? values2[i] : curve1.getValues(matrix1), - path1 = curve1.getPath(); - if (path1 !== current) { - current = path1; - locations = []; - arrays.push(locations); - } - if (self) { - getLoopIntersection(values1, curve1, locations, include); - } - for (var j = self ? i + 1 : 0; j < length2; j++) { - if (_returnFirst && locations.length) - return locations; - getCurveIntersections(values1, values2[j], curve1, curves2[j], - locations, include); - } - } - locations = []; - for (var i = 0, l = arrays.length; i < l; i++) { - Base.push(locations, arrays[i]); - } - return locations; - } - - function getOverlaps(v1, v2) { - - function getSquaredLineLength(v) { - var x = v[6] - v[0], - y = v[7] - v[1]; - return x * x + y * y; - } - - var abs = Math.abs, - getDistance = Line.getDistance, - timeEpsilon = 1e-8, - geomEpsilon = 1e-7, - straight1 = Curve.isStraight(v1), - straight2 = Curve.isStraight(v2), - straightBoth = straight1 && straight2, - flip = getSquaredLineLength(v1) < getSquaredLineLength(v2), - l1 = flip ? v2 : v1, - l2 = flip ? v1 : v2, - px = l1[0], py = l1[1], - vx = l1[6] - px, vy = l1[7] - py; - if (getDistance(px, py, vx, vy, l2[0], l2[1], true) < geomEpsilon && - getDistance(px, py, vx, vy, l2[6], l2[7], true) < geomEpsilon) { - if (!straightBoth && - getDistance(px, py, vx, vy, l1[2], l1[3], true) < geomEpsilon && - getDistance(px, py, vx, vy, l1[4], l1[5], true) < geomEpsilon && - getDistance(px, py, vx, vy, l2[2], l2[3], true) < geomEpsilon && - getDistance(px, py, vx, vy, l2[4], l2[5], true) < geomEpsilon) { - straight1 = straight2 = straightBoth = true; - } - } else if (straightBoth) { - return null; - } - if (straight1 ^ straight2) { - return null; - } - - var v = [v1, v2], - pairs = []; - for (var i = 0; i < 4 && pairs.length < 2; i++) { - var i1 = i & 1, - i2 = i1 ^ 1, - t1 = i >> 1, - t2 = Curve.getTimeOf(v[i1], new Point( - v[i2][t1 ? 6 : 0], - v[i2][t1 ? 7 : 1])); - if (t2 != null) { - var pair = i1 ? [t1, t2] : [t2, t1]; - if (!pairs.length || - abs(pair[0] - pairs[0][0]) > timeEpsilon && - abs(pair[1] - pairs[0][1]) > timeEpsilon) { - pairs.push(pair); - } - } - if (i > 2 && !pairs.length) - break; - } - if (pairs.length !== 2) { - pairs = null; - } else if (!straightBoth) { - var o1 = Curve.getPart(v1, pairs[0][0], pairs[1][0]), - o2 = Curve.getPart(v2, pairs[0][1], pairs[1][1]); - if (abs(o2[2] - o1[2]) > geomEpsilon || - abs(o2[3] - o1[3]) > geomEpsilon || - abs(o2[4] - o1[4]) > geomEpsilon || - abs(o2[5] - o1[5]) > geomEpsilon) - pairs = null; - } - return pairs; - } - - function getTimesWithTangent(v, tangent) { - var x0 = v[0], y0 = v[1], - x1 = v[2], y1 = v[3], - x2 = v[4], y2 = v[5], - x3 = v[6], y3 = v[7], - normalized = tangent.normalize(), - tx = normalized.x, - ty = normalized.y, - ax = 3 * x3 - 9 * x2 + 9 * x1 - 3 * x0, - ay = 3 * y3 - 9 * y2 + 9 * y1 - 3 * y0, - bx = 6 * x2 - 12 * x1 + 6 * x0, - by = 6 * y2 - 12 * y1 + 6 * y0, - cx = 3 * x1 - 3 * x0, - cy = 3 * y1 - 3 * y0, - den = 2 * ax * ty - 2 * ay * tx, - times = []; - if (Math.abs(den) < Numerical.CURVETIME_EPSILON) { - var num = ax * cy - ay * cx, - den = ax * by - ay * bx; - if (den != 0) { - var t = -num / den; - if (t >= 0 && t <= 1) times.push(t); - } - } else { - var delta = (bx * bx - 4 * ax * cx) * ty * ty + - (-2 * bx * by + 4 * ay * cx + 4 * ax * cy) * tx * ty + - (by * by - 4 * ay * cy) * tx * tx, - k = bx * ty - by * tx; - if (delta >= 0 && den != 0) { - var d = Math.sqrt(delta), - t0 = -(k + d) / den, - t1 = (-k + d) / den; - if (t0 >= 0 && t0 <= 1) times.push(t0); - if (t1 >= 0 && t1 <= 1) times.push(t1); - } - } - return times; - } - - return { - getIntersections: function(curve) { - var v1 = this.getValues(), - v2 = curve && curve !== this && curve.getValues(); - return v2 ? getCurveIntersections(v1, v2, this, curve, []) - : getLoopIntersection(v1, this, []); - }, - - statics: { - getOverlaps: getOverlaps, - getIntersections: getIntersections, - getCurveLineIntersections: getCurveLineIntersections, - getTimesWithTangent: getTimesWithTangent - } - }; -}); - -var CurveLocation = Base.extend({ - _class: 'CurveLocation', - - initialize: function CurveLocation(curve, time, point, _overlap, _distance) { - if (time >= 0.99999999) { - var next = curve.getNext(); - if (next) { - time = 0; - curve = next; - } - } - this._setCurve(curve); - this._time = time; - this._point = point || curve.getPointAtTime(time); - this._overlap = _overlap; - this._distance = _distance; - this._intersection = this._next = this._previous = null; - }, - - _setCurve: function(curve) { - var path = curve._path; - this._path = path; - this._version = path ? path._version : 0; - this._curve = curve; - this._segment = null; - this._segment1 = curve._segment1; - this._segment2 = curve._segment2; - }, - - _setSegment: function(segment) { - this._setCurve(segment.getCurve()); - this._segment = segment; - this._time = segment === this._segment1 ? 0 : 1; - this._point = segment._point.clone(); - }, - - getSegment: function() { - var segment = this._segment; - if (!segment) { - var curve = this.getCurve(), - time = this.getTime(); - if (time === 0) { - segment = curve._segment1; - } else if (time === 1) { - segment = curve._segment2; - } else if (time != null) { - segment = curve.getPartLength(0, time) - < curve.getPartLength(time, 1) - ? curve._segment1 - : curve._segment2; - } - this._segment = segment; - } - return segment; - }, - - getCurve: function() { - var path = this._path, - that = this; - if (path && path._version !== this._version) { - this._time = this._offset = this._curveOffset = this._curve = null; - } - - function trySegment(segment) { - var curve = segment && segment.getCurve(); - if (curve && (that._time = curve.getTimeOf(that._point)) != null) { - that._setCurve(curve); - return curve; - } - } - - return this._curve - || trySegment(this._segment) - || trySegment(this._segment1) - || trySegment(this._segment2.getPrevious()); - }, - - getPath: function() { - var curve = this.getCurve(); - return curve && curve._path; - }, - - getIndex: function() { - var curve = this.getCurve(); - return curve && curve.getIndex(); - }, - - getTime: function() { - var curve = this.getCurve(), - time = this._time; - return curve && time == null - ? this._time = curve.getTimeOf(this._point) - : time; - }, - - getParameter: '#getTime', - - getPoint: function() { - return this._point; - }, - - getOffset: function() { - var offset = this._offset; - if (offset == null) { - offset = 0; - var path = this.getPath(), - index = this.getIndex(); - if (path && index != null) { - var curves = path.getCurves(); - for (var i = 0; i < index; i++) - offset += curves[i].getLength(); - } - this._offset = offset += this.getCurveOffset(); - } - return offset; - }, - - getCurveOffset: function() { - var offset = this._curveOffset; - if (offset == null) { - var curve = this.getCurve(), - time = this.getTime(); - this._curveOffset = offset = time != null && curve - && curve.getPartLength(0, time); - } - return offset; - }, - - getIntersection: function() { - return this._intersection; - }, - - getDistance: function() { - return this._distance; - }, - - divide: function() { - var curve = this.getCurve(), - res = curve && curve.divideAtTime(this.getTime()); - if (res) { - this._setSegment(res._segment1); - } - return res; - }, - - split: function() { - var curve = this.getCurve(), - path = curve._path, - res = curve && curve.splitAtTime(this.getTime()); - if (res) { - this._setSegment(path.getLastSegment()); - } - return res; - }, - - equals: function(loc, _ignoreOther) { - var res = this === loc; - if (!res && loc instanceof CurveLocation) { - var c1 = this.getCurve(), - c2 = loc.getCurve(), - p1 = c1._path, - p2 = c2._path; - if (p1 === p2) { - var abs = Math.abs, - epsilon = 1e-7, - diff = abs(this.getOffset() - loc.getOffset()), - i1 = !_ignoreOther && this._intersection, - i2 = !_ignoreOther && loc._intersection; - res = (diff < epsilon - || p1 && abs(p1.getLength() - diff) < epsilon) - && (!i1 && !i2 || i1 && i2 && i1.equals(i2, true)); - } - } - return res; - }, - - toString: function() { - var parts = [], - point = this.getPoint(), - f = Formatter.instance; - if (point) - parts.push('point: ' + point); - var index = this.getIndex(); - if (index != null) - parts.push('index: ' + index); - var time = this.getTime(); - if (time != null) - parts.push('time: ' + f.number(time)); - if (this._distance != null) - parts.push('distance: ' + f.number(this._distance)); - return '{ ' + parts.join(', ') + ' }'; - }, - - isTouching: function() { - var inter = this._intersection; - if (inter && this.getTangent().isCollinear(inter.getTangent())) { - var curve1 = this.getCurve(), - curve2 = inter.getCurve(); - return !(curve1.isStraight() && curve2.isStraight() - && curve1.getLine().intersect(curve2.getLine())); - } - return false; - }, - - isCrossing: function() { - var inter = this._intersection; - if (!inter) - return false; - var t1 = this.getTime(), - t2 = inter.getTime(), - tMin = 1e-8, - tMax = 1 - tMin, - t1Inside = t1 >= tMin && t1 <= tMax, - t2Inside = t2 >= tMin && t2 <= tMax; - if (t1Inside && t2Inside) - return !this.isTouching(); - var c2 = this.getCurve(), - c1 = t1 < tMin ? c2.getPrevious() : c2, - c4 = inter.getCurve(), - c3 = t2 < tMin ? c4.getPrevious() : c4; - if (t1 > tMax) - c2 = c2.getNext(); - if (t2 > tMax) - c4 = c4.getNext(); - if (!c1 || !c2 || !c3 || !c4) - return false; - - var offsets = []; - - function addOffsets(curve, end) { - var v = curve.getValues(), - roots = Curve.classify(v).roots || Curve.getPeaks(v), - count = roots.length, - t = end && count > 1 ? roots[count - 1] - : count > 0 ? roots[0] - : 0.5; - offsets.push(Curve.getLength(v, end ? t : 0, end ? 1 : t) / 2); - } - - function isInRange(angle, min, max) { - return min < max - ? angle > min && angle < max - : angle > min || angle < max; - } - - if (!t1Inside) { - addOffsets(c1, true); - addOffsets(c2, false); - } - if (!t2Inside) { - addOffsets(c3, true); - addOffsets(c4, false); - } - var pt = this.getPoint(), - offset = Math.min.apply(Math, offsets), - v2 = t1Inside ? c2.getTangentAtTime(t1) - : c2.getPointAt(offset).subtract(pt), - v1 = t1Inside ? v2.negate() - : c1.getPointAt(-offset).subtract(pt), - v4 = t2Inside ? c4.getTangentAtTime(t2) - : c4.getPointAt(offset).subtract(pt), - v3 = t2Inside ? v4.negate() - : c3.getPointAt(-offset).subtract(pt), - a1 = v1.getAngle(), - a2 = v2.getAngle(), - a3 = v3.getAngle(), - a4 = v4.getAngle(); - return !!(t1Inside - ? (isInRange(a1, a3, a4) ^ isInRange(a2, a3, a4)) && - (isInRange(a1, a4, a3) ^ isInRange(a2, a4, a3)) - : (isInRange(a3, a1, a2) ^ isInRange(a4, a1, a2)) && - (isInRange(a3, a2, a1) ^ isInRange(a4, a2, a1))); - }, - - hasOverlap: function() { - return !!this._overlap; - } -}, Base.each(Curve._evaluateMethods, function(name) { - var get = name + 'At'; - this[name] = function() { - var curve = this.getCurve(), - time = this.getTime(); - return time != null && curve && curve[get](time, true); - }; -}, { - preserve: true -}), -new function() { - - function insert(locations, loc, merge) { - var length = locations.length, - l = 0, - r = length - 1; - - function search(index, dir) { - for (var i = index + dir; i >= -1 && i <= length; i += dir) { - var loc2 = locations[((i % length) + length) % length]; - if (!loc.getPoint().isClose(loc2.getPoint(), - 1e-7)) - break; - if (loc.equals(loc2)) - return loc2; - } - return null; - } - - while (l <= r) { - var m = (l + r) >>> 1, - loc2 = locations[m], - found; - if (merge && (found = loc.equals(loc2) ? loc2 - : (search(m, -1) || search(m, 1)))) { - if (loc._overlap) { - found._overlap = found._intersection._overlap = true; - } - return found; - } - var path1 = loc.getPath(), - path2 = loc2.getPath(), - diff = path1 !== path2 - ? path1._id - path2._id - : (loc.getIndex() + loc.getTime()) - - (loc2.getIndex() + loc2.getTime()); - if (diff < 0) { - r = m - 1; - } else { - l = m + 1; - } - } - locations.splice(l, 0, loc); - return loc; - } - - return { statics: { - insert: insert, - - expand: function(locations) { - var expanded = locations.slice(); - for (var i = locations.length - 1; i >= 0; i--) { - insert(expanded, locations[i]._intersection, false); - } - return expanded; - } - }}; -}); - -var PathItem = Item.extend({ - _class: 'PathItem', - _selectBounds: false, - _canScaleStroke: true, - beans: true, - - initialize: function PathItem() { - }, - - statics: { - create: function(arg) { - var data, - segments, - compound; - if (Base.isPlainObject(arg)) { - segments = arg.segments; - data = arg.pathData; - } else if (Array.isArray(arg)) { - segments = arg; - } else if (typeof arg === 'string') { - data = arg; - } - if (segments) { - var first = segments[0]; - compound = first && Array.isArray(first[0]); - } else if (data) { - compound = (data.match(/m/gi) || []).length > 1 - || /z\s*\S+/i.test(data); - } - var ctor = compound ? CompoundPath : Path; - return new ctor(arg); - } - }, - - _asPathItem: function() { - return this; - }, - - isClockwise: function() { - return this.getArea() >= 0; - }, - - setClockwise: function(clockwise) { - if (this.isClockwise() != (clockwise = !!clockwise)) - this.reverse(); - }, - - setPathData: function(data) { - - var parts = data && data.match(/[mlhvcsqtaz][^mlhvcsqtaz]*/ig), - coords, - relative = false, - previous, - control, - current = new Point(), - start = new Point(); - - function getCoord(index, coord) { - var val = +coords[index]; - if (relative) - val += current[coord]; - return val; - } - - function getPoint(index) { - return new Point( - getCoord(index, 'x'), - getCoord(index + 1, 'y') - ); - } - - this.clear(); - - for (var i = 0, l = parts && parts.length; i < l; i++) { - var part = parts[i], - command = part[0], - lower = command.toLowerCase(); - coords = part.match(/[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g); - var length = coords && coords.length; - relative = command === lower; - if (previous === 'z' && !/[mz]/.test(lower)) - this.moveTo(current); - switch (lower) { - case 'm': - case 'l': - var move = lower === 'm'; - for (var j = 0; j < length; j += 2) { - this[move ? 'moveTo' : 'lineTo'](current = getPoint(j)); - if (move) { - start = current; - move = false; - } - } - control = current; - break; - case 'h': - case 'v': - var coord = lower === 'h' ? 'x' : 'y'; - current = current.clone(); - for (var j = 0; j < length; j++) { - current[coord] = getCoord(j, coord); - this.lineTo(current); - } - control = current; - break; - case 'c': - for (var j = 0; j < length; j += 6) { - this.cubicCurveTo( - getPoint(j), - control = getPoint(j + 2), - current = getPoint(j + 4)); - } - break; - case 's': - for (var j = 0; j < length; j += 4) { - this.cubicCurveTo( - /[cs]/.test(previous) - ? current.multiply(2).subtract(control) - : current, - control = getPoint(j), - current = getPoint(j + 2)); - previous = lower; - } - break; - case 'q': - for (var j = 0; j < length; j += 4) { - this.quadraticCurveTo( - control = getPoint(j), - current = getPoint(j + 2)); - } - break; - case 't': - for (var j = 0; j < length; j += 2) { - this.quadraticCurveTo( - control = (/[qt]/.test(previous) - ? current.multiply(2).subtract(control) - : current), - current = getPoint(j)); - previous = lower; - } - break; - case 'a': - for (var j = 0; j < length; j += 7) { - this.arcTo(current = getPoint(j + 5), - new Size(+coords[j], +coords[j + 1]), - +coords[j + 2], +coords[j + 4], +coords[j + 3]); - } - break; - case 'z': - this.closePath(1e-12); - current = start; - break; - } - previous = lower; - } - }, - - _canComposite: function() { - return !(this.hasFill() && this.hasStroke()); - }, - - _contains: function(point) { - var winding = point.isInside( - this.getBounds({ internal: true, handle: true })) - ? this._getWinding(point) - : {}; - return winding.onPath || !!(this.getFillRule() === 'evenodd' - ? winding.windingL & 1 || winding.windingR & 1 - : winding.winding); - }, - - getIntersections: function(path, include, _matrix, _returnFirst) { - var self = this === path || !path, - matrix1 = this._matrix._orNullIfIdentity(), - matrix2 = self ? matrix1 - : (_matrix || path._matrix)._orNullIfIdentity(); - return self || this.getBounds(matrix1).intersects( - path.getBounds(matrix2), 1e-12) - ? Curve.getIntersections( - this.getCurves(), !self && path.getCurves(), include, - matrix1, matrix2, _returnFirst) - : []; - }, - - getCrossings: function(path) { - return this.getIntersections(path, function(inter) { - return inter.hasOverlap() || inter.isCrossing(); - }); - }, - - getNearestLocation: function() { - var point = Point.read(arguments), - curves = this.getCurves(), - minDist = Infinity, - minLoc = null; - for (var i = 0, l = curves.length; i < l; i++) { - var loc = curves[i].getNearestLocation(point); - if (loc._distance < minDist) { - minDist = loc._distance; - minLoc = loc; - } - } - return minLoc; - }, - - getNearestPoint: function() { - var loc = this.getNearestLocation.apply(this, arguments); - return loc ? loc.getPoint() : loc; - }, - - interpolate: function(from, to, factor) { - var isPath = !this._children, - name = isPath ? '_segments' : '_children', - itemsFrom = from[name], - itemsTo = to[name], - items = this[name]; - if (!itemsFrom || !itemsTo || itemsFrom.length !== itemsTo.length) { - throw new Error('Invalid operands in interpolate() call: ' + - from + ', ' + to); - } - var current = items.length, - length = itemsTo.length; - if (current < length) { - var ctor = isPath ? Segment : Path; - for (var i = current; i < length; i++) { - this.add(new ctor()); - } - } else if (current > length) { - this[isPath ? 'removeSegments' : 'removeChildren'](length, current); - } - for (var i = 0; i < length; i++) { - items[i].interpolate(itemsFrom[i], itemsTo[i], factor); - } - if (isPath) { - this.setClosed(from._closed); - this._changed(9); - } - }, - - compare: function(path) { - var ok = false; - if (path) { - var paths1 = this._children || [this], - paths2 = path._children ? path._children.slice() : [path], - length1 = paths1.length, - length2 = paths2.length, - matched = [], - count = 0; - ok = true; - for (var i1 = length1 - 1; i1 >= 0 && ok; i1--) { - var path1 = paths1[i1]; - ok = false; - for (var i2 = length2 - 1; i2 >= 0 && !ok; i2--) { - if (path1.compare(paths2[i2])) { - if (!matched[i2]) { - matched[i2] = true; - count++; - } - ok = true; - } - } - } - ok = ok && count === length2; - } - return ok; - }, - -}); - -var Path = PathItem.extend({ - _class: 'Path', - _serializeFields: { - segments: [], - closed: false - }, - - initialize: function Path(arg) { - this._closed = false; - this._segments = []; - this._version = 0; - var segments = Array.isArray(arg) - ? typeof arg[0] === 'object' - ? arg - : arguments - : arg && (arg.size === undefined && (arg.x !== undefined - || arg.point !== undefined)) - ? arguments - : null; - if (segments && segments.length > 0) { - this.setSegments(segments); - } else { - this._curves = undefined; - this._segmentSelection = 0; - if (!segments && typeof arg === 'string') { - this.setPathData(arg); - arg = null; - } - } - this._initialize(!segments && arg); - }, - - _equals: function(item) { - return this._closed === item._closed - && Base.equals(this._segments, item._segments); - }, - - copyContent: function(source) { - this.setSegments(source._segments); - this._closed = source._closed; - }, - - _changed: function _changed(flags) { - _changed.base.call(this, flags); - if (flags & 8) { - this._length = this._area = undefined; - if (flags & 32) { - this._version++; - } else if (this._curves) { - for (var i = 0, l = this._curves.length; i < l; i++) - this._curves[i]._changed(); - } - } else if (flags & 64) { - this._bounds = undefined; - } - }, - - getStyle: function() { - var parent = this._parent; - return (parent instanceof CompoundPath ? parent : this)._style; - }, - - getSegments: function() { - return this._segments; - }, - - setSegments: function(segments) { - var fullySelected = this.isFullySelected(), - length = segments && segments.length; - this._segments.length = 0; - this._segmentSelection = 0; - this._curves = undefined; - if (length) { - var last = segments[length - 1]; - if (typeof last === 'boolean') { - this.setClosed(last); - length--; - } - this._add(Segment.readList(segments, 0, {}, length)); - } - if (fullySelected) - this.setFullySelected(true); - }, - - getFirstSegment: function() { - return this._segments[0]; - }, - - getLastSegment: function() { - return this._segments[this._segments.length - 1]; - }, - - getCurves: function() { - var curves = this._curves, - segments = this._segments; - if (!curves) { - var length = this._countCurves(); - curves = this._curves = new Array(length); - for (var i = 0; i < length; i++) - curves[i] = new Curve(this, segments[i], - segments[i + 1] || segments[0]); - } - return curves; - }, - - getFirstCurve: function() { - return this.getCurves()[0]; - }, - - getLastCurve: function() { - var curves = this.getCurves(); - return curves[curves.length - 1]; - }, - - isClosed: function() { - return this._closed; - }, - - setClosed: function(closed) { - if (this._closed != (closed = !!closed)) { - this._closed = closed; - if (this._curves) { - var length = this._curves.length = this._countCurves(); - if (closed) - this._curves[length - 1] = new Curve(this, - this._segments[length - 1], this._segments[0]); - } - this._changed(41); - } - } -}, { - beans: true, - - getPathData: function(_matrix, _precision) { - var segments = this._segments, - length = segments.length, - f = new Formatter(_precision), - coords = new Array(6), - first = true, - curX, curY, - prevX, prevY, - inX, inY, - outX, outY, - parts = []; - - function addSegment(segment, skipLine) { - segment._transformCoordinates(_matrix, coords); - curX = coords[0]; - curY = coords[1]; - if (first) { - parts.push('M' + f.pair(curX, curY)); - first = false; - } else { - inX = coords[2]; - inY = coords[3]; - if (inX === curX && inY === curY - && outX === prevX && outY === prevY) { - if (!skipLine) { - var dx = curX - prevX, - dy = curY - prevY; - parts.push( - dx === 0 ? 'v' + f.number(dy) - : dy === 0 ? 'h' + f.number(dx) - : 'l' + f.pair(dx, dy)); - } - } else { - parts.push('c' + f.pair(outX - prevX, outY - prevY) - + ' ' + f.pair( inX - prevX, inY - prevY) - + ' ' + f.pair(curX - prevX, curY - prevY)); - } - } - prevX = curX; - prevY = curY; - outX = coords[4]; - outY = coords[5]; - } - - if (!length) - return ''; - - for (var i = 0; i < length; i++) - addSegment(segments[i]); - if (this._closed && length > 0) { - addSegment(segments[0], true); - parts.push('z'); - } - return parts.join(''); - }, - - isEmpty: function() { - return !this._segments.length; - }, - - _transformContent: function(matrix) { - var segments = this._segments, - coords = new Array(6); - for (var i = 0, l = segments.length; i < l; i++) - segments[i]._transformCoordinates(matrix, coords, true); - return true; - }, - - _add: function(segs, index) { - var segments = this._segments, - curves = this._curves, - amount = segs.length, - append = index == null, - index = append ? segments.length : index; - for (var i = 0; i < amount; i++) { - var segment = segs[i]; - if (segment._path) - segment = segs[i] = segment.clone(); - segment._path = this; - segment._index = index + i; - if (segment._selection) - this._updateSelection(segment, 0, segment._selection); - } - if (append) { - Base.push(segments, segs); - } else { - segments.splice.apply(segments, [index, 0].concat(segs)); - for (var i = index + amount, l = segments.length; i < l; i++) - segments[i]._index = i; - } - if (curves) { - var total = this._countCurves(), - start = index > 0 && index + amount - 1 === total ? index - 1 - : index, - insert = start, - end = Math.min(start + amount, total); - if (segs._curves) { - curves.splice.apply(curves, [start, 0].concat(segs._curves)); - insert += segs._curves.length; - } - for (var i = insert; i < end; i++) - curves.splice(i, 0, new Curve(this, null, null)); - this._adjustCurves(start, end); - } - this._changed(41); - return segs; - }, - - _adjustCurves: function(start, end) { - var segments = this._segments, - curves = this._curves, - curve; - for (var i = start; i < end; i++) { - curve = curves[i]; - curve._path = this; - curve._segment1 = segments[i]; - curve._segment2 = segments[i + 1] || segments[0]; - curve._changed(); - } - if (curve = curves[this._closed && !start ? segments.length - 1 - : start - 1]) { - curve._segment2 = segments[start] || segments[0]; - curve._changed(); - } - if (curve = curves[end]) { - curve._segment1 = segments[end]; - curve._changed(); - } - }, - - _countCurves: function() { - var length = this._segments.length; - return !this._closed && length > 0 ? length - 1 : length; - }, - - add: function(segment1 ) { - return arguments.length > 1 && typeof segment1 !== 'number' - ? this._add(Segment.readList(arguments)) - : this._add([ Segment.read(arguments) ])[0]; - }, - - insert: function(index, segment1 ) { - return arguments.length > 2 && typeof segment1 !== 'number' - ? this._add(Segment.readList(arguments, 1), index) - : this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegment: function() { - return this._add([ Segment.read(arguments) ])[0]; - }, - - insertSegment: function(index ) { - return this._add([ Segment.read(arguments, 1) ], index)[0]; - }, - - addSegments: function(segments) { - return this._add(Segment.readList(segments)); - }, - - insertSegments: function(index, segments) { - return this._add(Segment.readList(segments), index); - }, - - removeSegment: function(index) { - return this.removeSegments(index, index + 1)[0] || null; - }, - - removeSegments: function(start, end, _includeCurves) { - start = start || 0; - end = Base.pick(end, this._segments.length); - var segments = this._segments, - curves = this._curves, - count = segments.length, - removed = segments.splice(start, end - start), - amount = removed.length; - if (!amount) - return removed; - for (var i = 0; i < amount; i++) { - var segment = removed[i]; - if (segment._selection) - this._updateSelection(segment, segment._selection, 0); - segment._index = segment._path = null; - } - for (var i = start, l = segments.length; i < l; i++) - segments[i]._index = i; - if (curves) { - var index = start > 0 && end === count + (this._closed ? 1 : 0) - ? start - 1 - : start, - curves = curves.splice(index, amount); - for (var i = curves.length - 1; i >= 0; i--) - curves[i]._path = null; - if (_includeCurves) - removed._curves = curves.slice(1); - this._adjustCurves(index, index); - } - this._changed(41); - return removed; - }, - - clear: '#removeSegments', - - hasHandles: function() { - var segments = this._segments; - for (var i = 0, l = segments.length; i < l; i++) { - if (segments[i].hasHandles()) - return true; - } - return false; - }, - - clearHandles: function() { - var segments = this._segments; - for (var i = 0, l = segments.length; i < l; i++) - segments[i].clearHandles(); - }, - - getLength: function() { - if (this._length == null) { - var curves = this.getCurves(), - length = 0; - for (var i = 0, l = curves.length; i < l; i++) - length += curves[i].getLength(); - this._length = length; - } - return this._length; - }, - - getArea: function() { - var area = this._area; - if (area == null) { - var segments = this._segments, - closed = this._closed; - area = 0; - for (var i = 0, l = segments.length; i < l; i++) { - var last = i + 1 === l; - area += Curve.getArea(Curve.getValues( - segments[i], segments[last ? 0 : i + 1], - null, last && !closed)); - } - this._area = area; - } - return area; - }, - - isFullySelected: function() { - var length = this._segments.length; - return this.isSelected() && length > 0 && this._segmentSelection - === length * 7; - }, - - setFullySelected: function(selected) { - if (selected) - this._selectSegments(true); - this.setSelected(selected); - }, - - setSelection: function setSelection(selection) { - if (!(selection & 1)) - this._selectSegments(false); - setSelection.base.call(this, selection); - }, - - _selectSegments: function(selected) { - var segments = this._segments, - length = segments.length, - selection = selected ? 7 : 0; - this._segmentSelection = selection * length; - for (var i = 0; i < length; i++) - segments[i]._selection = selection; - }, - - _updateSelection: function(segment, oldSelection, newSelection) { - segment._selection = newSelection; - var selection = this._segmentSelection += newSelection - oldSelection; - if (selection > 0) - this.setSelected(true); - }, - - divideAt: function(location) { - var loc = this.getLocationAt(location), - curve; - return loc && (curve = loc.getCurve().divideAt(loc.getCurveOffset())) - ? curve._segment1 - : null; - }, - - splitAt: function(location) { - var loc = this.getLocationAt(location), - index = loc && loc.index, - time = loc && loc.time, - tMin = 1e-8, - tMax = 1 - tMin; - if (time > tMax) { - index++; - time = 0; - } - var curves = this.getCurves(); - if (index >= 0 && index < curves.length) { - if (time >= tMin) { - curves[index++].divideAtTime(time); - } - var segs = this.removeSegments(index, this._segments.length, true), - path; - if (this._closed) { - this.setClosed(false); - path = this; - } else { - path = new Path(Item.NO_INSERT); - path.insertAbove(this); - path.copyAttributes(this); - } - path._add(segs, 0); - this.addSegment(segs[0]); - return path; - } - return null; - }, - - split: function(index, time) { - var curve, - location = time === undefined ? index - : (curve = this.getCurves()[index]) - && curve.getLocationAtTime(time); - return location != null ? this.splitAt(location) : null; - }, - - join: function(path, tolerance) { - var epsilon = tolerance || 0; - if (path && path !== this) { - var segments = path._segments, - last1 = this.getLastSegment(), - last2 = path.getLastSegment(); - if (!last2) - return this; - if (last1 && last1._point.isClose(last2._point, epsilon)) - path.reverse(); - var first2 = path.getFirstSegment(); - if (last1 && last1._point.isClose(first2._point, epsilon)) { - last1.setHandleOut(first2._handleOut); - this._add(segments.slice(1)); - } else { - var first1 = this.getFirstSegment(); - if (first1 && first1._point.isClose(first2._point, epsilon)) - path.reverse(); - last2 = path.getLastSegment(); - if (first1 && first1._point.isClose(last2._point, epsilon)) { - first1.setHandleIn(last2._handleIn); - this._add(segments.slice(0, segments.length - 1), 0); - } else { - this._add(segments.slice()); - } - } - if (path._closed) - this._add([segments[0]]); - path.remove(); - } - var first = this.getFirstSegment(), - last = this.getLastSegment(); - if (first !== last && first._point.isClose(last._point, epsilon)) { - first.setHandleIn(last._handleIn); - last.remove(); - this.setClosed(true); - } - return this; - }, - - reduce: function(options) { - var curves = this.getCurves(), - simplify = options && options.simplify, - tolerance = simplify ? 1e-7 : 0; - for (var i = curves.length - 1; i >= 0; i--) { - var curve = curves[i]; - if (!curve.hasHandles() && (!curve.hasLength(tolerance) - || simplify && curve.isCollinear(curve.getNext()))) - curve.remove(); - } - return this; - }, - - reverse: function() { - this._segments.reverse(); - for (var i = 0, l = this._segments.length; i < l; i++) { - var segment = this._segments[i]; - var handleIn = segment._handleIn; - segment._handleIn = segment._handleOut; - segment._handleOut = handleIn; - segment._index = i; - } - this._curves = null; - this._changed(9); - }, - - flatten: function(flatness) { - var flattener = new PathFlattener(this, flatness || 0.25, 256, true), - parts = flattener.parts, - length = parts.length, - segments = []; - for (var i = 0; i < length; i++) { - segments.push(new Segment(parts[i].curve.slice(0, 2))); - } - if (!this._closed && length > 0) { - segments.push(new Segment(parts[length - 1].curve.slice(6))); - } - this.setSegments(segments); - }, - - simplify: function(tolerance) { - var segments = new PathFitter(this).fit(tolerance || 2.5); - if (segments) - this.setSegments(segments); - return !!segments; - }, - - smooth: function(options) { - var that = this, - opts = options || {}, - type = opts.type || 'asymmetric', - segments = this._segments, - length = segments.length, - closed = this._closed; - - function getIndex(value, _default) { - var index = value && value.index; - if (index != null) { - var path = value.path; - if (path && path !== that) - throw new Error(value._class + ' ' + index + ' of ' + path - + ' is not part of ' + that); - if (_default && value instanceof Curve) - index++; - } else { - index = typeof value === 'number' ? value : _default; - } - return Math.min(index < 0 && closed - ? index % length - : index < 0 ? index + length : index, length - 1); - } - - var loop = closed && opts.from === undefined && opts.to === undefined, - from = getIndex(opts.from, 0), - to = getIndex(opts.to, length - 1); - - if (from > to) { - if (closed) { - from -= length; - } else { - var tmp = from; - from = to; - to = tmp; - } - } - if (/^(?:asymmetric|continuous)$/.test(type)) { - var asymmetric = type === 'asymmetric', - min = Math.min, - amount = to - from + 1, - n = amount - 1, - padding = loop ? min(amount, 4) : 1, - paddingLeft = padding, - paddingRight = padding, - knots = []; - if (!closed) { - paddingLeft = min(1, from); - paddingRight = min(1, length - to - 1); - } - n += paddingLeft + paddingRight; - if (n <= 1) - return; - for (var i = 0, j = from - paddingLeft; i <= n; i++, j++) { - knots[i] = segments[(j < 0 ? j + length : j) % length]._point; - } - - var x = knots[0]._x + 2 * knots[1]._x, - y = knots[0]._y + 2 * knots[1]._y, - f = 2, - n_1 = n - 1, - rx = [x], - ry = [y], - rf = [f], - px = [], - py = []; - for (var i = 1; i < n; i++) { - var internal = i < n_1, - a = internal ? 1 : asymmetric ? 1 : 2, - b = internal ? 4 : asymmetric ? 2 : 7, - u = internal ? 4 : asymmetric ? 3 : 8, - v = internal ? 2 : asymmetric ? 0 : 1, - m = a / f; - f = rf[i] = b - m; - x = rx[i] = u * knots[i]._x + v * knots[i + 1]._x - m * x; - y = ry[i] = u * knots[i]._y + v * knots[i + 1]._y - m * y; - } - - px[n_1] = rx[n_1] / rf[n_1]; - py[n_1] = ry[n_1] / rf[n_1]; - for (var i = n - 2; i >= 0; i--) { - px[i] = (rx[i] - px[i + 1]) / rf[i]; - py[i] = (ry[i] - py[i + 1]) / rf[i]; - } - px[n] = (3 * knots[n]._x - px[n_1]) / 2; - py[n] = (3 * knots[n]._y - py[n_1]) / 2; - - for (var i = paddingLeft, max = n - paddingRight, j = from; - i <= max; i++, j++) { - var segment = segments[j < 0 ? j + length : j], - pt = segment._point, - hx = px[i] - pt._x, - hy = py[i] - pt._y; - if (loop || i < max) - segment.setHandleOut(hx, hy); - if (loop || i > paddingLeft) - segment.setHandleIn(-hx, -hy); - } - } else { - for (var i = from; i <= to; i++) { - segments[i < 0 ? i + length : i].smooth(opts, - !loop && i === from, !loop && i === to); - } - } - }, - - toShape: function(insert) { - if (!this._closed) - return null; - - var segments = this._segments, - type, - size, - radius, - topCenter; - - function isCollinear(i, j) { - var seg1 = segments[i], - seg2 = seg1.getNext(), - seg3 = segments[j], - seg4 = seg3.getNext(); - return seg1._handleOut.isZero() && seg2._handleIn.isZero() - && seg3._handleOut.isZero() && seg4._handleIn.isZero() - && seg2._point.subtract(seg1._point).isCollinear( - seg4._point.subtract(seg3._point)); - } - - function isOrthogonal(i) { - var seg2 = segments[i], - seg1 = seg2.getPrevious(), - seg3 = seg2.getNext(); - return seg1._handleOut.isZero() && seg2._handleIn.isZero() - && seg2._handleOut.isZero() && seg3._handleIn.isZero() - && seg2._point.subtract(seg1._point).isOrthogonal( - seg3._point.subtract(seg2._point)); - } - - function isArc(i) { - var seg1 = segments[i], - seg2 = seg1.getNext(), - handle1 = seg1._handleOut, - handle2 = seg2._handleIn, - kappa = 0.5522847498307936; - if (handle1.isOrthogonal(handle2)) { - var pt1 = seg1._point, - pt2 = seg2._point, - corner = new Line(pt1, handle1, true).intersect( - new Line(pt2, handle2, true), true); - return corner && Numerical.isZero(handle1.getLength() / - corner.subtract(pt1).getLength() - kappa) - && Numerical.isZero(handle2.getLength() / - corner.subtract(pt2).getLength() - kappa); - } - return false; - } - - function getDistance(i, j) { - return segments[i]._point.getDistance(segments[j]._point); - } - - if (!this.hasHandles() && segments.length === 4 - && isCollinear(0, 2) && isCollinear(1, 3) && isOrthogonal(1)) { - type = Shape.Rectangle; - size = new Size(getDistance(0, 3), getDistance(0, 1)); - topCenter = segments[1]._point.add(segments[2]._point).divide(2); - } else if (segments.length === 8 && isArc(0) && isArc(2) && isArc(4) - && isArc(6) && isCollinear(1, 5) && isCollinear(3, 7)) { - type = Shape.Rectangle; - size = new Size(getDistance(1, 6), getDistance(0, 3)); - radius = size.subtract(new Size(getDistance(0, 7), - getDistance(1, 2))).divide(2); - topCenter = segments[3]._point.add(segments[4]._point).divide(2); - } else if (segments.length === 4 - && isArc(0) && isArc(1) && isArc(2) && isArc(3)) { - if (Numerical.isZero(getDistance(0, 2) - getDistance(1, 3))) { - type = Shape.Circle; - radius = getDistance(0, 2) / 2; - } else { - type = Shape.Ellipse; - radius = new Size(getDistance(2, 0) / 2, getDistance(3, 1) / 2); - } - topCenter = segments[1]._point; - } - - if (type) { - var center = this.getPosition(true), - shape = new type({ - center: center, - size: size, - radius: radius, - insert: false - }); - shape.copyAttributes(this, true); - shape._matrix.prepend(this._matrix); - shape.rotate(topCenter.subtract(center).getAngle() + 90); - if (insert === undefined || insert) - shape.insertAbove(this); - return shape; - } - return null; - }, - - toPath: '#clone', - - compare: function compare(path) { - if (!path || path instanceof CompoundPath) - return compare.base.call(this, path); - var curves1 = this.getCurves(), - curves2 = path.getCurves(), - length1 = curves1.length, - length2 = curves2.length; - if (!length1 || !length2) { - return length1 == length2; - } - var v1 = curves1[0].getValues(), - values2 = [], - pos1 = 0, pos2, - end1 = 0, end2; - for (var i = 0; i < length2; i++) { - var v2 = curves2[i].getValues(); - values2.push(v2); - var overlaps = Curve.getOverlaps(v1, v2); - if (overlaps) { - pos2 = !i && overlaps[0][0] > 0 ? length2 - 1 : i; - end2 = overlaps[0][1]; - break; - } - } - var abs = Math.abs, - epsilon = 1e-8, - v2 = values2[pos2], - start2; - while (v1 && v2) { - var overlaps = Curve.getOverlaps(v1, v2); - if (overlaps) { - var t1 = overlaps[0][0]; - if (abs(t1 - end1) < epsilon) { - end1 = overlaps[1][0]; - if (end1 === 1) { - v1 = ++pos1 < length1 ? curves1[pos1].getValues() : null; - end1 = 0; - } - var t2 = overlaps[0][1]; - if (abs(t2 - end2) < epsilon) { - if (!start2) - start2 = [pos2, t2]; - end2 = overlaps[1][1]; - if (end2 === 1) { - if (++pos2 >= length2) - pos2 = 0; - v2 = values2[pos2] || curves2[pos2].getValues(); - end2 = 0; - } - if (!v1) { - return start2[0] === pos2 && start2[1] === end2; - } - continue; - } - } - } - break; - } - return false; - }, - - _hitTestSelf: function(point, options, viewMatrix, strokeMatrix) { - var that = this, - style = this.getStyle(), - segments = this._segments, - numSegments = segments.length, - closed = this._closed, - tolerancePadding = options._tolerancePadding, - strokePadding = tolerancePadding, - join, cap, miterLimit, - area, loc, res, - hitStroke = options.stroke && style.hasStroke(), - hitFill = options.fill && style.hasFill(), - hitCurves = options.curves, - strokeRadius = hitStroke - ? style.getStrokeWidth() / 2 - : hitFill && options.tolerance > 0 || hitCurves - ? 0 : null; - if (strokeRadius !== null) { - if (strokeRadius > 0) { - join = style.getStrokeJoin(); - cap = style.getStrokeCap(); - miterLimit = style.getMiterLimit(); - strokePadding = strokePadding.add( - Path._getStrokePadding(strokeRadius, strokeMatrix)); - } else { - join = cap = 'round'; - } - } - - function isCloseEnough(pt, padding) { - return point.subtract(pt).divide(padding).length <= 1; - } - - function checkSegmentPoint(seg, pt, name) { - if (!options.selected || pt.isSelected()) { - var anchor = seg._point; - if (pt !== anchor) - pt = pt.add(anchor); - if (isCloseEnough(pt, strokePadding)) { - return new HitResult(name, that, { - segment: seg, - point: pt - }); - } - } - } - - function checkSegmentPoints(seg, ends) { - return (ends || options.segments) - && checkSegmentPoint(seg, seg._point, 'segment') - || (!ends && options.handles) && ( - checkSegmentPoint(seg, seg._handleIn, 'handle-in') || - checkSegmentPoint(seg, seg._handleOut, 'handle-out')); - } - - function addToArea(point) { - area.add(point); - } - - function checkSegmentStroke(segment) { - var isJoin = closed || segment._index > 0 - && segment._index < numSegments - 1; - if ((isJoin ? join : cap) === 'round') { - return isCloseEnough(segment._point, strokePadding); - } else { - area = new Path({ internal: true, closed: true }); - if (isJoin) { - if (!segment.isSmooth()) { - Path._addBevelJoin(segment, join, strokeRadius, - miterLimit, null, strokeMatrix, addToArea, true); - } - } else if (cap === 'square') { - Path._addSquareCap(segment, cap, strokeRadius, null, - strokeMatrix, addToArea, true); - } - if (!area.isEmpty()) { - var loc; - return area.contains(point) - || (loc = area.getNearestLocation(point)) - && isCloseEnough(loc.getPoint(), tolerancePadding); - } - } - } - - if (options.ends && !options.segments && !closed) { - if (res = checkSegmentPoints(segments[0], true) - || checkSegmentPoints(segments[numSegments - 1], true)) - return res; - } else if (options.segments || options.handles) { - for (var i = 0; i < numSegments; i++) - if (res = checkSegmentPoints(segments[i])) - return res; - } - if (strokeRadius !== null) { - loc = this.getNearestLocation(point); - if (loc) { - var time = loc.getTime(); - if (time === 0 || time === 1 && numSegments > 1) { - if (!checkSegmentStroke(loc.getSegment())) - loc = null; - } else if (!isCloseEnough(loc.getPoint(), strokePadding)) { - loc = null; - } - } - if (!loc && join === 'miter' && numSegments > 1) { - for (var i = 0; i < numSegments; i++) { - var segment = segments[i]; - if (point.getDistance(segment._point) - <= miterLimit * strokeRadius - && checkSegmentStroke(segment)) { - loc = segment.getLocation(); - break; - } - } - } - } - return !loc && hitFill && this._contains(point) - || loc && !hitStroke && !hitCurves - ? new HitResult('fill', this) - : loc - ? new HitResult(hitStroke ? 'stroke' : 'curve', this, { - location: loc, - point: loc.getPoint() - }) - : null; - } - -}, Base.each(Curve._evaluateMethods, - function(name) { - this[name + 'At'] = function(offset) { - var loc = this.getLocationAt(offset); - return loc && loc[name](); - }; - }, -{ - beans: false, - - getLocationOf: function() { - var point = Point.read(arguments), - curves = this.getCurves(); - for (var i = 0, l = curves.length; i < l; i++) { - var loc = curves[i].getLocationOf(point); - if (loc) - return loc; - } - return null; - }, - - getOffsetOf: function() { - var loc = this.getLocationOf.apply(this, arguments); - return loc ? loc.getOffset() : null; - }, - - getLocationAt: function(offset) { - if (typeof offset === 'number') { - var curves = this.getCurves(), - length = 0; - for (var i = 0, l = curves.length; i < l; i++) { - var start = length, - curve = curves[i]; - length += curve.getLength(); - if (length > offset) { - return curve.getLocationAt(offset - start); - } - } - if (curves.length > 0 && offset <= this.getLength()) { - return new CurveLocation(curves[curves.length - 1], 1); - } - } else if (offset && offset.getPath && offset.getPath() === this) { - return offset; - } - return null; - }, - - getOffsetsWithTangent: function() { - var tangent = Point.read(arguments); - if (tangent.isZero()) { - return []; - } - - var offsets = []; - var curveStart = 0; - var curves = this.getCurves(); - for (var i = 0, l = curves.length; i < l; i++) { - var curve = curves[i]; - var curveTimes = curve.getTimesWithTangent(tangent); - for (var j = 0, m = curveTimes.length; j < m; j++) { - var offset = curveStart + curve.getOffsetAtTime(curveTimes[j]); - if (offsets.indexOf(offset) < 0) { - offsets.push(offset); - } - } - curveStart += curve.length; - } - return offsets; - } -}), -new function() { - - function drawHandles(ctx, segments, matrix, size) { - var half = size / 2, - coords = new Array(6), - pX, pY; - - function drawHandle(index) { - var hX = coords[index], - hY = coords[index + 1]; - if (pX != hX || pY != hY) { - ctx.beginPath(); - ctx.moveTo(pX, pY); - ctx.lineTo(hX, hY); - ctx.stroke(); - ctx.beginPath(); - ctx.arc(hX, hY, half, 0, Math.PI * 2, true); - ctx.fill(); - } - } - - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i], - selection = segment._selection; - segment._transformCoordinates(matrix, coords); - pX = coords[0]; - pY = coords[1]; - if (selection & 2) - drawHandle(2); - if (selection & 4) - drawHandle(4); - ctx.fillRect(pX - half, pY - half, size, size); - if (!(selection & 1)) { - var fillStyle = ctx.fillStyle; - ctx.fillStyle = '#ffffff'; - ctx.fillRect(pX - half + 1, pY - half + 1, size - 2, size - 2); - ctx.fillStyle = fillStyle; - } - } - } - - function drawSegments(ctx, path, matrix) { - var segments = path._segments, - length = segments.length, - coords = new Array(6), - first = true, - curX, curY, - prevX, prevY, - inX, inY, - outX, outY; - - function drawSegment(segment) { - if (matrix) { - segment._transformCoordinates(matrix, coords); - curX = coords[0]; - curY = coords[1]; - } else { - var point = segment._point; - curX = point._x; - curY = point._y; - } - if (first) { - ctx.moveTo(curX, curY); - first = false; - } else { - if (matrix) { - inX = coords[2]; - inY = coords[3]; - } else { - var handle = segment._handleIn; - inX = curX + handle._x; - inY = curY + handle._y; - } - if (inX === curX && inY === curY - && outX === prevX && outY === prevY) { - ctx.lineTo(curX, curY); - } else { - ctx.bezierCurveTo(outX, outY, inX, inY, curX, curY); - } - } - prevX = curX; - prevY = curY; - if (matrix) { - outX = coords[4]; - outY = coords[5]; - } else { - var handle = segment._handleOut; - outX = prevX + handle._x; - outY = prevY + handle._y; - } - } - - for (var i = 0; i < length; i++) - drawSegment(segments[i]); - if (path._closed && length > 0) - drawSegment(segments[0]); - } - - return { - _draw: function(ctx, param, viewMatrix, strokeMatrix) { - var dontStart = param.dontStart, - dontPaint = param.dontFinish || param.clip, - style = this.getStyle(), - hasFill = style.hasFill(), - hasStroke = style.hasStroke(), - dashArray = style.getDashArray(), - dashLength = !paper.support.nativeDash && hasStroke - && dashArray && dashArray.length; - - if (!dontStart) - ctx.beginPath(); - - if (hasFill || hasStroke && !dashLength || dontPaint) { - drawSegments(ctx, this, strokeMatrix); - if (this._closed) - ctx.closePath(); - } - - function getOffset(i) { - return dashArray[((i % dashLength) + dashLength) % dashLength]; - } - - if (!dontPaint && (hasFill || hasStroke)) { - this._setStyles(ctx, param, viewMatrix); - if (hasFill) { - ctx.fill(style.getFillRule()); - ctx.shadowColor = 'rgba(0,0,0,0)'; - } - if (hasStroke) { - if (dashLength) { - if (!dontStart) - ctx.beginPath(); - var flattener = new PathFlattener(this, 0.25, 32, false, - strokeMatrix), - length = flattener.length, - from = -style.getDashOffset(), to, - i = 0; - from = from % length; - while (from > 0) { - from -= getOffset(i--) + getOffset(i--); - } - while (from < length) { - to = from + getOffset(i++); - if (from > 0 || to > 0) - flattener.drawPart(ctx, - Math.max(from, 0), Math.max(to, 0)); - from = to + getOffset(i++); - } - } - ctx.stroke(); - } - } - }, - - _drawSelected: function(ctx, matrix) { - ctx.beginPath(); - drawSegments(ctx, this, matrix); - ctx.stroke(); - drawHandles(ctx, this._segments, matrix, paper.settings.handleSize); - } - }; -}, -new function() { - function getCurrentSegment(that) { - var segments = that._segments; - if (!segments.length) - throw new Error('Use a moveTo() command first'); - return segments[segments.length - 1]; - } - - return { - moveTo: function() { - var segments = this._segments; - if (segments.length === 1) - this.removeSegment(0); - if (!segments.length) - this._add([ new Segment(Point.read(arguments)) ]); - }, - - moveBy: function() { - throw new Error('moveBy() is unsupported on Path items.'); - }, - - lineTo: function() { - this._add([ new Segment(Point.read(arguments)) ]); - }, - - cubicCurveTo: function() { - var handle1 = Point.read(arguments), - handle2 = Point.read(arguments), - to = Point.read(arguments), - current = getCurrentSegment(this); - current.setHandleOut(handle1.subtract(current._point)); - this._add([ new Segment(to, handle2.subtract(to)) ]); - }, - - quadraticCurveTo: function() { - var handle = Point.read(arguments), - to = Point.read(arguments), - current = getCurrentSegment(this)._point; - this.cubicCurveTo( - handle.add(current.subtract(handle).multiply(1 / 3)), - handle.add(to.subtract(handle).multiply(1 / 3)), - to - ); - }, - - curveTo: function() { - var through = Point.read(arguments), - to = Point.read(arguments), - t = Base.pick(Base.read(arguments), 0.5), - t1 = 1 - t, - current = getCurrentSegment(this)._point, - handle = through.subtract(current.multiply(t1 * t1)) - .subtract(to.multiply(t * t)).divide(2 * t * t1); - if (handle.isNaN()) - throw new Error( - 'Cannot put a curve through points with parameter = ' + t); - this.quadraticCurveTo(handle, to); - }, - - arcTo: function() { - var abs = Math.abs, - sqrt = Math.sqrt, - current = getCurrentSegment(this), - from = current._point, - to = Point.read(arguments), - through, - peek = Base.peek(arguments), - clockwise = Base.pick(peek, true), - center, extent, vector, matrix; - if (typeof clockwise === 'boolean') { - var middle = from.add(to).divide(2), - through = middle.add(middle.subtract(from).rotate( - clockwise ? -90 : 90)); - } else if (Base.remain(arguments) <= 2) { - through = to; - to = Point.read(arguments); - } else { - var radius = Size.read(arguments), - isZero = Numerical.isZero; - if (isZero(radius.width) || isZero(radius.height)) - return this.lineTo(to); - var rotation = Base.read(arguments), - clockwise = !!Base.read(arguments), - large = !!Base.read(arguments), - middle = from.add(to).divide(2), - pt = from.subtract(middle).rotate(-rotation), - x = pt.x, - y = pt.y, - rx = abs(radius.width), - ry = abs(radius.height), - rxSq = rx * rx, - rySq = ry * ry, - xSq = x * x, - ySq = y * y; - var factor = sqrt(xSq / rxSq + ySq / rySq); - if (factor > 1) { - rx *= factor; - ry *= factor; - rxSq = rx * rx; - rySq = ry * ry; - } - factor = (rxSq * rySq - rxSq * ySq - rySq * xSq) / - (rxSq * ySq + rySq * xSq); - if (abs(factor) < 1e-12) - factor = 0; - if (factor < 0) - throw new Error( - 'Cannot create an arc with the given arguments'); - center = new Point(rx * y / ry, -ry * x / rx) - .multiply((large === clockwise ? -1 : 1) * sqrt(factor)) - .rotate(rotation).add(middle); - matrix = new Matrix().translate(center).rotate(rotation) - .scale(rx, ry); - vector = matrix._inverseTransform(from); - extent = vector.getDirectedAngle(matrix._inverseTransform(to)); - if (!clockwise && extent > 0) - extent -= 360; - else if (clockwise && extent < 0) - extent += 360; - } - if (through) { - var l1 = new Line(from.add(through).divide(2), - through.subtract(from).rotate(90), true), - l2 = new Line(through.add(to).divide(2), - to.subtract(through).rotate(90), true), - line = new Line(from, to), - throughSide = line.getSide(through); - center = l1.intersect(l2, true); - if (!center) { - if (!throughSide) - return this.lineTo(to); - throw new Error( - 'Cannot create an arc with the given arguments'); - } - vector = from.subtract(center); - extent = vector.getDirectedAngle(to.subtract(center)); - var centerSide = line.getSide(center, true); - if (centerSide === 0) { - extent = throughSide * abs(extent); - } else if (throughSide === centerSide) { - extent += extent < 0 ? 360 : -360; - } - } - var epsilon = 1e-7, - ext = abs(extent), - count = ext >= 360 ? 4 : Math.ceil((ext - epsilon) / 90), - inc = extent / count, - half = inc * Math.PI / 360, - z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), - segments = []; - for (var i = 0; i <= count; i++) { - var pt = to, - out = null; - if (i < count) { - out = vector.rotate(90).multiply(z); - if (matrix) { - pt = matrix._transformPoint(vector); - out = matrix._transformPoint(vector.add(out)) - .subtract(pt); - } else { - pt = center.add(vector); - } - } - if (!i) { - current.setHandleOut(out); - } else { - var _in = vector.rotate(-90).multiply(z); - if (matrix) { - _in = matrix._transformPoint(vector.add(_in)) - .subtract(pt); - } - segments.push(new Segment(pt, _in, out)); - } - vector = vector.rotate(inc); - } - this._add(segments); - }, - - lineBy: function() { - var to = Point.read(arguments), - current = getCurrentSegment(this)._point; - this.lineTo(current.add(to)); - }, - - curveBy: function() { - var through = Point.read(arguments), - to = Point.read(arguments), - parameter = Base.read(arguments), - current = getCurrentSegment(this)._point; - this.curveTo(current.add(through), current.add(to), parameter); - }, - - cubicCurveBy: function() { - var handle1 = Point.read(arguments), - handle2 = Point.read(arguments), - to = Point.read(arguments), - current = getCurrentSegment(this)._point; - this.cubicCurveTo(current.add(handle1), current.add(handle2), - current.add(to)); - }, - - quadraticCurveBy: function() { - var handle = Point.read(arguments), - to = Point.read(arguments), - current = getCurrentSegment(this)._point; - this.quadraticCurveTo(current.add(handle), current.add(to)); - }, - - arcBy: function() { - var current = getCurrentSegment(this)._point, - point = current.add(Point.read(arguments)), - clockwise = Base.pick(Base.peek(arguments), true); - if (typeof clockwise === 'boolean') { - this.arcTo(point, clockwise); - } else { - this.arcTo(point, current.add(Point.read(arguments))); - } - }, - - closePath: function(tolerance) { - this.setClosed(true); - this.join(this, tolerance); - } - }; -}, { - - _getBounds: function(matrix, options) { - var method = options.handle - ? 'getHandleBounds' - : options.stroke - ? 'getStrokeBounds' - : 'getBounds'; - return Path[method](this._segments, this._closed, this, matrix, options); - }, - -statics: { - getBounds: function(segments, closed, path, matrix, options, strokePadding) { - var first = segments[0]; - if (!first) - return new Rectangle(); - var coords = new Array(6), - prevCoords = first._transformCoordinates(matrix, new Array(6)), - min = prevCoords.slice(0, 2), - max = min.slice(), - roots = new Array(2); - - function processSegment(segment) { - segment._transformCoordinates(matrix, coords); - for (var i = 0; i < 2; i++) { - Curve._addBounds( - prevCoords[i], - prevCoords[i + 4], - coords[i + 2], - coords[i], - i, strokePadding ? strokePadding[i] : 0, min, max, roots); - } - var tmp = prevCoords; - prevCoords = coords; - coords = tmp; - } - - for (var i = 1, l = segments.length; i < l; i++) - processSegment(segments[i]); - if (closed) - processSegment(first); - return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]); - }, - - getStrokeBounds: function(segments, closed, path, matrix, options) { - var style = path.getStyle(), - stroke = style.hasStroke(), - strokeWidth = style.getStrokeWidth(), - strokeMatrix = stroke && path._getStrokeMatrix(matrix, options), - strokePadding = stroke && Path._getStrokePadding(strokeWidth, - strokeMatrix), - bounds = Path.getBounds(segments, closed, path, matrix, options, - strokePadding); - if (!stroke) - return bounds; - var strokeRadius = strokeWidth / 2, - join = style.getStrokeJoin(), - cap = style.getStrokeCap(), - miterLimit = style.getMiterLimit(), - joinBounds = new Rectangle(new Size(strokePadding)); - - function addPoint(point) { - bounds = bounds.include(point); - } - - function addRound(segment) { - bounds = bounds.unite( - joinBounds.setCenter(segment._point.transform(matrix))); - } - - function addJoin(segment, join) { - if (join === 'round' || segment.isSmooth()) { - addRound(segment); - } else { - Path._addBevelJoin(segment, join, strokeRadius, miterLimit, - matrix, strokeMatrix, addPoint); - } - } - - function addCap(segment, cap) { - if (cap === 'round') { - addRound(segment); - } else { - Path._addSquareCap(segment, cap, strokeRadius, matrix, - strokeMatrix, addPoint); - } - } - - var length = segments.length - (closed ? 0 : 1); - for (var i = 1; i < length; i++) - addJoin(segments[i], join); - if (closed) { - addJoin(segments[0], join); - } else if (length > 0) { - addCap(segments[0], cap); - addCap(segments[segments.length - 1], cap); - } - return bounds; - }, - - _getStrokePadding: function(radius, matrix) { - if (!matrix) - return [radius, radius]; - var hor = new Point(radius, 0).transform(matrix), - ver = new Point(0, radius).transform(matrix), - phi = hor.getAngleInRadians(), - a = hor.getLength(), - b = ver.getLength(); - var sin = Math.sin(phi), - cos = Math.cos(phi), - tan = Math.tan(phi), - tx = Math.atan2(b * tan, a), - ty = Math.atan2(b, tan * a); - return [Math.abs(a * Math.cos(tx) * cos + b * Math.sin(tx) * sin), - Math.abs(b * Math.sin(ty) * cos + a * Math.cos(ty) * sin)]; - }, - - _addBevelJoin: function(segment, join, radius, miterLimit, matrix, - strokeMatrix, addPoint, isArea) { - var curve2 = segment.getCurve(), - curve1 = curve2.getPrevious(), - point = curve2.getPoint1().transform(matrix), - normal1 = curve1.getNormalAtTime(1).multiply(radius) - .transform(strokeMatrix), - normal2 = curve2.getNormalAtTime(0).multiply(radius) - .transform(strokeMatrix); - if (normal1.getDirectedAngle(normal2) < 0) { - normal1 = normal1.negate(); - normal2 = normal2.negate(); - } - if (isArea) - addPoint(point); - addPoint(point.add(normal1)); - if (join === 'miter') { - var corner = new Line(point.add(normal1), - new Point(-normal1.y, normal1.x), true - ).intersect(new Line(point.add(normal2), - new Point(-normal2.y, normal2.x), true - ), true); - if (corner && point.getDistance(corner) <= miterLimit * radius) { - addPoint(corner); - } - } - addPoint(point.add(normal2)); - }, - - _addSquareCap: function(segment, cap, radius, matrix, strokeMatrix, - addPoint, isArea) { - var point = segment._point.transform(matrix), - loc = segment.getLocation(), - normal = loc.getNormal() - .multiply(loc.getTime() === 0 ? radius : -radius) - .transform(strokeMatrix); - if (cap === 'square') { - if (isArea) { - addPoint(point.subtract(normal)); - addPoint(point.add(normal)); - } - point = point.add(normal.rotate(-90)); - } - addPoint(point.add(normal)); - addPoint(point.subtract(normal)); - }, - - getHandleBounds: function(segments, closed, path, matrix, options) { - var style = path.getStyle(), - stroke = options.stroke && style.hasStroke(), - strokePadding, - joinPadding; - if (stroke) { - var strokeMatrix = path._getStrokeMatrix(matrix, options), - strokeRadius = style.getStrokeWidth() / 2, - joinRadius = strokeRadius; - if (style.getStrokeJoin() === 'miter') - joinRadius = strokeRadius * style.getMiterLimit(); - if (style.getStrokeCap() === 'square') - joinRadius = Math.max(joinRadius, strokeRadius * Math.SQRT2); - strokePadding = Path._getStrokePadding(strokeRadius, strokeMatrix); - joinPadding = Path._getStrokePadding(joinRadius, strokeMatrix); - } - var coords = new Array(6), - x1 = Infinity, - x2 = -x1, - y1 = x1, - y2 = x2; - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i]; - segment._transformCoordinates(matrix, coords); - for (var j = 0; j < 6; j += 2) { - var padding = !j ? joinPadding : strokePadding, - paddingX = padding ? padding[0] : 0, - paddingY = padding ? padding[1] : 0, - x = coords[j], - y = coords[j + 1], - xn = x - paddingX, - xx = x + paddingX, - yn = y - paddingY, - yx = y + paddingY; - if (xn < x1) x1 = xn; - if (xx > x2) x2 = xx; - if (yn < y1) y1 = yn; - if (yx > y2) y2 = yx; - } - } - return new Rectangle(x1, y1, x2 - x1, y2 - y1); - } -}}); - -Path.inject({ statics: new function() { - - var kappa = 0.5522847498307936, - ellipseSegments = [ - new Segment([-1, 0], [0, kappa ], [0, -kappa]), - new Segment([0, -1], [-kappa, 0], [kappa, 0 ]), - new Segment([1, 0], [0, -kappa], [0, kappa ]), - new Segment([0, 1], [kappa, 0 ], [-kappa, 0]) - ]; - - function createPath(segments, closed, args) { - var props = Base.getNamed(args), - path = new Path(props && props.insert == false && Item.NO_INSERT); - path._add(segments); - path._closed = closed; - return path.set(props, { insert: true }); - } - - function createEllipse(center, radius, args) { - var segments = new Array(4); - for (var i = 0; i < 4; i++) { - var segment = ellipseSegments[i]; - segments[i] = new Segment( - segment._point.multiply(radius).add(center), - segment._handleIn.multiply(radius), - segment._handleOut.multiply(radius) - ); - } - return createPath(segments, true, args); - } - - return { - Line: function() { - return createPath([ - new Segment(Point.readNamed(arguments, 'from')), - new Segment(Point.readNamed(arguments, 'to')) - ], false, arguments); - }, - - Circle: function() { - var center = Point.readNamed(arguments, 'center'), - radius = Base.readNamed(arguments, 'radius'); - return createEllipse(center, new Size(radius), arguments); - }, - - Rectangle: function() { - var rect = Rectangle.readNamed(arguments, 'rectangle'), - radius = Size.readNamed(arguments, 'radius', 0, - { readNull: true }), - bl = rect.getBottomLeft(true), - tl = rect.getTopLeft(true), - tr = rect.getTopRight(true), - br = rect.getBottomRight(true), - segments; - if (!radius || radius.isZero()) { - segments = [ - new Segment(bl), - new Segment(tl), - new Segment(tr), - new Segment(br) - ]; - } else { - radius = Size.min(radius, rect.getSize(true).divide(2)); - var rx = radius.width, - ry = radius.height, - hx = rx * kappa, - hy = ry * kappa; - segments = [ - new Segment(bl.add(rx, 0), null, [-hx, 0]), - new Segment(bl.subtract(0, ry), [0, hy]), - new Segment(tl.add(0, ry), null, [0, -hy]), - new Segment(tl.add(rx, 0), [-hx, 0], null), - new Segment(tr.subtract(rx, 0), null, [hx, 0]), - new Segment(tr.add(0, ry), [0, -hy], null), - new Segment(br.subtract(0, ry), null, [0, hy]), - new Segment(br.subtract(rx, 0), [hx, 0]) - ]; - } - return createPath(segments, true, arguments); - }, - - RoundRectangle: '#Rectangle', - - Ellipse: function() { - var ellipse = Shape._readEllipse(arguments); - return createEllipse(ellipse.center, ellipse.radius, arguments); - }, - - Oval: '#Ellipse', - - Arc: function() { - var from = Point.readNamed(arguments, 'from'), - through = Point.readNamed(arguments, 'through'), - to = Point.readNamed(arguments, 'to'), - props = Base.getNamed(arguments), - path = new Path(props && props.insert == false - && Item.NO_INSERT); - path.moveTo(from); - path.arcTo(through, to); - return path.set(props); - }, - - RegularPolygon: function() { - var center = Point.readNamed(arguments, 'center'), - sides = Base.readNamed(arguments, 'sides'), - radius = Base.readNamed(arguments, 'radius'), - step = 360 / sides, - three = sides % 3 === 0, - vector = new Point(0, three ? -radius : radius), - offset = three ? -1 : 0.5, - segments = new Array(sides); - for (var i = 0; i < sides; i++) - segments[i] = new Segment(center.add( - vector.rotate((i + offset) * step))); - return createPath(segments, true, arguments); - }, - - Star: function() { - var center = Point.readNamed(arguments, 'center'), - points = Base.readNamed(arguments, 'points') * 2, - radius1 = Base.readNamed(arguments, 'radius1'), - radius2 = Base.readNamed(arguments, 'radius2'), - step = 360 / points, - vector = new Point(0, -1), - segments = new Array(points); - for (var i = 0; i < points; i++) - segments[i] = new Segment(center.add(vector.rotate(step * i) - .multiply(i % 2 ? radius2 : radius1))); - return createPath(segments, true, arguments); - } - }; -}}); - -var CompoundPath = PathItem.extend({ - _class: 'CompoundPath', - _serializeFields: { - children: [] - }, - beans: true, - - initialize: function CompoundPath(arg) { - this._children = []; - this._namedChildren = {}; - if (!this._initialize(arg)) { - if (typeof arg === 'string') { - this.setPathData(arg); - } else { - this.addChildren(Array.isArray(arg) ? arg : arguments); - } - } - }, - - insertChildren: function insertChildren(index, items) { - var list = items, - first = list[0]; - if (first && typeof first[0] === 'number') - list = [list]; - for (var i = items.length - 1; i >= 0; i--) { - var item = list[i]; - if (list === items && !(item instanceof Path)) - list = Base.slice(list); - if (Array.isArray(item)) { - list[i] = new Path({ segments: item, insert: false }); - } else if (item instanceof CompoundPath) { - list.splice.apply(list, [i, 1].concat(item.removeChildren())); - item.remove(); - } - } - return insertChildren.base.call(this, index, list); - }, - - reduce: function reduce(options) { - var children = this._children; - for (var i = children.length - 1; i >= 0; i--) { - var path = children[i].reduce(options); - if (path.isEmpty()) - path.remove(); - } - if (!children.length) { - var path = new Path(Item.NO_INSERT); - path.copyAttributes(this); - path.insertAbove(this); - this.remove(); - return path; - } - return reduce.base.call(this); - }, - - isClosed: function() { - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) { - if (!children[i]._closed) - return false; - } - return true; - }, - - setClosed: function(closed) { - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) { - children[i].setClosed(closed); - } - }, - - getFirstSegment: function() { - var first = this.getFirstChild(); - return first && first.getFirstSegment(); - }, - - getLastSegment: function() { - var last = this.getLastChild(); - return last && last.getLastSegment(); - }, - - getCurves: function() { - var children = this._children, - curves = []; - for (var i = 0, l = children.length; i < l; i++) { - Base.push(curves, children[i].getCurves()); - } - return curves; - }, - - getFirstCurve: function() { - var first = this.getFirstChild(); - return first && first.getFirstCurve(); - }, - - getLastCurve: function() { - var last = this.getLastChild(); - return last && last.getLastCurve(); - }, - - getArea: function() { - var children = this._children, - area = 0; - for (var i = 0, l = children.length; i < l; i++) - area += children[i].getArea(); - return area; - }, - - getLength: function() { - var children = this._children, - length = 0; - for (var i = 0, l = children.length; i < l; i++) - length += children[i].getLength(); - return length; - }, - - getPathData: function(_matrix, _precision) { - var children = this._children, - paths = []; - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i], - mx = child._matrix; - paths.push(child.getPathData(_matrix && !mx.isIdentity() - ? _matrix.appended(mx) : _matrix, _precision)); - } - return paths.join(''); - }, - - _hitTestChildren: function _hitTestChildren(point, options, viewMatrix) { - return _hitTestChildren.base.call(this, point, - options.class === Path || options.type === 'path' ? options - : Base.set({}, options, { fill: false }), - viewMatrix); - }, - - _draw: function(ctx, param, viewMatrix, strokeMatrix) { - var children = this._children; - if (!children.length) - return; - - param = param.extend({ dontStart: true, dontFinish: true }); - ctx.beginPath(); - for (var i = 0, l = children.length; i < l; i++) - children[i].draw(ctx, param, strokeMatrix); - - if (!param.clip) { - this._setStyles(ctx, param, viewMatrix); - var style = this._style; - if (style.hasFill()) { - ctx.fill(style.getFillRule()); - ctx.shadowColor = 'rgba(0,0,0,0)'; - } - if (style.hasStroke()) - ctx.stroke(); - } - }, - - _drawSelected: function(ctx, matrix, selectionItems) { - var children = this._children; - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i], - mx = child._matrix; - if (!selectionItems[child._id]) { - child._drawSelected(ctx, mx.isIdentity() ? matrix - : matrix.appended(mx)); - } - } - } -}, -new function() { - function getCurrentPath(that, check) { - var children = that._children; - if (check && !children.length) - throw new Error('Use a moveTo() command first'); - return children[children.length - 1]; - } - - return Base.each(['lineTo', 'cubicCurveTo', 'quadraticCurveTo', 'curveTo', - 'arcTo', 'lineBy', 'cubicCurveBy', 'quadraticCurveBy', 'curveBy', - 'arcBy'], - function(key) { - this[key] = function() { - var path = getCurrentPath(this, true); - path[key].apply(path, arguments); - }; - }, { - moveTo: function() { - var current = getCurrentPath(this), - path = current && current.isEmpty() ? current - : new Path(Item.NO_INSERT); - if (path !== current) - this.addChild(path); - path.moveTo.apply(path, arguments); - }, - - moveBy: function() { - var current = getCurrentPath(this, true), - last = current && current.getLastSegment(), - point = Point.read(arguments); - this.moveTo(last ? point.add(last._point) : point); - }, - - closePath: function(tolerance) { - getCurrentPath(this, true).closePath(tolerance); - } - } - ); -}, Base.each(['reverse', 'flatten', 'simplify', 'smooth'], function(key) { - this[key] = function(param) { - var children = this._children, - res; - for (var i = 0, l = children.length; i < l; i++) { - res = children[i][key](param) || res; - } - return res; - }; -}, {})); - -PathItem.inject(new function() { - var min = Math.min, - max = Math.max, - abs = Math.abs, - operators = { - unite: { '1': true, '2': true }, - intersect: { '2': true }, - subtract: { '1': true }, - exclude: { '1': true, '-1': true } - }; - - function preparePath(path, resolve) { - var res = path.clone(false).reduce({ simplify: true }) - .transform(null, true, true); - return resolve - ? res.resolveCrossings().reorient( - res.getFillRule() === 'nonzero', true) - : res; - } - - function createResult(paths, simplify, path1, path2, options) { - var result = new CompoundPath(Item.NO_INSERT); - result.addChildren(paths, true); - result = result.reduce({ simplify: simplify }); - if (!(options && options.insert == false)) { - result.insertAbove(path2 && path1.isSibling(path2) - && path1.getIndex() < path2.getIndex() ? path2 : path1); - } - result.copyAttributes(path1, true); - return result; - } - - function traceBoolean(path1, path2, operation, options) { - if (options && (options.trace == false || options.stroke) && - /^(subtract|intersect)$/.test(operation)) - return splitBoolean(path1, path2, operation); - var _path1 = preparePath(path1, true), - _path2 = path2 && path1 !== path2 && preparePath(path2, true), - operator = operators[operation]; - operator[operation] = true; - if (_path2 && (operator.subtract || operator.exclude) - ^ (_path2.isClockwise() ^ _path1.isClockwise())) - _path2.reverse(); - var crossings = divideLocations( - CurveLocation.expand(_path1.getCrossings(_path2))), - paths1 = _path1._children || [_path1], - paths2 = _path2 && (_path2._children || [_path2]), - segments = [], - curves = [], - paths; - - function collect(paths) { - for (var i = 0, l = paths.length; i < l; i++) { - var path = paths[i]; - Base.push(segments, path._segments); - Base.push(curves, path.getCurves()); - path._overlapsOnly = true; - } - } - - if (crossings.length) { - collect(paths1); - if (paths2) - collect(paths2); - for (var i = 0, l = crossings.length; i < l; i++) { - propagateWinding(crossings[i]._segment, _path1, _path2, curves, - operator); - } - for (var i = 0, l = segments.length; i < l; i++) { - var segment = segments[i], - inter = segment._intersection; - if (!segment._winding) { - propagateWinding(segment, _path1, _path2, curves, operator); - } - if (!(inter && inter._overlap)) - segment._path._overlapsOnly = false; - } - paths = tracePaths(segments, operator); - } else { - paths = reorientPaths( - paths2 ? paths1.concat(paths2) : paths1.slice(), - function(w) { - return !!operator[w]; - }); - } - - return createResult(paths, true, path1, path2, options); - } - - function splitBoolean(path1, path2, operation) { - var _path1 = preparePath(path1), - _path2 = preparePath(path2), - crossings = _path1.getCrossings(_path2), - subtract = operation === 'subtract', - divide = operation === 'divide', - added = {}, - paths = []; - - function addPath(path) { - if (!added[path._id] && (divide || - _path2.contains(path.getPointAt(path.getLength() / 2)) - ^ subtract)) { - paths.unshift(path); - return added[path._id] = true; - } - } - - for (var i = crossings.length - 1; i >= 0; i--) { - var path = crossings[i].split(); - if (path) { - if (addPath(path)) - path.getFirstSegment().setHandleIn(0, 0); - _path1.getLastSegment().setHandleOut(0, 0); - } - } - addPath(_path1); - return createResult(paths, false, path1, path2); - } - - function linkIntersections(from, to) { - var prev = from; - while (prev) { - if (prev === to) - return; - prev = prev._previous; - } - while (from._next && from._next !== to) - from = from._next; - if (!from._next) { - while (to._previous) - to = to._previous; - from._next = to; - to._previous = from; - } - } - - function clearCurveHandles(curves) { - for (var i = curves.length - 1; i >= 0; i--) - curves[i].clearHandles(); - } - - function reorientPaths(paths, isInside, clockwise) { - var length = paths && paths.length; - if (length) { - var lookup = Base.each(paths, function (path, i) { - this[path._id] = { - container: null, - winding: path.isClockwise() ? 1 : -1, - index: i - }; - }, {}), - sorted = paths.slice().sort(function (a, b) { - return abs(b.getArea()) - abs(a.getArea()); - }), - first = sorted[0]; - if (clockwise == null) - clockwise = first.isClockwise(); - for (var i = 0; i < length; i++) { - var path1 = sorted[i], - entry1 = lookup[path1._id], - point = path1.getInteriorPoint(), - containerWinding = 0; - for (var j = i - 1; j >= 0; j--) { - var path2 = sorted[j]; - if (path2.contains(point)) { - var entry2 = lookup[path2._id]; - containerWinding = entry2.winding; - entry1.winding += containerWinding; - entry1.container = entry2.exclude ? entry2.container - : path2; - break; - } - } - if (isInside(entry1.winding) === isInside(containerWinding)) { - entry1.exclude = true; - paths[entry1.index] = null; - } else { - var container = entry1.container; - path1.setClockwise(container ? !container.isClockwise() - : clockwise); - } - } - } - return paths; - } - - function divideLocations(locations, include, clearLater) { - var results = include && [], - tMin = 1e-8, - tMax = 1 - tMin, - clearHandles = false, - clearCurves = clearLater || [], - clearLookup = clearLater && {}, - renormalizeLocs, - prevCurve, - prevTime; - - function getId(curve) { - return curve._path._id + '.' + curve._segment1._index; - } - - for (var i = (clearLater && clearLater.length) - 1; i >= 0; i--) { - var curve = clearLater[i]; - if (curve._path) - clearLookup[getId(curve)] = true; - } - - for (var i = locations.length - 1; i >= 0; i--) { - var loc = locations[i], - time = loc._time, - origTime = time, - exclude = include && !include(loc), - curve = loc._curve, - segment; - if (curve) { - if (curve !== prevCurve) { - clearHandles = !curve.hasHandles() - || clearLookup && clearLookup[getId(curve)]; - renormalizeLocs = []; - prevTime = null; - prevCurve = curve; - } else if (prevTime >= tMin) { - time /= prevTime; - } - } - if (exclude) { - if (renormalizeLocs) - renormalizeLocs.push(loc); - continue; - } else if (include) { - results.unshift(loc); - } - prevTime = origTime; - if (time < tMin) { - segment = curve._segment1; - } else if (time > tMax) { - segment = curve._segment2; - } else { - var newCurve = curve.divideAtTime(time, true); - if (clearHandles) - clearCurves.push(curve, newCurve); - segment = newCurve._segment1; - for (var j = renormalizeLocs.length - 1; j >= 0; j--) { - var l = renormalizeLocs[j]; - l._time = (l._time - time) / (1 - time); - } - } - loc._setSegment(segment); - var inter = segment._intersection, - dest = loc._intersection; - if (inter) { - linkIntersections(inter, dest); - var other = inter; - while (other) { - linkIntersections(other._intersection, inter); - other = other._next; - } - } else { - segment._intersection = dest; - } - } - if (!clearLater) - clearCurveHandles(clearCurves); - return results || locations; - } - - function getWinding(point, curves, dir, closed, dontFlip) { - var ia = dir ? 1 : 0, - io = ia ^ 1, - pv = [point.x, point.y], - pa = pv[ia], - po = pv[io], - windingEpsilon = 1e-9, - qualityEpsilon = 1e-6, - paL = pa - windingEpsilon, - paR = pa + windingEpsilon, - windingL = 0, - windingR = 0, - pathWindingL = 0, - pathWindingR = 0, - onPath = false, - onAnyPath = false, - quality = 1, - roots = [], - vPrev, - vClose; - - function addWinding(v) { - var o0 = v[io + 0], - o3 = v[io + 6]; - if (po < min(o0, o3) || po > max(o0, o3)) { - return; - } - var a0 = v[ia + 0], - a1 = v[ia + 2], - a2 = v[ia + 4], - a3 = v[ia + 6]; - if (o0 === o3) { - if (a0 < paR && a3 > paL || a3 < paR && a0 > paL) { - onPath = true; - } - return; - } - var t = po === o0 ? 0 - : po === o3 ? 1 - : paL > max(a0, a1, a2, a3) || paR < min(a0, a1, a2, a3) - ? 1 - : Curve.solveCubic(v, io, po, roots, 0, 1) > 0 - ? roots[0] - : 1, - a = t === 0 ? a0 - : t === 1 ? a3 - : Curve.getPoint(v, t)[dir ? 'y' : 'x'], - winding = o0 > o3 ? 1 : -1, - windingPrev = vPrev[io] > vPrev[io + 6] ? 1 : -1, - a3Prev = vPrev[ia + 6]; - if (po !== o0) { - if (a < paL) { - pathWindingL += winding; - } else if (a > paR) { - pathWindingR += winding; - } else { - onPath = true; - } - if (a > pa - qualityEpsilon && a < pa + qualityEpsilon) - quality /= 2; - } else { - if (winding !== windingPrev) { - if (a0 < paL) { - pathWindingL += winding; - } else if (a0 > paR) { - pathWindingR += winding; - } - } else if (a0 != a3Prev) { - if (a3Prev < paR && a > paR) { - pathWindingR += winding; - onPath = true; - } else if (a3Prev > paL && a < paL) { - pathWindingL += winding; - onPath = true; - } - } - quality = 0; - } - vPrev = v; - return !dontFlip && a > paL && a < paR - && Curve.getTangent(v, t)[dir ? 'x' : 'y'] === 0 - && getWinding(point, curves, !dir, closed, true); - } - - function handleCurve(v) { - var o0 = v[io + 0], - o1 = v[io + 2], - o2 = v[io + 4], - o3 = v[io + 6]; - if (po <= max(o0, o1, o2, o3) && po >= min(o0, o1, o2, o3)) { - var a0 = v[ia + 0], - a1 = v[ia + 2], - a2 = v[ia + 4], - a3 = v[ia + 6], - monoCurves = paL > max(a0, a1, a2, a3) || - paR < min(a0, a1, a2, a3) - ? [v] : Curve.getMonoCurves(v, dir), - res; - for (var i = 0, l = monoCurves.length; i < l; i++) { - if (res = addWinding(monoCurves[i])) - return res; - } - } - } - - for (var i = 0, l = curves.length; i < l; i++) { - var curve = curves[i], - path = curve._path, - v = curve.getValues(), - res; - if (!i || curves[i - 1]._path !== path) { - vPrev = null; - if (!path._closed) { - vClose = Curve.getValues( - path.getLastCurve().getSegment2(), - curve.getSegment1(), - null, !closed); - if (vClose[io] !== vClose[io + 6]) { - vPrev = vClose; - } - } - - if (!vPrev) { - vPrev = v; - var prev = path.getLastCurve(); - while (prev && prev !== curve) { - var v2 = prev.getValues(); - if (v2[io] !== v2[io + 6]) { - vPrev = v2; - break; - } - prev = prev.getPrevious(); - } - } - } - - if (res = handleCurve(v)) - return res; - - if (i + 1 === l || curves[i + 1]._path !== path) { - if (vClose && (res = handleCurve(vClose))) - return res; - if (onPath && !pathWindingL && !pathWindingR) { - pathWindingL = pathWindingR = path.isClockwise(closed) ^ dir - ? 1 : -1; - } - windingL += pathWindingL; - windingR += pathWindingR; - pathWindingL = pathWindingR = 0; - if (onPath) { - onAnyPath = true; - onPath = false; - } - vClose = null; - } - } - windingL = abs(windingL); - windingR = abs(windingR); - return { - winding: max(windingL, windingR), - windingL: windingL, - windingR: windingR, - quality: quality, - onPath: onAnyPath - }; - } - - function propagateWinding(segment, path1, path2, curves, operator) { - var chain = [], - start = segment, - totalLength = 0, - winding; - do { - var curve = segment.getCurve(), - length = curve.getLength(); - chain.push({ segment: segment, curve: curve, length: length }); - totalLength += length; - segment = segment.getNext(); - } while (segment && !segment._intersection && segment !== start); - var offsets = [0.5, 0.25, 0.75], - winding = { winding: 0, quality: -1 }, - tMin = 1e-8, - tMax = 1 - tMin; - for (var i = 0; i < offsets.length && winding.quality < 0.5; i++) { - var length = totalLength * offsets[i]; - for (var j = 0, l = chain.length; j < l; j++) { - var entry = chain[j], - curveLength = entry.length; - if (length <= curveLength) { - var curve = entry.curve, - path = curve._path, - parent = path._parent, - operand = parent instanceof CompoundPath ? parent : path, - t = Numerical.clamp(curve.getTimeAt(length), tMin, tMax), - pt = curve.getPointAtTime(t), - dir = abs(curve.getTangentAtTime(t).y) < Math.SQRT1_2; - var wind = null; - if (operator.subtract && path2) { - var pathWinding = operand === path1 - ? path2._getWinding(pt, dir, true) - : path1._getWinding(pt, dir, true); - if (operand === path1 && pathWinding.winding || - operand === path2 && !pathWinding.winding) { - if (pathWinding.quality < 1) { - continue; - } else { - wind = { winding: 0, quality: 1 }; - } - } - } - wind = wind || getWinding(pt, curves, dir, true); - if (wind.quality > winding.quality) - winding = wind; - break; - } - length -= curveLength; - } - } - for (var j = chain.length - 1; j >= 0; j--) { - chain[j].segment._winding = winding; - } - } - - function tracePaths(segments, operator) { - var paths = [], - starts; - - function isValid(seg) { - var winding; - return !!(seg && !seg._visited && (!operator - || operator[(winding = seg._winding || {}).winding] - && !(operator.unite && winding.winding === 2 - && winding.windingL && winding.windingR))); - } - - function isStart(seg) { - if (seg) { - for (var i = 0, l = starts.length; i < l; i++) { - if (seg === starts[i]) - return true; - } - } - return false; - } - - function visitPath(path) { - var segments = path._segments; - for (var i = 0, l = segments.length; i < l; i++) { - segments[i]._visited = true; - } - } - - function getCrossingSegments(segment, collectStarts) { - var inter = segment._intersection, - start = inter, - crossings = []; - if (collectStarts) - starts = [segment]; - - function collect(inter, end) { - while (inter && inter !== end) { - var other = inter._segment, - path = other && other._path; - if (path) { - var next = other.getNext() || path.getFirstSegment(), - nextInter = next._intersection; - if (other !== segment && (isStart(other) - || isStart(next) - || next && (isValid(other) && (isValid(next) - || nextInter && isValid(nextInter._segment)))) - ) { - crossings.push(other); - } - if (collectStarts) - starts.push(other); - } - inter = inter._next; - } - } - - if (inter) { - collect(inter); - while (inter && inter._prev) - inter = inter._prev; - collect(inter, start); - } - return crossings; - } - - segments.sort(function(seg1, seg2) { - var inter1 = seg1._intersection, - inter2 = seg2._intersection, - over1 = !!(inter1 && inter1._overlap), - over2 = !!(inter2 && inter2._overlap), - path1 = seg1._path, - path2 = seg2._path; - return over1 ^ over2 - ? over1 ? 1 : -1 - : !inter1 ^ !inter2 - ? inter1 ? 1 : -1 - : path1 !== path2 - ? path1._id - path2._id - : seg1._index - seg2._index; - }); - - for (var i = 0, l = segments.length; i < l; i++) { - var seg = segments[i], - valid = isValid(seg), - path = null, - finished = false, - closed = true, - branches = [], - branch, - visited, - handleIn; - if (valid && seg._path._overlapsOnly) { - var path1 = seg._path, - path2 = seg._intersection._segment._path; - if (path1.compare(path2)) { - if (path1.getArea()) - paths.push(path1.clone(false)); - visitPath(path1); - visitPath(path2); - valid = false; - } - } - while (valid) { - var first = !path, - crossings = getCrossingSegments(seg, first), - other = crossings.shift(), - finished = !first && (isStart(seg) || isStart(other)), - cross = !finished && other; - if (first) { - path = new Path(Item.NO_INSERT); - branch = null; - } - if (finished) { - if (seg.isFirst() || seg.isLast()) - closed = seg._path._closed; - seg._visited = true; - break; - } - if (cross && branch) { - branches.push(branch); - branch = null; - } - if (!branch) { - if (cross) - crossings.push(seg); - branch = { - start: path._segments.length, - crossings: crossings, - visited: visited = [], - handleIn: handleIn - }; - } - if (cross) - seg = other; - if (!isValid(seg)) { - path.removeSegments(branch.start); - for (var j = 0, k = visited.length; j < k; j++) { - visited[j]._visited = false; - } - visited.length = 0; - do { - seg = branch && branch.crossings.shift(); - if (!seg || !seg._path) { - seg = null; - branch = branches.pop(); - if (branch) { - visited = branch.visited; - handleIn = branch.handleIn; - } - } - } while (branch && !isValid(seg)); - if (!seg) - break; - } - var next = seg.getNext(); - path.add(new Segment(seg._point, handleIn, - next && seg._handleOut)); - seg._visited = true; - visited.push(seg); - seg = next || seg._path.getFirstSegment(); - handleIn = next && next._handleIn; - } - if (finished) { - if (closed) { - path.getFirstSegment().setHandleIn(handleIn); - path.setClosed(closed); - } - if (path.getArea() !== 0) { - paths.push(path); - } - } - } - return paths; - } - - return { - _getWinding: function(point, dir, closed) { - return getWinding(point, this.getCurves(), dir, closed); - }, - - unite: function(path, options) { - return traceBoolean(this, path, 'unite', options); - }, - - intersect: function(path, options) { - return traceBoolean(this, path, 'intersect', options); - }, - - subtract: function(path, options) { - return traceBoolean(this, path, 'subtract', options); - }, - - exclude: function(path, options) { - return traceBoolean(this, path, 'exclude', options); - }, - - divide: function(path, options) { - return options && (options.trace == false || options.stroke) - ? splitBoolean(this, path, 'divide') - : createResult([ - this.subtract(path, options), - this.intersect(path, options) - ], true, this, path, options); - }, - - resolveCrossings: function() { - var children = this._children, - paths = children || [this]; - - function hasOverlap(seg, path) { - var inter = seg && seg._intersection; - return inter && inter._overlap && inter._path === path; - } - - var hasOverlaps = false, - hasCrossings = false, - intersections = this.getIntersections(null, function(inter) { - return inter.hasOverlap() && (hasOverlaps = true) || - inter.isCrossing() && (hasCrossings = true); - }), - clearCurves = hasOverlaps && hasCrossings && []; - intersections = CurveLocation.expand(intersections); - if (hasOverlaps) { - var overlaps = divideLocations(intersections, function(inter) { - return inter.hasOverlap(); - }, clearCurves); - for (var i = overlaps.length - 1; i >= 0; i--) { - var overlap = overlaps[i], - path = overlap._path, - seg = overlap._segment, - prev = seg.getPrevious(), - next = seg.getNext(); - if (hasOverlap(prev, path) && hasOverlap(next, path)) { - seg.remove(); - prev._handleOut._set(0, 0); - next._handleIn._set(0, 0); - if (prev !== seg && !prev.getCurve().hasLength()) { - next._handleIn.set(prev._handleIn); - prev.remove(); - } - } - } - } - if (hasCrossings) { - divideLocations(intersections, hasOverlaps && function(inter) { - var curve1 = inter.getCurve(), - seg1 = inter.getSegment(), - other = inter._intersection, - curve2 = other._curve, - seg2 = other._segment; - if (curve1 && curve2 && curve1._path && curve2._path) - return true; - if (seg1) - seg1._intersection = null; - if (seg2) - seg2._intersection = null; - }, clearCurves); - if (clearCurves) - clearCurveHandles(clearCurves); - paths = tracePaths(Base.each(paths, function(path) { - Base.push(this, path._segments); - }, [])); - } - var length = paths.length, - item; - if (length > 1 && children) { - if (paths !== children) - this.setChildren(paths); - item = this; - } else if (length === 1 && !children) { - if (paths[0] !== this) - this.setSegments(paths[0].removeSegments()); - item = this; - } - if (!item) { - item = new CompoundPath(Item.NO_INSERT); - item.addChildren(paths); - item = item.reduce(); - item.copyAttributes(this); - this.replaceWith(item); - } - return item; - }, - - reorient: function(nonZero, clockwise) { - var children = this._children; - if (children && children.length) { - this.setChildren(reorientPaths(this.removeChildren(), - function(w) { - return !!(nonZero ? w : w & 1); - }, - clockwise)); - } else if (clockwise !== undefined) { - this.setClockwise(clockwise); - } - return this; - }, - - getInteriorPoint: function() { - var bounds = this.getBounds(), - point = bounds.getCenter(true); - if (!this.contains(point)) { - var curves = this.getCurves(), - y = point.y, - intercepts = [], - roots = []; - for (var i = 0, l = curves.length; i < l; i++) { - var v = curves[i].getValues(), - o0 = v[1], - o1 = v[3], - o2 = v[5], - o3 = v[7]; - if (y >= min(o0, o1, o2, o3) && y <= max(o0, o1, o2, o3)) { - var monoCurves = Curve.getMonoCurves(v); - for (var j = 0, m = monoCurves.length; j < m; j++) { - var mv = monoCurves[j], - mo0 = mv[1], - mo3 = mv[7]; - if ((mo0 !== mo3) && - (y >= mo0 && y <= mo3 || y >= mo3 && y <= mo0)){ - var x = y === mo0 ? mv[0] - : y === mo3 ? mv[6] - : Curve.solveCubic(mv, 1, y, roots, 0, 1) - === 1 - ? Curve.getPoint(mv, roots[0]).x - : (mv[0] + mv[6]) / 2; - intercepts.push(x); - } - } - } - } - if (intercepts.length > 1) { - intercepts.sort(function(a, b) { return a - b; }); - point.x = (intercepts[0] + intercepts[1]) / 2; - } - } - return point; - } - }; -}); - -var PathFlattener = Base.extend({ - _class: 'PathFlattener', - - initialize: function(path, flatness, maxRecursion, ignoreStraight, matrix) { - var curves = [], - parts = [], - length = 0, - minSpan = 1 / (maxRecursion || 32), - segments = path._segments, - segment1 = segments[0], - segment2; - - function addCurve(segment1, segment2) { - var curve = Curve.getValues(segment1, segment2, matrix); - curves.push(curve); - computeParts(curve, segment1._index, 0, 1); - } - - function computeParts(curve, index, t1, t2) { - if ((t2 - t1) > minSpan - && !(ignoreStraight && Curve.isStraight(curve)) - && !Curve.isFlatEnough(curve, flatness || 0.25)) { - var halves = Curve.subdivide(curve, 0.5), - tMid = (t1 + t2) / 2; - computeParts(halves[0], index, t1, tMid); - computeParts(halves[1], index, tMid, t2); - } else { - var dx = curve[6] - curve[0], - dy = curve[7] - curve[1], - dist = Math.sqrt(dx * dx + dy * dy); - if (dist > 0) { - length += dist; - parts.push({ - offset: length, - curve: curve, - index: index, - time: t2, - }); - } - } - } - - for (var i = 1, l = segments.length; i < l; i++) { - segment2 = segments[i]; - addCurve(segment1, segment2); - segment1 = segment2; - } - if (path._closed) - addCurve(segment2 || segment1, segments[0]); - this.curves = curves; - this.parts = parts; - this.length = length; - this.index = 0; - }, - - _get: function(offset) { - var parts = this.parts, - length = parts.length, - start, - i, j = this.index; - for (;;) { - i = j; - if (!j || parts[--j].offset < offset) - break; - } - for (; i < length; i++) { - var part = parts[i]; - if (part.offset >= offset) { - this.index = i; - var prev = parts[i - 1], - prevTime = prev && prev.index === part.index ? prev.time : 0, - prevOffset = prev ? prev.offset : 0; - return { - index: part.index, - time: prevTime + (part.time - prevTime) - * (offset - prevOffset) / (part.offset - prevOffset) - }; - } - } - return { - index: parts[length - 1].index, - time: 1 - }; - }, - - drawPart: function(ctx, from, to) { - var start = this._get(from), - end = this._get(to); - for (var i = start.index, l = end.index; i <= l; i++) { - var curve = Curve.getPart(this.curves[i], - i === start.index ? start.time : 0, - i === end.index ? end.time : 1); - if (i === start.index) - ctx.moveTo(curve[0], curve[1]); - ctx.bezierCurveTo.apply(ctx, curve.slice(2)); - } - } -}, Base.each(Curve._evaluateMethods, - function(name) { - this[name + 'At'] = function(offset) { - var param = this._get(offset); - return Curve[name](this.curves[param.index], param.time); - }; - }, {}) -); - -var PathFitter = Base.extend({ - initialize: function(path) { - var points = this.points = [], - segments = path._segments, - closed = path._closed; - for (var i = 0, prev, l = segments.length; i < l; i++) { - var point = segments[i].point; - if (!prev || !prev.equals(point)) { - points.push(prev = point.clone()); - } - } - if (closed) { - points.unshift(points[points.length - 1]); - points.push(points[1]); - } - this.closed = closed; - }, - - fit: function(error) { - var points = this.points, - length = points.length, - segments = null; - if (length > 0) { - segments = [new Segment(points[0])]; - if (length > 1) { - this.fitCubic(segments, error, 0, length - 1, - points[1].subtract(points[0]), - points[length - 2].subtract(points[length - 1])); - if (this.closed) { - segments.shift(); - segments.pop(); - } - } - } - return segments; - }, - - fitCubic: function(segments, error, first, last, tan1, tan2) { - var points = this.points; - if (last - first === 1) { - var pt1 = points[first], - pt2 = points[last], - dist = pt1.getDistance(pt2) / 3; - this.addCurve(segments, [pt1, pt1.add(tan1.normalize(dist)), - pt2.add(tan2.normalize(dist)), pt2]); - return; - } - var uPrime = this.chordLengthParameterize(first, last), - maxError = Math.max(error, error * error), - split, - parametersInOrder = true; - for (var i = 0; i <= 4; i++) { - var curve = this.generateBezier(first, last, uPrime, tan1, tan2); - var max = this.findMaxError(first, last, curve, uPrime); - if (max.error < error && parametersInOrder) { - this.addCurve(segments, curve); - return; - } - split = max.index; - if (max.error >= maxError) - break; - parametersInOrder = this.reparameterize(first, last, uPrime, curve); - maxError = max.error; - } - var tanCenter = points[split - 1].subtract(points[split + 1]); - this.fitCubic(segments, error, first, split, tan1, tanCenter); - this.fitCubic(segments, error, split, last, tanCenter.negate(), tan2); - }, - - addCurve: function(segments, curve) { - var prev = segments[segments.length - 1]; - prev.setHandleOut(curve[1].subtract(curve[0])); - segments.push(new Segment(curve[3], curve[2].subtract(curve[3]))); - }, - - generateBezier: function(first, last, uPrime, tan1, tan2) { - var epsilon = 1e-12, - abs = Math.abs, - points = this.points, - pt1 = points[first], - pt2 = points[last], - C = [[0, 0], [0, 0]], - X = [0, 0]; - - for (var i = 0, l = last - first + 1; i < l; i++) { - var u = uPrime[i], - t = 1 - u, - b = 3 * u * t, - b0 = t * t * t, - b1 = b * t, - b2 = b * u, - b3 = u * u * u, - a1 = tan1.normalize(b1), - a2 = tan2.normalize(b2), - tmp = points[first + i] - .subtract(pt1.multiply(b0 + b1)) - .subtract(pt2.multiply(b2 + b3)); - C[0][0] += a1.dot(a1); - C[0][1] += a1.dot(a2); - C[1][0] = C[0][1]; - C[1][1] += a2.dot(a2); - X[0] += a1.dot(tmp); - X[1] += a2.dot(tmp); - } - - var detC0C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1], - alpha1, - alpha2; - if (abs(detC0C1) > epsilon) { - var detC0X = C[0][0] * X[1] - C[1][0] * X[0], - detXC1 = X[0] * C[1][1] - X[1] * C[0][1]; - alpha1 = detXC1 / detC0C1; - alpha2 = detC0X / detC0C1; - } else { - var c0 = C[0][0] + C[0][1], - c1 = C[1][0] + C[1][1]; - alpha1 = alpha2 = abs(c0) > epsilon ? X[0] / c0 - : abs(c1) > epsilon ? X[1] / c1 - : 0; - } - - var segLength = pt2.getDistance(pt1), - eps = epsilon * segLength, - handle1, - handle2; - if (alpha1 < eps || alpha2 < eps) { - alpha1 = alpha2 = segLength / 3; - } else { - var line = pt2.subtract(pt1); - handle1 = tan1.normalize(alpha1); - handle2 = tan2.normalize(alpha2); - if (handle1.dot(line) - handle2.dot(line) > segLength * segLength) { - alpha1 = alpha2 = segLength / 3; - handle1 = handle2 = null; - } - } - - return [pt1, - pt1.add(handle1 || tan1.normalize(alpha1)), - pt2.add(handle2 || tan2.normalize(alpha2)), - pt2]; - }, - - reparameterize: function(first, last, u, curve) { - for (var i = first; i <= last; i++) { - u[i - first] = this.findRoot(curve, this.points[i], u[i - first]); - } - for (var i = 1, l = u.length; i < l; i++) { - if (u[i] <= u[i - 1]) - return false; - } - return true; - }, - - findRoot: function(curve, point, u) { - var curve1 = [], - curve2 = []; - for (var i = 0; i <= 2; i++) { - curve1[i] = curve[i + 1].subtract(curve[i]).multiply(3); - } - for (var i = 0; i <= 1; i++) { - curve2[i] = curve1[i + 1].subtract(curve1[i]).multiply(2); - } - var pt = this.evaluate(3, curve, u), - pt1 = this.evaluate(2, curve1, u), - pt2 = this.evaluate(1, curve2, u), - diff = pt.subtract(point), - df = pt1.dot(pt1) + diff.dot(pt2); - return Numerical.isZero(df) ? u : u - diff.dot(pt1) / df; - }, - - evaluate: function(degree, curve, t) { - var tmp = curve.slice(); - for (var i = 1; i <= degree; i++) { - for (var j = 0; j <= degree - i; j++) { - tmp[j] = tmp[j].multiply(1 - t).add(tmp[j + 1].multiply(t)); - } - } - return tmp[0]; - }, - - chordLengthParameterize: function(first, last) { - var u = [0]; - for (var i = first + 1; i <= last; i++) { - u[i - first] = u[i - first - 1] - + this.points[i].getDistance(this.points[i - 1]); - } - for (var i = 1, m = last - first; i <= m; i++) { - u[i] /= u[m]; - } - return u; - }, - - findMaxError: function(first, last, curve, u) { - var index = Math.floor((last - first + 1) / 2), - maxDist = 0; - for (var i = first + 1; i < last; i++) { - var P = this.evaluate(3, curve, u[i - first]); - var v = P.subtract(this.points[i]); - var dist = v.x * v.x + v.y * v.y; - if (dist >= maxDist) { - maxDist = dist; - index = i; - } - } - return { - error: maxDist, - index: index - }; - } -}); - -var TextItem = Item.extend({ - _class: 'TextItem', - _applyMatrix: false, - _canApplyMatrix: false, - _serializeFields: { - content: null - }, - _boundsOptions: { stroke: false, handle: false }, - - initialize: function TextItem(arg) { - this._content = ''; - this._lines = []; - var hasProps = arg && Base.isPlainObject(arg) - && arg.x === undefined && arg.y === undefined; - this._initialize(hasProps && arg, !hasProps && Point.read(arguments)); - }, - - _equals: function(item) { - return this._content === item._content; - }, - - copyContent: function(source) { - this.setContent(source._content); - }, - - getContent: function() { - return this._content; - }, - - setContent: function(content) { - this._content = '' + content; - this._lines = this._content.split(/\r\n|\n|\r/mg); - this._changed(521); - }, - - isEmpty: function() { - return !this._content; - }, - - getCharacterStyle: '#getStyle', - setCharacterStyle: '#setStyle', - - getParagraphStyle: '#getStyle', - setParagraphStyle: '#setStyle' -}); - -var PointText = TextItem.extend({ - _class: 'PointText', - - initialize: function PointText() { - TextItem.apply(this, arguments); - }, - - getPoint: function() { - var point = this._matrix.getTranslation(); - return new LinkedPoint(point.x, point.y, this, 'setPoint'); - }, - - setPoint: function() { - var point = Point.read(arguments); - this.translate(point.subtract(this._matrix.getTranslation())); - }, - - _draw: function(ctx, param, viewMatrix) { - if (!this._content) - return; - this._setStyles(ctx, param, viewMatrix); - var lines = this._lines, - style = this._style, - hasFill = style.hasFill(), - hasStroke = style.hasStroke(), - leading = style.getLeading(), - shadowColor = ctx.shadowColor; - ctx.font = style.getFontStyle(); - ctx.textAlign = style.getJustification(); - for (var i = 0, l = lines.length; i < l; i++) { - ctx.shadowColor = shadowColor; - var line = lines[i]; - if (hasFill) { - ctx.fillText(line, 0, 0); - ctx.shadowColor = 'rgba(0,0,0,0)'; - } - if (hasStroke) - ctx.strokeText(line, 0, 0); - ctx.translate(0, leading); - } - }, - - _getBounds: function(matrix, options) { - var style = this._style, - lines = this._lines, - numLines = lines.length, - justification = style.getJustification(), - leading = style.getLeading(), - width = this.getView().getTextWidth(style.getFontStyle(), lines), - x = 0; - if (justification !== 'left') - x -= width / (justification === 'center' ? 2: 1); - var rect = new Rectangle(x, - numLines ? - 0.75 * leading : 0, - width, numLines * leading); - return matrix ? matrix._transformBounds(rect, rect) : rect; - } -}); - -var Color = Base.extend(new function() { - var types = { - gray: ['gray'], - rgb: ['red', 'green', 'blue'], - hsb: ['hue', 'saturation', 'brightness'], - hsl: ['hue', 'saturation', 'lightness'], - gradient: ['gradient', 'origin', 'destination', 'highlight'] - }; - - var componentParsers = {}, - namedColors = { - transparent: [0, 0, 0, 0] - }, - colorCtx; - - function fromCSS(string) { - var match = string.match( - /^#([\da-f]{2})([\da-f]{2})([\da-f]{2})([\da-f]{2})?$/i - ) || string.match( - /^#([\da-f])([\da-f])([\da-f])([\da-f])?$/i - ), - type = 'rgb', - components; - if (match) { - var amount = match[4] ? 4 : 3; - components = new Array(amount); - for (var i = 0; i < amount; i++) { - var value = match[i + 1]; - components[i] = parseInt(value.length == 1 - ? value + value : value, 16) / 255; - } - } else if (match = string.match(/^(rgb|hsl)a?\((.*)\)$/)) { - type = match[1]; - components = match[2].split(/[,\s]+/g); - var isHSL = type === 'hsl'; - for (var i = 0, l = Math.min(components.length, 4); i < l; i++) { - var component = components[i]; - var value = parseFloat(component); - if (isHSL) { - if (i === 0) { - var unit = component.match(/([a-z]*)$/)[1]; - value *= ({ - turn: 360, - rad: 180 / Math.PI, - grad: 0.9 - }[unit] || 1); - } else if (i < 3) { - value /= 100; - } - } else if (i < 3) { - value /= 255; - } - components[i] = value; - } - } else { - var color = namedColors[string]; - if (!color) { - if (window) { - if (!colorCtx) { - colorCtx = CanvasProvider.getContext(1, 1); - colorCtx.globalCompositeOperation = 'copy'; - } - colorCtx.fillStyle = 'rgba(0,0,0,0)'; - colorCtx.fillStyle = string; - colorCtx.fillRect(0, 0, 1, 1); - var data = colorCtx.getImageData(0, 0, 1, 1).data; - color = namedColors[string] = [ - data[0] / 255, - data[1] / 255, - data[2] / 255 - ]; - } else { - color = [0, 0, 0]; - } - } - components = color.slice(); - } - return [type, components]; - } - - var hsbIndices = [ - [0, 3, 1], - [2, 0, 1], - [1, 0, 3], - [1, 2, 0], - [3, 1, 0], - [0, 1, 2] - ]; - - var converters = { - 'rgb-hsb': function(r, g, b) { - var max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - h = delta === 0 ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60; - return [h, max === 0 ? 0 : delta / max, max]; - }, - - 'hsb-rgb': function(h, s, b) { - h = (((h / 60) % 6) + 6) % 6; - var i = Math.floor(h), - f = h - i, - i = hsbIndices[i], - v = [ - b, - b * (1 - s), - b * (1 - s * f), - b * (1 - s * (1 - f)) - ]; - return [v[i[0]], v[i[1]], v[i[2]]]; - }, - - 'rgb-hsl': function(r, g, b) { - var max = Math.max(r, g, b), - min = Math.min(r, g, b), - delta = max - min, - achromatic = delta === 0, - h = achromatic ? 0 - : ( max == r ? (g - b) / delta + (g < b ? 6 : 0) - : max == g ? (b - r) / delta + 2 - : (r - g) / delta + 4) * 60, - l = (max + min) / 2, - s = achromatic ? 0 : l < 0.5 - ? delta / (max + min) - : delta / (2 - max - min); - return [h, s, l]; - }, - - 'hsl-rgb': function(h, s, l) { - h = (((h / 360) % 1) + 1) % 1; - if (s === 0) - return [l, l, l]; - var t3s = [ h + 1 / 3, h, h - 1 / 3 ], - t2 = l < 0.5 ? l * (1 + s) : l + s - l * s, - t1 = 2 * l - t2, - c = []; - for (var i = 0; i < 3; i++) { - var t3 = t3s[i]; - if (t3 < 0) t3 += 1; - if (t3 > 1) t3 -= 1; - c[i] = 6 * t3 < 1 - ? t1 + (t2 - t1) * 6 * t3 - : 2 * t3 < 1 - ? t2 - : 3 * t3 < 2 - ? t1 + (t2 - t1) * ((2 / 3) - t3) * 6 - : t1; - } - return c; - }, - - 'rgb-gray': function(r, g, b) { - return [r * 0.2989 + g * 0.587 + b * 0.114]; - }, - - 'gray-rgb': function(g) { - return [g, g, g]; - }, - - 'gray-hsb': function(g) { - return [0, 0, g]; - }, - - 'gray-hsl': function(g) { - return [0, 0, g]; - }, - - 'gradient-rgb': function() { - return []; - }, - - 'rgb-gradient': function() { - return []; - } - - }; - - return Base.each(types, function(properties, type) { - componentParsers[type] = []; - Base.each(properties, function(name, index) { - var part = Base.capitalize(name), - hasOverlap = /^(hue|saturation)$/.test(name), - parser = componentParsers[type][index] = type === 'gradient' - ? name === 'gradient' - ? function(value) { - var current = this._components[0]; - value = Gradient.read( - Array.isArray(value) - ? value - : arguments, 0, { readNull: true } - ); - if (current !== value) { - if (current) - current._removeOwner(this); - if (value) - value._addOwner(this); - } - return value; - } - : function() { - return Point.read(arguments, 0, { - readNull: name === 'highlight', - clone: true - }); - } - : function(value) { - return value == null || isNaN(value) ? 0 : +value; - }; - this['get' + part] = function() { - return this._type === type - || hasOverlap && /^hs[bl]$/.test(this._type) - ? this._components[index] - : this._convert(type)[index]; - }; - - this['set' + part] = function(value) { - if (this._type !== type - && !(hasOverlap && /^hs[bl]$/.test(this._type))) { - this._components = this._convert(type); - this._properties = types[type]; - this._type = type; - } - this._components[index] = parser.call(this, value); - this._changed(); - }; - }, this); - }, { - _class: 'Color', - _readIndex: true, - - initialize: function Color(arg) { - var args = arguments, - reading = this.__read, - read = 0, - type, - components, - alpha, - values; - if (Array.isArray(arg)) { - args = arg; - arg = args[0]; - } - var argType = arg != null && typeof arg; - if (argType === 'string' && arg in types) { - type = arg; - arg = args[1]; - if (Array.isArray(arg)) { - components = arg; - alpha = args[2]; - } else { - if (reading) - read = 1; - args = Base.slice(args, 1); - argType = typeof arg; - } - } - if (!components) { - values = argType === 'number' - ? args - : argType === 'object' && arg.length != null - ? arg - : null; - if (values) { - if (!type) - type = values.length >= 3 - ? 'rgb' - : 'gray'; - var length = types[type].length; - alpha = values[length]; - if (reading) { - read += values === arguments - ? length + (alpha != null ? 1 : 0) - : 1; - } - if (values.length > length) - values = Base.slice(values, 0, length); - } else if (argType === 'string') { - var converted = fromCSS(arg); - type = converted[0]; - components = converted[1]; - if (components.length === 4) { - alpha = components[3]; - components.length--; - } - } else if (argType === 'object') { - if (arg.constructor === Color) { - type = arg._type; - components = arg._components.slice(); - alpha = arg._alpha; - if (type === 'gradient') { - for (var i = 1, l = components.length; i < l; i++) { - var point = components[i]; - if (point) - components[i] = point.clone(); - } - } - } else if (arg.constructor === Gradient) { - type = 'gradient'; - values = args; - } else { - type = 'hue' in arg - ? 'lightness' in arg - ? 'hsl' - : 'hsb' - : 'gradient' in arg || 'stops' in arg - || 'radial' in arg - ? 'gradient' - : 'gray' in arg - ? 'gray' - : 'rgb'; - var properties = types[type], - parsers = componentParsers[type]; - this._components = components = []; - for (var i = 0, l = properties.length; i < l; i++) { - var value = arg[properties[i]]; - if (value == null && !i && type === 'gradient' - && 'stops' in arg) { - value = { - stops: arg.stops, - radial: arg.radial - }; - } - value = parsers[i].call(this, value); - if (value != null) - components[i] = value; - } - alpha = arg.alpha; - } - } - if (reading && type) - read = 1; - } - this._type = type || 'rgb'; - if (!components) { - this._components = components = []; - var parsers = componentParsers[this._type]; - for (var i = 0, l = parsers.length; i < l; i++) { - var value = parsers[i].call(this, values && values[i]); - if (value != null) - components[i] = value; - } - } - this._components = components; - this._properties = types[this._type]; - this._alpha = alpha; - if (reading) - this.__read = read; - return this; - }, - - set: '#initialize', - - _serialize: function(options, dictionary) { - var components = this.getComponents(); - return Base.serialize( - /^(gray|rgb)$/.test(this._type) - ? components - : [this._type].concat(components), - options, true, dictionary); - }, - - _changed: function() { - this._canvasStyle = null; - if (this._owner) - this._owner._changed(129); - }, - - _convert: function(type) { - var converter; - return this._type === type - ? this._components.slice() - : (converter = converters[this._type + '-' + type]) - ? converter.apply(this, this._components) - : converters['rgb-' + type].apply(this, - converters[this._type + '-rgb'].apply(this, - this._components)); - }, - - convert: function(type) { - return new Color(type, this._convert(type), this._alpha); - }, - - getType: function() { - return this._type; - }, - - setType: function(type) { - this._components = this._convert(type); - this._properties = types[type]; - this._type = type; - }, - - getComponents: function() { - var components = this._components.slice(); - if (this._alpha != null) - components.push(this._alpha); - return components; - }, - - getAlpha: function() { - return this._alpha != null ? this._alpha : 1; - }, - - setAlpha: function(alpha) { - this._alpha = alpha == null ? null : Math.min(Math.max(alpha, 0), 1); - this._changed(); - }, - - hasAlpha: function() { - return this._alpha != null; - }, - - equals: function(color) { - var col = Base.isPlainValue(color, true) - ? Color.read(arguments) - : color; - return col === this || col && this._class === col._class - && this._type === col._type - && this.getAlpha() === col.getAlpha() - && Base.equals(this._components, col._components) - || false; - }, - - toString: function() { - var properties = this._properties, - parts = [], - isGradient = this._type === 'gradient', - f = Formatter.instance; - for (var i = 0, l = properties.length; i < l; i++) { - var value = this._components[i]; - if (value != null) - parts.push(properties[i] + ': ' - + (isGradient ? value : f.number(value))); - } - if (this._alpha != null) - parts.push('alpha: ' + f.number(this._alpha)); - return '{ ' + parts.join(', ') + ' }'; - }, - - toCSS: function(hex) { - var components = this._convert('rgb'), - alpha = hex || this._alpha == null ? 1 : this._alpha; - function convert(val) { - return Math.round((val < 0 ? 0 : val > 1 ? 1 : val) * 255); - } - components = [ - convert(components[0]), - convert(components[1]), - convert(components[2]) - ]; - if (alpha < 1) - components.push(alpha < 0 ? 0 : alpha); - return hex - ? '#' + ((1 << 24) + (components[0] << 16) - + (components[1] << 8) - + components[2]).toString(16).slice(1) - : (components.length == 4 ? 'rgba(' : 'rgb(') - + components.join(',') + ')'; - }, - - toCanvasStyle: function(ctx, matrix) { - if (this._canvasStyle) - return this._canvasStyle; - if (this._type !== 'gradient') - return this._canvasStyle = this.toCSS(); - var components = this._components, - gradient = components[0], - stops = gradient._stops, - origin = components[1], - destination = components[2], - highlight = components[3], - inverse = matrix && matrix.inverted(), - canvasGradient; - if (inverse) { - origin = inverse._transformPoint(origin); - destination = inverse._transformPoint(destination); - if (highlight) - highlight = inverse._transformPoint(highlight); - } - if (gradient._radial) { - var radius = destination.getDistance(origin); - if (highlight) { - var vector = highlight.subtract(origin); - if (vector.getLength() > radius) - highlight = origin.add(vector.normalize(radius - 0.1)); - } - var start = highlight || origin; - canvasGradient = ctx.createRadialGradient(start.x, start.y, - 0, origin.x, origin.y, radius); - } else { - canvasGradient = ctx.createLinearGradient(origin.x, origin.y, - destination.x, destination.y); - } - for (var i = 0, l = stops.length; i < l; i++) { - var stop = stops[i], - offset = stop._offset; - canvasGradient.addColorStop( - offset == null ? i / (l - 1) : offset, - stop._color.toCanvasStyle()); - } - return this._canvasStyle = canvasGradient; - }, - - transform: function(matrix) { - if (this._type === 'gradient') { - var components = this._components; - for (var i = 1, l = components.length; i < l; i++) { - var point = components[i]; - matrix._transformPoint(point, point, true); - } - this._changed(); - } - }, - - statics: { - _types: types, - - random: function() { - var random = Math.random; - return new Color(random(), random(), random()); - } - } - }); -}, -new function() { - var operators = { - add: function(a, b) { - return a + b; - }, - - subtract: function(a, b) { - return a - b; - }, - - multiply: function(a, b) { - return a * b; - }, - - divide: function(a, b) { - return a / b; - } - }; - - return Base.each(operators, function(operator, name) { - this[name] = function(color) { - color = Color.read(arguments); - var type = this._type, - components1 = this._components, - components2 = color._convert(type); - for (var i = 0, l = components1.length; i < l; i++) - components2[i] = operator(components1[i], components2[i]); - return new Color(type, components2, - this._alpha != null - ? operator(this._alpha, color.getAlpha()) - : null); - }; - }, { - }); -}); - -var Gradient = Base.extend({ - _class: 'Gradient', - - initialize: function Gradient(stops, radial) { - this._id = UID.get(); - if (stops && Base.isPlainObject(stops)) { - this.set(stops); - stops = radial = null; - } - if (this._stops == null) { - this.setStops(stops || ['white', 'black']); - } - if (this._radial == null) { - this.setRadial(typeof radial === 'string' && radial === 'radial' - || radial || false); - } - }, - - _serialize: function(options, dictionary) { - return dictionary.add(this, function() { - return Base.serialize([this._stops, this._radial], - options, true, dictionary); - }); - }, - - _changed: function() { - for (var i = 0, l = this._owners && this._owners.length; i < l; i++) { - this._owners[i]._changed(); - } - }, - - _addOwner: function(color) { - if (!this._owners) - this._owners = []; - this._owners.push(color); - }, - - _removeOwner: function(color) { - var index = this._owners ? this._owners.indexOf(color) : -1; - if (index != -1) { - this._owners.splice(index, 1); - if (!this._owners.length) - this._owners = undefined; - } - }, - - clone: function() { - var stops = []; - for (var i = 0, l = this._stops.length; i < l; i++) { - stops[i] = this._stops[i].clone(); - } - return new Gradient(stops, this._radial); - }, - - getStops: function() { - return this._stops; - }, - - setStops: function(stops) { - if (stops.length < 2) { - throw new Error( - 'Gradient stop list needs to contain at least two stops.'); - } - var _stops = this._stops; - if (_stops) { - for (var i = 0, l = _stops.length; i < l; i++) - _stops[i]._owner = undefined; - } - _stops = this._stops = GradientStop.readList(stops, 0, { clone: true }); - for (var i = 0, l = _stops.length; i < l; i++) - _stops[i]._owner = this; - this._changed(); - }, - - getRadial: function() { - return this._radial; - }, - - setRadial: function(radial) { - this._radial = radial; - this._changed(); - }, - - equals: function(gradient) { - if (gradient === this) - return true; - if (gradient && this._class === gradient._class) { - var stops1 = this._stops, - stops2 = gradient._stops, - length = stops1.length; - if (length === stops2.length) { - for (var i = 0; i < length; i++) { - if (!stops1[i].equals(stops2[i])) - return false; - } - return true; - } - } - return false; - } -}); - -var GradientStop = Base.extend({ - _class: 'GradientStop', - - initialize: function GradientStop(arg0, arg1) { - var color = arg0, - offset = arg1; - if (typeof arg0 === 'object' && arg1 === undefined) { - if (Array.isArray(arg0) && typeof arg0[0] !== 'number') { - color = arg0[0]; - offset = arg0[1]; - } else if ('color' in arg0 || 'offset' in arg0 - || 'rampPoint' in arg0) { - color = arg0.color; - offset = arg0.offset || arg0.rampPoint || 0; - } - } - this.setColor(color); - this.setOffset(offset); - }, - - clone: function() { - return new GradientStop(this._color.clone(), this._offset); - }, - - _serialize: function(options, dictionary) { - var color = this._color, - offset = this._offset; - return Base.serialize(offset == null ? [color] : [color, offset], - options, true, dictionary); - }, - - _changed: function() { - if (this._owner) - this._owner._changed(129); - }, - - getOffset: function() { - return this._offset; - }, - - setOffset: function(offset) { - this._offset = offset; - this._changed(); - }, - - getRampPoint: '#getOffset', - setRampPoint: '#setOffset', - - getColor: function() { - return this._color; - }, - - setColor: function() { - var color = Color.read(arguments, 0, { clone: true }); - if (color) - color._owner = this; - this._color = color; - this._changed(); - }, - - equals: function(stop) { - return stop === this || stop && this._class === stop._class - && this._color.equals(stop._color) - && this._offset == stop._offset - || false; - } -}); - -var Style = Base.extend(new function() { - var itemDefaults = { - fillColor: null, - fillRule: 'nonzero', - strokeColor: null, - strokeWidth: 1, - strokeCap: 'butt', - strokeJoin: 'miter', - strokeScaling: true, - miterLimit: 10, - dashOffset: 0, - dashArray: [], - shadowColor: null, - shadowBlur: 0, - shadowOffset: new Point(), - selectedColor: null - }, - groupDefaults = Base.set({}, itemDefaults, { - fontFamily: 'sans-serif', - fontWeight: 'normal', - fontSize: 12, - leading: null, - justification: 'left' - }), - textDefaults = Base.set({}, groupDefaults, { - fillColor: new Color() - }), - flags = { - strokeWidth: 193, - strokeCap: 193, - strokeJoin: 193, - strokeScaling: 201, - miterLimit: 193, - fontFamily: 9, - fontWeight: 9, - fontSize: 9, - font: 9, - leading: 9, - justification: 9 - }, - item = { - beans: true - }, - fields = { - _class: 'Style', - beans: true, - - initialize: function Style(style, _owner, _project) { - this._values = {}; - this._owner = _owner; - this._project = _owner && _owner._project || _project - || paper.project; - this._defaults = !_owner || _owner instanceof Group ? groupDefaults - : _owner instanceof TextItem ? textDefaults - : itemDefaults; - if (style) - this.set(style); - } - }; - - Base.each(groupDefaults, function(value, key) { - var isColor = /Color$/.test(key), - isPoint = key === 'shadowOffset', - part = Base.capitalize(key), - flag = flags[key], - set = 'set' + part, - get = 'get' + part; - - fields[set] = function(value) { - var owner = this._owner, - children = owner && owner._children; - if (children && children.length > 0 - && !(owner instanceof CompoundPath)) { - for (var i = 0, l = children.length; i < l; i++) - children[i]._style[set](value); - } else if (key in this._defaults) { - var old = this._values[key]; - if (old !== value) { - if (isColor) { - if (old && old._owner !== undefined) { - old._owner = undefined; - old._canvasStyle = null; - } - if (value && value.constructor === Color) { - if (value._owner) - value = value.clone(); - value._owner = owner; - } - } - this._values[key] = value; - if (owner) - owner._changed(flag || 129); - } - } - }; - - fields[get] = function(_dontMerge) { - var owner = this._owner, - children = owner && owner._children, - value; - if (key in this._defaults && (!children || !children.length - || _dontMerge || owner instanceof CompoundPath)) { - var value = this._values[key]; - if (value === undefined) { - value = this._defaults[key]; - if (value && value.clone) - value = value.clone(); - } else { - var ctor = isColor ? Color : isPoint ? Point : null; - if (ctor && !(value && value.constructor === ctor)) { - this._values[key] = value = ctor.read([value], 0, - { readNull: true, clone: true }); - if (value && isColor) - value._owner = owner; - } - } - } else if (children) { - for (var i = 0, l = children.length; i < l; i++) { - var childValue = children[i]._style[get](); - if (!i) { - value = childValue; - } else if (!Base.equals(value, childValue)) { - return undefined; - } - } - } - return value; - }; - - item[get] = function(_dontMerge) { - return this._style[get](_dontMerge); - }; - - item[set] = function(value) { - this._style[set](value); - }; - }); - - Base.each({ - Font: 'FontFamily', - WindingRule: 'FillRule' - }, function(value, key) { - var get = 'get' + key, - set = 'set' + key; - fields[get] = item[get] = '#get' + value; - fields[set] = item[set] = '#set' + value; - }); - - Item.inject(item); - return fields; -}, { - set: function(style) { - var isStyle = style instanceof Style, - values = isStyle ? style._values : style; - if (values) { - for (var key in values) { - if (key in this._defaults) { - var value = values[key]; - this[key] = value && isStyle && value.clone - ? value.clone() : value; - } - } - } - }, - - equals: function(style) { - function compare(style1, style2, secondary) { - var values1 = style1._values, - values2 = style2._values, - defaults2 = style2._defaults; - for (var key in values1) { - var value1 = values1[key], - value2 = values2[key]; - if (!(secondary && key in values2) && !Base.equals(value1, - value2 === undefined ? defaults2[key] : value2)) - return false; - } - return true; - } - - return style === this || style && this._class === style._class - && compare(this, style) - && compare(style, this, true) - || false; - }, - - _dispose: function() { - var color; - color = this.getFillColor(); - if (color) color._canvasStyle = null; - color = this.getStrokeColor(); - if (color) color._canvasStyle = null; - color = this.getShadowColor(); - if (color) color._canvasStyle = null; - }, - - hasFill: function() { - var color = this.getFillColor(); - return !!color && color.alpha > 0; - }, - - hasStroke: function() { - var color = this.getStrokeColor(); - return !!color && color.alpha > 0 && this.getStrokeWidth() > 0; - }, - - hasShadow: function() { - var color = this.getShadowColor(); - return !!color && color.alpha > 0 && (this.getShadowBlur() > 0 - || !this.getShadowOffset().isZero()); - }, - - getView: function() { - return this._project._view; - }, - - getFontStyle: function() { - var fontSize = this.getFontSize(); - return this.getFontWeight() - + ' ' + fontSize + (/[a-z]/i.test(fontSize + '') ? ' ' : 'px ') - + this.getFontFamily(); - }, - - getFont: '#getFontFamily', - setFont: '#setFontFamily', - - getLeading: function getLeading() { - var leading = getLeading.base.call(this), - fontSize = this.getFontSize(); - if (/pt|em|%|px/.test(fontSize)) - fontSize = this.getView().getPixelSize(fontSize); - return leading != null ? leading : fontSize * 1.2; - } - -}); - -var DomElement = new function() { - function handlePrefix(el, name, set, value) { - var prefixes = ['', 'webkit', 'moz', 'Moz', 'ms', 'o'], - suffix = name[0].toUpperCase() + name.substring(1); - for (var i = 0; i < 6; i++) { - var prefix = prefixes[i], - key = prefix ? prefix + suffix : name; - if (key in el) { - if (set) { - el[key] = value; - } else { - return el[key]; - } - break; - } - } - } - - return { - getStyles: function(el) { - var doc = el && el.nodeType !== 9 ? el.ownerDocument : el, - view = doc && doc.defaultView; - return view && view.getComputedStyle(el, ''); - }, - - getBounds: function(el, viewport) { - var doc = el.ownerDocument, - body = doc.body, - html = doc.documentElement, - rect; - try { - rect = el.getBoundingClientRect(); - } catch (e) { - rect = { left: 0, top: 0, width: 0, height: 0 }; - } - var x = rect.left - (html.clientLeft || body.clientLeft || 0), - y = rect.top - (html.clientTop || body.clientTop || 0); - if (!viewport) { - var view = doc.defaultView; - x += view.pageXOffset || html.scrollLeft || body.scrollLeft; - y += view.pageYOffset || html.scrollTop || body.scrollTop; - } - return new Rectangle(x, y, rect.width, rect.height); - }, - - getViewportBounds: function(el) { - var doc = el.ownerDocument, - view = doc.defaultView, - html = doc.documentElement; - return new Rectangle(0, 0, - view.innerWidth || html.clientWidth, - view.innerHeight || html.clientHeight - ); - }, - - getOffset: function(el, viewport) { - return DomElement.getBounds(el, viewport).getPoint(); - }, - - getSize: function(el) { - return DomElement.getBounds(el, true).getSize(); - }, - - isInvisible: function(el) { - return DomElement.getSize(el).equals(new Size(0, 0)); - }, - - isInView: function(el) { - return !DomElement.isInvisible(el) - && DomElement.getViewportBounds(el).intersects( - DomElement.getBounds(el, true)); - }, - - isInserted: function(el) { - return document.body.contains(el); - }, - - getPrefixed: function(el, name) { - return el && handlePrefix(el, name); - }, - - setPrefixed: function(el, name, value) { - if (typeof name === 'object') { - for (var key in name) - handlePrefix(el, key, true, name[key]); - } else { - handlePrefix(el, name, true, value); - } - } - }; -}; - -var DomEvent = { - add: function(el, events) { - if (el) { - for (var type in events) { - var func = events[type], - parts = type.split(/[\s,]+/g); - for (var i = 0, l = parts.length; i < l; i++) { - var name = parts[i]; - var options = ( - el === document - && (name === 'touchstart' || name === 'touchmove') - ) ? { passive: false } : false; - el.addEventListener(name, func, options); - } - } - } - }, - - remove: function(el, events) { - if (el) { - for (var type in events) { - var func = events[type], - parts = type.split(/[\s,]+/g); - for (var i = 0, l = parts.length; i < l; i++) - el.removeEventListener(parts[i], func, false); - } - } - }, - - getPoint: function(event) { - var pos = event.targetTouches - ? event.targetTouches.length - ? event.targetTouches[0] - : event.changedTouches[0] - : event; - return new Point( - pos.pageX || pos.clientX + document.documentElement.scrollLeft, - pos.pageY || pos.clientY + document.documentElement.scrollTop - ); - }, - - getTarget: function(event) { - return event.target || event.srcElement; - }, - - getRelatedTarget: function(event) { - return event.relatedTarget || event.toElement; - }, - - getOffset: function(event, target) { - return DomEvent.getPoint(event).subtract(DomElement.getOffset( - target || DomEvent.getTarget(event))); - } -}; - -DomEvent.requestAnimationFrame = new function() { - var nativeRequest = DomElement.getPrefixed(window, 'requestAnimationFrame'), - requested = false, - callbacks = [], - timer; - - function handleCallbacks() { - var functions = callbacks; - callbacks = []; - for (var i = 0, l = functions.length; i < l; i++) - functions[i](); - requested = nativeRequest && callbacks.length; - if (requested) - nativeRequest(handleCallbacks); - } - - return function(callback) { - callbacks.push(callback); - if (nativeRequest) { - if (!requested) { - nativeRequest(handleCallbacks); - requested = true; - } - } else if (!timer) { - timer = setInterval(handleCallbacks, 1000 / 60); - } - }; -}; - -var View = Base.extend(Emitter, { - _class: 'View', - - initialize: function View(project, element) { - - function getSize(name) { - return element[name] || parseInt(element.getAttribute(name), 10); - } - - function getCanvasSize() { - var size = DomElement.getSize(element); - return size.isNaN() || size.isZero() - ? new Size(getSize('width'), getSize('height')) - : size; - } - - var size; - if (window && element) { - this._id = element.getAttribute('id'); - if (this._id == null) - element.setAttribute('id', this._id = 'view-' + View._id++); - DomEvent.add(element, this._viewEvents); - var none = 'none'; - DomElement.setPrefixed(element.style, { - userDrag: none, - userSelect: none, - touchCallout: none, - contentZooming: none, - tapHighlightColor: 'rgba(0,0,0,0)' - }); - - if (PaperScope.hasAttribute(element, 'resize')) { - var that = this; - DomEvent.add(window, this._windowEvents = { - resize: function() { - that.setViewSize(getCanvasSize()); - } - }); - } - - size = getCanvasSize(); - - if (PaperScope.hasAttribute(element, 'stats') - && typeof Stats !== 'undefined') { - this._stats = new Stats(); - var stats = this._stats.domElement, - style = stats.style, - offset = DomElement.getOffset(element); - style.position = 'absolute'; - style.left = offset.x + 'px'; - style.top = offset.y + 'px'; - document.body.appendChild(stats); - } - } else { - size = new Size(element); - element = null; - } - this._project = project; - this._scope = project._scope; - this._element = element; - if (!this._pixelRatio) - this._pixelRatio = window && window.devicePixelRatio || 1; - this._setElementSize(size.width, size.height); - this._viewSize = size; - View._views.push(this); - View._viewsById[this._id] = this; - (this._matrix = new Matrix())._owner = this; - if (!View._focused) - View._focused = this; - this._frameItems = {}; - this._frameItemCount = 0; - this._itemEvents = { native: {}, virtual: {} }; - this._autoUpdate = !paper.agent.node; - this._needsUpdate = false; - }, - - remove: function() { - if (!this._project) - return false; - if (View._focused === this) - View._focused = null; - View._views.splice(View._views.indexOf(this), 1); - delete View._viewsById[this._id]; - var project = this._project; - if (project._view === this) - project._view = null; - DomEvent.remove(this._element, this._viewEvents); - DomEvent.remove(window, this._windowEvents); - this._element = this._project = null; - this.off('frame'); - this._animate = false; - this._frameItems = {}; - return true; - }, - - _events: Base.each( - Item._itemHandlers.concat(['onResize', 'onKeyDown', 'onKeyUp']), - function(name) { - this[name] = {}; - }, { - onFrame: { - install: function() { - this.play(); - }, - - uninstall: function() { - this.pause(); - } - } - } - ), - - _animate: false, - _time: 0, - _count: 0, - - getAutoUpdate: function() { - return this._autoUpdate; - }, - - setAutoUpdate: function(autoUpdate) { - this._autoUpdate = autoUpdate; - if (autoUpdate) - this.requestUpdate(); - }, - - update: function() { - }, - - draw: function() { - this.update(); - }, - - requestUpdate: function() { - if (!this._requested) { - var that = this; - DomEvent.requestAnimationFrame(function() { - that._requested = false; - if (that._animate) { - that.requestUpdate(); - var element = that._element; - if ((!DomElement.getPrefixed(document, 'hidden') - || PaperScope.getAttribute(element, 'keepalive') - === 'true') && DomElement.isInView(element)) { - that._handleFrame(); - } - } - if (that._autoUpdate) - that.update(); - }); - this._requested = true; - } - }, - - play: function() { - this._animate = true; - this.requestUpdate(); - }, - - pause: function() { - this._animate = false; - }, - - _handleFrame: function() { - paper = this._scope; - var now = Date.now() / 1000, - delta = this._last ? now - this._last : 0; - this._last = now; - this.emit('frame', new Base({ - delta: delta, - time: this._time += delta, - count: this._count++ - })); - if (this._stats) - this._stats.update(); - }, - - _animateItem: function(item, animate) { - var items = this._frameItems; - if (animate) { - items[item._id] = { - item: item, - time: 0, - count: 0 - }; - if (++this._frameItemCount === 1) - this.on('frame', this._handleFrameItems); - } else { - delete items[item._id]; - if (--this._frameItemCount === 0) { - this.off('frame', this._handleFrameItems); - } - } - }, - - _handleFrameItems: function(event) { - for (var i in this._frameItems) { - var entry = this._frameItems[i]; - entry.item.emit('frame', new Base(event, { - time: entry.time += event.delta, - count: entry.count++ - })); - } - }, - - _changed: function() { - this._project._changed(4097); - this._bounds = this._decomposed = undefined; - }, - - getElement: function() { - return this._element; - }, - - getPixelRatio: function() { - return this._pixelRatio; - }, - - getResolution: function() { - return this._pixelRatio * 72; - }, - - getViewSize: function() { - var size = this._viewSize; - return new LinkedSize(size.width, size.height, this, 'setViewSize'); - }, - - setViewSize: function() { - var size = Size.read(arguments), - delta = size.subtract(this._viewSize); - if (delta.isZero()) - return; - this._setElementSize(size.width, size.height); - this._viewSize.set(size); - this._changed(); - this.emit('resize', { size: size, delta: delta }); - if (this._autoUpdate) { - this.update(); - } - }, - - _setElementSize: function(width, height) { - var element = this._element; - if (element) { - if (element.width !== width) - element.width = width; - if (element.height !== height) - element.height = height; - } - }, - - getBounds: function() { - if (!this._bounds) - this._bounds = this._matrix.inverted()._transformBounds( - new Rectangle(new Point(), this._viewSize)); - return this._bounds; - }, - - getSize: function() { - return this.getBounds().getSize(); - }, - - isVisible: function() { - return DomElement.isInView(this._element); - }, - - isInserted: function() { - return DomElement.isInserted(this._element); - }, - - getPixelSize: function(size) { - var element = this._element, - pixels; - if (element) { - var parent = element.parentNode, - temp = document.createElement('div'); - temp.style.fontSize = size; - parent.appendChild(temp); - pixels = parseFloat(DomElement.getStyles(temp).fontSize); - parent.removeChild(temp); - } else { - pixels = parseFloat(pixels); - } - return pixels; - }, - - getTextWidth: function(font, lines) { - return 0; - } -}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) { - var rotate = key === 'rotate'; - this[key] = function() { - var value = (rotate ? Base : Point).read(arguments), - center = Point.read(arguments, 0, { readNull: true }); - return this.transform(new Matrix()[key](value, - center || this.getCenter(true))); - }; -}, { - _decompose: function() { - return this._decomposed || (this._decomposed = this._matrix.decompose()); - }, - - translate: function() { - var mx = new Matrix(); - return this.transform(mx.translate.apply(mx, arguments)); - }, - - getCenter: function() { - return this.getBounds().getCenter(); - }, - - setCenter: function() { - var center = Point.read(arguments); - this.translate(this.getCenter().subtract(center)); - }, - - getZoom: function() { - var decomposed = this._decompose(), - scaling = decomposed && decomposed.scaling; - return scaling ? (scaling.x + scaling.y) / 2 : 0; - }, - - setZoom: function(zoom) { - this.transform(new Matrix().scale(zoom / this.getZoom(), - this.getCenter())); - }, - - getRotation: function() { - var decomposed = this._decompose(); - return decomposed && decomposed.rotation; - }, - - setRotation: function(rotation) { - var current = this.getRotation(); - if (current != null && rotation != null) { - this.rotate(rotation - current); - } - }, - - getScaling: function() { - var decomposed = this._decompose(), - scaling = decomposed && decomposed.scaling; - return scaling - ? new LinkedPoint(scaling.x, scaling.y, this, 'setScaling') - : undefined; - }, - - setScaling: function() { - var current = this.getScaling(), - scaling = Point.read(arguments, 0, { clone: true, readNull: true }); - if (current && scaling) { - this.scale(scaling.x / current.x, scaling.y / current.y); - } - }, - - getMatrix: function() { - return this._matrix; - }, - - setMatrix: function() { - var matrix = this._matrix; - matrix.initialize.apply(matrix, arguments); - }, - - transform: function(matrix) { - this._matrix.append(matrix); - }, - - scrollBy: function() { - this.translate(Point.read(arguments).negate()); - } -}), { - - projectToView: function() { - return this._matrix._transformPoint(Point.read(arguments)); - }, - - viewToProject: function() { - return this._matrix._inverseTransform(Point.read(arguments)); - }, - - getEventPoint: function(event) { - return this.viewToProject(DomEvent.getOffset(event, this._element)); - }, - -}, { - statics: { - _views: [], - _viewsById: {}, - _id: 0, - - create: function(project, element) { - if (document && typeof element === 'string') - element = document.getElementById(element); - var ctor = window ? CanvasView : View; - return new ctor(project, element); - } - } -}, -new function() { - if (!window) - return; - var prevFocus, - tempFocus, - dragging = false, - mouseDown = false; - - function getView(event) { - var target = DomEvent.getTarget(event); - return target.getAttribute && View._viewsById[ - target.getAttribute('id')]; - } - - function updateFocus() { - var view = View._focused; - if (!view || !view.isVisible()) { - for (var i = 0, l = View._views.length; i < l; i++) { - if ((view = View._views[i]).isVisible()) { - View._focused = tempFocus = view; - break; - } - } - } - } - - function handleMouseMove(view, event, point) { - view._handleMouseEvent('mousemove', event, point); - } - - var navigator = window.navigator, - mousedown, mousemove, mouseup; - if (navigator.pointerEnabled || navigator.msPointerEnabled) { - mousedown = 'pointerdown MSPointerDown'; - mousemove = 'pointermove MSPointerMove'; - mouseup = 'pointerup pointercancel MSPointerUp MSPointerCancel'; - } else { - mousedown = 'touchstart'; - mousemove = 'touchmove'; - mouseup = 'touchend touchcancel'; - if (!('ontouchstart' in window && navigator.userAgent.match( - /mobile|tablet|ip(ad|hone|od)|android|silk/i))) { - mousedown += ' mousedown'; - mousemove += ' mousemove'; - mouseup += ' mouseup'; - } - } - - var viewEvents = {}, - docEvents = { - mouseout: function(event) { - var view = View._focused, - target = DomEvent.getRelatedTarget(event); - if (view && (!target || target.nodeName === 'HTML')) { - var offset = DomEvent.getOffset(event, view._element), - x = offset.x, - abs = Math.abs, - ax = abs(x), - max = 1 << 25, - diff = ax - max; - offset.x = abs(diff) < ax ? diff * (x < 0 ? -1 : 1) : x; - handleMouseMove(view, event, view.viewToProject(offset)); - } - }, - - scroll: updateFocus - }; - - viewEvents[mousedown] = function(event) { - var view = View._focused = getView(event); - if (!dragging) { - dragging = true; - view._handleMouseEvent('mousedown', event); - } - }; - - docEvents[mousemove] = function(event) { - var view = View._focused; - if (!mouseDown) { - var target = getView(event); - if (target) { - if (view !== target) { - if (view) - handleMouseMove(view, event); - if (!prevFocus) - prevFocus = view; - view = View._focused = tempFocus = target; - } - } else if (tempFocus && tempFocus === view) { - if (prevFocus && !prevFocus.isInserted()) - prevFocus = null; - view = View._focused = prevFocus; - prevFocus = null; - updateFocus(); - } - } - if (view) - handleMouseMove(view, event); - }; - - docEvents[mousedown] = function() { - mouseDown = true; - }; - - docEvents[mouseup] = function(event) { - var view = View._focused; - if (view && dragging) - view._handleMouseEvent('mouseup', event); - mouseDown = dragging = false; - }; - - DomEvent.add(document, docEvents); - - DomEvent.add(window, { - load: updateFocus - }); - - var called = false, - prevented = false, - fallbacks = { - doubleclick: 'click', - mousedrag: 'mousemove' - }, - wasInView = false, - overView, - downPoint, - lastPoint, - downItem, - overItem, - dragItem, - clickItem, - clickTime, - dblClick; - - function emitMouseEvent(obj, target, type, event, point, prevPoint, - stopItem) { - var stopped = false, - mouseEvent; - - function emit(obj, type) { - if (obj.responds(type)) { - if (!mouseEvent) { - mouseEvent = new MouseEvent(type, event, point, - target || obj, - prevPoint ? point.subtract(prevPoint) : null); - } - if (obj.emit(type, mouseEvent)) { - called = true; - if (mouseEvent.prevented) - prevented = true; - if (mouseEvent.stopped) - return stopped = true; - } - } else { - var fallback = fallbacks[type]; - if (fallback) - return emit(obj, fallback); - } - } - - while (obj && obj !== stopItem) { - if (emit(obj, type)) - break; - obj = obj._parent; - } - return stopped; - } - - function emitMouseEvents(view, hitItem, type, event, point, prevPoint) { - view._project.removeOn(type); - prevented = called = false; - return (dragItem && emitMouseEvent(dragItem, null, type, event, - point, prevPoint) - || hitItem && hitItem !== dragItem - && !hitItem.isDescendant(dragItem) - && emitMouseEvent(hitItem, null, type, event, point, prevPoint, - dragItem) - || emitMouseEvent(view, dragItem || hitItem || view, type, event, - point, prevPoint)); - } - - var itemEventsMap = { - mousedown: { - mousedown: 1, - mousedrag: 1, - click: 1, - doubleclick: 1 - }, - mouseup: { - mouseup: 1, - mousedrag: 1, - click: 1, - doubleclick: 1 - }, - mousemove: { - mousedrag: 1, - mousemove: 1, - mouseenter: 1, - mouseleave: 1 - } - }; - - return { - _viewEvents: viewEvents, - - _handleMouseEvent: function(type, event, point) { - var itemEvents = this._itemEvents, - hitItems = itemEvents.native[type], - nativeMove = type === 'mousemove', - tool = this._scope.tool, - view = this; - - function responds(type) { - return itemEvents.virtual[type] || view.responds(type) - || tool && tool.responds(type); - } - - if (nativeMove && dragging && responds('mousedrag')) - type = 'mousedrag'; - if (!point) - point = this.getEventPoint(event); - - var inView = this.getBounds().contains(point), - hit = hitItems && inView && view._project.hitTest(point, { - tolerance: 0, - fill: true, - stroke: true - }), - hitItem = hit && hit.item || null, - handle = false, - mouse = {}; - mouse[type.substr(5)] = true; - - if (hitItems && hitItem !== overItem) { - if (overItem) { - emitMouseEvent(overItem, null, 'mouseleave', event, point); - } - if (hitItem) { - emitMouseEvent(hitItem, null, 'mouseenter', event, point); - } - overItem = hitItem; - } - if (wasInView ^ inView) { - emitMouseEvent(this, null, inView ? 'mouseenter' : 'mouseleave', - event, point); - overView = inView ? this : null; - handle = true; - } - if ((inView || mouse.drag) && !point.equals(lastPoint)) { - emitMouseEvents(this, hitItem, nativeMove ? type : 'mousemove', - event, point, lastPoint); - handle = true; - } - wasInView = inView; - if (mouse.down && inView || mouse.up && downPoint) { - emitMouseEvents(this, hitItem, type, event, point, downPoint); - if (mouse.down) { - dblClick = hitItem === clickItem - && (Date.now() - clickTime < 300); - downItem = clickItem = hitItem; - if (!prevented && hitItem) { - var item = hitItem; - while (item && !item.responds('mousedrag')) - item = item._parent; - if (item) - dragItem = hitItem; - } - downPoint = point; - } else if (mouse.up) { - if (!prevented && hitItem === downItem) { - clickTime = Date.now(); - emitMouseEvents(this, hitItem, dblClick ? 'doubleclick' - : 'click', event, point, downPoint); - dblClick = false; - } - downItem = dragItem = null; - } - wasInView = false; - handle = true; - } - lastPoint = point; - if (handle && tool) { - called = tool._handleMouseEvent(type, event, point, mouse) - || called; - } - - if ( - event.cancelable !== false - && (called && !mouse.move || mouse.down && responds('mouseup')) - ) { - event.preventDefault(); - } - }, - - _handleKeyEvent: function(type, event, key, character) { - var scope = this._scope, - tool = scope.tool, - keyEvent; - - function emit(obj) { - if (obj.responds(type)) { - paper = scope; - obj.emit(type, keyEvent = keyEvent - || new KeyEvent(type, event, key, character)); - } - } - - if (this.isVisible()) { - emit(this); - if (tool && tool.responds(type)) - emit(tool); - } - }, - - _countItemEvent: function(type, sign) { - var itemEvents = this._itemEvents, - native = itemEvents.native, - virtual = itemEvents.virtual; - for (var key in itemEventsMap) { - native[key] = (native[key] || 0) - + (itemEventsMap[key][type] || 0) * sign; - } - virtual[type] = (virtual[type] || 0) + sign; - }, - - statics: { - updateFocus: updateFocus, - - _resetState: function() { - dragging = mouseDown = called = wasInView = false; - prevFocus = tempFocus = overView = downPoint = lastPoint = - downItem = overItem = dragItem = clickItem = clickTime = - dblClick = null; - } - } - }; -}); - -var CanvasView = View.extend({ - _class: 'CanvasView', - - initialize: function CanvasView(project, canvas) { - if (!(canvas instanceof window.HTMLCanvasElement)) { - var size = Size.read(arguments, 1); - if (size.isZero()) - throw new Error( - 'Cannot create CanvasView with the provided argument: ' - + Base.slice(arguments, 1)); - canvas = CanvasProvider.getCanvas(size); - } - var ctx = this._context = canvas.getContext('2d'); - ctx.save(); - this._pixelRatio = 1; - if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) { - var deviceRatio = window.devicePixelRatio || 1, - backingStoreRatio = DomElement.getPrefixed(ctx, - 'backingStorePixelRatio') || 1; - this._pixelRatio = deviceRatio / backingStoreRatio; - } - View.call(this, project, canvas); - this._needsUpdate = true; - }, - - remove: function remove() { - this._context.restore(); - return remove.base.call(this); - }, - - _setElementSize: function _setElementSize(width, height) { - var pixelRatio = this._pixelRatio; - _setElementSize.base.call(this, width * pixelRatio, height * pixelRatio); - if (pixelRatio !== 1) { - var element = this._element, - ctx = this._context; - if (!PaperScope.hasAttribute(element, 'resize')) { - var style = element.style; - style.width = width + 'px'; - style.height = height + 'px'; - } - ctx.restore(); - ctx.save(); - ctx.scale(pixelRatio, pixelRatio); - } - }, - - getPixelSize: function getPixelSize(size) { - var agent = paper.agent, - pixels; - if (agent && agent.firefox) { - pixels = getPixelSize.base.call(this, size); - } else { - var ctx = this._context, - prevFont = ctx.font; - ctx.font = size + ' serif'; - pixels = parseFloat(ctx.font); - ctx.font = prevFont; - } - return pixels; - }, - - getTextWidth: function(font, lines) { - var ctx = this._context, - prevFont = ctx.font, - width = 0; - ctx.font = font; - for (var i = 0, l = lines.length; i < l; i++) - width = Math.max(width, ctx.measureText(lines[i]).width); - ctx.font = prevFont; - return width; - }, - - update: function() { - if (!this._needsUpdate) - return false; - var project = this._project, - ctx = this._context, - size = this._viewSize; - ctx.clearRect(0, 0, size.width + 1, size.height + 1); - if (project) - project.draw(ctx, this._matrix, this._pixelRatio); - this._needsUpdate = false; - return true; - } -}); - -var Event = Base.extend({ - _class: 'Event', - - initialize: function Event(event) { - this.event = event; - this.type = event && event.type; - }, - - prevented: false, - stopped: false, - - preventDefault: function() { - this.prevented = true; - this.event.preventDefault(); - }, - - stopPropagation: function() { - this.stopped = true; - this.event.stopPropagation(); - }, - - stop: function() { - this.stopPropagation(); - this.preventDefault(); - }, - - getTimeStamp: function() { - return this.event.timeStamp; - }, - - getModifiers: function() { - return Key.modifiers; - } -}); - -var KeyEvent = Event.extend({ - _class: 'KeyEvent', - - initialize: function KeyEvent(type, event, key, character) { - this.type = type; - this.event = event; - this.key = key; - this.character = character; - }, - - toString: function() { - return "{ type: '" + this.type - + "', key: '" + this.key - + "', character: '" + this.character - + "', modifiers: " + this.getModifiers() - + " }"; - } -}); - -var Key = new function() { - var keyLookup = { - '\t': 'tab', - ' ': 'space', - '\b': 'backspace', - '\x7f': 'delete', - 'Spacebar': 'space', - 'Del': 'delete', - 'Win': 'meta', - 'Esc': 'escape' - }, - - charLookup = { - 'tab': '\t', - 'space': ' ', - 'enter': '\r' - }, - - keyMap = {}, - charMap = {}, - metaFixMap, - downKey, - - modifiers = new Base({ - shift: false, - control: false, - alt: false, - meta: false, - capsLock: false, - space: false - }).inject({ - option: { - get: function() { - return this.alt; - } - }, - - command: { - get: function() { - var agent = paper && paper.agent; - return agent && agent.mac ? this.meta : this.control; - } - } - }); - - function getKey(event) { - var key = event.key || event.keyIdentifier; - key = /^U\+/.test(key) - ? String.fromCharCode(parseInt(key.substr(2), 16)) - : /^Arrow[A-Z]/.test(key) ? key.substr(5) - : key === 'Unidentified' || key === undefined - ? String.fromCharCode(event.keyCode) - : key; - return keyLookup[key] || - (key.length > 1 ? Base.hyphenate(key) : key.toLowerCase()); - } - - function handleKey(down, key, character, event) { - var type = down ? 'keydown' : 'keyup', - view = View._focused, - name; - keyMap[key] = down; - if (down) { - charMap[key] = character; - } else { - delete charMap[key]; - } - if (key.length > 1 && (name = Base.camelize(key)) in modifiers) { - modifiers[name] = down; - var agent = paper && paper.agent; - if (name === 'meta' && agent && agent.mac) { - if (down) { - metaFixMap = {}; - } else { - for (var k in metaFixMap) { - if (k in charMap) - handleKey(false, k, metaFixMap[k], event); - } - metaFixMap = null; - } - } - } else if (down && metaFixMap) { - metaFixMap[key] = character; - } - if (view) { - view._handleKeyEvent(down ? 'keydown' : 'keyup', event, key, - character); - } - } - - DomEvent.add(document, { - keydown: function(event) { - var key = getKey(event), - agent = paper && paper.agent; - if (key.length > 1 || agent && (agent.chrome && (event.altKey - || agent.mac && event.metaKey - || !agent.mac && event.ctrlKey))) { - handleKey(true, key, - charLookup[key] || (key.length > 1 ? '' : key), event); - } else { - downKey = key; - } - }, - - keypress: function(event) { - if (downKey) { - var key = getKey(event), - code = event.charCode, - character = code >= 32 ? String.fromCharCode(code) - : key.length > 1 ? '' : key; - if (key !== downKey) { - key = character.toLowerCase(); - } - handleKey(true, key, character, event); - downKey = null; - } - }, - - keyup: function(event) { - var key = getKey(event); - if (key in charMap) - handleKey(false, key, charMap[key], event); - } - }); - - DomEvent.add(window, { - blur: function(event) { - for (var key in charMap) - handleKey(false, key, charMap[key], event); - } - }); - - return { - modifiers: modifiers, - - isDown: function(key) { - return !!keyMap[key]; - } - }; -}; - -var MouseEvent = Event.extend({ - _class: 'MouseEvent', - - initialize: function MouseEvent(type, event, point, target, delta) { - this.type = type; - this.event = event; - this.point = point; - this.target = target; - this.delta = delta; - }, - - toString: function() { - return "{ type: '" + this.type - + "', point: " + this.point - + ', target: ' + this.target - + (this.delta ? ', delta: ' + this.delta : '') - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var ToolEvent = Event.extend({ - _class: 'ToolEvent', - _item: null, - - initialize: function ToolEvent(tool, type, event) { - this.tool = tool; - this.type = type; - this.event = event; - }, - - _choosePoint: function(point, toolPoint) { - return point ? point : toolPoint ? toolPoint.clone() : null; - }, - - getPoint: function() { - return this._choosePoint(this._point, this.tool._point); - }, - - setPoint: function(point) { - this._point = point; - }, - - getLastPoint: function() { - return this._choosePoint(this._lastPoint, this.tool._lastPoint); - }, - - setLastPoint: function(lastPoint) { - this._lastPoint = lastPoint; - }, - - getDownPoint: function() { - return this._choosePoint(this._downPoint, this.tool._downPoint); - }, - - setDownPoint: function(downPoint) { - this._downPoint = downPoint; - }, - - getMiddlePoint: function() { - if (!this._middlePoint && this.tool._lastPoint) { - return this.tool._point.add(this.tool._lastPoint).divide(2); - } - return this._middlePoint; - }, - - setMiddlePoint: function(middlePoint) { - this._middlePoint = middlePoint; - }, - - getDelta: function() { - return !this._delta && this.tool._lastPoint - ? this.tool._point.subtract(this.tool._lastPoint) - : this._delta; - }, - - setDelta: function(delta) { - this._delta = delta; - }, - - getCount: function() { - return this.tool[/^mouse(down|up)$/.test(this.type) - ? '_downCount' : '_moveCount']; - }, - - setCount: function(count) { - this.tool[/^mouse(down|up)$/.test(this.type) ? 'downCount' : 'count'] - = count; - }, - - getItem: function() { - if (!this._item) { - var result = this.tool._scope.project.hitTest(this.getPoint()); - if (result) { - var item = result.item, - parent = item._parent; - while (/^(Group|CompoundPath)$/.test(parent._class)) { - item = parent; - parent = parent._parent; - } - this._item = item; - } - } - return this._item; - }, - - setItem: function(item) { - this._item = item; - }, - - toString: function() { - return '{ type: ' + this.type - + ', point: ' + this.getPoint() - + ', count: ' + this.getCount() - + ', modifiers: ' + this.getModifiers() - + ' }'; - } -}); - -var Tool = PaperScopeItem.extend({ - _class: 'Tool', - _list: 'tools', - _reference: 'tool', - _events: ['onMouseDown', 'onMouseUp', 'onMouseDrag', 'onMouseMove', - 'onActivate', 'onDeactivate', 'onEditOptions', 'onKeyDown', - 'onKeyUp'], - - initialize: function Tool(props) { - PaperScopeItem.call(this); - this._moveCount = -1; - this._downCount = -1; - this.set(props); - }, - - getMinDistance: function() { - return this._minDistance; - }, - - setMinDistance: function(minDistance) { - this._minDistance = minDistance; - if (minDistance != null && this._maxDistance != null - && minDistance > this._maxDistance) { - this._maxDistance = minDistance; - } - }, - - getMaxDistance: function() { - return this._maxDistance; - }, - - setMaxDistance: function(maxDistance) { - this._maxDistance = maxDistance; - if (this._minDistance != null && maxDistance != null - && maxDistance < this._minDistance) { - this._minDistance = maxDistance; - } - }, - - getFixedDistance: function() { - return this._minDistance == this._maxDistance - ? this._minDistance : null; - }, - - setFixedDistance: function(distance) { - this._minDistance = this._maxDistance = distance; - }, - - _handleMouseEvent: function(type, event, point, mouse) { - paper = this._scope; - if (mouse.drag && !this.responds(type)) - type = 'mousemove'; - var move = mouse.move || mouse.drag, - responds = this.responds(type), - minDistance = this.minDistance, - maxDistance = this.maxDistance, - called = false, - tool = this; - function update(minDistance, maxDistance) { - var pt = point, - toolPoint = move ? tool._point : (tool._downPoint || pt); - if (move) { - if (tool._moveCount >= 0 && pt.equals(toolPoint)) { - return false; - } - if (toolPoint && (minDistance != null || maxDistance != null)) { - var vector = pt.subtract(toolPoint), - distance = vector.getLength(); - if (distance < (minDistance || 0)) - return false; - if (maxDistance) { - pt = toolPoint.add(vector.normalize( - Math.min(distance, maxDistance))); - } - } - tool._moveCount++; - } - tool._point = pt; - tool._lastPoint = toolPoint || pt; - if (mouse.down) { - tool._moveCount = -1; - tool._downPoint = pt; - tool._downCount++; - } - return true; - } - - function emit() { - if (responds) { - called = tool.emit(type, new ToolEvent(tool, type, event)) - || called; - } - } - - if (mouse.down) { - update(); - emit(); - } else if (mouse.up) { - update(null, maxDistance); - emit(); - } else if (responds) { - while (update(minDistance, maxDistance)) - emit(); - } - return called; - } - -}); - -var Http = { - request: function(options) { - var xhr = new self.XMLHttpRequest(); - xhr.open((options.method || 'get').toUpperCase(), options.url, - Base.pick(options.async, true)); - if (options.mimeType) - xhr.overrideMimeType(options.mimeType); - xhr.onload = function() { - var status = xhr.status; - if (status === 0 || status === 200) { - if (options.onLoad) { - options.onLoad.call(xhr, xhr.responseText); - } - } else { - xhr.onerror(); - } - }; - xhr.onerror = function() { - var status = xhr.status, - message = 'Could not load "' + options.url + '" (Status: ' - + status + ')'; - if (options.onError) { - options.onError(message, status); - } else { - throw new Error(message); - } - }; - return xhr.send(null); - } -}; - -var CanvasProvider = { - canvases: [], - - getCanvas: function(width, height) { - if (!window) - return null; - var canvas, - clear = true; - if (typeof width === 'object') { - height = width.height; - width = width.width; - } - if (this.canvases.length) { - canvas = this.canvases.pop(); - } else { - canvas = document.createElement('canvas'); - clear = false; - } - var ctx = canvas.getContext('2d'); - if (!ctx) { - throw new Error('Canvas ' + canvas + - ' is unable to provide a 2D context.'); - } - if (canvas.width === width && canvas.height === height) { - if (clear) - ctx.clearRect(0, 0, width + 1, height + 1); - } else { - canvas.width = width; - canvas.height = height; - } - ctx.save(); - return canvas; - }, - - getContext: function(width, height) { - var canvas = this.getCanvas(width, height); - return canvas ? canvas.getContext('2d') : null; - }, - - release: function(obj) { - var canvas = obj && obj.canvas ? obj.canvas : obj; - if (canvas && canvas.getContext) { - canvas.getContext('2d').restore(); - this.canvases.push(canvas); - } - } -}; - -var BlendMode = new function() { - var min = Math.min, - max = Math.max, - abs = Math.abs, - sr, sg, sb, sa, - br, bg, bb, ba, - dr, dg, db; - - function getLum(r, g, b) { - return 0.2989 * r + 0.587 * g + 0.114 * b; - } - - function setLum(r, g, b, l) { - var d = l - getLum(r, g, b); - dr = r + d; - dg = g + d; - db = b + d; - var l = getLum(dr, dg, db), - mn = min(dr, dg, db), - mx = max(dr, dg, db); - if (mn < 0) { - var lmn = l - mn; - dr = l + (dr - l) * l / lmn; - dg = l + (dg - l) * l / lmn; - db = l + (db - l) * l / lmn; - } - if (mx > 255) { - var ln = 255 - l, - mxl = mx - l; - dr = l + (dr - l) * ln / mxl; - dg = l + (dg - l) * ln / mxl; - db = l + (db - l) * ln / mxl; - } - } - - function getSat(r, g, b) { - return max(r, g, b) - min(r, g, b); - } - - function setSat(r, g, b, s) { - var col = [r, g, b], - mx = max(r, g, b), - mn = min(r, g, b), - md; - mn = mn === r ? 0 : mn === g ? 1 : 2; - mx = mx === r ? 0 : mx === g ? 1 : 2; - md = min(mn, mx) === 0 ? max(mn, mx) === 1 ? 2 : 1 : 0; - if (col[mx] > col[mn]) { - col[md] = (col[md] - col[mn]) * s / (col[mx] - col[mn]); - col[mx] = s; - } else { - col[md] = col[mx] = 0; - } - col[mn] = 0; - dr = col[0]; - dg = col[1]; - db = col[2]; - } - - var modes = { - multiply: function() { - dr = br * sr / 255; - dg = bg * sg / 255; - db = bb * sb / 255; - }, - - screen: function() { - dr = br + sr - (br * sr / 255); - dg = bg + sg - (bg * sg / 255); - db = bb + sb - (bb * sb / 255); - }, - - overlay: function() { - dr = br < 128 ? 2 * br * sr / 255 : 255 - 2 * (255 - br) * (255 - sr) / 255; - dg = bg < 128 ? 2 * bg * sg / 255 : 255 - 2 * (255 - bg) * (255 - sg) / 255; - db = bb < 128 ? 2 * bb * sb / 255 : 255 - 2 * (255 - bb) * (255 - sb) / 255; - }, - - 'soft-light': function() { - var t = sr * br / 255; - dr = t + br * (255 - (255 - br) * (255 - sr) / 255 - t) / 255; - t = sg * bg / 255; - dg = t + bg * (255 - (255 - bg) * (255 - sg) / 255 - t) / 255; - t = sb * bb / 255; - db = t + bb * (255 - (255 - bb) * (255 - sb) / 255 - t) / 255; - }, - - 'hard-light': function() { - dr = sr < 128 ? 2 * sr * br / 255 : 255 - 2 * (255 - sr) * (255 - br) / 255; - dg = sg < 128 ? 2 * sg * bg / 255 : 255 - 2 * (255 - sg) * (255 - bg) / 255; - db = sb < 128 ? 2 * sb * bb / 255 : 255 - 2 * (255 - sb) * (255 - bb) / 255; - }, - - 'color-dodge': function() { - dr = br === 0 ? 0 : sr === 255 ? 255 : min(255, 255 * br / (255 - sr)); - dg = bg === 0 ? 0 : sg === 255 ? 255 : min(255, 255 * bg / (255 - sg)); - db = bb === 0 ? 0 : sb === 255 ? 255 : min(255, 255 * bb / (255 - sb)); - }, - - 'color-burn': function() { - dr = br === 255 ? 255 : sr === 0 ? 0 : max(0, 255 - (255 - br) * 255 / sr); - dg = bg === 255 ? 255 : sg === 0 ? 0 : max(0, 255 - (255 - bg) * 255 / sg); - db = bb === 255 ? 255 : sb === 0 ? 0 : max(0, 255 - (255 - bb) * 255 / sb); - }, - - darken: function() { - dr = br < sr ? br : sr; - dg = bg < sg ? bg : sg; - db = bb < sb ? bb : sb; - }, - - lighten: function() { - dr = br > sr ? br : sr; - dg = bg > sg ? bg : sg; - db = bb > sb ? bb : sb; - }, - - difference: function() { - dr = br - sr; - if (dr < 0) - dr = -dr; - dg = bg - sg; - if (dg < 0) - dg = -dg; - db = bb - sb; - if (db < 0) - db = -db; - }, - - exclusion: function() { - dr = br + sr * (255 - br - br) / 255; - dg = bg + sg * (255 - bg - bg) / 255; - db = bb + sb * (255 - bb - bb) / 255; - }, - - hue: function() { - setSat(sr, sg, sb, getSat(br, bg, bb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - saturation: function() { - setSat(br, bg, bb, getSat(sr, sg, sb)); - setLum(dr, dg, db, getLum(br, bg, bb)); - }, - - luminosity: function() { - setLum(br, bg, bb, getLum(sr, sg, sb)); - }, - - color: function() { - setLum(sr, sg, sb, getLum(br, bg, bb)); - }, - - add: function() { - dr = min(br + sr, 255); - dg = min(bg + sg, 255); - db = min(bb + sb, 255); - }, - - subtract: function() { - dr = max(br - sr, 0); - dg = max(bg - sg, 0); - db = max(bb - sb, 0); - }, - - average: function() { - dr = (br + sr) / 2; - dg = (bg + sg) / 2; - db = (bb + sb) / 2; - }, - - negation: function() { - dr = 255 - abs(255 - sr - br); - dg = 255 - abs(255 - sg - bg); - db = 255 - abs(255 - sb - bb); - } - }; - - var nativeModes = this.nativeModes = Base.each([ - 'source-over', 'source-in', 'source-out', 'source-atop', - 'destination-over', 'destination-in', 'destination-out', - 'destination-atop', 'lighter', 'darker', 'copy', 'xor' - ], function(mode) { - this[mode] = true; - }, {}); - - var ctx = CanvasProvider.getContext(1, 1); - if (ctx) { - Base.each(modes, function(func, mode) { - var darken = mode === 'darken', - ok = false; - ctx.save(); - try { - ctx.fillStyle = darken ? '#300' : '#a00'; - ctx.fillRect(0, 0, 1, 1); - ctx.globalCompositeOperation = mode; - if (ctx.globalCompositeOperation === mode) { - ctx.fillStyle = darken ? '#a00' : '#300'; - ctx.fillRect(0, 0, 1, 1); - ok = ctx.getImageData(0, 0, 1, 1).data[0] !== darken - ? 170 : 51; - } - } catch (e) {} - ctx.restore(); - nativeModes[mode] = ok; - }); - CanvasProvider.release(ctx); - } - - this.process = function(mode, srcContext, dstContext, alpha, offset) { - var srcCanvas = srcContext.canvas, - normal = mode === 'normal'; - if (normal || nativeModes[mode]) { - dstContext.save(); - dstContext.setTransform(1, 0, 0, 1, 0, 0); - dstContext.globalAlpha = alpha; - if (!normal) - dstContext.globalCompositeOperation = mode; - dstContext.drawImage(srcCanvas, offset.x, offset.y); - dstContext.restore(); - } else { - var process = modes[mode]; - if (!process) - return; - var dstData = dstContext.getImageData(offset.x, offset.y, - srcCanvas.width, srcCanvas.height), - dst = dstData.data, - src = srcContext.getImageData(0, 0, - srcCanvas.width, srcCanvas.height).data; - for (var i = 0, l = dst.length; i < l; i += 4) { - sr = src[i]; - br = dst[i]; - sg = src[i + 1]; - bg = dst[i + 1]; - sb = src[i + 2]; - bb = dst[i + 2]; - sa = src[i + 3]; - ba = dst[i + 3]; - process(); - var a1 = sa * alpha / 255, - a2 = 1 - a1; - dst[i] = a1 * dr + a2 * br; - dst[i + 1] = a1 * dg + a2 * bg; - dst[i + 2] = a1 * db + a2 * bb; - dst[i + 3] = sa * alpha + a2 * ba; - } - dstContext.putImageData(dstData, offset.x, offset.y); - } - }; -}; - -var SvgElement = new function() { - var svg = 'http://www.w3.org/2000/svg', - xmlns = 'http://www.w3.org/2000/xmlns', - xlink = 'http://www.w3.org/1999/xlink', - attributeNamespace = { - href: xlink, - xlink: xmlns, - xmlns: xmlns + '/', - 'xmlns:xlink': xmlns + '/' - }; - - function create(tag, attributes, formatter) { - return set(document.createElementNS(svg, tag), attributes, formatter); - } - - function get(node, name) { - var namespace = attributeNamespace[name], - value = namespace - ? node.getAttributeNS(namespace, name) - : node.getAttribute(name); - return value === 'null' ? null : value; - } - - function set(node, attributes, formatter) { - for (var name in attributes) { - var value = attributes[name], - namespace = attributeNamespace[name]; - if (typeof value === 'number' && formatter) - value = formatter.number(value); - if (namespace) { - node.setAttributeNS(namespace, name, value); - } else { - node.setAttribute(name, value); - } - } - return node; - } - - return { - svg: svg, - xmlns: xmlns, - xlink: xlink, - - create: create, - get: get, - set: set - }; -}; - -var SvgStyles = Base.each({ - fillColor: ['fill', 'color'], - fillRule: ['fill-rule', 'string'], - strokeColor: ['stroke', 'color'], - strokeWidth: ['stroke-width', 'number'], - strokeCap: ['stroke-linecap', 'string'], - strokeJoin: ['stroke-linejoin', 'string'], - strokeScaling: ['vector-effect', 'lookup', { - true: 'none', - false: 'non-scaling-stroke' - }, function(item, value) { - return !value - && (item instanceof PathItem - || item instanceof Shape - || item instanceof TextItem); - }], - miterLimit: ['stroke-miterlimit', 'number'], - dashArray: ['stroke-dasharray', 'array'], - dashOffset: ['stroke-dashoffset', 'number'], - fontFamily: ['font-family', 'string'], - fontWeight: ['font-weight', 'string'], - fontSize: ['font-size', 'number'], - justification: ['text-anchor', 'lookup', { - left: 'start', - center: 'middle', - right: 'end' - }], - opacity: ['opacity', 'number'], - blendMode: ['mix-blend-mode', 'style'] -}, function(entry, key) { - var part = Base.capitalize(key), - lookup = entry[2]; - this[key] = { - type: entry[1], - property: key, - attribute: entry[0], - toSVG: lookup, - fromSVG: lookup && Base.each(lookup, function(value, name) { - this[value] = name; - }, {}), - exportFilter: entry[3], - get: 'get' + part, - set: 'set' + part - }; -}, {}); - -new function() { - var formatter; - - function getTransform(matrix, coordinates, center) { - var attrs = new Base(), - trans = matrix.getTranslation(); - if (coordinates) { - matrix = matrix._shiftless(); - var point = matrix._inverseTransform(trans); - attrs[center ? 'cx' : 'x'] = point.x; - attrs[center ? 'cy' : 'y'] = point.y; - trans = null; - } - if (!matrix.isIdentity()) { - var decomposed = matrix.decompose(); - if (decomposed) { - var parts = [], - angle = decomposed.rotation, - scale = decomposed.scaling, - skew = decomposed.skewing; - if (trans && !trans.isZero()) - parts.push('translate(' + formatter.point(trans) + ')'); - if (angle) - parts.push('rotate(' + formatter.number(angle) + ')'); - if (!Numerical.isZero(scale.x - 1) - || !Numerical.isZero(scale.y - 1)) - parts.push('scale(' + formatter.point(scale) +')'); - if (skew.x) - parts.push('skewX(' + formatter.number(skew.x) + ')'); - if (skew.y) - parts.push('skewY(' + formatter.number(skew.y) + ')'); - attrs.transform = parts.join(' '); - } else { - attrs.transform = 'matrix(' + matrix.getValues().join(',') + ')'; - } - } - return attrs; - } - - function exportGroup(item, options) { - var attrs = getTransform(item._matrix), - children = item._children; - var node = SvgElement.create('g', attrs, formatter); - for (var i = 0, l = children.length; i < l; i++) { - var child = children[i]; - var childNode = exportSVG(child, options); - if (childNode) { - if (child.isClipMask()) { - var clip = SvgElement.create('clipPath'); - clip.appendChild(childNode); - setDefinition(child, clip, 'clip'); - SvgElement.set(node, { - 'clip-path': 'url(#' + clip.id + ')' - }); - } else { - node.appendChild(childNode); - } - } - } - return node; - } - - function exportRaster(item, options) { - var attrs = getTransform(item._matrix, true), - size = item.getSize(), - image = item.getImage(); - attrs.x -= size.width / 2; - attrs.y -= size.height / 2; - attrs.width = size.width; - attrs.height = size.height; - attrs.href = options.embedImages == false && image && image.src - || item.toDataURL(); - return SvgElement.create('image', attrs, formatter); - } - - function exportPath(item, options) { - var matchShapes = options.matchShapes; - if (matchShapes) { - var shape = item.toShape(false); - if (shape) - return exportShape(shape, options); - } - var segments = item._segments, - length = segments.length, - type, - attrs = getTransform(item._matrix); - if (matchShapes && length >= 2 && !item.hasHandles()) { - if (length > 2) { - type = item._closed ? 'polygon' : 'polyline'; - var parts = []; - for (var i = 0; i < length; i++) { - parts.push(formatter.point(segments[i]._point)); - } - attrs.points = parts.join(' '); - } else { - type = 'line'; - var start = segments[0]._point, - end = segments[1]._point; - attrs.set({ - x1: start.x, - y1: start.y, - x2: end.x, - y2: end.y - }); - } - } else { - type = 'path'; - attrs.d = item.getPathData(null, options.precision); - } - return SvgElement.create(type, attrs, formatter); - } - - function exportShape(item) { - var type = item._type, - radius = item._radius, - attrs = getTransform(item._matrix, true, type !== 'rectangle'); - if (type === 'rectangle') { - type = 'rect'; - var size = item._size, - width = size.width, - height = size.height; - attrs.x -= width / 2; - attrs.y -= height / 2; - attrs.width = width; - attrs.height = height; - if (radius.isZero()) - radius = null; - } - if (radius) { - if (type === 'circle') { - attrs.r = radius; - } else { - attrs.rx = radius.width; - attrs.ry = radius.height; - } - } - return SvgElement.create(type, attrs, formatter); - } - - function exportCompoundPath(item, options) { - var attrs = getTransform(item._matrix); - var data = item.getPathData(null, options.precision); - if (data) - attrs.d = data; - return SvgElement.create('path', attrs, formatter); - } - - function exportSymbolItem(item, options) { - var attrs = getTransform(item._matrix, true), - definition = item._definition, - node = getDefinition(definition, 'symbol'), - definitionItem = definition._item, - bounds = definitionItem.getBounds(); - if (!node) { - node = SvgElement.create('symbol', { - viewBox: formatter.rectangle(bounds) - }); - node.appendChild(exportSVG(definitionItem, options)); - setDefinition(definition, node, 'symbol'); - } - attrs.href = '#' + node.id; - attrs.x += bounds.x; - attrs.y += bounds.y; - attrs.width = bounds.width; - attrs.height = bounds.height; - attrs.overflow = 'visible'; - return SvgElement.create('use', attrs, formatter); - } - - function exportGradient(color) { - var gradientNode = getDefinition(color, 'color'); - if (!gradientNode) { - var gradient = color.getGradient(), - radial = gradient._radial, - origin = color.getOrigin(), - destination = color.getDestination(), - attrs; - if (radial) { - attrs = { - cx: origin.x, - cy: origin.y, - r: origin.getDistance(destination) - }; - var highlight = color.getHighlight(); - if (highlight) { - attrs.fx = highlight.x; - attrs.fy = highlight.y; - } - } else { - attrs = { - x1: origin.x, - y1: origin.y, - x2: destination.x, - y2: destination.y - }; - } - attrs.gradientUnits = 'userSpaceOnUse'; - gradientNode = SvgElement.create((radial ? 'radial' : 'linear') - + 'Gradient', attrs, formatter); - var stops = gradient._stops; - for (var i = 0, l = stops.length; i < l; i++) { - var stop = stops[i], - stopColor = stop._color, - alpha = stopColor.getAlpha(), - offset = stop._offset; - attrs = { - offset: offset == null ? i / (l - 1) : offset - }; - if (stopColor) - attrs['stop-color'] = stopColor.toCSS(true); - if (alpha < 1) - attrs['stop-opacity'] = alpha; - gradientNode.appendChild( - SvgElement.create('stop', attrs, formatter)); - } - setDefinition(color, gradientNode, 'color'); - } - return 'url(#' + gradientNode.id + ')'; - } - - function exportText(item) { - var node = SvgElement.create('text', getTransform(item._matrix, true), - formatter); - node.textContent = item._content; - return node; - } - - var exporters = { - Group: exportGroup, - Layer: exportGroup, - Raster: exportRaster, - Path: exportPath, - Shape: exportShape, - CompoundPath: exportCompoundPath, - SymbolItem: exportSymbolItem, - PointText: exportText - }; - - function applyStyle(item, node, isRoot) { - var attrs = {}, - parent = !isRoot && item.getParent(), - style = []; - - if (item._name != null) - attrs.id = item._name; - - Base.each(SvgStyles, function(entry) { - var get = entry.get, - type = entry.type, - value = item[get](); - if (entry.exportFilter - ? entry.exportFilter(item, value) - : !parent || !Base.equals(parent[get](), value)) { - if (type === 'color' && value != null) { - var alpha = value.getAlpha(); - if (alpha < 1) - attrs[entry.attribute + '-opacity'] = alpha; - } - if (type === 'style') { - style.push(entry.attribute + ': ' + value); - } else { - attrs[entry.attribute] = value == null ? 'none' - : type === 'color' ? value.gradient - ? exportGradient(value, item) - : value.toCSS(true) - : type === 'array' ? value.join(',') - : type === 'lookup' ? entry.toSVG[value] - : value; - } - } - }); - - if (style.length) - attrs.style = style.join(';'); - - if (attrs.opacity === 1) - delete attrs.opacity; - - if (!item._visible) - attrs.visibility = 'hidden'; - - return SvgElement.set(node, attrs, formatter); - } - - var definitions; - function getDefinition(item, type) { - if (!definitions) - definitions = { ids: {}, svgs: {} }; - return item && definitions.svgs[type + '-' - + (item._id || item.__id || (item.__id = UID.get('svg')))]; - } - - function setDefinition(item, node, type) { - if (!definitions) - getDefinition(); - var typeId = definitions.ids[type] = (definitions.ids[type] || 0) + 1; - node.id = type + '-' + typeId; - definitions.svgs[type + '-' + (item._id || item.__id)] = node; - } - - function exportDefinitions(node, options) { - var svg = node, - defs = null; - if (definitions) { - svg = node.nodeName.toLowerCase() === 'svg' && node; - for (var i in definitions.svgs) { - if (!defs) { - if (!svg) { - svg = SvgElement.create('svg'); - svg.appendChild(node); - } - defs = svg.insertBefore(SvgElement.create('defs'), - svg.firstChild); - } - defs.appendChild(definitions.svgs[i]); - } - definitions = null; - } - return options.asString - ? new self.XMLSerializer().serializeToString(svg) - : svg; - } - - function exportSVG(item, options, isRoot) { - var exporter = exporters[item._class], - node = exporter && exporter(item, options); - if (node) { - var onExport = options.onExport; - if (onExport) - node = onExport(item, node, options) || node; - var data = JSON.stringify(item._data); - if (data && data !== '{}' && data !== 'null') - node.setAttribute('data-paper-data', data); - } - return node && applyStyle(item, node, isRoot); - } - - function setOptions(options) { - if (!options) - options = {}; - formatter = new Formatter(options.precision); - return options; - } - - Item.inject({ - exportSVG: function(options) { - options = setOptions(options); - return exportDefinitions(exportSVG(this, options, true), options); - } - }); - - Project.inject({ - exportSVG: function(options) { - options = setOptions(options); - var children = this._children, - view = this.getView(), - bounds = Base.pick(options.bounds, 'view'), - mx = options.matrix || bounds === 'view' && view._matrix, - matrix = mx && Matrix.read([mx]), - rect = bounds === 'view' - ? new Rectangle([0, 0], view.getViewSize()) - : bounds === 'content' - ? Item._getBounds(children, matrix, { stroke: true }) - .rect - : Rectangle.read([bounds], 0, { readNull: true }), - attrs = { - version: '1.1', - xmlns: SvgElement.svg, - 'xmlns:xlink': SvgElement.xlink, - }; - if (rect) { - attrs.width = rect.width; - attrs.height = rect.height; - if (rect.x || rect.y) - attrs.viewBox = formatter.rectangle(rect); - } - var node = SvgElement.create('svg', attrs, formatter), - parent = node; - if (matrix && !matrix.isIdentity()) { - parent = node.appendChild(SvgElement.create('g', - getTransform(matrix), formatter)); - } - for (var i = 0, l = children.length; i < l; i++) { - parent.appendChild(exportSVG(children[i], options, true)); - } - return exportDefinitions(node, options); - } - }); -}; - -new function() { - - var definitions = {}, - rootSize; - - function getValue(node, name, isString, allowNull, allowPercent) { - var value = SvgElement.get(node, name), - res = value == null - ? allowNull - ? null - : isString ? '' : 0 - : isString - ? value - : parseFloat(value); - return /%\s*$/.test(value) - ? (res / 100) * (allowPercent ? 1 - : rootSize[/x|^width/.test(name) ? 'width' : 'height']) - : res; - } - - function getPoint(node, x, y, allowNull, allowPercent) { - x = getValue(node, x || 'x', false, allowNull, allowPercent); - y = getValue(node, y || 'y', false, allowNull, allowPercent); - return allowNull && (x == null || y == null) ? null - : new Point(x, y); - } - - function getSize(node, w, h, allowNull, allowPercent) { - w = getValue(node, w || 'width', false, allowNull, allowPercent); - h = getValue(node, h || 'height', false, allowNull, allowPercent); - return allowNull && (w == null || h == null) ? null - : new Size(w, h); - } - - function convertValue(value, type, lookup) { - return value === 'none' ? null - : type === 'number' ? parseFloat(value) - : type === 'array' ? - value ? value.split(/[\s,]+/g).map(parseFloat) : [] - : type === 'color' ? getDefinition(value) || value - : type === 'lookup' ? lookup[value] - : value; - } - - function importGroup(node, type, options, isRoot) { - var nodes = node.childNodes, - isClip = type === 'clippath', - isDefs = type === 'defs', - item = new Group(), - project = item._project, - currentStyle = project._currentStyle, - children = []; - if (!isClip && !isDefs) { - item = applyAttributes(item, node, isRoot); - project._currentStyle = item._style.clone(); - } - if (isRoot) { - var defs = node.querySelectorAll('defs'); - for (var i = 0, l = defs.length; i < l; i++) { - importNode(defs[i], options, false); - } - } - for (var i = 0, l = nodes.length; i < l; i++) { - var childNode = nodes[i], - child; - if (childNode.nodeType === 1 - && !/^defs$/i.test(childNode.nodeName) - && (child = importNode(childNode, options, false)) - && !(child instanceof SymbolDefinition)) - children.push(child); - } - item.addChildren(children); - if (isClip) - item = applyAttributes(item.reduce(), node, isRoot); - project._currentStyle = currentStyle; - if (isClip || isDefs) { - item.remove(); - item = null; - } - return item; - } - - function importPoly(node, type) { - var coords = node.getAttribute('points').match( - /[+-]?(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?/g), - points = []; - for (var i = 0, l = coords.length; i < l; i += 2) - points.push(new Point( - parseFloat(coords[i]), - parseFloat(coords[i + 1]))); - var path = new Path(points); - if (type === 'polygon') - path.closePath(); - return path; - } - - function importPath(node) { - return PathItem.create(node.getAttribute('d')); - } - - function importGradient(node, type) { - var id = (getValue(node, 'href', true) || '').substring(1), - radial = type === 'radialgradient', - gradient; - if (id) { - gradient = definitions[id].getGradient(); - if (gradient._radial ^ radial) { - gradient = gradient.clone(); - gradient._radial = radial; - } - } else { - var nodes = node.childNodes, - stops = []; - for (var i = 0, l = nodes.length; i < l; i++) { - var child = nodes[i]; - if (child.nodeType === 1) - stops.push(applyAttributes(new GradientStop(), child)); - } - gradient = new Gradient(stops, radial); - } - var origin, destination, highlight, - scaleToBounds = getValue(node, 'gradientUnits', true) !== - 'userSpaceOnUse'; - if (radial) { - origin = getPoint(node, 'cx', 'cy', false, scaleToBounds); - destination = origin.add( - getValue(node, 'r', false, false, scaleToBounds), 0); - highlight = getPoint(node, 'fx', 'fy', true, scaleToBounds); - } else { - origin = getPoint(node, 'x1', 'y1', false, scaleToBounds); - destination = getPoint(node, 'x2', 'y2', false, scaleToBounds); - } - var color = applyAttributes( - new Color(gradient, origin, destination, highlight), node); - color._scaleToBounds = scaleToBounds; - return null; - } - - var importers = { - '#document': function (node, type, options, isRoot) { - var nodes = node.childNodes; - for (var i = 0, l = nodes.length; i < l; i++) { - var child = nodes[i]; - if (child.nodeType === 1) - return importNode(child, options, isRoot); - } - }, - g: importGroup, - svg: importGroup, - clippath: importGroup, - polygon: importPoly, - polyline: importPoly, - path: importPath, - lineargradient: importGradient, - radialgradient: importGradient, - - image: function (node) { - var raster = new Raster(getValue(node, 'href', true)); - raster.on('load', function() { - var size = getSize(node); - this.setSize(size); - var center = getPoint(node).add(size.divide(2)); - this._matrix.append(new Matrix().translate(center)); - }); - return raster; - }, - - symbol: function(node, type, options, isRoot) { - return new SymbolDefinition( - importGroup(node, type, options, isRoot), true); - }, - - defs: importGroup, - - use: function(node) { - var id = (getValue(node, 'href', true) || '').substring(1), - definition = definitions[id], - point = getPoint(node); - return definition - ? definition instanceof SymbolDefinition - ? definition.place(point) - : definition.clone().translate(point) - : null; - }, - - circle: function(node) { - return new Shape.Circle( - getPoint(node, 'cx', 'cy'), - getValue(node, 'r')); - }, - - ellipse: function(node) { - return new Shape.Ellipse({ - center: getPoint(node, 'cx', 'cy'), - radius: getSize(node, 'rx', 'ry') - }); - }, - - rect: function(node) { - return new Shape.Rectangle(new Rectangle( - getPoint(node), - getSize(node) - ), getSize(node, 'rx', 'ry')); - }, - - line: function(node) { - return new Path.Line( - getPoint(node, 'x1', 'y1'), - getPoint(node, 'x2', 'y2')); - }, - - text: function(node) { - var text = new PointText(getPoint(node).add( - getPoint(node, 'dx', 'dy'))); - text.setContent(node.textContent.trim() || ''); - return text; - } - }; - - function applyTransform(item, value, name, node) { - if (item.transform) { - var transforms = (node.getAttribute(name) || '').split(/\)\s*/g), - matrix = new Matrix(); - for (var i = 0, l = transforms.length; i < l; i++) { - var transform = transforms[i]; - if (!transform) - break; - var parts = transform.split(/\(\s*/), - command = parts[0], - v = parts[1].split(/[\s,]+/g); - for (var j = 0, m = v.length; j < m; j++) - v[j] = parseFloat(v[j]); - switch (command) { - case 'matrix': - matrix.append( - new Matrix(v[0], v[1], v[2], v[3], v[4], v[5])); - break; - case 'rotate': - matrix.rotate(v[0], v[1] || 0, v[2] || 0); - break; - case 'translate': - matrix.translate(v[0], v[1] || 0); - break; - case 'scale': - matrix.scale(v); - break; - case 'skewX': - matrix.skew(v[0], 0); - break; - case 'skewY': - matrix.skew(0, v[0]); - break; - } - } - item.transform(matrix); - } - } - - function applyOpacity(item, value, name) { - var key = name === 'fill-opacity' ? 'getFillColor' : 'getStrokeColor', - color = item[key] && item[key](); - if (color) - color.setAlpha(parseFloat(value)); - } - - var attributes = Base.set(Base.each(SvgStyles, function(entry) { - this[entry.attribute] = function(item, value) { - if (item[entry.set]) { - item[entry.set](convertValue(value, entry.type, entry.fromSVG)); - if (entry.type === 'color') { - var color = item[entry.get](); - if (color) { - if (color._scaleToBounds) { - var bounds = item.getBounds(); - color.transform(new Matrix() - .translate(bounds.getPoint()) - .scale(bounds.getSize())); - } - } - } - } - }; - }, {}), { - id: function(item, value) { - definitions[value] = item; - if (item.setName) - item.setName(value); - }, - - 'clip-path': function(item, value) { - var clip = getDefinition(value); - if (clip) { - clip = clip.clone(); - clip.setClipMask(true); - if (item instanceof Group) { - item.insertChild(0, clip); - } else { - return new Group(clip, item); - } - } - }, - - gradientTransform: applyTransform, - transform: applyTransform, - - 'fill-opacity': applyOpacity, - 'stroke-opacity': applyOpacity, - - visibility: function(item, value) { - if (item.setVisible) - item.setVisible(value === 'visible'); - }, - - display: function(item, value) { - if (item.setVisible) - item.setVisible(value !== null); - }, - - 'stop-color': function(item, value) { - if (item.setColor) - item.setColor(value); - }, - - 'stop-opacity': function(item, value) { - if (item._color) - item._color.setAlpha(parseFloat(value)); - }, - - offset: function(item, value) { - if (item.setOffset) { - var percent = value.match(/(.*)%$/); - item.setOffset(percent ? percent[1] / 100 : parseFloat(value)); - } - }, - - viewBox: function(item, value, name, node, styles) { - var rect = new Rectangle(convertValue(value, 'array')), - size = getSize(node, null, null, true), - group, - matrix; - if (item instanceof Group) { - var scale = size ? size.divide(rect.getSize()) : 1, - matrix = new Matrix().scale(scale) - .translate(rect.getPoint().negate()); - group = item; - } else if (item instanceof SymbolDefinition) { - if (size) - rect.setSize(size); - group = item._item; - } - if (group) { - if (getAttribute(node, 'overflow', styles) !== 'visible') { - var clip = new Shape.Rectangle(rect); - clip.setClipMask(true); - group.addChild(clip); - } - if (matrix) - group.transform(matrix); - } - } - }); - - function getAttribute(node, name, styles) { - var attr = node.attributes[name], - value = attr && attr.value; - if (!value && node.style) { - var style = Base.camelize(name); - value = node.style[style]; - if (!value && styles.node[style] !== styles.parent[style]) - value = styles.node[style]; - } - return !value ? undefined - : value === 'none' ? null - : value; - } - - function applyAttributes(item, node, isRoot) { - var parent = node.parentNode, - styles = { - node: DomElement.getStyles(node) || {}, - parent: !isRoot && !/^defs$/i.test(parent.tagName) - && DomElement.getStyles(parent) || {} - }; - Base.each(attributes, function(apply, name) { - var value = getAttribute(node, name, styles); - item = value !== undefined - && apply(item, value, name, node, styles) || item; - }); - return item; - } - - function getDefinition(value) { - var match = value && value.match(/\((?:["'#]*)([^"')]+)/), - name = match && match[1], - res = name && definitions[window - ? name.replace(window.location.href.split('#')[0] + '#', '') - : name]; - if (res && res._scaleToBounds) { - res = res.clone(); - res._scaleToBounds = true; - } - return res; - } - - function importNode(node, options, isRoot) { - var type = node.nodeName.toLowerCase(), - isElement = type !== '#document', - body = document.body, - container, - parent, - next; - if (isRoot && isElement) { - rootSize = paper.getView().getSize(); - rootSize = getSize(node, null, null, true) || rootSize; - container = SvgElement.create('svg', { - style: 'stroke-width: 1px; stroke-miterlimit: 10' - }); - parent = node.parentNode; - next = node.nextSibling; - container.appendChild(node); - body.appendChild(container); - } - var settings = paper.settings, - applyMatrix = settings.applyMatrix, - insertItems = settings.insertItems; - settings.applyMatrix = false; - settings.insertItems = false; - var importer = importers[type], - item = importer && importer(node, type, options, isRoot) || null; - settings.insertItems = insertItems; - settings.applyMatrix = applyMatrix; - if (item) { - if (isElement && !(item instanceof Group)) - item = applyAttributes(item, node, isRoot); - var onImport = options.onImport, - data = isElement && node.getAttribute('data-paper-data'); - if (onImport) - item = onImport(node, item, options) || item; - if (options.expandShapes && item instanceof Shape) { - item.remove(); - item = item.toPath(); - } - if (data) - item._data = JSON.parse(data); - } - if (container) { - body.removeChild(container); - if (parent) { - if (next) { - parent.insertBefore(node, next); - } else { - parent.appendChild(node); - } - } - } - if (isRoot) { - definitions = {}; - if (item && Base.pick(options.applyMatrix, applyMatrix)) - item.matrix.apply(true, true); - } - return item; - } - - function importSVG(source, options, owner) { - if (!source) - return null; - options = typeof options === 'function' ? { onLoad: options } - : options || {}; - var scope = paper, - item = null; - - function onLoad(svg) { - try { - var node = typeof svg === 'object' ? svg : new self.DOMParser() - .parseFromString(svg, 'image/svg+xml'); - if (!node.nodeName) { - node = null; - throw new Error('Unsupported SVG source: ' + source); - } - paper = scope; - item = importNode(node, options, true); - if (!options || options.insert !== false) { - owner._insertItem(undefined, item); - } - var onLoad = options.onLoad; - if (onLoad) - onLoad(item, svg); - } catch (e) { - onError(e); - } - } - - function onError(message, status) { - var onError = options.onError; - if (onError) { - onError(message, status); - } else { - throw new Error(message); - } - } - - if (typeof source === 'string' && !/^.*JQ%) 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

7O{wQtjl+0Fj?4_mxS}BVMj^=<)BUQ#b}Ay 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�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 diff --git a/docs/images/chapters/canonical/675217e6df3d75c86503dc2af623e14e.png b/docs/images/chapters/canonical/675217e6df3d75c86503dc2af623e14e.png deleted file mode 100644 index eea3208c7f2f4716fcb4d6ded975eae7f2fd3489..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23395 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 literal 0 HcmV?d00001 diff --git a/docs/images/chapters/canonical/c086e72bd8aaeab37436515ab251b2df.png b/docs/images/chapters/canonical/c086e72bd8aaeab37436515ab251b2df.png new file mode 100644 index 0000000000000000000000000000000000000000..488ba3b5422143ca512e7af7a2cde26bb8d8eb30 GIT binary patch literal 24180 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 Scripts are disabled. Showing fallback image. - + @@ -341,7 +341,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -350,7 +350,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -1229,7 +1229,7 @@ function getCubicRoots(pa, pb, pc, pd) { Scripts are disabled. Showing fallback image. - + @@ -1296,7 +1296,7 @@ function getCubicRoots(pa, pb, pc, pd) { Scripts are disabled. Showing fallback image. - + @@ -1501,7 +1501,7 @@ y = curve.get(t).y Scripts are disabled. Showing fallback image. - + @@ -1521,7 +1521,7 @@ y = curve.get(t).y Scripts are disabled. Showing fallback image. - + @@ -1554,13 +1554,13 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + Scripts are disabled. Showing fallback image. - + @@ -1588,7 +1588,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1675,7 +1675,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1689,7 +1689,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1743,7 +1743,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1752,7 +1752,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1761,7 +1761,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1864,7 +1864,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -2087,7 +2087,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2096,7 +2096,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2120,7 +2120,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2129,7 +2129,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2146,7 +2146,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2203,7 +2203,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2319,7 +2319,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + diff --git a/docs/ja-JP/index.html b/docs/ja-JP/index.html index 46235b53..a128be1c 100644 --- a/docs/ja-JP/index.html +++ b/docs/ja-JP/index.html @@ -334,7 +334,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -343,7 +343,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -352,7 +352,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -1225,7 +1225,7 @@ function getCubicRoots(pa, pb, pc, pd) { Scripts are disabled. Showing fallback image. - + @@ -1292,7 +1292,7 @@ function getCubicRoots(pa, pb, pc, pd) { Scripts are disabled. Showing fallback image. - + @@ -1497,7 +1497,7 @@ y = curve.get(t).y Scripts are disabled. Showing fallback image. - + @@ -1517,7 +1517,7 @@ y = curve.get(t).y Scripts are disabled. Showing fallback image. - + @@ -1550,13 +1550,13 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + Scripts are disabled. Showing fallback image. - + @@ -1584,7 +1584,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1671,7 +1671,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1685,7 +1685,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1739,7 +1739,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1748,7 +1748,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1757,7 +1757,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1860,7 +1860,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -2083,7 +2083,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2092,7 +2092,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2116,7 +2116,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2125,7 +2125,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2142,7 +2142,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2199,7 +2199,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2315,7 +2315,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + diff --git a/docs/js/custom-element/lib/perform-code-surgery.js b/docs/js/custom-element/lib/perform-code-surgery.js index 02f73f35..2d765594 100644 --- a/docs/js/custom-element/lib/perform-code-surgery.js +++ b/docs/js/custom-element/lib/perform-code-surgery.js @@ -22,7 +22,7 @@ export default function performCodeSurgery(code) { // 3. rewrite all public GraphicsAPI functions to have the required `this.` prefix GraphicsAPI.methods.forEach((fn) => { - const re = new RegExp(`([\\s\\r\\n])${fn}\\(`, `g`); + const re = new RegExp(`([({\\s\\r\\n])${fn}\\(`, `g`); code = code.replace(re, `$1this.${fn}(`); }); diff --git a/docs/zh-CN/index.html b/docs/zh-CN/index.html index 855f51bf..dad0d8d8 100644 --- a/docs/zh-CN/index.html +++ b/docs/zh-CN/index.html @@ -328,7 +328,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -337,7 +337,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -346,7 +346,7 @@ function Bezier(3,t): Scripts are disabled. Showing fallback image. - + @@ -1219,7 +1219,7 @@ function getCubicRoots(pa, pb, pc, pd) { Scripts are disabled. Showing fallback image. - + @@ -1286,7 +1286,7 @@ function getCubicRoots(pa, pb, pc, pd) { Scripts are disabled. Showing fallback image. - + @@ -1491,7 +1491,7 @@ y = curve.get(t).y Scripts are disabled. Showing fallback image. - + @@ -1511,7 +1511,7 @@ y = curve.get(t).y Scripts are disabled. Showing fallback image. - + @@ -1544,13 +1544,13 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + Scripts are disabled. Showing fallback image. - + @@ -1578,7 +1578,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1665,7 +1665,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1679,7 +1679,7 @@ lli = function(line1, line2): Scripts are disabled. Showing fallback image. - + @@ -1733,7 +1733,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1742,7 +1742,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1751,7 +1751,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -1854,7 +1854,7 @@ for (coordinate, index) in LUT: Scripts are disabled. Showing fallback image. - + @@ -2077,7 +2077,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2086,7 +2086,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2110,7 +2110,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2119,7 +2119,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2136,7 +2136,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2193,7 +2193,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - + @@ -2309,7 +2309,7 @@ for p = 1 to points.length-3 (inclusive): Scripts are disabled. Showing fallback image. - +