* 'master' of https://github.com/paperjs/paper.js: (56 commits)
  Fix regressions in Raster caused by faulty merge.
  Store data in _data rather than on the image itself.
  Clean up @trankek's fix for node a bit.
  Explain compact = true in Project#_serialize()
  Properly fix issue with Project#exportJSON() creating separate projects on import.
  Update straps.js to version 1.1.0
  Rename options.server to options.node
  Remove all create() constructors for basic types since new constructors are now faster.
  Make sure project we import into is active.
  Unbox project data in Project#importJSON(), as we don't want to create a new project object.
  Remove need for _needsRedraw() calls by replacing it with a boolean flag.
  Apply "pending" matrix in group when it receives content.
  Move main Item insertion code from #insertChild() to #insertChildren().
  Fix documentation warning.
  Handle exporting of Numerical and PaperScript in export.js
  Update straps.js to latest version.
  Accessors cannot define the writable property.
  Properly export Numerical and PaperScript again.
  Only reset matrices in Groups when it could actually be applied to the content.
  Set options.stats = false for build.sh and Node.js
  ...
This commit is contained in:
hkrish 2013-05-29 19:09:07 +02:00
commit cdaab794f2
63 changed files with 834 additions and 893 deletions

View file

@ -31,4 +31,4 @@ then
fi fi
./preprocess.sh $MODE ../src/paper.js "-d '{ \"browser\": true }' -i '../src/constants.js'" ../dist/paper.js ./preprocess.sh $MODE ../src/paper.js "-d '{ \"browser\": true }' -i '../src/constants.js'" ../dist/paper.js
#./preprocess.sh $MODE ../src/paper.js "-d '{ \"server\": true }' -i '../src/constants.js'" ../dist/paper-server.js #./preprocess.sh $MODE ../src/paper.js "-d '{ \"node\": true }' -i '../src/constants.js'" ../dist/paper-node.js

View file

@ -24,10 +24,19 @@
# commented Preprocessed, still formated and commented # commented Preprocessed, still formated and commented
# stripped Preprocessed, formated but without comments # stripped Preprocessed, formated but without comments
VERSION=0.8 # Get the date from the git log:
DATE=$(git log -1 --pretty=format:%ad) DATE=$(git log -1 --pretty=format:%ad)
# Extract the paper.js version from package.json:
COMMAND="./prepro.js -d '{ \"version\": $VERSION, \"date\": \"$DATE\", \"parser\": \"acorn\", \"svg\": true, \"fatline\": false }' $3 $2" VERSION=$(node -e "
process.stdout.write(require('../package.json').version)
")
# Load and evaluate the options from options.js, and convert it an escaped json:
OPTIONS=$(printf '%q' $(node -e "
eval(require('fs').readFileSync('../src/options.js', 'utf8'));
process.stdout.write(JSON.stringify(options));
"))
# Build the prepo.js command out of it, passing on version and date as defines:
COMMAND="./prepro.js -d $OPTIONS -d '{ \"version\": \"$VERSION\", \"date\": \"$DATE\", \"stats\": false }' $3 $2"
case $1 in case $1 in
commented) commented)

View file

@ -1,4 +1,5 @@
// Uncomment this to turn on fatline clipping in paper.js too
options.fatline = true;
paper.install(window); paper.install(window);
/** /**
@ -235,40 +236,40 @@ function runTests() {
prepareTest('Results - Boolean tests (Time taken per test)', container, 'big'); prepareTest('Results - Boolean tests (Time taken per test)', container, 'big');
var x = 80.5, y = 15.5, width = 500, height = 190, i, txt, ny, var x = 80.5, y = 15.5, width = 500, height = 190, i, txt, ny,
yy = y + height, xx = x + width; yy = y + height, xx = x + width;
var ppaperfill = new Path(), pfatfill = new Path(); var ppaper = new Path(),
var ppaper = new Path(), pfat = new Path(); pfat = new Path();
var max = testdata.reduce(function(a, b) { return Math.max(a, b.paperTime + b.fatTime); }, 0) + 20; var max = testdata.reduce(function(a, b) {
return Math.max(a, b.paperTime + b.fatTime);
}, 0) + 20;
var vscale = height / max, hscale = width / testdata.length; var vscale = height / max, hscale = width / testdata.length;
var caxes = '#999', ctxt = '#222', ctxt2 = '#555', cpaper = '#268BD2', cpaperfill ='#B5E1FF', var caxes = '#999', ctxt = '#222', ctxt2 = '#555', cpaper = '#268BD2', cpaperfill ='#B5E1FF',
cfat = '#D33682', cfatfill = '#FFADD4'; cfat = '#D33682', cfatfill = '#FFADD4';
new Path.Line(x, yy, xx, yy).style.strokeColor = caxes; new Path.Line(x, yy, xx, yy).strokeColor = caxes;
new Path.Line(x, yy, x, y).style.strokeColor = caxes; new Path.Line(x, yy, x, y).strokeColor = caxes;
for (i = 0; i < 10 ; i++) { for (i = 0; i < 10 ; i++) {
ny = yy - vscale * max * i / 10; ny = yy - vscale * max * i / 10;
new Path.Line(x, ny, x-5, ny).style.strokeColor = caxes; new Path.Line(x, ny, x-5, ny).strokeColor = caxes;
txt = new PointText([x-10, ny]); txt = new PointText([x-10, ny]);
txt.justification = 'right'; txt.justification = 'right';
txt.fillColor = (i%2)? ctxt: ctxt2; txt.fillColor = (i%2)? ctxt: ctxt2;
txt.content = (max * i / 10).toFixed(1) + ((!i)? ' ms' : ''); txt.content = (max * i / 10).toFixed(1) + ((!i)? ' ms' : '');
} }
ppaperfill.add(new Segment(x, yy)); ppaper.add(x, yy);
pfatfill.add(new Segment(x, yy)); pfat.add(x, yy);
var vx = x, clr = ctxt; var vx = x, clr = ctxt;
var coords = [], avgPaper = 0, avgFat = 0, var coords = [], avgPaper = 0, avgFat = 0,
maxSpeedup = -Infinity, minSpeedup = Infinity, avgSpeedup = 0; maxSpeedup = -Infinity, minSpeedup = Infinity, avgSpeedup = 0;
testdata.map(function(data) { testdata.map(function(data) {
avgPaper += data.paperTime; avgPaper += data.paperTime;
ny = yy - (data.paperTime + data.fatTime) * vscale; ny = yy - (data.paperTime /*+ data.fatTime */) * vscale;
ppaper.add(new Segment([vx, ny])); ppaper.add(vx, ny);
ppaperfill.add(new Segment([vx, ny]));
var np = new Point(vx, ny); var np = new Point(vx, ny);
np._data = data; np._data = data;
np._datatype = 'paper'; np._datatype = 'paper';
coords.push(np); coords.push(np);
avgFat += data.fatTime; avgFat += data.fatTime;
ny = yy - (data.fatTime) * vscale; ny = yy - (data.fatTime) * vscale;
pfat.add(new Segment([vx, ny])); pfat.add(vx, ny);
pfatfill.add(new Segment([vx, ny]));
np = new Point(vx, ny); np = new Point(vx, ny);
np._data = data; np._data = data;
np._datatype = 'fat'; np._datatype = 'fat';
@ -279,7 +280,7 @@ function runTests() {
if (speedup < minSpeedup) minSpeedup = speedup; if (speedup < minSpeedup) minSpeedup = speedup;
avgSpeedup += speedup; avgSpeedup += speedup;
new Path.Line(vx, yy, vx, yy + 5).style.strokeColor = caxes; new Path.Line(vx, yy, vx, yy + 5).strokeColor = caxes;
txt = new PointText([vx, yy+18]); txt = new PointText([vx, yy+18]);
txt.justification = 'left'; txt.justification = 'left';
txt.fillColor = clr; txt.fillColor = clr;
@ -288,23 +289,25 @@ function runTests() {
if (!data.success) { if (!data.success) {
var p = new Path.Line(vx, y, vx, yy); var p = new Path.Line(vx, y, vx, yy);
p.style.strokeWidth = 5; p.strokeWidth = 5;
p.style.strokeColor = '#f00'; p.strokeColor = '#f00';
} }
clr = (clr === ctxt)? ctxt2 : ctxt; clr = (clr === ctxt)? ctxt2 : ctxt;
vx += hscale; vx += hscale;
}); });
ppaper.style.strokeWidth = 2; ppaper.strokeWidth = 2;
ppaper.style.strokeColor = cpaper; ppaper.strokeColor = cpaper;
ppaperfill.add(new Segment(vx-hscale, yy)); ppaper.add(vx-hscale, yy);
ppaperfill.closed = true; ppaper.closed = true;
ppaperfill.style.fillColor = cpaperfill; ppaper.fillColor = cpaperfill;
pfat.style.strokeWidth = 2; ppaper.opacity = 0.75;
pfat.style.strokeColor = cfat; pfat.strokeWidth = 2;
pfatfill.add(new Segment(vx-hscale, yy)); pfat.strokeColor = cfat;
pfatfill.closed = true; pfat.add(vx-hscale, yy);
pfatfill.style.fillColor = cfatfill; pfat.closed = true;
pfat.fillColor = cfatfill;
pfat.opacity = 0.75;
avgPaper/= testdata.length; avgPaper/= testdata.length;
avgFat/= testdata.length; avgFat/= testdata.length;
@ -312,13 +315,13 @@ function runTests() {
maxSpeedup = Math.round(maxSpeedup); maxSpeedup = Math.round(maxSpeedup);
minSpeedup = Math.round(minSpeedup); minSpeedup = Math.round(minSpeedup);
ny = Math.round(yy - avgPaper * vscale) + 0.5; ny = Math.round(yy - avgPaper * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cpaper; new Path.Line(x, ny, xx, ny).strokeColor = cpaper;
txt = new PointText([xx, ny]); txt = new PointText([xx, ny]);
txt.justification = 'right'; txt.justification = 'right';
txt.fillColor = cpaper; txt.fillColor = cpaper;
txt.content = avgPaper.toFixed(1); txt.content = avgPaper.toFixed(1);
ny = Math.round(yy - avgFat * vscale) + 0.5; ny = Math.round(yy - avgFat * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cfat; new Path.Line(x, ny, xx, ny).strokeColor = cfat;
txt = new PointText([xx, ny]); txt = new PointText([xx, ny]);
txt.justification = 'right'; txt.justification = 'right';
txt.fillColor = cfat; txt.fillColor = cfat;
@ -358,10 +361,10 @@ function runTests() {
if (dist > 500) { return; } if (dist > 500) { return; }
if (pnt && data) { if (pnt && data) {
var p = new Path.Line(pnt.x+0.5, y, pnt.x+0.5, yy); var p = new Path.Line(pnt.x+0.5, y, pnt.x+0.5, yy);
p.style.strokeColor = '#000'; p.strokeColor = '#000';
p.removeOnMove(); p.removeOnMove();
p = new Path.Circle(pnt, 3); p = new Path.Circle(pnt, 3);
p.style.fillColor = (type === 'fat')? '#D33682' :'#268BD2'; p.fillColor = (type === 'fat')? '#D33682' :'#268BD2';
p.removeOnMove(); p.removeOnMove();
var txt = new PointText([ 500, 20 ]); var txt = new PointText([ 500, 20 ]);
txt.content = 'subdiv : ' + data.paperTime.toFixed(1) + ' ms'; txt.content = 'subdiv : ' + data.paperTime.toFixed(1) + ' ms';
@ -563,8 +566,8 @@ function markPoint(pnt, t, c, tc, remove) {
c = c || '#000'; c = c || '#000';
if (remove === undefined) { remove = true; } if (remove === undefined) { remove = true; }
var cir = new Path.Circle(pnt, 2); var cir = new Path.Circle(pnt, 2);
cir.style.fillColor = c; cir.fillColor = c;
cir.style.strokeColor = tc; cir.strokeColor = tc;
if (t !== undefined || t !== null) { if (t !== undefined || t !== null) {
var text = new PointText(pnt.add([0, -3])); var text = new PointText(pnt.add([0, -3]));
text.justification = 'center'; text.justification = 'center';
@ -588,7 +591,7 @@ function markCurve(crv, c, flag) {
new Segment([crv[0], crv[1]], null, [crv[2] - crv[0], crv[3] - crv[1]]), new Segment([crv[0], crv[1]], null, [crv[2] - crv[0], crv[3] - crv[1]]),
new Segment([crv[6], crv[7]], [crv[4] - crv[6], crv[5] - crv[7]], null) new Segment([crv[6], crv[7]], [crv[4] - crv[6], crv[5] - crv[7]], null)
); );
window.__p1.style.strokeColor = c; window.__p1.strokeColor = c;
// window.__p1.fullySelected = true; // window.__p1.fullySelected = true;
} else { } else {
if (window.__p2) window.__p2.remove(); if (window.__p2) window.__p2.remove();
@ -596,7 +599,7 @@ function markCurve(crv, c, flag) {
new Segment([crv[0], crv[1]], null, [crv[2] - crv[0], crv[3] - crv[1]]), new Segment([crv[0], crv[1]], null, [crv[2] - crv[0], crv[3] - crv[1]]),
new Segment([crv[6], crv[7]], [crv[4] - crv[6], crv[5] - crv[7]], null) new Segment([crv[6], crv[7]], [crv[4] - crv[6], crv[5] - crv[7]], null)
); );
window.__p2.style.strokeColor = c; window.__p2.strokeColor = c;
// window.__p2.fullySelected = true; // window.__p2.fullySelected = true;
} }
view.draw(); view.draw();
@ -624,8 +627,8 @@ function annotateSegment(s, t, c, tc, remove, skipCurves) {
var t1 = crv.getNormal(0).normalize(10); var t1 = crv.getNormal(0).normalize(10);
var p = s.point.clone().add(t1); var p = s.point.clone().add(t1);
var cir = new Path.Circle(s.point, 2); var cir = new Path.Circle(s.point, 2);
cir.style.fillColor = c; cir.fillColor = c;
cir.style.strokeColor = tc; cir.strokeColor = tc;
var text = new PointText(p); var text = new PointText(p);
text.justification = 'center'; text.justification = 'center';
text.fillColor = c; text.fillColor = c;
@ -657,8 +660,8 @@ function annotateCurve(crv, t, c, tc, remove) {
text.justification = 'center'; text.justification = 'center';
text.fillColor = tc; text.fillColor = tc;
text.content = t; text.content = t;
l.style.strokeColor = l2.style.strokeColor = c; l.strokeColor = l2.strokeColor = c;
cir.style.fillColor = c; cir.fillColor = c;
if (remove) { if (remove) {
l.removeOnMove(); l.removeOnMove();
l2.removeOnMove(); l2.removeOnMove();
@ -677,11 +680,11 @@ function plotDataRandom(testdata) {
testdata.sort(function(a,b) { return a.ratio - b.ratio; }); testdata.sort(function(a,b) { return a.ratio - b.ratio; });
var vscale = height / max, hscale = width / testdata.length; var vscale = height / max, hscale = width / testdata.length;
var caxes = '#999', ctxt = '#222', cpaper = '#268BD2', cfat = '#D33682'; var caxes = '#999', ctxt = '#222', cpaper = '#268BD2', cfat = '#D33682';
new Path.Line(x, yy, xx, yy).style.strokeColor = caxes; new Path.Line(x, yy, xx, yy).strokeColor = caxes;
new Path.Line(x, yy, x, y).style.strokeColor = caxes; new Path.Line(x, yy, x, y).strokeColor = caxes;
for (i = 0; i < 10 ; i++) { for (i = 0; i < 10 ; i++) {
ny = yy - vscale * max * i / 10; ny = yy - vscale * max * i / 10;
new Path.Line(x, ny, x-5, ny).style.strokeColor = caxes; new Path.Line(x, ny, x-5, ny).strokeColor = caxes;
txt = new PointText([x-10, ny]); txt = new PointText([x-10, ny]);
txt.justification = 'right'; txt.justification = 'right';
txt.fillColor = ctxt; txt.fillColor = ctxt;
@ -699,13 +702,13 @@ function plotDataRandom(testdata) {
var avgPaper = 0, avgFat = 0; var avgPaper = 0, avgFat = 0;
testdata.map(function(data) { testdata.map(function(data) {
avgPaper += data.paperTime; avgPaper += data.paperTime;
ny = yy - (data.paperTime + data.fatTime) * vscale; ny = yy - (data.paperTime /* + data.fatTime*/) * vscale;
ppaper.add(new Segment([vx, ny])); ppaper.add(vx, ny);
avgFat += data.fatTime; avgFat += data.fatTime;
ny = yy - (data.fatTime) * vscale; ny = yy - (data.fatTime) * vscale;
pfat.add(new Segment([vx, ny])); pfat.add(vx, ny);
new Path.Line(vx, yy, vx, yy + 5 + ((count%2)? step:0)).style.strokeColor = caxes; new Path.Line(vx, yy, vx, yy + 5 + ((count%2)? step:0)).strokeColor = caxes;
txt = new PointText([vx, yy+18 + ((count%2)? step:0) ]); txt = new PointText([vx, yy+18 + ((count%2)? step:0) ]);
txt.justification = 'center'; txt.justification = 'center';
txt.fillColor = ctxt; txt.fillColor = ctxt;
@ -718,29 +721,31 @@ function plotDataRandom(testdata) {
if (!data.success) { if (!data.success) {
var p = new Path.Line(vx, y, vx, yy); var p = new Path.Line(vx, y, vx, yy);
p.style.strokeWidth = 5; p.strokeWidth = 5;
p.style.strokeColor = '#f00'; p.strokeColor = '#f00';
} }
++count; ++count;
vx += hscale; vx += hscale;
}); });
ppaper.smooth(); // ppaper.smooth();
ppaper.style.strokeWidth = 2; ppaper.strokeWidth = 2;
ppaper.style.strokeColor = cpaper; ppaper.strokeColor = cpaper;
pfat.smooth(); ppaper.opacity = 0.75;
pfat.style.strokeWidth = 2; // pfat.smooth();
pfat.style.strokeColor = cfat; pfat.strokeWidth = 2;
pfat.strokeColor = cfat;
pfat.opacity = 0.75;
avgPaper/= testdata.length; avgPaper/= testdata.length;
avgFat/= testdata.length; avgFat/= testdata.length;
ny = Math.round(yy - avgPaper * vscale) + 0.5; ny = Math.round(yy - avgPaper * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cpaper; new Path.Line(x, ny, xx, ny).strokeColor = cpaper;
txt = new PointText([xx, ny]); txt = new PointText([xx, ny]);
txt.justification = 'right'; txt.justification = 'right';
txt.fillColor = cpaper; txt.fillColor = cpaper;
txt.content = avgPaper.toFixed(1); txt.content = avgPaper.toFixed(1);
ny = Math.round(yy - avgFat * vscale) + 0.5; ny = Math.round(yy - avgFat * vscale) + 0.5;
new Path.Line(x, ny, xx, ny).style.strokeColor = cfat; new Path.Line(x, ny, xx, ny).strokeColor = cfat;
txt = new PointText([xx, ny]); txt = new PointText([xx, ny]);
txt.justification = 'right'; txt.justification = 'right';
txt.fillColor = cfat; txt.fillColor = cfat;
@ -749,80 +754,78 @@ function plotDataRandom(testdata) {
view.draw(); view.draw();
} }
function drawFatline(v1) { function drawFatline(v1) {
function signum(num) { function signum(num) {
return (num > 0)? 1 : (num < 0)? -1 : 0; return (num > 0)? 1 : (num < 0)? -1 : 0;
} }
var l = new Line([v1[0], v1[1]], [v1[6], v1[7]], false); var l = new Line([v1[0], v1[1]], [v1[6], v1[7]], false);
var p1 = new Point(v1[2], v1[3]), p2 = new Point(v1[4], v1[5]); var p1 = new Point(v1[2], v1[3]), p2 = new Point(v1[4], v1[5]);
var d1 = l.getSide(p1) * l.getDistance(p1) || 0; var d1 = l.getSide(p1) * l.getDistance(p1) || 0;
var d2 = l.getSide(p2) * l.getDistance(p2) || 0; var d2 = l.getSide(p2) * l.getDistance(p2) || 0;
var dmin, dmax; var dmin, dmax;
if (d1 * d2 > 0) { if (d1 * d2 > 0) {
// 3/4 * min{0, d1, d2} // 3/4 * min{0, d1, d2}
dmin = 0.75 * Math.min(0, d1, d2); dmin = 0.75 * Math.min(0, d1, d2);
dmax = 0.75 * Math.max(0, d1, d2); dmax = 0.75 * Math.max(0, d1, d2);
} else { } else {
// 4/9 * min{0, d1, d2} // 4/9 * min{0, d1, d2}
dmin = 4 * Math.min(0, d1, d2) / 9.0; dmin = 4 * Math.min(0, d1, d2) / 9.0;
dmax = 4 * Math.max(0, d1, d2) / 9.0; dmax = 4 * Math.max(0, d1, d2) / 9.0;
} }
var ll = new Path.Line(v1[0], v1[1], v1[6], v1[7]); var ll = new Path.Line(v1[0], v1[1], v1[6], v1[7]);
window.__p3.push(ll); window.__p3.push(ll);
window.__p3[window.__p3.length-1].style.strokeColor = new Color(0,0,0.9, 0.8); window.__p3[window.__p3.length-1].strokeColor = new Color(0,0,0.9, 0.8);
var lp1 = ll.segments[0].point; var lp1 = ll.segments[0].point;
var lp2 = ll.segments[1].point; var lp2 = ll.segments[1].point;
var pm = l.vector, pm1 = pm.rotate(signum(dmin) * -90), pm2 = pm.rotate(signum(dmax) * -90); var pm = l.vector, pm1 = pm.rotate(signum(dmin) * -90), pm2 = pm.rotate(signum(dmax) * -90);
var p11 = lp1.add(pm1.normalize(Math.abs(dmin))); var p11 = lp1.add(pm1.normalize(Math.abs(dmin)));
var p12 = lp2.add(pm1.normalize(Math.abs(dmin))); var p12 = lp2.add(pm1.normalize(Math.abs(dmin)));
var p21 = lp1.add(pm2.normalize(Math.abs(dmax))); var p21 = lp1.add(pm2.normalize(Math.abs(dmax)));
var p22 = lp2.add(pm2.normalize(Math.abs(dmax))); var p22 = lp2.add(pm2.normalize(Math.abs(dmax)));
window.__p3.push(new Path.Line(p11, p12)); window.__p3.push(new Path.Line(p11, p12));
window.__p3[window.__p3.length-1].style.strokeColor = new Color(0,0,0.9); window.__p3[window.__p3.length-1].strokeColor = new Color(0,0,0.9);
window.__p3.push(new Path.Line(p21, p22)); window.__p3.push(new Path.Line(p21, p22));
window.__p3[window.__p3.length-1].style.strokeColor = new Color(0,0,0.9); window.__p3[window.__p3.length-1].strokeColor = new Color(0,0,0.9);
} }
function plotD_vs_t(x, y, arr, arr2, v, dmin, dmax, tmin, tmax, yscale, tvalue) { function plotD_vs_t(x, y, arr, arr2, v, dmin, dmax, tmin, tmax, yscale, tvalue) {
yscale = yscale || 1; yscale = yscale || 1;
new Path.Line(x, y-100, x, y+100).style.strokeColor = '#aaa'; new Path.Line(x, y-100, x, y+100).strokeColor = '#aaa';
new Path.Line(x, y, x + 200, y).style.strokeColor = '#aaa'; new Path.Line(x, y, x + 200, y).strokeColor = '#aaa';
var clr = (tvalue)? '#a00' : '#00a'; var clr = (tvalue)? '#a00' : '#00a';
if (window.__p3) window.__p3.map(function(a) {a.remove();}); if (window.__p3) window.__p3.map(function(a) {a.remove();});
window.__p3 = []; window.__p3 = [];
drawFatline(v); drawFatline(v);
window.__p3.push(new Path.Line(x, y + dmin * yscale, x + 200, y + dmin * yscale)); window.__p3.push(new Path.Line(x, y + dmin * yscale, x + 200, y + dmin * yscale));
window.__p3[window.__p3.length-1].style.strokeColor = '#000'; window.__p3[window.__p3.length-1].strokeColor = '#000';
window.__p3.push(new Path.Line(x, y + dmax * yscale, x + 200, y + dmax * yscale)); window.__p3.push(new Path.Line(x, y + dmax * yscale, x + 200, y + dmax * yscale));
window.__p3[window.__p3.length-1].style.strokeColor = '#000'; window.__p3[window.__p3.length-1].strokeColor = '#000';
window.__p3.push(new Path.Line(x + tmin * 190, y-100, x + tmin * 190, y+100)); window.__p3.push(new Path.Line(x + tmin * 190, y-100, x + tmin * 190, y+100));
window.__p3[window.__p3.length-1].style.strokeColor = clr; window.__p3[window.__p3.length-1].strokeColor = clr;
window.__p3.push(new Path.Line(x + tmax * 190, y-100, x + tmax * 190, y+100)); window.__p3.push(new Path.Line(x + tmax * 190, y-100, x + tmax * 190, y+100));
window.__p3[window.__p3.length-1].style.strokeColor = clr; window.__p3[window.__p3.length-1].strokeColor = clr;
for (var i = 0; i < arr.length; i++) { for (var i = 0; i < arr.length; i++) {
window.__p3.push(new Path.Line(new Point(x + arr[i][0] * 190, y + arr[i][1] * yscale), window.__p3.push(new Path.Line(new Point(x + arr[i][0] * 190, y + arr[i][1] * yscale),
new Point(x + arr[i][2] * 190, y + arr[i][3] * yscale))); new Point(x + arr[i][2] * 190, y + arr[i][3] * yscale)));
window.__p3[window.__p3.length-1].style.strokeColor = '#999'; window.__p3[window.__p3.length-1].strokeColor = '#999';
} }
var pnt = []; var pnt = [];
var arr2x = [ 0.0, 0.333333333, 0.6666666666, 1.0 ]; var arr2x = [ 0.0, 0.333333333, 0.6666666666, 1.0 ];
for (var i = 0; i < arr2.length; i++) { for (var i = 0; i < arr2.length; i++) {
pnt.push(new Point(x + arr2x[i] * 190, y + arr2[i] * yscale)); pnt.push(new Point(x + arr2x[i] * 190, y + arr2[i] * yscale));
window.__p3.push(new Path.Circle(pnt[pnt.length-1], 2)); window.__p3.push(new Path.Circle(pnt[pnt.length-1], 2));
window.__p3[window.__p3.length-1].style.fillColor = '#000'; window.__p3[window.__p3.length-1].fillColor = '#000';
} }
// var pth = new Path(pnt[0], pnt[1], pnt[2], pnt[3]); // var pth = new Path(pnt[0], pnt[1], pnt[2], pnt[3]);
// pth.closed = true; // pth.closed = true;
window.__p3.push(new Path( window.__p3.push(new Path(
new Segment(pnt[0], null, pnt[1].subtract(pnt[0])), new Segment(pnt[0], null, pnt[1].subtract(pnt[0])),
new Segment(pnt[3], pnt[2].subtract(pnt[3]), null))); new Segment(pnt[3], pnt[2].subtract(pnt[3]), null)));
window.__p3[window.__p3.length-1].style.strokeColor = clr; window.__p3[window.__p3.length-1].strokeColor = clr;
view.draw(); view.draw();
} }

2
lib/acorn-min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -29,7 +29,7 @@
exports.version = "0.2.01"; exports.version = "0.2.01";
// The main exported interface (under `this.acorn` when in the // The main exported interface (under `self.acorn` when in the
// browser) is a `parse` function that takes a code string and // browser) is a `parse` function that takes a code string and
// returns an abstract syntax tree as specified by [Mozilla parser // returns an abstract syntax tree as specified by [Mozilla parser
// API][api], with the caveat that the SpiderMonkey-specific syntax // API][api], with the caveat that the SpiderMonkey-specific syntax
@ -407,7 +407,7 @@
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/; var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]/;
var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc"; var nonASCIIidentifierStartChars = "\xaa\xb5\xba\xc0-\xd6\xd8-\xf6\xf8-\u02c1\u02c6-\u02d1\u02e0-\u02e4\u02ec\u02ee\u0370-\u0374\u0376\u0377\u037a-\u037d\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0481\u048a-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05d0-\u05ea\u05f0-\u05f2\u0620-\u064a\u066e\u066f\u0671-\u06d3\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u06fc\u06ff\u0710\u0712-\u072f\u074d-\u07a5\u07b1\u07ca-\u07ea\u07f4\u07f5\u07fa\u0800-\u0815\u081a\u0824\u0828\u0840-\u0858\u08a0\u08a2-\u08ac\u0904-\u0939\u093d\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097f\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd\u09ce\u09dc\u09dd\u09df-\u09e1\u09f0\u09f1\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a59-\u0a5c\u0a5e\u0a72-\u0a74\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd\u0ad0\u0ae0\u0ae1\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b5c\u0b5d\u0b5f-\u0b61\u0b71\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bd0\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c33\u0c35-\u0c39\u0c3d\u0c58\u0c59\u0c60\u0c61\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd\u0cde\u0ce0\u0ce1\u0cf1\u0cf2\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d\u0d4e\u0d60\u0d61\u0d7a-\u0d7f\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0edc-\u0edf\u0f00\u0f40-\u0f47\u0f49-\u0f6c\u0f88-\u0f8c\u1000-\u102a\u103f\u1050-\u1055\u105a-\u105d\u1061\u1065\u1066\u106e-\u1070\u1075-\u1081\u108e\u10a0-\u10c5\u10c7\u10cd\u10d0-\u10fa\u10fc-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1380-\u138f\u13a0-\u13f4\u1401-\u166c\u166f-\u167f\u1681-\u169a\u16a0-\u16ea\u16ee-\u16f0\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17d7\u17dc\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191c\u1950-\u196d\u1970-\u1974\u1980-\u19ab\u19c1-\u19c7\u1a00-\u1a16\u1a20-\u1a54\u1aa7\u1b05-\u1b33\u1b45-\u1b4b\u1b83-\u1ba0\u1bae\u1baf\u1bba-\u1be5\u1c00-\u1c23\u1c4d-\u1c4f\u1c5a-\u1c7d\u1ce9-\u1cec\u1cee-\u1cf1\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u2160-\u2188\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u2e2f\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u31a0-\u31ba\u31f0-\u31ff\u3400-\u4db5\u4e00-\u9fcc\ua000-\ua48c\ua4d0-\ua4fd\ua500-\ua60c\ua610-\ua61f\ua62a\ua62b\ua640-\ua66e\ua67f-\ua697\ua6a0-\ua6ef\ua717-\ua71f\ua722-\ua788\ua78b-\ua78e\ua790-\ua793\ua7a0-\ua7aa\ua7f8-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua822\ua840-\ua873\ua882-\ua8b3\ua8f2-\ua8f7\ua8fb\ua90a-\ua925\ua930-\ua946\ua960-\ua97c\ua984-\ua9b2\ua9cf\uaa00-\uaa28\uaa40-\uaa42\uaa44-\uaa4b\uaa60-\uaa76\uaa7a\uaa80-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaadd\uaae0-\uaaea\uaaf2-\uaaf4\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uabc0-\uabe2\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\uf900-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\ufb1d\ufb1f-\ufb28\ufb2a-\ufb36\ufb38-\ufb3c\ufb3e\ufb40\ufb41\ufb43\ufb44\ufb46-\ufbb1\ufbd3-\ufd3d\ufd50-\ufd8f\ufd92-\ufdc7\ufdf0-\ufdfb\ufe70-\ufe74\ufe76-\ufefc\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc";
var nonASCIIidentifierChars = "\u0371-\u0374\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; var nonASCIIidentifierChars = "\u0300-\u036f\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u0620-\u0649\u0672-\u06d3\u06e7-\u06e8\u06fb-\u06fc\u0730-\u074a\u0800-\u0814\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0840-\u0857\u08e4-\u08fe\u0900-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962-\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09d7\u09df-\u09e0\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2-\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b5f-\u0b60\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c01-\u0c03\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62-\u0c63\u0c66-\u0c6f\u0c82\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2-\u0ce3\u0ce6-\u0cef\u0d02\u0d03\u0d46-\u0d48\u0d57\u0d62-\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0df2\u0df3\u0e34-\u0e3a\u0e40-\u0e45\u0e50-\u0e59\u0eb4-\u0eb9\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f41-\u0f47\u0f71-\u0f84\u0f86-\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u1000-\u1029\u1040-\u1049\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u170e-\u1710\u1720-\u1730\u1740-\u1750\u1772\u1773\u1780-\u17b2\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u1920-\u192b\u1930-\u193b\u1951-\u196d\u19b0-\u19c0\u19c8-\u19c9\u19d0-\u19d9\u1a00-\u1a15\u1a20-\u1a53\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1b46-\u1b4b\u1b50-\u1b59\u1b6b-\u1b73\u1bb0-\u1bb9\u1be6-\u1bf3\u1c00-\u1c22\u1c40-\u1c49\u1c5b-\u1c7d\u1cd0-\u1cd2\u1d00-\u1dbe\u1e01-\u1f15\u200c\u200d\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2d81-\u2d96\u2de0-\u2dff\u3021-\u3028\u3099\u309a\ua640-\ua66d\ua674-\ua67d\ua69f\ua6f0-\ua6f1\ua7f8-\ua800\ua806\ua80b\ua823-\ua827\ua880-\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8f3-\ua8f7\ua900-\ua909\ua926-\ua92d\ua930-\ua945\ua980-\ua983\ua9b3-\ua9c0\uaa00-\uaa27\uaa40-\uaa41\uaa4c-\uaa4d\uaa50-\uaa59\uaa7b\uaae0-\uaae9\uaaf2-\uaaf3\uabc0-\uabe1\uabec\uabed\uabf0-\uabf9\ufb20-\ufb28\ufe00-\ufe0f\ufe20-\ufe26\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f";
var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); var nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]");
var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); var nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]");
@ -1716,4 +1716,4 @@
return finishNode(node, "Identifier"); return finishNode(node, "Identifier");
} }
}); });

View file

@ -1,36 +1,31 @@
/** /**
* Straps.js - Inheritance library with support for bean-style accessors and * straps.js - Class inheritance library with support for bean-style accessors
* AOP patterns.
* *
* Copyright (c) 2006 - 2013 Juerg Lehni * Copyright (c) 2006 - 2013 Juerg Lehni
* http://lehni.org/ * http://lehni.org/
* *
* Distributed under the MIT license. * Distributed under the MIT license.
* *
* straps.js was created by extracting and simplifying the inheritance code from * straps.js was created by extracting and simplifying the inheritance framework
* boostrap.js, a JavaScript DOM library, also published by Juerg Lehni: * from boostrap.js, a JavaScript DOM library, also published by Juerg Lehni:
* https://github.com/lehni/bootstrap.js * https://github.com/lehni/bootstrap.js
* The name was changed due to Twitter's introduction of their CSS framework
* with the same name.
* *
* Inspirations: * Inspirations:
* http://dean.edwards.name/weblog/2006/03/base/ * http://dean.edwards.name/weblog/2006/03/base/
* http://dev.helma.org/Wiki/JavaScript+Inheritance+Sugar/ * http://dev.helma.org/Wiki/JavaScript+Inheritance+Sugar/
*/ */
var Base = this.Base = new function() { // Straps scope var Base = new function() {
var hidden = /^(statics|generics|preserve|enumerable|prototype|toString|valueOf)$/, var hidden = /^(statics|generics|preserve|enumerable|prototype|toString|valueOf)$/,
proto = Object.prototype, toString = Object.prototype.toString,
toString = proto.toString,
proto = Array.prototype, proto = Array.prototype,
isArray = Array.isArray = Array.isArray || function(obj) {
return toString.call(obj) === '[object Array]';
},
slice = proto.slice, slice = proto.slice,
forEach = proto.forEach || function(iter, bind) { forEach = proto.forEach || function(iter, bind) {
for (var i = 0, l = this.length; i < l; i++) for (var i = 0, l = this.length; i < l; i++)
iter.call(bind, this[i], i, this); iter.call(bind, this[i], i, this);
}, },
forIn = function(iter, bind) { forIn = function(iter, bind) {
// Do not use Object.keys for iteration as iterators might modify // Do not use Object.keys for iteration as iterators might modify
// the object we're iterating over, making the hasOwnProperty still // the object we're iterating over, making the hasOwnProperty still
@ -39,52 +34,54 @@ var Base = this.Base = new function() { // Straps scope
if (this.hasOwnProperty(i)) if (this.hasOwnProperty(i))
iter.call(bind, this[i], i, this); iter.call(bind, this[i], i, this);
}, },
// A ahort cut to a simplified version of Object.create that only
isArray = Array.isArray = Array.isArray || function(obj) {
return toString.call(obj) === '[object Array]';
},
// A short-cut to a simplified version of Object.create that only
// supports the first parameter (in the emulation): // supports the first parameter (in the emulation):
create = Object.create || function(proto) { create = Object.create || function(proto) {
// From all browsers that do not offer Object.create(), we only // From all browsers that do not offer Object.create(), we only
// support Firefox 3.5 & 3.5, and this hack works there: // support Firefox 3.5 & 3.6, and this hack works there:
return { __proto__: proto }; return { __proto__: proto };
}, },
_define = Object.defineProperty,
_describe = Object.getOwnPropertyDescriptor;
// Support a mixed environment of some ECMAScript 5 features present, describe = Object.getOwnPropertyDescriptor || function(obj, name) {
// along with __defineGetter/Setter__ functions, as found in browsers today. // Emulate Object.getOwnPropertyDescriptor for outdated browsers
function define(obj, name, desc) { var get = obj.__lookupGetter__ && obj.__lookupGetter__(name);
// Unfortunately Safari seems to ignore configurable: true and return get
// does not override existing properties, so we need to delete ? { get: get, set: obj.__lookupSetter__(name),
// first: enumerable: true, configurable: true }
if (_define) { : obj.hasOwnProperty(name)
try { ? { value: obj[name], enumerable: true,
delete obj[name]; configurable: true, writable: true }
return _define(obj, name, desc); : null;
} catch (e) {} },
}
if ((desc.get || desc.set) && obj.__defineGetter__) {
if (desc.get) obj.__defineGetter__(name, desc.get);
if (desc.set) obj.__defineSetter__(name, desc.set);
} else {
obj[name] = desc.value;
}
return obj;
}
function describe(obj, name) { _define = Object.defineProperty || function(obj, name, desc) {
if (_describe) { // Emulate Object.defineProperty for outdated browsers
try { if ((desc.get || desc.set) && obj.__defineGetter__) {
return _describe(obj, name); if (desc.get)
} catch (e) {} obj.__defineGetter__(name, desc.get);
} if (desc.set)
var get = obj.__lookupGetter__ && obj.__lookupGetter__(name); obj.__defineSetter__(name, desc.set);
return get } else {
? { get: get, set: obj.__lookupSetter__(name), enumerable: true, obj[name] = desc.value;
configurable: true } }
: obj.hasOwnProperty(name) return obj;
? { value: obj[name], enumerable: true, configurable: true, },
writable: true }
: null; define = function(obj, name, desc) {
} // Both Safari and Chrome at one point ignored configurable = true
// and did not allow overriding of existing properties:
// https://code.google.com/p/chromium/issues/detail?id=72736
// https://bugs.webkit.org/show_bug.cgi?id=54289
// The workaround is to delete the property first.
// TODO: Remove this fix in July 2014, and use _define directly.
delete obj[name];
return _define(obj, name, desc);
};
/** /**
* Private function that injects functions from src into dest, overriding * Private function that injects functions from src into dest, overriding
@ -109,58 +106,34 @@ var Base = this.Base = new function() { // Straps scope
// string values starting with '#' // string values starting with '#'
if (typeof val === 'string' && val[0] === '#') if (typeof val === 'string' && val[0] === '#')
val = src[val.substring(1)] || val; val = src[val.substring(1)] || val;
var func = typeof val === 'function', var isFunc = typeof val === 'function',
res = val, res = val,
// Only lookup previous value if we preserve or define a // Only lookup previous value if we preserve or define a
// function that might need it for this.base(). If we're // function that might need it for this.base(). If we're
// defining a getter, don't lookup previous value, but look if // defining a getter, don't lookup previous value, but look if
// the property exists (name in dest) and store result in prev // the property exists (name in dest) and store result in prev
prev = preserve || func prev = preserve || isFunc
? (val && val.get ? name in dest : dest[name]) : null; ? (val && val.get ? name in dest : dest[name]) : null;
if ((dontCheck || val !== undefined && src.hasOwnProperty(name)) if ((dontCheck || val !== undefined && src.hasOwnProperty(name))
&& (!preserve || !prev)) { && (!preserve || !prev)) {
if (func) { // Expose the 'super' function (meaning the one this function is
if (prev && /\bthis\.base\b/.test(val)) { // overriding) through #base:
var fromBase = base && base[name] == prev; if (isFunc && prev)
res = function() { val.base = prev;
// Look up the base function each time if we can, // Produce bean properties if getters are specified. This does
// to reflect changes to the base class after // not produce properties for setter-only properties. Just
// inheritance. // collect beans for now, and look them up in dest at the end of
var tmp = describe(this, 'base'); // fields injection. This ensures base works for beans too, and
define(this, 'base', { value: fromBase // inherits setters for redefined getters in subclasses. Only
? base[name] : prev, configurable: true }); // add getter beans if they do not expect arguments. Functions
try { // that should function both with optional arguments and as
return val.apply(this, arguments); // beans should not declare the parameters and use the arguments
} finally { // array internally instead.
tmp ? define(this, 'base', tmp) if (isFunc && beans && val.length === 0
: delete this.base; && (bean = name.match(/^(get|is)(([A-Z])(.*))$/)))
} beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]);
};
// Make wrapping closure pretend to be the original
// function on inspection
res.toString = function() {
return val.toString();
};
res.valueOf = function() {
return val.valueOf();
};
}
// Produce bean properties if getters are specified. This
// does not produce properties for setter-only properties.
// Just collect beans for now, and look them up in dest at
// the end of fields injection. This ensures this.base()
// works in beans too, and inherits setters for redefined
// getters in subclasses. Only add getter beans if they do
// not expect arguments. Functions that should function both
// with optional arguments and as beans should not declare
// the parameters and use the arguments array internally
// instead.
if (beans && val.length === 0
&& (bean = name.match(/^(get|is)(([A-Z])(.*))$/)))
beans.push([ bean[3].toLowerCase() + bean[4], bean[2] ]);
}
// No need to look up getter if this is a function already. // No need to look up getter if this is a function already.
if (!res || func || !res.get) if (!res || isFunc || !res.get)
res = { value: res, writable: true }; res = { value: res, writable: true };
// Only set/change configurable and enumerable if this field is // Only set/change configurable and enumerable if this field is
// configurable // configurable
@ -171,7 +144,7 @@ var Base = this.Base = new function() { // Straps scope
} }
define(dest, name, res); define(dest, name, res);
} }
if (generics && func && (!preserve || !generics[name])) { if (generics && isFunc && (!preserve || !generics[name])) {
generics[name] = function(bind) { generics[name] = function(bind) {
// Do not call Array.slice generic here, as on Safari, // Do not call Array.slice generic here, as on Safari,
// this seems to confuse scopes (calling another // this seems to confuse scopes (calling another
@ -210,10 +183,11 @@ var Base = this.Base = new function() { // Straps scope
function each(obj, iter, bind, asArray) { function each(obj, iter, bind, asArray) {
try { try {
if (obj) if (obj)
(asArray || asArray === undefined && isArray(obj) (asArray || typeof asArray === 'undefined' && isArray(obj)
? forEach : forIn).call(obj, iter, bind = bind || obj); ? forEach : forIn).call(obj, iter, bind = bind || obj);
} catch (e) { } catch (e) {
if (e !== Base.stop) throw e; if (e !== Base.stop)
throw e;
} }
return bind; return bind;
} }
@ -225,7 +199,8 @@ var Base = this.Base = new function() { // Straps scope
} }
// Inject into new ctor object that's passed to inject(), and then returned // Inject into new ctor object that's passed to inject(), and then returned
return inject(function() {}, { // as the Base class.
return inject(function Base() {}, {
inject: function(src/*, ... */) { inject: function(src/*, ... */) {
if (src) { if (src) {
var proto = this.prototype, var proto = this.prototype,
@ -252,16 +227,19 @@ var Base = this.Base = new function() { // Straps scope
}, },
extend: function(src/* , ... */) { extend: function(src/* , ... */) {
var ctor = function() { var base = this,
// Call the constructor function, if defined ctor;
if (this.initialize) // Look for an initialize function in all injection objects and use
return this.initialize.apply(this, arguments); // it directly as the actual constructor.
for (var i = 0, l = arguments.length; i < l; i++)
if (ctor = arguments[i].initialize)
break;
// If no initialize function is provided, create a constructor that
// simply calls the base constructor.
ctor = ctor || function() {
base.apply(this, arguments);
}; };
ctor.prototype = create(this.prototype); ctor.prototype = create(this.prototype);
// Add a toString function that delegates to initialize if possible
ctor.toString = function() {
return (this.prototype.initialize || function() {}).toString();
};
// The new prototype extends the constructor on which extend is // The new prototype extends the constructor on which extend is
// called. Fix constructor. // called. Fix constructor.
define(ctor.prototype, 'constructor', define(ctor.prototype, 'constructor',
@ -320,8 +298,8 @@ var Base = this.Base = new function() { // Straps scope
define: define, define: define,
describe: describe, describe: describe,
// Base.create does something different from Object.create, it only // Base.create does something different from Object.create:
// works on constructors and uses their prototype. // It works on constructors and uses their prototype.
create: function(ctor) { create: function(ctor) {
return create(ctor.prototype); return create(ctor.prototype);
}, },
@ -331,10 +309,12 @@ var Base = this.Base = new function() { // Straps scope
* plain Base object, as produced by Base.merge(). * plain Base object, as produced by Base.merge().
*/ */
isPlainObject: function(obj) { isPlainObject: function(obj) {
var proto = obj !== null && typeof obj === 'object' var ctor = obj != null && obj.constructor;
&& Object.getPrototypeOf(obj); // We also need to check for ctor.name === 'Object', in case
return proto && (proto === Object.prototype // this is an object from another global scope (e.g. an iframe,
|| proto === Base.prototype); // or another vm context in node.js).
return ctor && (ctor === Object || ctor === Base
|| ctor.name === 'Object');
}, },
check: function(obj) { check: function(obj) {
@ -342,9 +322,8 @@ var Base = this.Base = new function() { // Straps scope
}, },
/** /**
* Returns the first argument that is defined. * Returns the first argument that is defined. null is counted as
* Null is counted as defined too, since !== undefined is used for * defined too, as !== undefined is used for comparisons.
* comparisons. In this it differs from Mootools!
*/ */
pick: function() { pick: function() {
for (var i = 0, l = arguments.length; i < l; i++) for (var i = 0, l = arguments.length; i < l; i++)
@ -354,13 +333,10 @@ var Base = this.Base = new function() { // Straps scope
}, },
/** /**
* A special constant, to be thrown by closures passed to each() * Base.stop can be thrown by iterators passed to each()
* *
* $continue / Base.next is not implemented, as the same * continue (Base.next) is not implemented, as the same can achieved
* functionality can achieved by using return in the closure. * by using return in the iterator.
* In prototype, the implementation of $continue also leads to a
* huge speed decrease, as the closure is wrapped in another closure
* that does nothing else than handling $continue.
*/ */
stop: {} stop: {}
} }

View file

@ -1,6 +1,6 @@
{ {
"name": "paper", "name": "paper",
"version": "0.8.3", "version": "0.9.0",
"main": "./src/node/index.js", "main": "./src/node/index.js",
"engines": { "node": ">= 0.4.0" }, "engines": { "node": ">= 0.4.0" },
"dependencies": { "dependencies": {

View file

@ -15,32 +15,33 @@
* *
* @class The Line object represents.. * @class The Line object represents..
*/ */
var Line = this.Line = Base.extend(/** @lends Line# */{ var Line = Base.extend(/** @lends Line# */{
// DOCS: document Line class and constructor // DOCS: document Line class and constructor
/** /**
* Creates a Line object. * Creates a Line object.
* *
* @param {Point} point1 * @param {Point} point1
* @param {Point} point2 * @param {Point} point2
* @param {Boolean} [infinite=true] * @param {Boolean} [asVector=false]
*/ */
initialize: function(point1, point2, infinite) { initialize: function Line(arg0, arg1, arg2, arg3, arg4) {
// Convention: With 3 parameters, both points are absolute, and infinite var asVector = false;
// controls wether the line extends beyond the defining points, meaning if (arguments.length >= 4) {
// intersection outside the line segment are allowed. this._px = arg0;
// With two parameters, the 2nd parameter is a direction, and infinite this._py = arg1;
// is automatially true, since we're describing an infinite line. this._vx = arg2;
var _point1 = Point.read(arguments), this._vy = arg3;
_point2 = Point.read(arguments), asVector = arg4;
_infinite = Base.read(arguments);
if (_infinite !== undefined) {
this.point = _point1;
this.vector = _point2.subtract(_point1);
this.infinite = _infinite;
} else { } else {
this.point = _point1; this._px = arg0.x;
this.vector = _point2; this._py = arg0.y;
this.infinite = true; this._vx = arg1.x;
this._vy = arg1.y;
asVector = arg2;
}
if (!asVector) {
this._vx -= this._px;
this._vy -= this._py;
} }
}, },
@ -50,6 +51,9 @@ var Line = this.Line = Base.extend(/** @lends Line# */{
* @name Line#point * @name Line#point
* @type Point * @type Point
*/ */
getPoint: function() {
return new Point(this._px, this._py);
},
/** /**
* The vector of the line * The vector of the line
@ -57,33 +61,21 @@ var Line = this.Line = Base.extend(/** @lends Line# */{
* @name Line#vector * @name Line#vector
* @type Point * @type Point
*/ */
getVector: function() {
/** return new Point(this._vx, this._vy);
* Specifies whether the line extends infinitely },
*
* @name Line#infinite
* @type Boolean
*/
/** /**
* @param {Line} line * @param {Line} line
* @param {Boolean} [isInfinite=false]
* @return {Point} the intersection point of the lines, {@code undefined} * @return {Point} the intersection point of the lines, {@code undefined}
* if the two lines are colinear, or {@code null} if they don't intersect. * if the two lines are colinear, or {@code null} if they don't intersect.
*/ */
intersect: function(line) { intersect: function(line, isInfinite) {
var cross = this.vector.cross(line.vector); return Line.intersect(
// Avoid divisions by 0, and errors when getting too close to 0 this._px, this._py, this._vx, this._vy,
if (Numerical.isZero(cross)) line._px, line._py, line._vx, line._vy,
return undefined; true, isInfinite);
var v = line.point.subtract(this.point),
t1 = v.cross(line.vector) / cross,
t2 = v.cross(this.vector) / cross;
// Check the ranges of t parameters if the line is not allowed to
// extend beyond the definition points.
return (this.infinite || 0 <= t1 && t1 <= 1)
&& (line.infinite || 0 <= t2 && t2 <= 1)
? this.point.add(this.vector.multiply(t1))
: null;
}, },
// DOCS: document Line#getSide(point) // DOCS: document Line#getSide(point)
@ -92,18 +84,9 @@ var Line = this.Line = Base.extend(/** @lends Line# */{
* @return {Number} * @return {Number}
*/ */
getSide: function(point) { getSide: function(point) {
var v1 = this.vector, return Line.getSide(
v2 = point.subtract(this.point), this._px, this._py, this._vx, this._vy,
ccw = v2.cross(v1); point.x, point.y, true);
if (ccw === 0) {
ccw = v2.dot(v1);
if (ccw > 0) {
ccw = v2.subtract(v1).dot(v1);
if (ccw < 0)
ccw = 0;
}
}
return ccw < 0 ? -1 : ccw > 0 ? 1 : 0;
}, },
// DOCS: document Line#getDistance(point) // DOCS: document Line#getDistance(point)
@ -112,33 +95,70 @@ var Line = this.Line = Base.extend(/** @lends Line# */{
* @return {Number} * @return {Number}
*/ */
getDistance: function(point) { getDistance: function(point) {
var m = this.vector.y / this.vector.x, // slope return Math.abs(Line.getSignedDistance(
b = this.point.y - (m * this.point.x); // y offset this._px, this._py, this._vx, this._vy,
// Distance to the linear equation point.x, point.y, true));
var dist = Math.abs(point.y - (m * point.x) - b) / Math.sqrt(m * m + 1);
return this.infinite ? dist : Math.min(dist,
point.getDistance(this.point),
point.getDistance(this.point.add(this.vector)));
}, },
statics: { statics: /** @lends Line */{
intersect: function(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2, infinite) { intersect: function(apx, apy, avx, avy, bpx, bpy, bvx, bvy, asVector,
var adx = ax2 - ax1, isInfinite) {
ady = ay2 - ay1, // Convert 2nd points to vectors if they are not specified as such.
bdx = bx2 - bx1, if (!asVector) {
bdy = by2 - by1, avx -= apx;
dx = ax1 - bx1, avy -= apy;
dy = ay1 - by1, bvx -= bpx;
cross = bdy * adx - bdx * ady; bvy -= bpy;
if (!Numerical.isZero(cross)) {
var ta = (bdx * dy - bdy * dx) / cross,
tb = (adx * dy - ady * dx) / cross;
if ((infinite || 0 <= ta && ta <= 1)
&& (infinite || 0 <= tb && tb <= 1))
return Point.create(
ax1 + ta * adx,
ay1 + ta * ady);
} }
var cross = bvy * avx - bvx * avy;
// Avoid divisions by 0, and errors when getting too close to 0
if (!Numerical.isZero(cross)) {
var dx = apx - bpx,
dy = apy - bpy,
ta = (bvx * dy - bvy * dx) / cross,
tb = (avx * dy - avy * dx) / cross;
// Check the ranges of t parameters if the line is not allowed
// to extend beyond the definition points.
if ((isInfinite || 0 <= ta && ta <= 1)
&& (isInfinite || 0 <= tb && tb <= 1))
return new Point(
apx + ta * avx,
apy + ta * avy);
}
},
getSide: function(px, py, vx, vy, x, y, asVector) {
if (!asVector) {
vx -= px;
vy -= py;
}
var v2x = x - px,
v2y = y - py,
ccw = v2x * vy - v2y * vx; // ccw = v2.cross(v1);
if (ccw === 0) {
ccw = v2x * vx + v2y * vy; // ccw = v2.dot(v1);
if (ccw > 0) {
// ccw = v2.subtract(v1).dot(v1);
v2x -= vx;
v2y -= vy;
ccw = v2x * vx + v2y * vy;
if (ccw < 0)
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;
}
// Cache these values since they're used heavily in fatline code
var m = vy / vx, // slope
b = py - m * px; // y offset
// Distance to the linear equation
return (y - (m * x) - b) / Math.sqrt(m * m + 1);
} }
} }
}); });

View file

@ -37,9 +37,7 @@
* knowledge of the underlying matrix (as opposed to say simply performing * knowledge of the underlying matrix (as opposed to say simply performing
* matrix multiplication). * matrix multiplication).
*/ */
var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{ var Matrix = Base.extend(/** @lends Matrix# */{
_class: 'Matrix',
/** /**
* Creates a 2D affine transform. * Creates a 2D affine transform.
* *
@ -50,7 +48,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
* @param {Number} tx The translateX coordinate of the transform * @param {Number} tx The translateX coordinate of the transform
* @param {Number} ty The translateY coordinate of the transform * @param {Number} ty The translateY coordinate of the transform
*/ */
initialize: function(arg) { initialize: function Matrix(arg) {
var count = arguments.length, var count = arguments.length,
ok = true; ok = true;
if (count == 6) { if (count == 6) {
@ -101,7 +99,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
* @return {Matrix} A copy of this transform. * @return {Matrix} A copy of this transform.
*/ */
clone: function() { clone: function() {
return Matrix.create(this._a, this._c, this._b, this._d, return new Matrix(this._a, this._c, this._b, this._d,
this._tx, this._ty); this._tx, this._ty);
}, },
@ -518,7 +516,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
return { return {
translation: this.getTranslation(), translation: this.getTranslation(),
scaling: Point.create(scaleX, scaleY), scaling: new Point(scaleX, scaleY),
rotation: -Math.atan2(b, a) * 180 / Math.PI, rotation: -Math.atan2(b, a) * 180 / Math.PI,
shearing: shear shearing: shear
}; };
@ -585,7 +583,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
*/ */
getTranslation: function() { getTranslation: function() {
// No decomposition is required to extract translation, so treat this // No decomposition is required to extract translation, so treat this
return Point.create(this._tx, this._ty); return new Point(this._tx, this._ty);
}, },
/** /**
@ -620,7 +618,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
*/ */
inverted: function() { inverted: function() {
var det = this._getDeterminant(); var det = this._getDeterminant();
return det && Matrix.create( return det && new Matrix(
this._d / det, this._d / det,
-this._c / det, -this._c / det,
-this._b / det, -this._b / det,
@ -630,7 +628,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
}, },
shiftless: function() { shiftless: function() {
return Matrix.create(this._a, this._c, this._b, this._d, 0, 0); return new Matrix(this._a, this._c, this._b, this._d, 0, 0);
}, },
/** /**
@ -640,13 +638,6 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
*/ */
applyToContext: function(ctx) { applyToContext: function(ctx) {
ctx.transform(this._a, this._c, this._b, this._d, this._tx, this._ty); ctx.transform(this._a, this._c, this._b, this._d, this._tx, this._ty);
},
statics: /** @lends Matrix */{
// See Point.create()
create: function(a, c, b, d, tx, ty) {
return Base.create(Matrix).set(a, c, b, d, tx, ty);
}
} }
}, new function() { }, new function() {
return Base.each({ return Base.each({

View file

@ -23,8 +23,7 @@
* console.log(point.x); // 10 * console.log(point.x); // 10
* console.log(point.y); // 5 * console.log(point.y); // 5
*/ */
var Point = this.Point = Base.extend(/** @lends Point# */{ var Point = Base.extend(/** @lends Point# */{
_class: 'Point',
// Tell Base.read that the Point constructor supports reading with index // Tell Base.read that the Point constructor supports reading with index
_readIndex: true, _readIndex: true,
@ -129,7 +128,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
* @param {Point} point * @param {Point} point
* @name Point#initialize * @name Point#initialize
*/ */
initialize: function(arg0, arg1) { initialize: function Point(arg0, arg1) {
var type = typeof arg0; var type = typeof arg0;
if (type === 'number') { if (type === 'number') {
var hasY = typeof arg1 === 'number'; var hasY = typeof arg1 === 'number';
@ -217,7 +216,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
* @returns {Point} the cloned point * @returns {Point} the cloned point
*/ */
clone: function() { clone: function() {
return Point.create(this.x, this.y); return new Point(this.x, this.y);
}, },
/** /**
@ -269,7 +268,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
*/ */
add: function(point) { add: function(point) {
point = Point.read(arguments); point = Point.read(arguments);
return Point.create(this.x + point.x, this.y + point.y); return new Point(this.x + point.x, this.y + point.y);
}, },
/** /**
@ -305,7 +304,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
*/ */
subtract: function(point) { subtract: function(point) {
point = Point.read(arguments); point = Point.read(arguments);
return Point.create(this.x - point.x, this.y - point.y); return new Point(this.x - point.x, this.y - point.y);
}, },
/** /**
@ -341,7 +340,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
*/ */
multiply: function(point) { multiply: function(point) {
point = Point.read(arguments); point = Point.read(arguments);
return Point.create(this.x * point.x, this.y * point.y); return new Point(this.x * point.x, this.y * point.y);
}, },
/** /**
@ -377,7 +376,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
*/ */
divide: function(point) { divide: function(point) {
point = Point.read(arguments); point = Point.read(arguments);
return Point.create(this.x / point.x, this.y / point.y); return new Point(this.x / point.x, this.y / point.y);
}, },
/** /**
@ -410,11 +409,11 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
*/ */
modulo: function(point) { modulo: function(point) {
point = Point.read(arguments); point = Point.read(arguments);
return Point.create(this.x % point.x, this.y % point.y); return new Point(this.x % point.x, this.y % point.y);
}, },
negate: function() { negate: function() {
return Point.create(-this.x, -this.y); return new Point(-this.x, -this.y);
}, },
/** /**
@ -501,7 +500,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
length = 1; length = 1;
var current = this.getLength(), var current = this.getLength(),
scale = current != 0 ? length / current : 0, scale = current != 0 ? length / current : 0,
point = Point.create(this.x * scale, this.y * scale); point = new Point(this.x * scale, this.y * scale);
// Preserve angle. // Preserve angle.
point._angle = this._angle; point._angle = this._angle;
return point; return point;
@ -650,7 +649,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
var point = center ? this.subtract(center) : this, var point = center ? this.subtract(center) : this,
s = Math.sin(angle), s = Math.sin(angle),
c = Math.cos(angle); c = Math.cos(angle);
point = Point.create( point = new Point(
point.x * c - point.y * s, point.x * c - point.y * s,
point.y * c + point.x * s point.y * c + point.x * s
); );
@ -754,10 +753,10 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
project: function(point) { project: function(point) {
point = Point.read(arguments); point = Point.read(arguments);
if (point.isZero()) { if (point.isZero()) {
return Point.create(0, 0); return new Point(0, 0);
} else { } else {
var scale = this.dot(point) / point.dot(point); var scale = this.dot(point) / point.dot(point);
return Point.create( return new Point(
point.x * scale, point.x * scale,
point.y * scale point.y * scale
); );
@ -775,23 +774,6 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
*/ */
statics: /** @lends Point */{ statics: /** @lends Point */{
/**
* Provide a faster creator for Points out of two coordinates that
* does not rely on Point#initialize at all. This speeds up all math
* operations a lot.
*
* @ignore
*/
create: function(x, y) {
// Don't use the shorter form as we want absolute maximum
// performance here:
// return Base.create(Point).set(x, y);
var point = Base.create(Point);
point.x = x;
point.y = y;
return point;
},
/** /**
* Returns a new point object with the smallest {@link #x} and * Returns a new point object with the smallest {@link #x} and
* {@link #y} of the supplied points. * {@link #y} of the supplied points.
@ -810,7 +792,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
min: function(point1, point2) { min: function(point1, point2) {
var _point1 = Point.read(arguments); var _point1 = Point.read(arguments);
_point2 = Point.read(arguments); _point2 = Point.read(arguments);
return Point.create( return new Point(
Math.min(_point1.x, _point2.x), Math.min(_point1.x, _point2.x),
Math.min(_point1.y, _point2.y) Math.min(_point1.y, _point2.y)
); );
@ -834,7 +816,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
max: function(point1, point2) { max: function(point1, point2) {
var _point1 = Point.read(arguments); var _point1 = Point.read(arguments);
_point2 = Point.read(arguments); _point2 = Point.read(arguments);
return Point.create( return new Point(
Math.max(_point1.x, _point2.x), Math.max(_point1.x, _point2.x),
Math.max(_point1.y, _point2.y) Math.max(_point1.y, _point2.y)
); );
@ -855,7 +837,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
* var point = maxPoint * randomPoint; * var point = maxPoint * randomPoint;
*/ */
random: function() { random: function() {
return Point.create(Math.random(), Math.random()); return new Point(Math.random(), Math.random());
} }
} }
}, new function() { // Scope for injecting round, ceil, floor, abs: }, new function() { // Scope for injecting round, ceil, floor, abs:
@ -922,7 +904,7 @@ var Point = this.Point = Base.extend(/** @lends Point# */{
return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) {
var op = Math[name]; var op = Math[name];
this[name] = function() { this[name] = function() {
return Point.create(op(this.x), op(this.y)); return new Point(op(this.x), op(this.y));
}; };
}, {}); }, {});
}); });
@ -970,7 +952,7 @@ var LinkedPoint = Point.extend({
// through an optional parameter that can be passed to the getters. // through an optional parameter that can be passed to the getters.
// See e.g. Rectangle#getPoint(true). // See e.g. Rectangle#getPoint(true).
if (dontLink) if (dontLink)
return Point.create(x, y); return new Point(x, y);
var point = Base.create(LinkedPoint); var point = Base.create(LinkedPoint);
point._x = x; point._x = x;
point._y = y; point._y = y;

View file

@ -17,8 +17,7 @@
* point (x, y), its width, and its height. It should not be confused with a * point (x, y), its width, and its height. It should not be confused with a
* rectangular path, it is not an item. * rectangular path, it is not an item.
*/ */
var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{ var Rectangle = Base.extend(/** @lends Rectangle# */{
_class: 'Rectangle',
// Tell Base.read that the Rectangle constructor supports reading with index // Tell Base.read that the Rectangle constructor supports reading with index
_readIndex: true, _readIndex: true,
@ -72,7 +71,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
* @name Rectangle#initialize * @name Rectangle#initialize
* @param {Rectangle} rt * @param {Rectangle} rt
*/ */
initialize: function(arg0, arg1, arg2, arg3) { initialize: function Rectangle(arg0, arg1, arg2, arg3) {
var type = typeof arg0, var type = typeof arg0,
read = 0; read = 0;
if (type === 'number') { if (type === 'number') {
@ -191,7 +190,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
* Returns a copy of the rectangle. * Returns a copy of the rectangle.
*/ */
clone: function() { clone: function() {
return Rectangle.create(this.x, this.y, this.width, this.height); return new Rectangle(this.x, this.y, this.width, this.height);
}, },
/** /**
@ -652,7 +651,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
y1 = Math.max(this.y, rect.y), y1 = Math.max(this.y, rect.y),
x2 = Math.min(this.x + this.width, rect.x + rect.width), x2 = Math.min(this.x + this.width, rect.x + rect.width),
y2 = Math.min(this.y + this.height, rect.y + rect.height); y2 = Math.min(this.y + this.height, rect.y + rect.height);
return Rectangle.create(x1, y1, x2 - x1, y2 - y1); return new Rectangle(x1, y1, x2 - x1, y2 - y1);
}, },
/** /**
@ -669,7 +668,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
y1 = Math.min(this.y, rect.y), y1 = Math.min(this.y, rect.y),
x2 = Math.max(this.x + this.width, rect.x + rect.width), x2 = Math.max(this.x + this.width, rect.x + rect.width),
y2 = Math.max(this.y + this.height, rect.y + rect.height); y2 = Math.max(this.y + this.height, rect.y + rect.height);
return Rectangle.create(x1, y1, x2 - x1, y2 - y1); return new Rectangle(x1, y1, x2 - x1, y2 - y1);
}, },
/** /**
@ -692,7 +691,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
y1 = Math.min(this.y, point.y), y1 = Math.min(this.y, point.y),
x2 = Math.max(this.x + this.width, point.x), x2 = Math.max(this.x + this.width, point.x),
y2 = Math.max(this.y + this.height, point.y); y2 = Math.max(this.y + this.height, point.y);
return Rectangle.create(x1, y1, x2 - x1, y2 - y1); return new Rectangle(x1, y1, x2 - x1, y2 - y1);
}, },
/** /**
@ -716,7 +715,7 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
expand: function(hor, ver) { expand: function(hor, ver) {
if (ver === undefined) if (ver === undefined)
ver = hor; ver = hor;
return Rectangle.create(this.x - hor / 2, this.y - ver / 2, return new Rectangle(this.x - hor / 2, this.y - ver / 2,
this.width + hor, this.height + ver); this.width + hor, this.height + ver);
}, },
@ -740,13 +739,6 @@ var Rectangle = this.Rectangle = Base.extend(/** @lends Rectangle# */{
scale: function(hor, ver) { scale: function(hor, ver) {
return this.expand(this.width * hor - this.width, return this.expand(this.width * hor - this.width,
this.height * (ver === undefined ? hor : ver) - this.height); this.height * (ver === undefined ? hor : ver) - this.height);
},
statics: {
// See Point.create()
create: function(x, y, width, height) {
return Base.create(Rectangle).set(x, y, width, height);
}
} }
}, new function() { }, new function() {
return Base.each([ return Base.each([

View file

@ -22,8 +22,7 @@
* console.log(size.width); // 10 * console.log(size.width); // 10
* console.log(size.height); // 5 * console.log(size.height); // 5
*/ */
var Size = this.Size = Base.extend(/** @lends Size# */{ var Size = Base.extend(/** @lends Size# */{
_class: 'Size',
// Tell Base.read that the Point constructor supports reading with index // Tell Base.read that the Point constructor supports reading with index
_readIndex: true, _readIndex: true,
@ -90,7 +89,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
* console.log(size.width); // 50 * console.log(size.width); // 50
* console.log(size.height); // 50 * console.log(size.height); // 50
*/ */
initialize: function(arg0, arg1) { initialize: function Size(arg0, arg1) {
var type = typeof arg0; var type = typeof arg0;
if (type === 'number') { if (type === 'number') {
var hasHeight = typeof arg1 === 'number'; var hasHeight = typeof arg1 === 'number';
@ -164,7 +163,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
* Returns a copy of the size. * Returns a copy of the size.
*/ */
clone: function() { clone: function() {
return Size.create(this.width, this.height); return new Size(this.width, this.height);
}, },
/** /**
@ -214,7 +213,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
*/ */
add: function(size) { add: function(size) {
size = Size.read(arguments); size = Size.read(arguments);
return Size.create(this.width + size.width, this.height + size.height); return new Size(this.width + size.width, this.height + size.height);
}, },
/** /**
@ -249,7 +248,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
*/ */
subtract: function(size) { subtract: function(size) {
size = Size.read(arguments); size = Size.read(arguments);
return Size.create(this.width - size.width, this.height - size.height); return new Size(this.width - size.width, this.height - size.height);
}, },
/** /**
@ -283,7 +282,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
*/ */
multiply: function(size) { multiply: function(size) {
size = Size.read(arguments); size = Size.read(arguments);
return Size.create(this.width * size.width, this.height * size.height); return new Size(this.width * size.width, this.height * size.height);
}, },
/** /**
@ -317,7 +316,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
*/ */
divide: function(size) { divide: function(size) {
size = Size.read(arguments); size = Size.read(arguments);
return Size.create(this.width / size.width, this.height / size.height); return new Size(this.width / size.width, this.height / size.height);
}, },
/** /**
@ -350,11 +349,11 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
*/ */
modulo: function(size) { modulo: function(size) {
size = Size.read(arguments); size = Size.read(arguments);
return Size.create(this.width % size.width, this.height % size.height); return new Size(this.width % size.width, this.height % size.height);
}, },
negate: function() { negate: function() {
return Size.create(-this.width, -this.height); return new Size(-this.width, -this.height);
}, },
/** /**
@ -377,11 +376,6 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
}, },
statics: /** @lends Size */{ statics: /** @lends Size */{
// See Point.create()
create: function(width, height) {
return Base.create(Size).set(width, height);
},
/** /**
* Returns a new size object with the smallest {@link #width} and * Returns a new size object with the smallest {@link #width} and
* {@link #height} of the supplied sizes. * {@link #height} of the supplied sizes.
@ -398,7 +392,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
* console.log(minSize); // {width: 10, height: 5} * console.log(minSize); // {width: 10, height: 5}
*/ */
min: function(size1, size2) { min: function(size1, size2) {
return Size.create( return new Size(
Math.min(size1.width, size2.width), Math.min(size1.width, size2.width),
Math.min(size1.height, size2.height)); Math.min(size1.height, size2.height));
}, },
@ -419,7 +413,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
* console.log(maxSize); // {width: 200, height: 100} * console.log(maxSize); // {width: 200, height: 100}
*/ */
max: function(size1, size2) { max: function(size1, size2) {
return Size.create( return new Size(
Math.max(size1.width, size2.width), Math.max(size1.width, size2.width),
Math.max(size1.height, size2.height)); Math.max(size1.height, size2.height));
}, },
@ -437,7 +431,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
* var size = maxSize * randomSize; * var size = maxSize * randomSize;
*/ */
random: function() { random: function() {
return Size.create(Math.random(), Math.random()); return new Size(Math.random(), Math.random());
} }
} }
}, new function() { // Scope for injecting round, ceil, floor, abs: }, new function() { // Scope for injecting round, ceil, floor, abs:
@ -505,7 +499,7 @@ var Size = this.Size = Base.extend(/** @lends Size# */{
return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) { return Base.each(['round', 'ceil', 'floor', 'abs'], function(name) {
var op = Math[name]; var op = Math[name];
this[name] = function() { this[name] = function() {
return Size.create(op(this.width), op(this.height)); return new Size(op(this.width), op(this.height));
}; };
}, {}); }, {});
}); });
@ -551,7 +545,7 @@ var LinkedSize = Size.extend({
create: function(owner, setter, width, height, dontLink) { create: function(owner, setter, width, height, dontLink) {
// See LinkedPoint.create() for an explanation about dontLink. // See LinkedPoint.create() for an explanation about dontLink.
if (dontLink) if (dontLink)
return Size.create(width, height); return new Size(width, height);
var size = Base.create(LinkedSize); var size = Base.create(LinkedSize);
size._width = width; size._width = width;
size._height = height; size._height = height;

View file

@ -16,7 +16,7 @@ var CanvasProvider = {
canvases: [], canvases: [],
getCanvas: function(width, height) { getCanvas: function(width, height) {
var size = height === undefined ? width : Size.create(width, height); var size = height === undefined ? width : new Size(width, height);
if (this.canvases.length) { if (this.canvases.length) {
var canvas = this.canvases.pop(); var canvas = this.canvases.pop();
// If they are not the same size, we don't need to clear them // If they are not the same size, we don't need to clear them

View file

@ -17,7 +17,7 @@
*/ */
// Extend Base with utility functions used across the library. Also set // Extend Base with utility functions used across the library. Also set
// this.Base on the injection scope, since straps.js ommits that. // this.Base on the injection scope, since straps.js ommits that.
this.Base = Base.inject(/** @lends Base# */{ Base.inject(/** @lends Base# */{
// Have generics versions of #clone() and #toString(): // Have generics versions of #clone() and #toString():
generics: true, generics: true,
@ -36,7 +36,7 @@ this.Base = Base.inject(/** @lends Base# */{
*/ */
toString: function() { toString: function() {
return this._id != null return this._id != null
? (this._class || 'Object') + (this._name ? (this.constructor.name || 'Object') + (this._name
? " '" + this._name + "'" ? " '" + this._name + "'"
: ' @' + this._id) : ' @' + this._id)
: '{ ' + Base.each(this, function(value, key) { : '{ ' + Base.each(this, function(value, key) {
@ -80,15 +80,17 @@ this.Base = Base.inject(/** @lends Base# */{
statics: /** @lends Base */{ statics: /** @lends Base */{
_classes: {}, // Keep track of all named classes for serialization and exporting.
// Also register the Base class itself.
exports: new Base({ Base: Base }),
extend: function(src) { extend: function extend(src) {
// Override Base.extend() with a version that registers classes that // Override Base.extend() to register named classes in Base.exports,
// define #_class inside the Base._classes lookup, for // for deserialization and injection into PaperScope.
// deserialization. var res = extend.base.apply(this, arguments),
var res = this.base.apply(this, arguments); name = res.name;
if (src._class) if (name)
Base._classes[src._class] = res; Base.exports[name] = res;
return res; return res;
}, },
@ -289,11 +291,12 @@ this.Base = Base.inject(/** @lends Base# */{
ref = this.references[id]; ref = this.references[id];
if (!ref) { if (!ref) {
this.length++; this.length++;
var res = create.call(item); var res = create.call(item),
name = item.constructor.name;
// Also automatically insert class for dictionary // Also automatically insert class for dictionary
// entries. // entries.
if (item._class && res[0] !== item._class) if (name && res[0] !== name)
res.unshift(item._class); res.unshift(name);
this.definitions[id] = res; this.definitions[id] = res;
ref = this.references[id] = [id]; ref = this.references[id] = [id];
} }
@ -306,13 +309,18 @@ this.Base = Base.inject(/** @lends Base# */{
// If we don't serialize to compact form (meaning no type // If we don't serialize to compact form (meaning no type
// identifier), see if _serialize didn't already add the class, // identifier), see if _serialize didn't already add the class,
// e.g. for classes that do not support compact form. // e.g. for classes that do not support compact form.
if (obj._class && !compact && res[0] !== obj._class) var name = obj.constructor.name;
res.unshift(obj._class); if (name && !compact && !res._compact && res[0] !== name)
res.unshift(name);
} else if (Array.isArray(obj)) { } else if (Array.isArray(obj)) {
res = []; res = [];
for (var i = 0, l = obj.length; i < l; i++) for (var i = 0, l = obj.length; i < l; i++)
res[i] = Base.serialize(obj[i], options, compact, res[i] = Base.serialize(obj[i], options, compact,
dictionary); dictionary);
// Mark array as compact, so obj._serialize handling above
// doesn't add the constructor name again.
if (compact)
res._compact = true;
} else if (Base.isPlainObject(obj)) { } else if (Base.isPlainObject(obj)) {
res = {}; res = {};
for (var i in obj) for (var i in obj)
@ -332,7 +340,7 @@ this.Base = Base.inject(/** @lends Base# */{
/** /**
* Deserializes from parsed JSON data. A simple convention is followed: * Deserializes from parsed JSON data. A simple convention is followed:
* Array values with a string at the first position are links to * Array values with a string at the first position are links to
* deserializable types through Base._classes, and the values following * deserializable types through Base.exports, and the values following
* in the array are the arguments to their initialize function. * in the array are the arguments to their initialize function.
* Any other value is passed on unmodified. * Any other value is passed on unmodified.
* The passed data is recoursively traversed and converted, leaves first * The passed data is recoursively traversed and converted, leaves first
@ -356,7 +364,7 @@ this.Base = Base.inject(/** @lends Base# */{
// if so return its definition instead. // if so return its definition instead.
if (data.dictionary && obj.length == 1 && /^#/.test(type)) if (data.dictionary && obj.length == 1 && /^#/.test(type))
return data.dictionary[type]; return data.dictionary[type];
type = Base._classes[type]; type = Base.exports[type];
} }
res = []; res = [];
// Skip first type entry for arguments // Skip first type entry for arguments

View file

@ -98,7 +98,7 @@ var Callback = {
statics: { statics: {
// Override inject() so that sub-classes automatically add the accessors // Override inject() so that sub-classes automatically add the accessors
// for the event handler functions (e.g. #onMouseDown) for each property // for the event handler functions (e.g. #onMouseDown) for each property
inject: function(/* src, ... */) { inject: function inject(/* src, ... */) {
for (var i = 0, l = arguments.length; i < l; i++) { for (var i = 0, l = arguments.length; i < l; i++) {
var src = arguments[i], var src = arguments[i],
events = src._events; events = src._events;
@ -132,7 +132,7 @@ var Callback = {
}); });
src._eventTypes = types; src._eventTypes = types;
} }
this.base(src); inject.base.call(this, src);
} }
return this; return this;
} }

View file

@ -32,7 +32,7 @@
* The global {@link paper} object is simply a reference to the currently active * The global {@link paper} object is simply a reference to the currently active
* {@code PaperScope}. * {@code PaperScope}.
*/ */
var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{ var PaperScope = Base.extend(/** @lends PaperScope# */{
/** /**
* Creates a PaperScope object. * Creates a PaperScope object.
@ -40,7 +40,7 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
* @name PaperScope#initialize * @name PaperScope#initialize
* @function * @function
*/ */
initialize: function(script) { initialize: function PaperScope(script) {
// script is only used internally, when creating scopes for PaperScript. // script is only used internally, when creating scopes for PaperScript.
// Whenever a PaperScope is created, it automatically becomes the active // Whenever a PaperScope is created, it automatically becomes the active
// one. // one.
@ -71,11 +71,11 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
}, },
/** /**
* The version of Paper.js, as a float number. * The version of Paper.js, as a string.
* *
* @type Number * @type String
*/ */
version: /*#=*/ options.version, version: '/*#=*/ options.version',
/** /**
* The currently active project. * The currently active project.
@ -139,7 +139,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
Base.each(['project', 'view', 'tool'], function(key) { Base.each(['project', 'view', 'tool'], function(key) {
Base.define(scope, key, { Base.define(scope, key, {
configurable: true, configurable: true,
writable: true,
get: function() { get: function() {
return that[key]; return that[key];
} }

View file

@ -20,8 +20,8 @@
/*#*/ } else if (options.parser == 'esprima') { /*#*/ } else if (options.parser == 'esprima') {
/*#*/ include('../../lib/esprima-min.js'); /*#*/ include('../../lib/esprima-min.js');
/*#*/ } /*#*/ }
var PaperScript = this.PaperScript = new function() { var PaperScript = new function() {
// Operators to overload // Operators to overload
var binaryOperators = { var binaryOperators = {

View file

@ -1,24 +0,0 @@
/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
* Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
* http://lehni.org/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
/*#*/ if (options.version == 'dev') {
// When in dev mode, also export all classes through PaperScope, to mimick
// scoping behavior of the built library.
Base.each(this, function(val, key) {
if (val && val.prototype instanceof Base || val === Base)
PaperScope.prototype[key] = val;
});
// See paper.js for the non-dev version of this code. We cannot handle dev there
// due to the seperate loading of all source files, which are only availabe
// after the execution of paper.js
var paper = new PaperScope();
/*#*/ } // options.version == 'dev'

View file

@ -158,7 +158,7 @@ var DomElement = new function() {
var doc = el.ownerDocument, var doc = el.ownerDocument,
view = doc.defaultView, view = doc.defaultView,
html = doc.documentElement; html = doc.documentElement;
return Rectangle.create(0, 0, return new Rectangle(0, 0,
view.innerWidth || html.clientWidth, view.innerWidth || html.clientWidth,
view.innerHeight || html.clientHeight view.innerHeight || html.clientHeight
); );

View file

@ -49,7 +49,7 @@ var DomEvent = {
? event.targetTouches[0] ? event.targetTouches[0]
: event.changedTouches[0] : event.changedTouches[0]
: event; : event;
return Point.create( return new Point(
pos.pageX || pos.clientX + document.documentElement.scrollLeft, pos.pageX || pos.clientX + document.documentElement.scrollLeft,
pos.pageY || pos.clientY + document.documentElement.scrollTop pos.pageY || pos.clientY + document.documentElement.scrollTop
); );

18
src/export.js Normal file
View file

@ -0,0 +1,18 @@
/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
* Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
* http://lehni.org/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
// Add PaperScript and Numerical to exports, inject all exports into PaperScope,
// and create the initial paper object, all in one condensed statement:
var paper = new (PaperScope.inject(Base.exports.inject({
PaperScript: PaperScript,
Numerical: Numerical
})))();

View file

@ -20,7 +20,10 @@
* *
* @extends Group * @extends Group
*/ */
var Clip = this.Clip = Group.extend(/** @lends Clip# */{ var Clip = Group.extend(/** @lends Clip# */{
_class: 'Clip', _applyMatrix: false,
_applyMatrix: false
initialize: function Clip() {
Group.apply(this, arguments);
}
}); });

View file

@ -19,8 +19,7 @@
* *
* @extends Item * @extends Item
*/ */
var Group = this.Group = Item.extend(/** @lends Group# */{ var Group = Item.extend(/** @lends Group# */{
_class: 'Group',
_serializeFields: { _serializeFields: {
children: [] children: []
}, },
@ -88,8 +87,8 @@ var Group = this.Group = Item.extend(/** @lends Group# */{
* position: view.center * position: view.center
* }); * });
*/ */
initialize: function(arg) { initialize: function Group(arg) {
this.base(); Item.call(this);
// Allow Group to have children and named children // Allow Group to have children and named children
this._children = []; this._children = [];
this._namedChildren = {}; this._namedChildren = {};
@ -97,9 +96,12 @@ var Group = this.Group = Item.extend(/** @lends Group# */{
this.addChildren(Array.isArray(arg) ? arg : arguments); this.addChildren(Array.isArray(arg) ? arg : arguments);
}, },
_changed: function(flags) { _changed: function _changed(flags) {
// Don't use this.base() for reasons of performance. _changed.base.call(this, flags);
Item.prototype._changed.call(this, flags); if (flags & /*#=*/ ChangeFlag.HIERARCHY && !this._matrix.isIdentity()) {
// Apply matrix now that we have content.
this.applyMatrix();
}
if (flags & (/*#=*/ ChangeFlag.HIERARCHY | /*#=*/ ChangeFlag.CLIPPING)) { if (flags & (/*#=*/ ChangeFlag.HIERARCHY | /*#=*/ ChangeFlag.CLIPPING)) {
// Clear cached clip item whenever hierarchy changes // Clear cached clip item whenever hierarchy changes
delete this._clipItem; delete this._clipItem;

View file

@ -17,8 +17,8 @@
* test. It is returned by {@link Item#hitTest(point)} and * test. It is returned by {@link Item#hitTest(point)} and
* {@link Project#hitTest(point)}. * {@link Project#hitTest(point)}.
*/ */
var HitResult = this.HitResult = Base.extend(/** @lends HitResult# */{ var HitResult = Base.extend(/** @lends HitResult# */{
initialize: function(type, item, values) { initialize: function HitResult(type, item, values) {
this.type = type; this.type = type;
this.item = item; this.item = item;
// Inject passed values, so we can be flexible about the HitResult // Inject passed values, so we can be flexible about the HitResult

View file

@ -20,23 +20,27 @@
* is unique to their type, but share the underlying properties and functions * is unique to their type, but share the underlying properties and functions
* that they inherit from Item. * that they inherit from Item.
*/ */
var Item = this.Item = Base.extend(Callback, { var Item = Base.extend(Callback, /** @lends Item# */{
statics: { statics: {
/** /**
* Override Item.extend() to merge the subclass' _serializeFields with * Override Item.extend() to merge the subclass' _serializeFields with
* the parent class' _serializeFields. * the parent class' _serializeFields.
*
* @private
*/ */
extend: function(src) { extend: function extend(src) {
if (src._serializeFields) if (src._serializeFields)
src._serializeFields = Base.merge( src._serializeFields = Base.merge(
this.prototype._serializeFields, src._serializeFields); this.prototype._serializeFields, src._serializeFields);
// Derive the _type string from _class var res = extend.base.apply(this, arguments),
if (src._class) name = res.name;
src._type = Base.hyphenate(src._class); // Derive the _type string from constructor name
return this.base.apply(this, arguments); if (name)
res.prototype._type = Base.hyphenate(name);
return res;
} }
} },
}, /** @lends Item# */{
// All items apply their matrix by default. // All items apply their matrix by default.
// Exceptions are Raster, PlacedSymbol, Clip and Shape. // Exceptions are Raster, PlacedSymbol, Clip and Shape.
_applyMatrix: true, _applyMatrix: true,
@ -55,7 +59,7 @@ var Item = this.Item = Base.extend(Callback, {
data: {} data: {}
}, },
initialize: function(point) { initialize: function Item(point) {
// Define this Item's unique id. // Define this Item's unique id.
this._id = Item._id = (Item._id || 0) + 1; this._id = Item._id = (Item._id || 0) + 1;
// If _project is already set, the item was already moved into the DOM // If _project is already set, the item was already moved into the DOM
@ -168,7 +172,7 @@ var Item = this.Item = Base.extend(Callback, {
serialize(this._style._defaults); serialize(this._style._defaults);
// There is no compact form for Item serialization, we always keep the // There is no compact form for Item serialization, we always keep the
// type. // type.
return [ this._class, props ]; return [ this.constructor.name, props ];
}, },
/** /**
@ -198,7 +202,7 @@ var Item = this.Item = Base.extend(Callback, {
this._clearBoundsCache(); this._clearBoundsCache();
} }
if (flags & /*#=*/ ChangeFlag.APPEARANCE) { if (flags & /*#=*/ ChangeFlag.APPEARANCE) {
this._project._needsRedraw(); this._project._needsRedraw = true;
} }
// If this item is a symbol's definition, notify it of the change too // If this item is a symbol's definition, notify it of the change too
if (this._parentSymbol) if (this._parentSymbol)
@ -878,7 +882,7 @@ var Item = this.Item = Base.extend(Callback, {
} }
} }
return isFinite(x1) return isFinite(x1)
? Rectangle.create(x1, y1, x2 - x1, y2 - y1) ? new Rectangle(x1, y1, x2 - x1, y2 - y1)
: new Rectangle(); : new Rectangle();
}, },
@ -1428,7 +1432,6 @@ var Item = this.Item = Base.extend(Callback, {
* @param {Item} item The item to be added as a child * @param {Item} item The item to be added as a child
*/ */
addChild: function(item, _preserve) { addChild: function(item, _preserve) {
// Pass on internal _preserve boolean, for CompoundPath#insertChild
return this.insertChild(undefined, item, _preserve); return this.insertChild(undefined, item, _preserve);
}, },
@ -1441,21 +1444,8 @@ var Item = this.Item = Base.extend(Callback, {
* @param {Item} item The item to be appended as a child * @param {Item} item The item to be appended as a child
*/ */
insertChild: function(index, item, _preserve) { insertChild: function(index, item, _preserve) {
// _preserve parameter is not used here, but CompoundPath#insertChild() var res = this.insertChildren(index, [item], _preserve);
// needs it. return res && res[0];
if (this._children) {
item._remove(true);
Base.splice(this._children, [item], index, 0);
item._parent = this;
item._setProject(this._project);
// Setting the name again makes sure all name lookup structures are
// kept in sync.
if (item._name)
item.setName(item._name);
this._changed(/*#=*/ Change.HIERARCHY);
return item;
}
return null;
}, },
/** /**
@ -1477,25 +1467,42 @@ var Item = this.Item = Base.extend(Callback, {
* @param {Number} index * @param {Number} index
* @param {Item[]} items The items to be appended as children * @param {Item[]} items The items to be appended as children
*/ */
insertChildren: function(index, items, _preserve) { insertChildren: function(index, items, _preserve, _type) {
// We need to clone items because it might be // CompoundPath#insertChildren() requires _preserve and _type:
// an Item#children array. Use Array.prototype.slice because // _preserve avoids changing of the children's path orientation
// in certain cases items is an arguments object // _type enforces the inserted type.
items = items && Array.prototype.slice.apply(items); var children = this._children;
var children = this._children, if (children && items && items.length > 0) {
length = children.length, // We need to clone items because it might be
i = index; // an Item#children array. Also, we're removing elements if they
for (var j = 0, l = items && items.length; j < l; j++) { // don't match _type. Use Array.prototype.slice becaus items can be
if (this.insertChild(i, items[j], _preserve)) { // an arguments object.
// We need to keep track of how much the list actually grows, items = Array.prototype.slice.apply(items);
// bcause we might be removing and inserting into the same list, // Remove the items from their parents first, since they might be
// in which case the size would not chage. // inserted into their own parents, affecting indices.
var newLength = children.length; // Use the loop also to filter out wrong _type.
i += newLength - length; for (var i = items.length - 1; i >= 0; i--) {
length = newLength; var item = items[i];
if (_type && item._type !== _type)
items.splice(i, 1);
else
item._remove(true);
} }
Base.splice(children, items, index, 0);
for (var i = 0, l = items.length; i < l; i++) {
var item = items[i];
item._parent = this;
item._setProject(this._project);
// Setting the name again makes sure all name lookup structures
// are kept in sync.
if (item._name)
item.setName(item._name);
}
this._changed(/*#=*/ Change.HIERARCHY);
} else {
items = null;
} }
return i != index; return items;
}, },
/** /**
@ -2220,9 +2227,10 @@ var Item = this.Item = Base.extend(Callback, {
}, },
_transformContent: function(matrix, applyMatrix) { _transformContent: function(matrix, applyMatrix) {
if (this._children) { var children = this._children;
for (var i = 0, l = this._children.length; i < l; i++) if (children && children.length > 0) {
this._children[i].transform(matrix, applyMatrix); for (var i = 0, l = children.length; i < l; i++)
children[i].transform(matrix, applyMatrix);
return true; return true;
} }
}, },
@ -2332,7 +2340,7 @@ var Item = this.Item = Base.extend(Callback, {
? rectangle.width / bounds.width ? rectangle.width / bounds.width
: rectangle.height / bounds.height, : rectangle.height / bounds.height,
newBounds = new Rectangle(new Point(), newBounds = new Rectangle(new Point(),
Size.create(bounds.width * scale, bounds.height * scale)); new Size(bounds.width * scale, bounds.height * scale));
newBounds.setCenter(rectangle.getCenter()); newBounds.setCenter(rectangle.getCenter());
this.setBounds(newBounds); this.setBounds(newBounds);
}, },
@ -2877,7 +2885,7 @@ var Item = this.Item = Base.extend(Callback, {
// so we draw onto it, instead of the parentCtx // so we draw onto it, instead of the parentCtx
parentCtx = ctx; parentCtx = ctx;
ctx = CanvasProvider.getContext( ctx = CanvasProvider.getContext(
bounds.getSize().ceil().add(Size.create(1, 1))); bounds.getSize().ceil().add(new Size(1, 1)));
} }
ctx.save(); ctx.save();
// Translate the context so the topLeft of the item is at (0, 0) // Translate the context so the topLeft of the item is at (0, 0)

View file

@ -22,8 +22,7 @@
* *
* @extends Group * @extends Group
*/ */
var Layer = this.Layer = Group.extend(/** @lends Layer# */{ var Layer = Group.extend(/** @lends Layer# */{
_class: 'Layer',
// DOCS: improve constructor code example. // DOCS: improve constructor code example.
/** /**
* Creates a new Layer item and places it at the end of the * Creates a new Layer item and places it at the end of the
@ -57,11 +56,11 @@ var Layer = this.Layer = Group.extend(/** @lends Layer# */{
* position: view.center * position: view.center
* }); * });
*/ */
initialize: function(items) { initialize: function Layer(items) {
this._project = paper.project; this._project = paper.project;
// Push it onto project.layers and set index: // Push it onto project.layers and set index:
this._index = this._project.layers.push(this) - 1; this._index = this._project.layers.push(this) - 1;
this.base.apply(this, arguments); Group.apply(this, arguments);
this.activate(); this.activate();
}, },
@ -69,9 +68,9 @@ var Layer = this.Layer = Group.extend(/** @lends Layer# */{
* Removes the layer from its project's layers list * Removes the layer from its project's layers list
* or its parent's children list. * or its parent's children list.
*/ */
_remove: function(notify) { _remove: function _remove(notify) {
if (this._parent) if (this._parent)
return this.base(notify); return _remove.base.call(this, notify);
if (this._index != null) { if (this._index != null) {
if (this._project.activeLayer === this) if (this._project.activeLayer === this)
this._project.activeLayer = this.getNextSibling() this._project.activeLayer = this.getNextSibling()
@ -79,24 +78,24 @@ var Layer = this.Layer = Group.extend(/** @lends Layer# */{
Base.splice(this._project.layers, null, this._index, 1); Base.splice(this._project.layers, null, this._index, 1);
// Tell project we need a redraw. This is similar to _changed() // Tell project we need a redraw. This is similar to _changed()
// mechanism. // mechanism.
this._project._needsRedraw(); this._project._needsRedraw = true;
return true; return true;
} }
return false; return false;
}, },
getNextSibling: function() { getNextSibling: function getNextSibling() {
return this._parent ? this.base() return this._parent ? getNextSibling.base.call(this)
: this._project.layers[this._index + 1] || null; : this._project.layers[this._index + 1] || null;
}, },
getPreviousSibling: function() { getPreviousSibling: function getPreviousSibling() {
return this._parent ? this.base() return this._parent ? getPreviousSibling.base.call(this)
: this._project.layers[this._index - 1] || null; : this._project.layers[this._index - 1] || null;
}, },
isInserted: function() { isInserted: function isInserted() {
return this._parent ? this.base() : this._index != null; return this._parent ? isInserted.base.call(this) : this._index != null;
}, },
/** /**
@ -114,7 +113,7 @@ var Layer = this.Layer = Group.extend(/** @lends Layer# */{
} }
}, new function () { }, new function () {
function insert(above) { function insert(above) {
return function(item) { return function insert(item) {
// If the item is a layer and contained within Project#layers, use // If the item is a layer and contained within Project#layers, use
// our own version of move(). // our own version of move().
if (item instanceof Layer && !item._parent if (item instanceof Layer && !item._parent
@ -124,7 +123,7 @@ var Layer = this.Layer = Group.extend(/** @lends Layer# */{
this._setProject(item._project); this._setProject(item._project);
return true; return true;
} }
return this.base(item); return insert.base.call(this, item);
}; };
} }

View file

@ -18,8 +18,7 @@
* *
* @extends Item * @extends Item
*/ */
var PlacedSymbol = this.PlacedSymbol = Item.extend(/** @lends PlacedSymbol# */{ var PlacedSymbol = Item.extend(/** @lends PlacedSymbol# */{
_class: 'PlacedSymbol',
_applyMatrix: false, _applyMatrix: false,
// PlacedSymbol uses strokeBounds for bounds // PlacedSymbol uses strokeBounds for bounds
_boundsGetter: { getBounds: 'getStrokeBounds' }, _boundsGetter: { getBounds: 'getStrokeBounds' },
@ -68,11 +67,11 @@ var PlacedSymbol = this.PlacedSymbol = Item.extend(/** @lends PlacedSymbol# */{
* instance.scale(0.25 + Math.random() * 0.75); * instance.scale(0.25 + Math.random() * 0.75);
* } * }
*/ */
initialize: function(arg0, arg1) { initialize: function PlacedSymbol(arg0, arg1) {
// Support two forms of item initialization: Passing one object literal // Support two forms of item initialization: Passing one object literal
// describing all the different properties to be set, or a symbol (arg0) // describing all the different properties to be set, or a symbol (arg0)
// and a point where it should be placed (arg1). // and a point where it should be placed (arg1).
this.base(arg1 !== undefined && Point.read(arguments, 1)); Item.call(this, arg1 !== undefined && Point.read(arguments, 1));
// If we can handle setting properties through object literal, we're all // If we can handle setting properties through object literal, we're all
// set. Otherwise we need to set symbol. // set. Otherwise we need to set symbol.
if (arg0 && !this._set(arg0)) if (arg0 && !this._set(arg0))

View file

@ -17,8 +17,7 @@
* *
* @extends Item * @extends Item
*/ */
var Raster = this.Raster = Item.extend(/** @lends Raster# */{ var Raster = Item.extend(/** @lends Raster# */{
_class: 'Raster',
_applyMatrix: false, _applyMatrix: false,
// Raster doesn't make the distinction between the different bounds, // Raster doesn't make the distinction between the different bounds,
// so use the same name for all of them // so use the same name for all of them
@ -72,11 +71,11 @@ var Raster = this.Raster = Item.extend(/** @lends Raster# */{
* raster.scale(0.5); * raster.scale(0.5);
* raster.rotate(10); * raster.rotate(10);
*/ */
initialize: function(object, position) { initialize: function Raster(object, position) {
// Support two forms of item initialization: Passing one object literal // Support two forms of item initialization: Passing one object literal
// describing all the different properties to be set, or an image // describing all the different properties to be set, or an image
// (object) and a point where it should be placed (point). // (object) and a point where it should be placed (point).
this.base(position !== undefined && Point.read(arguments, 1)); Item.call(this, position !== undefined && Point.read(arguments, 1));
// If we can handle setting properties through object literal, we're all // If we can handle setting properties through object literal, we're all
// set. Otherwise we need to check the type of object: // set. Otherwise we need to check the type of object:
if (object && !this._set(object)) { if (object && !this._set(object)) {
@ -164,7 +163,7 @@ var Raster = this.Raster = Item.extend(/** @lends Raster# */{
orig = new Point(0, 0).transform(matrix), orig = new Point(0, 0).transform(matrix),
u = new Point(1, 0).transform(matrix).subtract(orig), u = new Point(1, 0).transform(matrix).subtract(orig),
v = new Point(0, 1).transform(matrix).subtract(orig); v = new Point(0, 1).transform(matrix).subtract(orig);
return Size.create( return new Size(
72 / u.getLength(), 72 / u.getLength(),
72 / v.getLength() 72 / v.getLength()
); );
@ -218,7 +217,7 @@ var Raster = this.Raster = Item.extend(/** @lends Raster# */{
if (this._canvas) if (this._canvas)
CanvasProvider.release(this._canvas); CanvasProvider.release(this._canvas);
this._canvas = canvas; this._canvas = canvas;
this._size = Size.create(canvas.width, canvas.height); this._size = new Size(canvas.width, canvas.height);
this._image = null; this._image = null;
this._context = null; this._context = null;
this._changed(/*#=*/ Change.GEOMETRY | /*#=*/ Change.PIXELS); this._changed(/*#=*/ Change.GEOMETRY | /*#=*/ Change.PIXELS);
@ -239,10 +238,10 @@ var Raster = this.Raster = Item.extend(/** @lends Raster# */{
CanvasProvider.release(this._canvas); CanvasProvider.release(this._canvas);
this._image = image; this._image = image;
/*#*/ if (options.browser) { /*#*/ if (options.browser) {
this._size = Size.create(image.naturalWidth, image.naturalHeight); this._size = new Size(image.naturalWidth, image.naturalHeight);
/*#*/ } else if (options.server) { /*#*/ } else if (options.node) {
this._size = Size.create(image.width, image.height); this._size = new Size(image.width, image.height);
/*#*/ } // options.server /*#*/ } // options.node
this._canvas = null; this._canvas = null;
this._context = null; this._context = null;
this._changed(/*#=*/ Change.GEOMETRY); this._changed(/*#=*/ Change.GEOMETRY);
@ -296,14 +295,22 @@ var Raster = this.Raster = Item.extend(/** @lends Raster# */{
} else if (!image.src) { } else if (!image.src) {
image.src = src; image.src = src;
} }
/*#*/ } else if (options.server) {
// If we're running on the server and it's a string,
// load it from disk:
// TODO: load images async, calling setImage once loaded as above
var image = new Image();
image.src = fs.readFileSync(src);
/*#*/ } // options.server
this.setImage(image); this.setImage(image);
/*#*/ } else if (options.node) {
var image = new Image();
// If we're running on the server and it's a string,
// check if it is a data URL
if (/^data:/.test(src)) {
// Preserve the data in this._data since canvas-node eats it.
// TODO: Fix canvas-node instead
image.src = this._data = src;
} else {
// Load it from disk:
// TODO: load images async, calling setImage once loaded as above.
image.src = fs.readFileSync(src);
}
this.setImage(image);
/*#*/ } // options.node
}, },
// DOCS: document Raster#getElement // DOCS: document Raster#getElement
@ -334,9 +341,14 @@ var Raster = this.Raster = Item.extend(/** @lends Raster# */{
toDataURL: function() { toDataURL: function() {
// See if the linked image is base64 encoded already, if so reuse it, // See if the linked image is base64 encoded already, if so reuse it,
// otherwise try using canvas.toDataURL() // otherwise try using canvas.toDataURL()
/*#*/ if (options.node) {
if (this._data)
return this._data;
/*#*/ } else {
var src = this._image && this._image.src; var src = this._image && this._image.src;
if (/^data:/.test(src)) if (/^data:/.test(src))
return src; return src;
/*#*/ }
var canvas = this.getCanvas(); var canvas = this.getCanvas();
return canvas ? canvas.toDataURL() : null; return canvas ? canvas.toDataURL() : null;
}, },
@ -375,7 +387,7 @@ var Raster = this.Raster = Item.extend(/** @lends Raster# */{
bounds = new Rectangle(object); bounds = new Rectangle(object);
} else if (object.x) { } else if (object.x) {
// Create a rectangle of 1px size around the specified coordinates // Create a rectangle of 1px size around the specified coordinates
bounds = Rectangle.create(object.x - 0.5, object.y - 0.5, 1, 1); bounds = new Rectangle(object.x - 0.5, object.y - 0.5, 1, 1);
} }
// Use a sample size of max 32 x 32 pixels, into which the path is // Use a sample size of max 32 x 32 pixels, into which the path is
// scaled as a clipping path, and then the actual image is drawn in and // scaled as a clipping path, and then the actual image is drawn in and

View file

@ -17,12 +17,11 @@
* *
* @extends Item * @extends Item
*/ */
var Shape = this.Shape = Item.extend(/** @lends Shape# */{ var Shape = Item.extend(/** @lends Shape# */{
_class: 'Shape',
_applyMatrix: false, _applyMatrix: false,
initialize: function(type, point, size) { initialize: function Shape(type, point, size) {
this.base(point); Item.call(this, point);
this._type = type; this._type = type;
this._size = size; this._size = size;
}, },
@ -67,10 +66,10 @@ var Shape = this.Shape = Item.extend(/** @lends Shape# */{
} }
}, },
_contains: function(point) { _contains: function _contains(point) {
switch (this._type) { switch (this._type) {
case 'rect': case 'rect':
return this.base(point); return _contains.base.call(this, point);
case 'circle': case 'circle':
case 'ellipse': case 'ellipse':
return point.divide(this._size).getLength() <= 0.5; return point.divide(this._size).getLength() <= 0.5;

View file

@ -14,17 +14,7 @@
// 'preprocess' it on the fly in the browser, avoiding the step of having to // 'preprocess' it on the fly in the browser, avoiding the step of having to
// manually preprocess it after each change. // manually preprocess it after each change.
// Define options for compile-time preprocessing.
var options = {
parser: 'acorn',
version: 'dev',
browser: true,
stats: true,
svg: true,
fatline: true,
debug: false
};
// This folder is specified relatively to the lib folder from which prepro.js is // This folder is specified relatively to the lib folder from which prepro.js is
// loaded, and which is referenced as the root. // loaded, and which is referenced as the root.
include('../src/options.js');
include('../src/paper.js'); include('../src/paper.js');

View file

@ -16,24 +16,23 @@ var fs = require('fs'),
// Node Canvas library: https://github.com/learnboost/node-canvas // Node Canvas library: https://github.com/learnboost/node-canvas
Canvas = require('canvas'), Canvas = require('canvas'),
jsdom = require('jsdom'), jsdom = require('jsdom'),
domToHtml = require('jsdom/lib/jsdom/browser/domtohtml').domToHtml, domToHtml = require('jsdom/lib/jsdom/browser/domtohtml').domToHtml;
json = require('../../package.json');
var options = { // Load the options from load.js, but evaluate into local scope:
parser: 'acorn', eval(fs.readFileSync(path.resolve(__dirname, '../options.js'), 'utf8'));
// Use 'dev' for on-the fly compilation of separate files ,but update after. // Change node.js specific settings. Use 'dev' version for on-the fly
version: 'dev', // compilation of separate files, and set to correct value after.
server: true, options.version = 'dev';
svg: true, options.browser = false;
fatline: false options.node = true;
}; options.stats = false;
// Create a document and a window using jsdom, e.g. for exportSVG() // Create a document and a window using jsdom, e.g. for exportSVG()
var doc = jsdom.jsdom("<html><body></body></html>"), var doc = jsdom.jsdom("<html><body></body></html>"),
win = doc.createWindow(); win = doc.createWindow();
// Define XMLSerializer. // Define XMLSerializer and DOMParser shims, to emulate browser behavior.
// TODO: Put this into a simple node module, with dependency on jsdom // TODO: Put this into a simple node module, with dependency on jsdom?
function XMLSerializer() { function XMLSerializer() {
} }
@ -41,7 +40,7 @@ XMLSerializer.prototype.serializeToString = function(node) {
var text = domToHtml(node); var text = domToHtml(node);
// Fix a jsdom issue where linearGradient gets converted to lineargradient: // Fix a jsdom issue where linearGradient gets converted to lineargradient:
// https://github.com/tmpvar/jsdom/issues/620 // https://github.com/tmpvar/jsdom/issues/620
return text.replace(/(linear|radial)(gradient)/g, function(all, type) { return text.replace(/(linear|radial)gradient/g, function(all, type) {
return type + 'Gradient'; return type + 'Gradient';
}); });
}; };
@ -89,26 +88,13 @@ var context = vm.createContext({
// Load Paper.js library files: // Load Paper.js library files:
context.include('paper.js'); context.include('paper.js');
// Since the context used for Paper.js compilation, and the context in which
// Node.js scripts are executed do not share the definition of Object, we need
// to redefine Base.isPlainObject() here.
// So instead of checking for Object.prototype, we're checking
// proto.constructor.name for 'Object'
var Base = context.Base;
Base.isPlainObject = function(obj) {
var proto = obj !== null && typeof obj === 'object'
&& Object.getPrototypeOf(obj);
return proto && (proto.constructor.name === 'Object'
|| proto === Base.prototype);
};
context.PaperScope.inject({ context.PaperScope.inject({
// Expose the Canvas, XMLSerializer & DOMParser to PaperScope: // Expose the Canvas, XMLSerializer & DOMParser to PaperScope:
Canvas: Canvas, Canvas: Canvas,
XMLSerializer: XMLSerializer, XMLSerializer: XMLSerializer,
DOMParser: DOMParser, DOMParser: DOMParser,
// Also fix version. Remove 2nd dot, so we can make a float out of it: // Also set the correct version from package.json
version: parseFloat(json.version.replace(/(.)(\d)$/, '$2')) version: require('../../package.json').version
}); });
require.extensions['.pjs'] = function(module, uri) { require.extensions['.pjs'] = function(module, uri) {

24
src/options.js Normal file
View file

@ -0,0 +1,24 @@
/*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/
*
* Copyright (c) 2011 - 2013, Juerg Lehni & Jonathan Puckey
* http://lehni.org/ & http://jonathanpuckey.com/
*
* Distributed under the MIT license. See LICENSE file for details.
*
* All rights reserved.
*/
// Define default options for compile-time preprocessing. These are also used
// for building, but some values are overridden (e.g. version, stats).
var options = {
parser: 'acorn',
version: 'dev',
browser: true,
stats: true,
svg: true,
fatline: false,
debug: false
};

View file

@ -35,14 +35,14 @@ var paper = new function() {
// Inline Bootstrap core (the Base class) inside the paper scope first: // Inline Bootstrap core (the Base class) inside the paper scope first:
/*#*/ include('../lib/straps.js'); /*#*/ include('../lib/straps.js');
/*#*/ if (options.version == 'dev') {
/*#*/ include('constants.js');
/*#*/ } // options.version == 'dev'
/*#*/ if (options.stats) { /*#*/ if (options.stats) {
/*#*/ include('../lib/stats.js'); /*#*/ include('../lib/stats.js');
/*#*/ } // options.stats /*#*/ } // options.stats
/*#*/ if (options.version == 'dev') {
/*#*/ include('constants.js');
/*#*/ } // options.version == 'dev'
/*#*/ include('core/Base.js'); /*#*/ include('core/Base.js');
/*#*/ include('core/Callback.js'); /*#*/ include('core/Callback.js');
/*#*/ include('core/PaperScope.js'); /*#*/ include('core/PaperScope.js');
@ -53,7 +53,7 @@ var paper = new function() {
// Include Paper classes, which are later injected into PaperScope by setting // Include Paper classes, which are later injected into PaperScope by setting
// them on the 'this' object, e.g.: // them on the 'this' object, e.g.:
// var Point = this.Point = Base.extend(...); // var Point = Base.extend(...);
/*#*/ include('basic/Point.js'); /*#*/ include('basic/Point.js');
/*#*/ include('basic/Size.js'); /*#*/ include('basic/Size.js');
@ -126,18 +126,7 @@ var paper = new function() {
/*#*/ } // options.svg /*#*/ } // options.svg
/*#*/ include('core/PaperScript.js'); /*#*/ include('core/PaperScript.js');
/*#*/ include('core/initialize.js');
/*#*/ if (options.server) { /*#*/ include('export.js');
return paper; return paper;
/*#*/ } else if (options.version != 'dev') {
// Finally inject the classes set on 'this' into the PaperScope class and create
// the first PaperScope and return it, all in one statement.
// The version for 'dev' of this happens in core/initialize.js, since it depends
// on sequentiality of include() loading.
// Mark this object as enumerable, so all the injected classes can be enumerated
// again in PaperScope#install().
this.enumerable = true;
return new (PaperScope.inject(this));
/*#*/ } // options.version != 'dev'
}; };

View file

@ -20,8 +20,7 @@
* *
* @extends PathItem * @extends PathItem
*/ */
var CompoundPath = this.CompoundPath = PathItem.extend(/** @lends CompoundPath# */{ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
_class: 'CompoundPath',
_serializeFields: { _serializeFields: {
pathData: '' pathData: ''
}, },
@ -49,8 +48,8 @@ var CompoundPath = this.CompoundPath = PathItem.extend(/** @lends CompoundPath#
* // Move the inner circle 5pt to the right: * // Move the inner circle 5pt to the right:
* compoundPath.children[1].position.x += 5; * compoundPath.children[1].position.x += 5;
*/ */
initialize: function(arg) { initialize: function CompoundPath(arg) {
this.base(); PathItem.call(this);
// CompoundPath has children and supports named children. // CompoundPath has children and supports named children.
this._children = []; this._children = [];
this._namedChildren = {}; this._namedChildren = {};
@ -58,18 +57,20 @@ var CompoundPath = this.CompoundPath = PathItem.extend(/** @lends CompoundPath#
this.addChildren(Array.isArray(arg) ? arg : arguments); this.addChildren(Array.isArray(arg) ? arg : arguments);
}, },
insertChild: function(index, item, _preserve) { insertChildren: function insertChildren(index, items, _preserve) {
// Only allow the insertion of paths // Pass on 'path' for _type, to make sure that only paths are added as
if (item._type !== 'path') // children.
return null; items = insertChildren.base.call(this, index, items, _preserve, 'path');
item = this.base(index, item);
// All children except for the bottom one (first one in list) are set // All children except for the bottom one (first one in list) are set
// to anti-clockwise orientation, so that they appear as holes, but // to anti-clockwise orientation, so that they appear as holes, but
// only if their orientation was not already specified before // only if their orientation was not already specified before
// (= _clockwise is defined). // (= _clockwise is defined).
if (!_preserve && item && item._clockwise === undefined) for (var i = 0, l = !_preserve && items && items.length; i < l; i++) {
item.setClockwise(item._index == 0); var item = items[i];
return item; if (item._clockwise === undefined)
item.setClockwise(item._index === 0);
}
return items;
}, },
/** /**
@ -223,8 +224,9 @@ var CompoundPath = this.CompoundPath = PathItem.extend(/** @lends CompoundPath#
return (children.length & 1) == 1 && children; return (children.length & 1) == 1 && children;
}, },
_hitTest: function(point, options) { _hitTest: function _hitTest(point, options) {
var res = this.base(point, Base.merge(options, { fill: false })); var res = _hitTest.base.call(this, point,
Base.merge(options, { fill: false }));
if (!res && options.fill && this._style.getFillColor()) { if (!res && options.fill && this._style.getFillColor()) {
res = this._contains(point); res = this._contains(point);
res = res ? new HitResult('fill', res[0]) : null; res = res ? new HitResult('fill', res[0]) : null;

View file

@ -24,7 +24,7 @@
* convenient ways to work with parts of the path, finding lengths, positions or * convenient ways to work with parts of the path, finding lengths, positions or
* tangents at given offsets. * tangents at given offsets.
*/ */
var Curve = this.Curve = Base.extend(/** @lends Curve# */{ var Curve = Base.extend(/** @lends Curve# */{
/** /**
* Creates a new curve object. * Creates a new curve object.
* *
@ -55,7 +55,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
* @param {Number} x2 * @param {Number} x2
* @param {Number} y2 * @param {Number} y2
*/ */
initialize: function(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) { initialize: function Curve(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
var count = arguments.length; var count = arguments.length;
if (count === 0) { if (count === 0) {
this._segment1 = new Segment(); this._segment1 = new Segment();
@ -243,7 +243,7 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
var coords = this.getValues(), var coords = this.getValues(),
points = []; points = [];
for (var i = 0; i < 8; i += 2) for (var i = 0; i < 8; i += 2)
points.push(Point.create(coords[i], coords[i + 1])); points.push(new Point(coords[i], coords[i + 1]));
return points; return points;
}, },
@ -408,9 +408,9 @@ var Curve = this.Curve = Base.extend(/** @lends Curve# */{
// Create the new segment, convert absolute -> relative: // Create the new segment, convert absolute -> relative:
var x = left[6], y = left[7], var x = left[6], y = left[7],
segment = new Segment(Point.create(x, y), segment = new Segment(new Point(x, y),
!isLinear && Point.create(left[4] - x, left[5] - y), !isLinear && new Point(left[4] - x, left[5] - y),
!isLinear && Point.create(right[2] - x, right[3] - y)); !isLinear && new Point(right[2] - x, right[3] - y));
// Insert it in the segments list, if needed: // Insert it in the segments list, if needed:
if (this._path) { if (this._path) {
@ -662,7 +662,7 @@ statics: {
for (var i = 0; i < 2; i++) for (var i = 0; i < 2; i++)
Curve._addBounds(v[i], v[i + 2], v[i + 4], v[i + 6], Curve._addBounds(v[i], v[i + 2], v[i + 4], v[i + 6],
i, 0, min, max, roots); i, 0, min, max, roots);
return Rectangle.create(min[0], min[1], max[0] - min[0], max[1] - min[1]); return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]);
}, },
/** /**
@ -697,8 +697,8 @@ statics: {
// Only add strokeWidth to bounds for points which lie within 0 < t < 1 // Only add strokeWidth to bounds for points which lie within 0 < t < 1
// The corner cases for cap and join are handled in getStrokeBounds() // The corner cases for cap and join are handled in getStrokeBounds()
add(v3, 0); add(v3, 0);
for (var j = 0; j < count; j++) { for (var i = 0; i < count; i++) {
var t = roots[j], var t = roots[i],
u = 1 - t; u = 1 - t;
// Test for good roots and only add to bounds if good. // Test for good roots and only add to bounds if good.
if (tMin < t && t < tMax) if (tMin < t && t < tMax)
@ -1023,7 +1023,7 @@ new function() { // Scope for methods that require numerical integration
a, b, 16, /*#=*/ Numerical.TOLERANCE); a, b, 16, /*#=*/ Numerical.TOLERANCE);
} }
}; };
}, new function() { // Scope for Curve intersection }, new function() { // Scope for intersection using bezier fat-line clipping
function addLocation(locations, curve1, parameter, point, curve2) { function addLocation(locations, curve1, parameter, point, curve2) {
// Avoid duplicates when hitting segments (closed paths too) // Avoid duplicates when hitting segments (closed paths too)
var first = locations[0], var first = locations[0],
@ -1033,7 +1033,7 @@ new function() { // Scope for methods that require numerical integration
locations.push(new CurveLocation(curve1, parameter, point, curve2)); locations.push(new CurveLocation(curve1, parameter, point, curve2));
} }
function getCurveIntersections(v1, v2, curve1, curve2, locations, function addCurveIntersections(v1, v2, curve1, curve2, locations,
range1, range2, recursion) { range1, range2, recursion) {
/*#*/ if (options.fatline) { /*#*/ if (options.fatline) {
// NOTE: range1 and range1 are only used for recusion // NOTE: range1 and range1 are only used for recusion
@ -1097,17 +1097,17 @@ new function() { // Scope for methods that require numerical integration
if (range1[1] - range1[0] > range2[1] - range2[0]) { if (range1[1] - range1[0] > range2[1] - range2[0]) {
// subdivide v1 and recurse // subdivide v1 and recurse
var t = (range1[0] + range1[1]) / 2; var t = (range1[0] + range1[1]) / 2;
getCurveIntersections(v1, v2, curve1, curve2, locations, addCurveIntersections(v1, v2, curve1, curve2, locations,
[ range1[0], t ], range2, recursion); [ range1[0], t ], range2, recursion);
getCurveIntersections(v1, v2, curve1, curve2, locations, addCurveIntersections(v1, v2, curve1, curve2, locations,
[ t, range1[1] ], range2, recursion); [ t, range1[1] ], range2, recursion);
break; break;
} else { } else {
// subdivide v2 and recurse // subdivide v2 and recurse
var t = (range2[0] + range2[1]) / 2; var t = (range2[0] + range2[1]) / 2;
getCurveIntersections(v1, v2, curve1, curve2, locations, addCurveIntersections(v1, v2, curve1, curve2, locations,
range1, [ range2[0], t ], recursion); range1, [ range2[0], t ], recursion);
getCurveIntersections(v1, v2, curve1, curve2, locations, addCurveIntersections(v1, v2, curve1, curve2, locations,
range1, [ t, range2[1] ], recursion); range1, [ t, range2[1] ], recursion);
break; break;
} }
@ -1123,12 +1123,16 @@ new function() { // Scope for methods that require numerical integration
// Check if one of the parameter range has converged completely to a // Check if one of the parameter range has converged completely to a
// point. Now things could get only worse if we iterate more for the // point. Now things could get only worse if we iterate more for the
// other curve to converge if it hasn't yet happened so. // other curve to converge if it hasn't yet happened so.
var converged1 = Math.abs(range1[1] - range1[0]) < /*#=*/ Numerical.TOLERANCE, if (Math.abs(range1[1] - range1[0]) < /*#=*/ Numerical.TOLERANCE) {
converged2 = Math.abs(range2[1] - range2[0]) < /*#=*/ Numerical.TOLERANCE; var t = (range1[0] + range1[1]) / 2;
if (converged1 || converged2) { addLocation(locations, curve1, t,
addLocation(locations, curve1, null, converged1 Curve.evaluate(v1, t, true, 0), curve2);
? curve1.getPointAt(range1[0], true) break;
: curve2.getPointAt(range2[0], true), curve2); }
if (Math.abs(range2[1] - range2[0]) < /*#=*/ Numerical.TOLERANCE) {
var t = (range2[0] + range2[1]) / 2;
addLocation(locations, curve2, t,
Curve.evaluate(v2, t, true, 0), curve1);
break; break;
} }
// see if either or both of the curves are flat enough to be treated // see if either or both of the curves are flat enough to be treated
@ -1137,10 +1141,10 @@ new function() { // Scope for methods that require numerical integration
flat2 = Curve.isFlatEnough(part2, /*#=*/ Numerical.TOLERANCE); flat2 = Curve.isFlatEnough(part2, /*#=*/ Numerical.TOLERANCE);
if (flat1 || flat2) { if (flat1 || flat2) {
(flat1 && flat2 (flat1 && flat2
? getLineLineIntersection ? addLineIntersection
// Use curve line intersection method while specifying // Use curve line intersection method while specifying
// which curve to be treated as line // which curve to be treated as line
: getCurveLineIntersections)(part1, part2, : addCurveLineIntersections)(part1, part2,
curve1, curve2, locations, flat1); curve1, curve2, locations, flat1);
break; break;
} }
@ -1158,15 +1162,7 @@ new function() { // Scope for methods that require numerical integration
&& (Curve.isLinear(v2) && (Curve.isLinear(v2)
|| Curve.isFlatEnough(v2, /*#=*/ Numerical.TOLERANCE))) { || Curve.isFlatEnough(v2, /*#=*/ Numerical.TOLERANCE))) {
// See if the parametric equations of the lines interesct. // See if the parametric equations of the lines interesct.
// var point = new Line(v1[0], v1[1], v1[6], v1[7], false) addLineIntersection(v1, v2, curve1, curve2, locations);
// .intersect(new Line(v2[0], v2[1], v2[6], v2[7], false));
// Use static version without creation of Line objects, but it
// doesn't seem to yield measurable speed improvements!
var point = Line.intersect(
v1[0], v1[1], v1[6], v1[7],
v2[0], v2[1], v2[6], v2[7], false);
if (point)
addLocation(locations, curve1, null, point, curve2);
} else { } else {
// Subdivide both curves, and see if they intersect. // Subdivide both curves, and see if they intersect.
// If one of the curves is flat already, no further subdivion // If one of the curves is flat already, no further subdivion
@ -1200,6 +1196,7 @@ new function() { // Scope for methods that require numerical integration
p2x = v1[4], p2y = v1[5], p3x = v1[6], p3y = v1[7], p2x = v1[4], p2y = v1[5], p3x = v1[6], p3y = v1[7],
q0x = v2[0], q0y = v2[1], q1x = v2[2], q1y = v2[3], q0x = v2[0], q0y = v2[1], q1x = v2[2], q1y = v2[3],
q2x = v2[4], q2y = v2[5], q3x = v2[6], q3y = v2[7], q2x = v2[4], q2y = v2[5], q3x = v2[6], q3y = v2[7],
getSignedDistance = Line.getSignedDistance,
// Calculate the fat-line L for P is the baseline l and two // Calculate the fat-line L for P is the baseline l and two
// offsets which completely encloses the curve P. // offsets which completely encloses the curve P.
d1 = getSignedDistance(p0x, p0y, p3x, p3y, p1x, p1y) || 0, d1 = getSignedDistance(p0x, p0y, p3x, p3y, p1x, p1y) || 0,
@ -1213,20 +1210,19 @@ new function() { // Scope for methods that require numerical integration
dq0 = getSignedDistance(p0x, p0y, p3x, p3y, q0x, q0y), dq0 = getSignedDistance(p0x, p0y, p3x, p3y, q0x, q0y),
dq1 = getSignedDistance(p0x, p0y, p3x, p3y, q1x, q1y), dq1 = getSignedDistance(p0x, p0y, p3x, p3y, q1x, q1y),
dq2 = getSignedDistance(p0x, p0y, p3x, p3y, q2x, q2y), dq2 = getSignedDistance(p0x, p0y, p3x, p3y, q2x, q2y),
dq3 = getSignedDistance(p0x, p0y, p3x, p3y, q3x, q3y), dq3 = getSignedDistance(p0x, p0y, p3x, p3y, q3x, q3y);
// Find the minimum and maximum distances from l, this is useful for // Find the minimum and maximum distances from l, this is useful for
// checking whether the curves intersect with each other or not. // checking whether the curves intersect with each other or not.
mindist = Math.min(dq0, dq1, dq2, dq3),
maxdist = Math.max(dq0, dq1, dq2, dq3);
// If the fatlines don't overlap, we have no intersections! // If the fatlines don't overlap, we have no intersections!
if (dmin > maxdist || dmax < mindist) if (dmin > Math.max(dq0, dq1, dq2, dq3)
|| dmax < Math.min(dq0, dq1, dq2, dq3))
return 0; return 0;
var Dt = getConvexHull(dq0, dq1, dq2, dq3), var hull = getConvexHull(dq0, dq1, dq2, dq3),
tmp; swap;
if (dq3 < dq0) { if (dq3 < dq0) {
tmp = dmin; swap = dmin;
dmin = dmax; dmin = dmax;
dmax = tmp; dmax = swap;
} }
// Calculate the convex hull for non-parametric bezier curve D(ti, di(t)) // Calculate the convex hull for non-parametric bezier curve D(ti, di(t))
// Now we clip the convex hulls for D(ti, di(t)) with dmin and dmax // Now we clip the convex hulls for D(ti, di(t)) with dmin and dmax
@ -1235,31 +1231,29 @@ new function() { // Scope for methods that require numerical integration
var tmaxdmin = -Infinity, var tmaxdmin = -Infinity,
tmin = Infinity, tmin = Infinity,
tmax = -Infinity; tmax = -Infinity;
for (var i = 0, l = Dt.length; i < l; i++) { for (var i = 0, l = hull.length; i < l; i++) {
var Dtl = Dt[i], var p1 = hull[i],
dtlx1 = Dtl[0], p2 = hull[(i + 1) % l];
dtly1 = Dtl[1], if (p2[1] < p1[1]) {
dtlx2 = Dtl[2], swap = p2;
dtly2 = Dtl[3]; p2 = p1;
if (dtly2 < dtly1) { p1 = swap;
tmp = dtly2;
dtly2 = dtly1;
dtly1 = tmp;
tmp = dtlx2;
dtlx2 = dtlx1;
dtlx1 = tmp;
} }
// We know that (dtlx2 - dtlx1) is never 0 var x1 = p1[0],
var inv = (dtly2 - dtly1) / (dtlx2 - dtlx1); y1 = p1[1],
if (dmin >= dtly1 && dmin <= dtly2) { x2 = p2[0],
var ixdx = dtlx1 + (dmin - dtly1) / inv; y2 = p2[1];
// We know that (x2 - x1) is never 0
var inv = (y2 - y1) / (x2 - x1);
if (dmin >= y1 && dmin <= y2) {
var ixdx = x1 + (dmin - y1) / inv;
if (ixdx < tmin) if (ixdx < tmin)
tmin = ixdx; tmin = ixdx;
if (ixdx > tmaxdmin) if (ixdx > tmaxdmin)
tmaxdmin = ixdx; tmaxdmin = ixdx;
} }
if (dmax >= dtly1 && dmax <= dtly2) { if (dmax >= y1 && dmax <= y2) {
var ixdx = dtlx1 + (dmax - dtly1) / inv; var ixdx = x1 + (dmax - y1) / inv;
if (ixdx > tmax) if (ixdx > tmax)
tmax = ixdx; tmax = ixdx;
if (ixdx < tmin) if (ixdx < tmin)
@ -1269,11 +1263,11 @@ new function() { // Scope for methods that require numerical integration
// Return the parameter values for v2 for which we can be sure that the // Return the parameter values for v2 for which we can be sure that the
// intersection with v1 lies within. // intersection with v1 lies within.
if (tmin !== Infinity && tmax !== -Infinity) { if (tmin !== Infinity && tmax !== -Infinity) {
var mindmin = Math.min(dmin, dmax), var min = Math.min(dmin, dmax),
mindmax = Math.max(dmin, dmax); max = Math.max(dmin, dmax);
if (dq3 > mindmin && dq3 < mindmax) if (dq3 > min && dq3 < max)
tmax = 1; tmax = 1;
if (dq0 > mindmin && dq0 < mindmax) if (dq0 > min && dq0 < max)
tmin = 0; tmin = 0;
if (tmaxdmin > tmax) if (tmaxdmin > tmax)
tmax = 1; tmax = 1;
@ -1304,79 +1298,48 @@ new function() { // Scope for methods that require numerical integration
* Calculating convex-hull is much easier than a set of arbitrary points. * Calculating convex-hull is much easier than a set of arbitrary points.
*/ */
function getConvexHull(dq0, dq1, dq2, dq3) { function getConvexHull(dq0, dq1, dq2, dq3) {
var distq1 = getSignedDistance(0, dq0, 1, dq3, 1 / 3, dq1), var p0 = [ 0, dq0 ],
distq2 = getSignedDistance(0, dq0, 1, dq3, 2 / 3, dq2); p1 = [ 1 / 3, dq1 ],
// Check if [1/3, dq1] and [2/3, dq2] are on the same side of line p2 = [ 2 / 3, dq2 ],
// [0,dq0, 1,dq3] p3 = [ 1, dq3 ],
if (distq1 * distq2 < 0) { // Find signed distance of p1 and p2 from line [ p0, p3 ]
// dq1 and dq2 lie on different sides on [0, q0, 1, q3]. The hull is getSignedDistance = Line.getSignedDistance,
// a quadrilateral and line [0, q0, 1, q3] is NOT part of the hull dist1 = getSignedDistance(0, dq0, 1, dq3, 1 / 3, dq1),
// so we are pretty much done here. dist2 = getSignedDistance(0, dq0, 1, dq3, 2 / 3, dq2);
return [ // Check if p1 and p2 are on the same side of the line [ p0, p3 ]
[ 0, dq0, 1 / 3, dq1 ], if (dist1 * dist2 < 0) {
[ 1 / 3, dq1, 1, dq3 ], // p1 and p2 lie on different sides of [ p0, p3 ]. The hull is a
[ 2 / 3, dq2, 0, dq0 ], // quadrilateral and line [ p0, p3 ] is NOT part of the hull so we
[ 1, dq3, 2 / 3, dq2 ] // are pretty much done here.
]; return [ p0, p1, p3, p2 ];
} }
// dq1 and dq2 lie on the same sides on [0, q0, 1, q3]. The hull can be // p1 and p2 lie on the same sides of [ p0, p3 ]. The hull can be
// a triangle or a quadrilateral and line [0, q0, 1, q3] is part of the // a triangle or a quadrilateral and line [ p0, p3 ] is part of the
// hull. Check if the hull is a triangle or a quadrilateral. // hull. Check if the hull is a triangle or a quadrilateral.
var dqMaxX, dqMaxY, vqa1a2X, vqa1a2Y, vqa1MaxX, vqa1MaxY, vqa1MinX, vqa1MinY; var pmax, cross;
if (Math.abs(distq1) > Math.abs(distq2)) { if (Math.abs(dist1) > Math.abs(dist2)) {
dqMaxX = 1 / 3; pmax = p1;
dqMaxY = dq1;
// apex is dq3 and the other apex point is dq0 vector // apex is dq3 and the other apex point is dq0 vector
// dqapex->dqapex2 or base vector which is already part of the hull. // dqapex->dqapex2 or base vector which is already part of the hull.
vqa1a2X = 1; // cross = (vqa1a2X * vqa1MinY - vqa1a2Y * vqa1MinX)
vqa1a2Y = dq3 - dq0; // * (vqa1MaxX * vqa1MinY - vqa1MaxY * vqa1MinX)
// vector dqapex->dqMax cross = (dq3 - dq2 - (dq3 - dq0) / 3)
vqa1MaxX = 2 / 3; * (2 * (dq3 - dq2) - dq3 + dq1) / 3;
vqa1MaxY = dq3 - dq1;
// vector dqapex->dqmin
vqa1MinX = 1 / 3;
vqa1MinY = dq3 - dq2;
} else { } else {
dqMaxX = 2 / 3; pmax = p2;
dqMaxY = dq2;
// apex is dq0 in this case, and the other apex point is dq3 vector // apex is dq0 in this case, and the other apex point is dq3 vector
// dqapex->dqapex2 or base vector which is already part of the hull. // dqapex->dqapex2 or base vector which is already part of the hull.
vqa1a2X = -1; cross = (dq1 - dq0 + (dq0 - dq3) / 3)
vqa1a2Y = dq0 - dq3; * (-2 * (dq0 - dq1) + dq0 - dq2) / 3;
// vector dqapex->dqMax
vqa1MaxX = -2 / 3;
vqa1MaxY = dq0 - dq2;
// vector dqapex->dqmin
vqa1MinX = -1 / 3;
vqa1MinY = dq0 - dq1;
} }
// Compare cross products of these vectors to determine, if // Compare cross products of these vectors to determine if the point is
// point is in triangles [ dq3, dqMax, dq0 ] or [ dq0, dqMax, dq3 ] // in the triangle [ p3, pmax, p0 ], or if it is a quadrilateral.
var a1a2_a1Min = vqa1a2X * vqa1MinY - vqa1a2Y * vqa1MinX, return cross < 0
a1Max_a1Min = vqa1MaxX * vqa1MinY - vqa1MaxY * vqa1MinX; // p2 is inside the triangle, hull is a triangle.
return a1a2_a1Min * a1Max_a1Min < 0 ? [ p0, pmax, p3 ]
// Point [2/3, dq2] is inside the triangle, hull is a triangle.
? [
[ 0, dq0, dqMaxX, dqMaxY ],
[ dqMaxX, dqMaxY, 1, dq3 ],
[ 1, dq3, 0, dq0 ]
]
// Convexhull is a quadrilateral and we need all lines in the // Convexhull is a quadrilateral and we need all lines in the
// correct order where line [0, q0, 1, q3] is part of the hull. // correct order where line [ p1, p3 ] is part of the hull.
: [ : [ p0, p1, p2, p3 ];
[ 0, dq0, 1 / 3, dq1 ],
[ 1 / 3, dq1, 2 / 3, dq2 ],
[ 2 / 3, dq2, 1, dq3 ],
[ 1, dq3, 0, dq0 ]
];
}
// This is basically an "unrolled" version of #Line.getDistance() with sign
// May be a static method could be better!
function getSignedDistance(a1x, a1y, a2x, a2y, bx, by) {
var m = (a2y - a1y) / (a2x - a1x),
b = a1y - (m * a1x);
return (by - (m * bx) - b) / Math.sqrt(m * m + 1);
} }
/*#*/ } // options.fatline /*#*/ } // options.fatline
@ -1386,7 +1349,7 @@ new function() { // Scope for methods that require numerical integration
* line is on the X axis, and solve the implicit equations for the X axis * line is on the X axis, and solve the implicit equations for the X axis
* and the curve. * and the curve.
*/ */
function getCurveLineIntersections(v1, v2, curve1, curve2, locations, flip) { function addCurveLineIntersections(v1, v2, curve1, curve2, locations, flip) {
if (flip === undefined) if (flip === undefined)
flip = Curve.isLinear(v1); flip = Curve.isLinear(v1);
var vc = flip ? v2 : v1, var vc = flip ? v2 : v1,
@ -1432,17 +1395,17 @@ new function() { // Scope for methods that require numerical integration
} }
} }
function getLineLineIntersection(v1, v2, curve1, curve2, locations) { function addLineIntersection(v1, v2, curve1, curve2, locations) {
var point = Line.intersect( var point = Line.intersect(
v1[0], v1[1], v1[6], v1[7], v1[0], v1[1], v1[6], v1[7],
v2[0], v2[1], v2[6], v2[7], false); v2[0], v2[1], v2[6], v2[7]);
// Passing null for parameter leads to lazy determination of parameter // Passing null for parameter leads to lazy determination of parameter
// values in CurveLocation#getParameter() only once they are requested. // values in CurveLocation#getParameter() only once they are requested.
if (point) if (point)
addLocation(locations, curve1, null, point, curve2); addLocation(locations, curve1, null, point, curve2);
} }
return { statics: { return { statics: /** @lends Curve */{
// We need to provide the original left curve reference to the // We need to provide the original left curve reference to the
// #getIntersections() calls as it is required to create the resulting // #getIntersections() calls as it is required to create the resulting
// CurveLocation objects. // CurveLocation objects.
@ -1452,10 +1415,10 @@ new function() { // Scope for methods that require numerical integration
// Determine the correct intersection method based on values of // Determine the correct intersection method based on values of
// linear1 & 2: // linear1 & 2:
(linear1 && linear2 (linear1 && linear2
? getLineLineIntersection ? addLineIntersection
: linear1 || linear2 : linear1 || linear2
? getCurveLineIntersections ? addCurveLineIntersections
: getCurveIntersections)(v1, v2, curve1, curve2, locations); : addCurveIntersections)(v1, v2, curve1, curve2, locations);
return locations; return locations;
} }
}}; }};

View file

@ -26,7 +26,7 @@
* {@link PathItem#getIntersections(path)}, * {@link PathItem#getIntersections(path)},
* etc. * etc.
*/ */
var CurveLocation = this.CurveLocation = Base.extend(/** @lends CurveLocation# */{ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
// DOCS: CurveLocation class description: add these back when the mentioned // DOCS: CurveLocation class description: add these back when the mentioned
// functioned have been added: {@link Path#split(location)} // functioned have been added: {@link Path#split(location)}
/** /**
@ -36,7 +36,8 @@ var CurveLocation = this.CurveLocation = Base.extend(/** @lends CurveLocation# *
* @param {Number} parameter * @param {Number} parameter
* @param {Point} point * @param {Point} point
*/ */
initialize: function(curve, parameter, point, _otherCurve, _distance) { initialize: function CurveLocation(curve, parameter, point, _otherCurve,
_distance) {
// Define this CurveLocation's unique id. // Define this CurveLocation's unique id.
this._id = CurveLocation._id = (CurveLocation._id || 0) + 1; this._id = CurveLocation._id = (CurveLocation._id || 0) + 1;
this._curve = curve; this._curve = curve;

View file

@ -274,7 +274,7 @@ Path.inject({ statics: new function() {
var center = Point.readNamed(arguments, 'center'), var center = Point.readNamed(arguments, 'center'),
radius = Base.readNamed(arguments, 'radius'); radius = Base.readNamed(arguments, 'radius');
return createEllipse(new Rectangle(center.subtract(radius), return createEllipse(new Rectangle(center.subtract(radius),
Size.create(radius * 2, radius * 2))) new Size(radius * 2, radius * 2)))
.set(Base.getNamed(arguments)); .set(Base.getNamed(arguments));
}, },

View file

@ -18,8 +18,7 @@
* @extends PathItem * @extends PathItem
*/ */
// DOCS: Explain that path matrix is always applied with each transformation. // DOCS: Explain that path matrix is always applied with each transformation.
var Path = this.Path = PathItem.extend(/** @lends Path# */{ var Path = PathItem.extend(/** @lends Path# */{
_class: 'Path',
_serializeFields: { _serializeFields: {
segments: [], segments: [],
closed: false closed: false
@ -67,10 +66,10 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
* selected: true * selected: true
* }); * });
*/ */
initialize: function(arg) { initialize: function Path(arg) {
this._closed = false; this._closed = false;
this._segments = []; this._segments = [];
this.base(); Item.call(this);
// arg can either be an object literal describing properties to be set // arg can either be an object literal describing properties to be set
// on the path, a list of segments to be set, or the first of multiple // on the path, a list of segments to be set, or the first of multiple
// arguments describing separate segments. // arguments describing separate segments.
@ -788,12 +787,12 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
this.setSelected(selected); this.setSelected(selected);
}, },
setSelected: function(selected) { setSelected: function setSelected(selected) {
// Deselect all segments when path is marked as not selected // Deselect all segments when path is marked as not selected
if (!selected) if (!selected)
this._selectSegments(false); this._selectSegments(false);
// No need to pass true for noChildren since Path has none anyway. // No need to pass true for noChildren since Path has none anyway.
this.base(selected); setSelected.base.call(this, selected);
}, },
_selectSegments: function(selected) { _selectSegments: function(selected) {
@ -1982,13 +1981,13 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
segment.setHandleIn(handleIn.subtract(segment._point)); segment.setHandleIn(handleIn.subtract(segment._point));
if (i < n) { if (i < n) {
segment.setHandleOut( segment.setHandleOut(
Point.create(x[i], y[i]).subtract(segment._point)); new Point(x[i], y[i]).subtract(segment._point));
if (i < n - 1) if (i < n - 1)
handleIn = Point.create( handleIn = new Point(
2 * knots[i + 1]._x - x[i + 1], 2 * knots[i + 1]._x - x[i + 1],
2 * knots[i + 1]._y - y[i + 1]); 2 * knots[i + 1]._y - y[i + 1]);
else else
handleIn = Point.create( handleIn = new Point(
(knots[n]._x + x[n - 1]) / 2, (knots[n]._x + x[n - 1]) / 2,
(knots[n]._y + y[n - 1]) / 2); (knots[n]._y + y[n - 1]) / 2);
} }
@ -2104,11 +2103,11 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
// Construct the two perpendicular middle lines to (from, through) // Construct the two perpendicular middle lines to (from, through)
// and (through, to), and intersect them to get the center // and (through, to), and intersect them to get the center
var l1 = new Line(from.add(through).divide(2), var l1 = new Line(from.add(through).divide(2),
through.subtract(from).rotate(90)), through.subtract(from).rotate(90), true),
l2 = new Line(through.add(to).divide(2), l2 = new Line(through.add(to).divide(2),
to.subtract(through).rotate(90)), to.subtract(through).rotate(90), true),
center = l1.intersect(l2), center = l1.intersect(l2, true),
line = new Line(from, to, true), line = new Line(from, to),
throughSide = line.getSide(through); throughSide = line.getSide(through);
if (!center) { if (!center) {
// If the two lines are colinear, there cannot be an arc as the // If the two lines are colinear, there cannot be an arc as the
@ -2179,7 +2178,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
throughVector = Point.read(throughVector); throughVector = Point.read(throughVector);
toVector = Point.read(toVector); toVector = Point.read(toVector);
var current = getCurrentSegment(this)._point; var current = getCurrentSegment(this)._point;
this.arcBy(current.add(throughVector), current.add(toVector)); this.arcTo(current.add(throughVector), current.add(toVector));
}, },
closePath: function() { closePath: function() {
@ -2283,7 +2282,7 @@ statics: {
processSegment(segments[i]); processSegment(segments[i]);
if (closed) if (closed)
processSegment(first); processSegment(first);
return Rectangle.create(min[0], min[1], max[0] - min[0], max[1] - min[1]); return new Rectangle(min[0], min[1], max[0] - min[0], max[1] - min[1]);
}, },
/** /**
@ -2305,8 +2304,8 @@ statics: {
// Get rotated hor and ver vectors, and determine rotation angle // Get rotated hor and ver vectors, and determine rotation angle
// and elipse values from them: // and elipse values from them:
var mx = matrix.shiftless(), var mx = matrix.shiftless(),
hor = mx.transform(Point.create(radius, 0)), hor = mx.transform(new Point(radius, 0)),
ver = mx.transform(Point.create(0, radius)), ver = mx.transform(new Point(0, radius)),
phi = hor.getAngleInRadians(), phi = hor.getAngleInRadians(),
a = hor.getLength(), a = hor.getLength(),
b = ver.getLength(); b = ver.getLength();
@ -2389,10 +2388,10 @@ statics: {
normal2 = curve2.getNormalAt(0, true).normalize(miterRadius), normal2 = curve2.getNormalAt(0, true).normalize(miterRadius),
// Intersect the two lines // Intersect the two lines
line1 = new Line(point.add(normal1), line1 = new Line(point.add(normal1),
Point.create(-normal1.y, normal1.x)), new Point(-normal1.y, normal1.x), true),
line2 = new Line(point.add(normal2), line2 = new Line(point.add(normal2),
Point.create(-normal2.y, normal2.x)), new Point(-normal2.y, normal2.x), true),
corner = line1.intersect(line2); corner = line1.intersect(line2, true);
// Now measure the distance from the segment to the // Now measure the distance from the segment to the
// intersection, which his half of the miter distance // intersection, which his half of the miter distance
if (!corner || point.getDistance(corner) > miterLimit) { if (!corner || point.getDistance(corner) > miterLimit) {
@ -2466,7 +2465,7 @@ statics: {
if (yx > y2) y2 = yx; if (yx > y2) y2 = yx;
} }
} }
return Rectangle.create(x1, y1, x2 - x1, y2 - y1); return new Rectangle(x1, y1, x2 - x1, y2 - y1);
}, },
/** /**

View file

@ -158,7 +158,7 @@ PathItem.inject(new function() {
if (segment.getPrevious()._invalid) if (segment.getPrevious()._invalid)
segment.setHandleIn(intersection segment.setHandleIn(intersection
? intersection._handleIn ? intersection._handleIn
: Point.create(0, 0)); : new Point(0, 0));
do { do {
segment._visited = true; segment._visited = true;
if (segment._invalid && segment._intersection) { if (segment._invalid && segment._intersection) {

View file

@ -19,7 +19,11 @@
* *
* @extends Item * @extends Item
*/ */
var PathItem = this.PathItem = Item.extend(/** @lends PathItem# */{ var PathItem = Item.extend(/** @lends PathItem# */{
initialize: function PathItem() {
Item.apply(this, arguments);
},
/** /**
* Returns all intersections between two {@link PathItem} items as an array * Returns all intersections between two {@link PathItem} items as an array
* of {@link CurveLocation} objects. {@link CompoundPath} items are also * of {@link CurveLocation} objects. {@link CompoundPath} items are also

View file

@ -22,9 +22,7 @@
* {@link Segment#handleOut}), describing the tangents of the two {@link Curve} * {@link Segment#handleOut}), describing the tangents of the two {@link Curve}
* objects that are connected by this segment. * objects that are connected by this segment.
*/ */
var Segment = this.Segment = Base.extend(/** @lends Segment# */{ var Segment = Base.extend(/** @lends Segment# */{
_class: 'Segment',
/** /**
* Creates a new Segment object. * Creates a new Segment object.
* *
@ -110,7 +108,7 @@ var Segment = this.Segment = Base.extend(/** @lends Segment# */{
* path.strokeColor = 'black'; * path.strokeColor = 'black';
* @ignore * @ignore
*/ */
initialize: function(arg0, arg1, arg2, arg3, arg4, arg5) { initialize: function Segment(arg0, arg1, arg2, arg3, arg4, arg5) {
var count = arguments.length, var count = arguments.length,
createPoint = SegmentPoint.create, createPoint = SegmentPoint.create,
point, handleIn, handleOut; point, handleIn, handleOut;

View file

@ -30,7 +30,7 @@
* An array of all open projects is accessible through the * An array of all open projects is accessible through the
* {@link PaperScope#projects} variable. * {@link PaperScope#projects} variable.
*/ */
var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{ var Project = PaperScopeItem.extend(/** @lends Project# */{
_list: 'projects', _list: 'projects',
_reference: 'project', _reference: 'project',
@ -44,10 +44,10 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
* @param {View|HTMLCanvasElement} view Either a view object or an HTML * @param {View|HTMLCanvasElement} view Either a view object or an HTML
* Canvas element that should be wrapped in a newly created view. * Canvas element that should be wrapped in a newly created view.
*/ */
initialize: function(view) { initialize: function Project(view) {
// Activate straight away by passing true to base(), so paper.project is // Activate straight away by passing true to base(), so paper.project is
// set, as required by Layer and DoumentView constructors. // set, as required by Layer and DoumentView constructors.
this.base(true); PaperScopeItem.call(this, true);
this.layers = []; this.layers = [];
this.symbols = []; this.symbols = [];
this._currentStyle = new Style(); this._currentStyle = new Style();
@ -69,12 +69,8 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
// into the active project automatically. We might want to add proper // into the active project automatically. We might want to add proper
// project serialization later, but deserialization of a layers array // project serialization later, but deserialization of a layers array
// will always work. // will always work.
return Base.serialize(this.layers, options, false, dictionary); // Pass true for compact, so 'Project' does not get added as the class
}, return Base.serialize(this.layers, options, true, dictionary);
_needsRedraw: function() {
if (this.view)
this.view._redrawNeeded = true;
}, },
/** /**
@ -97,8 +93,8 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
* Removes this project from the {@link PaperScope#projects} list, and also * Removes this project from the {@link PaperScope#projects} list, and also
* removes its view, if one was defined. * removes its view, if one was defined.
*/ */
remove: function() { remove: function remove() {
if (!this.base()) if (!remove.base.call(this))
return false; return false;
if (this.view) if (this.view)
this.view.remove(); this.view.remove();
@ -271,6 +267,7 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
// DOCS: Figure out a way to group these together with importSVG / exportSVG // DOCS: Figure out a way to group these together with importSVG / exportSVG
importJSON: function(json) { importJSON: function(json) {
this.activate();
return Base.importJSON(json); return Base.importJSON(json);
}, },

View file

@ -19,9 +19,7 @@
* internal properties such as segment lists and gradient positions don't need * internal properties such as segment lists and gradient positions don't need
* to be updated with every transformation. * to be updated with every transformation.
*/ */
var Symbol = this.Symbol = Base.extend(/** @lends Symbol# */{ var Symbol = Base.extend(/** @lends Symbol# */{
_class: 'Symbol',
/** /**
* Creates a Symbol item. * Creates a Symbol item.
* *
@ -59,7 +57,7 @@ var Symbol = this.Symbol = Base.extend(/** @lends Symbol# */{
* instance.scale(0.25 + Math.random() * 0.75); * instance.scale(0.25 + Math.random() * 0.75);
* } * }
*/ */
initialize: function(item, dontCenter) { initialize: function Symbol(item, dontCenter) {
// Define this Symbols's unique id. // Define this Symbols's unique id.
this._id = Symbol._id = (Symbol._id || 0) + 1; this._id = Symbol._id = (Symbol._id || 0) + 1;
this.project = paper.project; this.project = paper.project;
@ -72,7 +70,7 @@ var Symbol = this.Symbol = Base.extend(/** @lends Symbol# */{
_serialize: function(options, dictionary) { _serialize: function(options, dictionary) {
return dictionary.add(this, function() { return dictionary.add(this, function() {
return Base.serialize([this._class, this._definition], return Base.serialize([this.constructor.name, this._definition],
options, false, dictionary); options, false, dictionary);
}); });
}, },

View file

@ -40,7 +40,7 @@
* // converted to a Color. * // converted to a Color.
* circle.fillColor = '#ff0000'; * circle.fillColor = '#ff0000';
*/ */
var Color = this.Color = Base.extend(new function() { var Color = Base.extend(new function() {
var types = { var types = {
gray: ['gray'], gray: ['gray'],
@ -275,7 +275,6 @@ var Color = this.Color = Base.extend(new function() {
}; };
}, this); }, this);
}, /** @lends Color# */{ }, /** @lends Color# */{
_class: 'Color',
// Tell Base.read that the Point constructor supports reading with index // Tell Base.read that the Point constructor supports reading with index
_readIndex: true, _readIndex: true,
@ -436,7 +435,7 @@ var Color = this.Color = Base.extend(new function() {
* // 100% and a lightness of 50%: * // 100% and a lightness of 50%:
* circle.fillColor = { hue: 90, saturation: 1, lightness: 0.5 }; * circle.fillColor = { hue: 90, saturation: 1, lightness: 0.5 };
*/ */
initialize: function(arg) { initialize: function Color(arg) {
// We are storing color internally as an array of components // We are storing color internally as an array of components
var slice = Array.prototype.slice, var slice = Array.prototype.slice,
args = arguments, args = arguments,
@ -503,7 +502,7 @@ var Color = this.Color = Base.extend(new function() {
: nameToRGB(arg); : nameToRGB(arg);
type = 'rgb'; type = 'rgb';
} else if (argType === 'object') { } else if (argType === 'object') {
if (arg._class === 'Color') { if (arg.constructor === Color) {
type = arg._type; type = arg._type;
components = arg._components.slice(); components = arg._components.slice();
alpha = arg._alpha; alpha = arg._alpha;
@ -516,7 +515,7 @@ var Color = this.Color = Base.extend(new function() {
components[i] = point.clone(); components[i] = point.clone();
} }
} }
} else if (arg._class === 'Gradient') { } else if (arg.constructor === Gradient) {
type = 'gradient'; type = 'gradient';
values = args; values = args;
} else { } else {

View file

@ -59,11 +59,9 @@
* destination: path.bounds.rightCenter * destination: path.bounds.rightCenter
* }; * };
*/ */
var Gradient = this.Gradient = Base.extend(/** @lends Gradient# */{ var Gradient = Base.extend(/** @lends Gradient# */{
_class: 'Gradient',
// DOCS: Document #initialize() // DOCS: Document #initialize()
initialize: function(stops, radial) { initialize: function Gradient(stops, radial) {
// Define this Gradient's unique id. // Define this Gradient's unique id.
this._id = Gradient._id = (Gradient._id || 0) + 1; this._id = Gradient._id = (Gradient._id || 0) + 1;
if (stops && this._set(stops)) if (stops && this._set(stops))

View file

@ -16,7 +16,7 @@
* *
* @class The GradientStop object. * @class The GradientStop object.
*/ */
var GradientStop = this.GradientStop = Base.extend(/** @lends GradientStop# */{ var GradientStop = Base.extend(/** @lends GradientStop# */{
/** /**
* Creates a GradientStop object. * Creates a GradientStop object.
* *
@ -24,7 +24,7 @@ var GradientStop = this.GradientStop = Base.extend(/** @lends GradientStop# */{
* @param {Number} [rampPoint=0] the position of the stop on the gradient * @param {Number} [rampPoint=0] the position of the stop on the gradient
* ramp as a value between 0 and 1. * ramp as a value between 0 and 1.
*/ */
initialize: function(arg0, arg1) { initialize: function GradientStop(arg0, arg1) {
if (arg0) { if (arg0) {
var color, rampPoint; var color, rampPoint;
if (arg1 === undefined && Array.isArray(arg0)) { if (arg1 === undefined && Array.isArray(arg0)) {

View file

@ -65,7 +65,7 @@
* }; * };
* *
*/ */
var Style = this.Style = Base.extend(new function() { var Style = Base.extend(new function() {
// windingRule / resolution / fillOverprint / strokeOverprint are currently // windingRule / resolution / fillOverprint / strokeOverprint are currently
// not supported. // not supported.
var defaults = { var defaults = {
@ -201,7 +201,7 @@ var Style = this.Style = Base.extend(new function() {
Item.inject(item); Item.inject(item);
return fields; return fields;
}, /** @lends Style# */{ }, /** @lends Style# */{
initialize: function(style) { initialize: function Style(style) {
// We keep values in a separate object that we can iterate over. // We keep values in a separate object that we can iterate over.
this._values = {}; this._values = {};
if (this._item instanceof TextItem) if (this._item instanceof TextItem)
@ -223,9 +223,9 @@ var Style = this.Style = Base.extend(new function() {
} }
}, },
getLeading: function() { getLeading: function getLeading() {
// Override leading to return fontSize * 1.2 by default. // Override leading to return fontSize * 1.2 by default.
var leading = this.base(); var leading = getLeading.base.call(this);
return leading != null ? leading : this.getFontSize() * 1.2; return leading != null ? leading : this.getFontSize() * 1.2;
}, },

View file

@ -122,10 +122,10 @@ new function() {
if (handle1.isOrthogonal(handle2)) { if (handle1.isOrthogonal(handle2)) {
var from = segment._point, var from = segment._point,
to = next._point, to = next._point,
// Find hte corner point by intersecting the lines described // Find the corner point by intersecting the lines described
// by both handles: // by both handles:
corner = new Line(from, handle1).intersect( corner = new Line(from, handle1, true).intersect(
new Line(to, handle2)); new Line(to, handle2, true), true);
return corner && Numerical.isZero(handle1.getLength() / return corner && Numerical.isZero(handle1.getLength() /
corner.subtract(from).getLength() - kappa) corner.subtract(from).getLength() - kappa)
&& Numerical.isZero(handle2.getLength() / && Numerical.isZero(handle2.getLength() /

View file

@ -44,14 +44,14 @@ new function() {
x = getValue(node, x, false, allowNull); x = getValue(node, x, false, allowNull);
y = getValue(node, y, false, allowNull); y = getValue(node, y, false, allowNull);
return allowNull && x == null && y == null ? null return allowNull && x == null && y == null ? null
: Point.create(x || 0, y || 0); : new Point(x || 0, y || 0);
} }
function getSize(node, w, h, allowNull) { function getSize(node, w, h, allowNull) {
w = getValue(node, w, false, allowNull); w = getValue(node, w, false, allowNull);
h = getValue(node, h, false, allowNull); h = getValue(node, h, false, allowNull);
return allowNull && w == null && h == null ? null return allowNull && w == null && h == null ? null
: Size.create(w || 0, h || 0); : new Size(w || 0, h || 0);
} }
// Converts a string attribute value to the specified type // Converts a string attribute value to the specified type
@ -383,7 +383,8 @@ new function() {
'stop-color': function(item, value) { 'stop-color': function(item, value) {
// http://www.w3.org/TR/SVG/pservers.html#StopColorProperty // http://www.w3.org/TR/SVG/pservers.html#StopColorProperty
item.setColor(value); if (item.setColor)
item.setColor(value);
}, },
'stop-opacity': function(item, value) { 'stop-opacity': function(item, value) {

View file

@ -19,9 +19,7 @@
* *
* @extends TextItem * @extends TextItem
*/ */
var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{ var PointText = TextItem.extend(/** @lends PointText# */{
_class: 'PointText',
/** /**
* Creates a point text item * Creates a point text item
* *
@ -43,6 +41,9 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{
* fontSize: 25 * fontSize: 25
* }); * });
*/ */
initialize: function PointText() {
TextItem.apply(this, arguments);
},
clone: function() { clone: function() {
return this._clone(new PointText()); return this._clone(new PointText());
@ -109,7 +110,7 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{
x -= width / (justification === 'center' ? 2: 1); x -= width / (justification === 'center' ? 2: 1);
// Until we don't have baseline measuring, assume leading / 4 as a // Until we don't have baseline measuring, assume leading / 4 as a
// rough guess: // rough guess:
var bounds = Rectangle.create(x, var bounds = new Rectangle(x,
count ? leading / 4 + (count - 1) * leading : 0, count ? leading / 4 + (count - 1) * leading : 0,
width, -count * leading); width, -count * leading);
return matrix ? matrix._transformBounds(bounds, bounds) : bounds; return matrix ? matrix._transformBounds(bounds, bounds) : bounds;

View file

@ -21,7 +21,7 @@
* *
* @extends Item * @extends Item
*/ */
var TextItem = this.TextItem = Item.extend(/** @lends TextItem# */{ var TextItem = Item.extend(/** @lends TextItem# */{
_boundsSelected: true, _boundsSelected: true,
_serializeFields: { _serializeFields: {
content: null content: null
@ -30,7 +30,7 @@ var TextItem = this.TextItem = Item.extend(/** @lends TextItem# */{
// so use the same name for all of them // so use the same name for all of them
_boundsGetter: 'getBounds', _boundsGetter: 'getBounds',
initialize: function(arg) { initialize: function TextItem(arg) {
// Support two forms of item initialization: Passing one object literal // Support two forms of item initialization: Passing one object literal
// describing all the different properties to be set, or a point where // describing all the different properties to be set, or a point where
// it should be placed (arg). // it should be placed (arg).
@ -38,7 +38,7 @@ var TextItem = this.TextItem = Item.extend(/** @lends TextItem# */{
// might be a properties object literal for #setPropeties() at the end. // might be a properties object literal for #setPropeties() at the end.
var hasProperties = arg && Base.isPlainObject(arg) var hasProperties = arg && Base.isPlainObject(arg)
&& arg.x === undefined && arg.y === undefined; && arg.x === undefined && arg.y === undefined;
this.base(hasProperties ? null : Point.read(arguments)); Item.call(this, hasProperties ? null : Point.read(arguments));
this._content = ''; this._content = '';
this._lines = []; this._lines = [];
if (hasProperties) if (hasProperties)
@ -77,9 +77,9 @@ var TextItem = this.TextItem = Item.extend(/** @lends TextItem# */{
* } * }
*/ */
_clone: function(copy) { _clone: function _clone(copy) {
copy.setContent(this._content); copy.setContent(this._content);
return this.base(copy); return _clone.base.call(this, copy);
}, },
getContent: function() { getContent: function() {

View file

@ -42,7 +42,7 @@
* path.add(event.point); * path.add(event.point);
* } * }
*/ */
var Tool = this.Tool = PaperScopeItem.extend(/** @lends Tool# */{ var Tool = PaperScopeItem.extend(/** @lends Tool# */{
_list: 'tools', _list: 'tools',
_reference: '_tool', // PaperScope has accessor for #tool _reference: '_tool', // PaperScope has accessor for #tool
_events: [ 'onActivate', 'onDeactivate', 'onEditOptions', _events: [ 'onActivate', 'onDeactivate', 'onEditOptions',
@ -50,8 +50,8 @@ var Tool = this.Tool = PaperScopeItem.extend(/** @lends Tool# */{
'onKeyDown', 'onKeyUp' ], 'onKeyDown', 'onKeyUp' ],
// DOCS: rewrite Tool constructor explanation // DOCS: rewrite Tool constructor explanation
initialize: function(props) { initialize: function Tool(props) {
this.base(); PaperScopeItem.call(this);
this._firstMove = true; this._firstMove = true;
this._count = 0; this._count = 0;
this._downCount = 0; this._downCount = 0;
@ -322,7 +322,7 @@ var Tool = this.Tool = PaperScopeItem.extend(/** @lends Tool# */{
return true; return true;
}, },
fire: function(type, event) { fire: function fire(type, event) {
// Override Callback#fire() so we can handle items marked in removeOn*() // Override Callback#fire() so we can handle items marked in removeOn*()
// calls first,. // calls first,.
var sets = Tool._removeSets; var sets = Tool._removeSets;
@ -346,7 +346,7 @@ var Tool = this.Tool = PaperScopeItem.extend(/** @lends Tool# */{
sets[type] = null; sets[type] = null;
} }
} }
return this.base(type, event); return fire.base.call(this, type, event);
}, },
_onHandleEvent: function(type, point, event) { _onHandleEvent: function(type, point, event) {

View file

@ -21,11 +21,11 @@
* *
* @extends Event * @extends Event
*/ */
var ToolEvent = this.ToolEvent = Event.extend(/** @lends ToolEvent# */{ var ToolEvent = Event.extend(/** @lends ToolEvent# */{
// Have ToolEvent#item fall back to returning null, not undefined. // Have ToolEvent#item fall back to returning null, not undefined.
_item: null, _item: null,
initialize: function(tool, type, event) { initialize: function ToolEvent(tool, type, event) {
this.tool = tool; this.tool = tool;
this.type = type; this.type = type;
this.event = event; this.event = event;

View file

@ -22,19 +22,19 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
* @param {HTMLCanvasElement} canvas The canvas object that this view should * @param {HTMLCanvasElement} canvas The canvas object that this view should
* wrap * wrap
*/ */
initialize: function(canvas) { initialize: function CanvasView(canvas) {
// Handle canvas argument // Handle canvas argument
if (!(canvas instanceof HTMLCanvasElement)) { if (!(canvas instanceof HTMLCanvasElement)) {
// 2nd argument onwards could be view size, otherwise use default: // 2nd argument onwards could be view size, otherwise use default:
var size = Size.read(arguments, 1); var size = Size.read(arguments, 1);
if (size.isZero()) if (size.isZero())
size = Size.create(1024, 768); size = new Size(1024, 768);
canvas = CanvasProvider.getCanvas(size); canvas = CanvasProvider.getCanvas(size);
} }
this._context = canvas.getContext('2d'); this._context = canvas.getContext('2d');
// Have Item count installed mouse events. // Have Item count installed mouse events.
this._eventCounters = {}; this._eventCounters = {};
this.base(canvas); View.call(this, canvas);
}, },
/** /**
@ -44,7 +44,7 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
* @function * @function
*/ */
draw: function(checkRedraw) { draw: function(checkRedraw) {
if (checkRedraw && !this._redrawNeeded) if (checkRedraw && !this._project._needsRedraw)
return false; return false;
// Initial tests conclude that clearing the canvas using clearRect // Initial tests conclude that clearing the canvas using clearRect
// is always faster than setting canvas.width = canvas.width // is always faster than setting canvas.width = canvas.width
@ -53,7 +53,7 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
size = this._viewSize; size = this._viewSize;
ctx.clearRect(0, 0, size._width + 1, size._height + 1); ctx.clearRect(0, 0, size._width + 1, size._height + 1);
this._project.draw(ctx, this._matrix); this._project.draw(ctx, this._matrix);
this._redrawNeeded = false; this._project._needsRedraw = false;
return true; return true;
} }
}, new function() { // Item based mouse handling: }, new function() { // Item based mouse handling:
@ -169,8 +169,8 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
}; };
}); });
/*#*/ if (options.server) { /*#*/ if (options.node) {
// Node.js server based image exporting code. // Node.js based image exporting code.
CanvasView.inject(new function() { CanvasView.inject(new function() {
// Utility function that converts a number to a string with // Utility function that converts a number to a string with
// x amount of padded 0 digits: // x amount of padded 0 digits:
@ -252,4 +252,4 @@ CanvasView.inject(new function() {
} }
}; };
}); });
/*#*/ } // options.server /*#*/ } // options.node

View file

@ -14,7 +14,7 @@
* @name Component * @name Component
* @class * @class
*/ */
var Component = this.Component = Base.extend(Callback, /** @lends Component# */{ var Component = Base.extend(Callback, /** @lends Component# */{
_events: [ 'onChange', 'onClick' ], _events: [ 'onChange', 'onClick' ],
_types: { _types: {
@ -58,7 +58,7 @@ var Component = this.Component = Base.extend(Callback, /** @lends Component# */{
} }
}, },
initialize: function(obj) { initialize: function Component(obj) {
this._type = obj.type in this._types this._type = obj.type in this._types
? obj.type ? obj.type
: 'options' in obj : 'options' in obj

View file

@ -14,8 +14,8 @@
* @name Event * @name Event
* @class * @class
*/ */
var Event = this.Event = Base.extend(/** @lends Event# */{ var Event = Base.extend(/** @lends Event# */{
initialize: function(event) { initialize: function Event(event) {
this.event = event; this.event = event;
}, },

View file

@ -14,7 +14,7 @@
* @name Key * @name Key
* @namespace * @namespace
*/ */
var Key = this.Key = new function() { var Key = new function() {
// TODO: Make sure the keys are called the same as in Scriptographer // TODO: Make sure the keys are called the same as in Scriptographer
// Missing: tab, cancel, clear, page-down, page-up, comma, minus, period, // Missing: tab, cancel, clear, page-down, page-up, comma, minus, period,
// slash, etc etc etc. // slash, etc etc etc.

View file

@ -20,9 +20,9 @@
* *
* @extends Event * @extends Event
*/ */
var KeyEvent = this.KeyEvent = Event.extend(/** @lends KeyEvent# */{ var KeyEvent = Event.extend(/** @lends KeyEvent# */{
initialize: function(down, key, character, event) { initialize: function KeyEvent(down, key, character, event) {
this.base(event); Event.call(this, event);
this.type = down ? 'keydown' : 'keyup'; this.type = down ? 'keydown' : 'keyup';
this.key = key; this.key = key;
this.character = character; this.character = character;

View file

@ -22,9 +22,9 @@
* *
* @extends Event * @extends Event
*/ */
var MouseEvent = this.MouseEvent = Event.extend(/** @lends MouseEvent# */{ var MouseEvent = Event.extend(/** @lends MouseEvent# */{
initialize: function(type, event, point, target, delta) { initialize: function MouseEvent(type, event, point, target, delta) {
this.base(event); Event.call(this, event);
this.type = type; this.type = type;
this.point = point; this.point = point;
this.target = target; this.target = target;

View file

@ -14,10 +14,10 @@
* @name Palette * @name Palette
* @class * @class
*/ */
var Palette = this.Palette = Base.extend(Callback, /** @lends Palette# */{ var Palette = Base.extend(Callback, /** @lends Palette# */{
_events: [ 'onChange' ], _events: [ 'onChange' ],
initialize: function(title, components, values) { initialize: function Palette(title, components, values) {
var parent = DomElement.find('.palettejs-panel') var parent = DomElement.find('.palettejs-panel')
|| DomElement.find('body').appendChild( || DomElement.find('body').appendChild(
DomElement.create('div', { 'class': 'palettejs-panel' })); DomElement.create('div', { 'class': 'palettejs-panel' }));
@ -49,7 +49,6 @@ var Palette = this.Palette = Base.extend(Callback, /** @lends Palette# */{
Base.define(values, name, { Base.define(values, name, {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
writable: true,
get: function() { get: function() {
return component._value; return component._value;
}, },

View file

@ -19,8 +19,8 @@
* center, both useful for constructing artwork that should appear centered on * center, both useful for constructing artwork that should appear centered on
* screen. * screen.
*/ */
var View = this.View = Base.extend(Callback, /** @lends View# */{ var View = Base.extend(Callback, /** @lends View# */{
initialize: function(element) { initialize: function View(element) {
// Store reference to the currently active global paper scope, and the // Store reference to the currently active global paper scope, and the
// active project, which will be represented by this view // active project, which will be represented by this view
this._scope = paper; this._scope = paper;
@ -60,7 +60,7 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
// If the element is invisible, we cannot directly access // If the element is invisible, we cannot directly access
// element.width / height, because they would appear 0. // element.width / height, because they would appear 0.
// Reading the attributes still works. // Reading the attributes still works.
size = Size.create(parseInt(element.getAttribute('width'), 10), size = new Size(parseInt(element.getAttribute('width'), 10),
parseInt(element.getAttribute('height'), 10)); parseInt(element.getAttribute('height'), 10));
// If no size was specified on the canvas, read it from CSS // If no size was specified on the canvas, read it from CSS
if (size.isNaN()) if (size.isNaN())
@ -83,11 +83,11 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
style.top = offset.y + 'px'; style.top = offset.y + 'px';
document.body.appendChild(stats); document.body.appendChild(stats);
} }
/*#*/ } else if (options.server) { /*#*/ } else if (options.node) {
// Generate an id for this view // Generate an id for this view
this._id = 'view-' + View._id++; this._id = 'view-' + View._id++;
size = Size.create(element.width, element.height); size = new Size(element.width, element.height);
/*#*/ } // options.server /*#*/ } // options.node
// Keep track of views internally // Keep track of views internally
View._views.push(this); View._views.push(this);
// Link this id to our view // Link this id to our view
@ -235,7 +235,7 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
}, },
_redraw: function() { _redraw: function() {
this._redrawNeeded = true; this._project._needsRedraw = true;
if (this._handlingFrame) if (this._handlingFrame)
return; return;
if (this._animate) { if (this._animate) {

View file

@ -30,6 +30,8 @@ var Formatter = Base.extend({
* @param {Number} num the number to be converted to a string * @param {Number} num the number to be converted to a string
*/ */
number: function(val) { number: function(val) {
// It would be nice to use Number#toFixed() instead, but it pads with 0,
// unecessarily consuming space.
return Math.round(val * this.multiplier) / this.multiplier; return Math.round(val * this.multiplier) / this.multiplier;
}, },

View file

@ -10,7 +10,7 @@
* All rights reserved. * All rights reserved.
*/ */
var Numerical = this.Numerical = new function() { var Numerical = new function() {
// Lookup tables for abscissas and weights with values for n = 2 .. 16. // Lookup tables for abscissas and weights with values for n = 2 .. 16.
// As values are symetric, only store half of them and addapt algorithm // As values are symetric, only store half of them and addapt algorithm