merge upstream

This commit is contained in:
hkrish 2013-05-09 14:30:28 +02:00
commit fce29e4b75
36 changed files with 647 additions and 534 deletions

View file

@ -0,0 +1,50 @@
var paper = require('paper'),
path = require('path'),
fs = require('fs');
paper.setup(new paper.Canvas(300, 600));
with (paper) {
var stops = [new Color(1, 1, 0, 0), 'red', 'black'];
var radius = view.bounds.width * 0.4,
from = new Point(view.center.x),
to = from.add(radius, 0);
var circle = new Path.Circle({
center: from,
radius: radius,
fillColor: {
stops: stops,
radial: true,
origin: from,
destination: to
},
strokeColor: 'black'
});
var from = view.bounds.leftCenter,
to = view.bounds.bottomRight;
var rect = new Path.Rectangle({
from: from,
to: to,
fillColor: {
stops: stops,
radial: false,
origin: from,
destination: to
},
strokeColor: 'black'
});
rect.rotate(45).scale(0.7);
var svg = new XMLSerializer().serializeToString(project.exportSVG());
console.log(svg);
fs.writeFile(path.resolve(__dirname, 'out.svg'),svg, function (err) {
if (err) throw err;
console.log('Saved!');
});
}

View file

@ -0,0 +1,22 @@
var paper = require('paper'),
path = require('path'),
fs = require('fs');
paper.setup(new paper.Canvas(300, 600));
with (paper) {
fs.readFile('./in.svg', { encoding: 'utf8' }, function (err, data) {
if (err)
throw err;
project.importSVG(data);
paper.view.exportFrames({
amount: 1,
directory: __dirname,
onComplete: function() {
console.log('Done exporting.');
},
onProgress: function(event) {
console.log(event.percentage + '% complete, frame took: ' + event.delta);
}
});
});
}

View file

@ -1,5 +1,6 @@
require('../../node.js/');
var paper = require('./Tadpoles');
require('paper');
var paper = require('./Tadpoles.pjs');
paper.view.exportFrames({
amount: 400,
directory: __dirname,

View file

@ -277,4 +277,4 @@ function onFrame(event) {
function onResize(event) {
size = view.size;
heartPath.position = view.center;
}
}

16
examples/Node.js/in.svg Normal file
View file

@ -0,0 +1,16 @@
<svg x="0" y="0" width="300" height="600" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink">
<linearGradient x1="45" y1="345" x2="255" y2="555" gradientUnits="userSpaceOnUse" id="gradient-2">
<stop offset="0" stop-color="rgb(255, 255, 0)" stop-opacity="0"></stop>
<stop offset="0.5" stop-color="rgb(255, 0, 0)"></stop>
<stop offset="1" stop-color="rgb(0, 0, 0)"></stop>
</linearGradient>
<radialGradient cx="150" cy="150" r="120" gradientUnits="userSpaceOnUse" id="gradient-1">
<stop offset="0" stop-color="rgb(255, 255, 0)" stop-opacity="0"></stop>
<stop offset="0.5" stop-color="rgb(255, 0, 0)"></stop>
<stop offset="1" stop-color="rgb(0, 0, 0)"></stop>
</radialGradient>
<g fill="none" stroke="rgb(0, 0, 0)" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0">
<circle cx="150" cy="150" r="120" fill="url(#gradient-1)"></circle>
<rect x="45" y="345" width="210" height="210" transform="rotate(45,150,450)" fill="url(#gradient-2)"></rect>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -15,7 +15,7 @@
var items = project.activeLayer.firstChild.children;
var mouseIsDown = false;
for (var i = 0; i < items.length; i++) {
items[i].attach({
items[i].on({
mousedown: function(event) {
mouseIsDown = true;
},

View file

@ -5,103 +5,26 @@
<title>Gradients</title>
<script type="text/javascript" src="../../dist/paper.js"></script>
<script type="text/paperscript" canvas="canvas">
project.importSVG(document.getElementById('Layer_1'));
project.importSVG(document.getElementById('svg'));
</script>
</head>
<body>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="500" height="1000" enable-background="new 0 0 595.28 841.89" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="69" y1="239.5" x2="530" y2="239.5">
<stop offset="0" style="stop-color:#231F20"/>
<stop offset="0.0896" style="stop-color:#231F20;stop-opacity:0.9104"/>
<stop offset="1" style="stop-color:#231F20;stop-opacity:0"/>
</linearGradient>
<rect x="69" y="210" fill="url(#SVGID_1_)" width="461" height="59"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="69" y1="162.5" x2="530" y2="162.5">
<stop offset="0" style="stop-color:#00A14B"/>
<stop offset="0.0031" style="stop-color:#0BA449"/>
<stop offset="0.0203" style="stop-color:#43B13D"/>
<stop offset="0.038" style="stop-color:#75BD33"/>
<stop offset="0.0559" style="stop-color:#A0C72A"/>
<stop offset="0.074" style="stop-color:#C2CF23"/>
<stop offset="0.0922" style="stop-color:#DDD61E"/>
<stop offset="0.1107" style="stop-color:#F0DA1A"/>
<stop offset="0.1298" style="stop-color:#FBDD18"/>
<stop offset="0.15" style="stop-color:#FFDE17"/>
<stop offset="0.3" style="stop-color:#F26522"/>
<stop offset="0.47" style="stop-color:#00A14B"/>
<stop offset="0.64" style="stop-color:#FFDE17"/>
<stop offset="0.8012" style="stop-color:#F26522"/>
<stop offset="1" style="stop-color:#00A14B"/>
</linearGradient>
<rect x="69" y="133" fill="url(#SVGID_2_)" width="461" height="59"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="69" y1="91.5" x2="530" y2="91.5">
<stop offset="0%" style="stop-color:#00A14B"/>
<stop offset="0.31%" style="stop-color:#0BA449"/>
<stop offset="2%" style="stop-color:#43B13D"/>
<stop offset="3.8%" style="stop-color:#75BD33"/>
<stop offset="5.59%" style="stop-color:#A0C72A"/>
<stop offset="7.4%" style="stop-color:#C2CF23"/>
<stop offset="9.22%" style="stop-color:#DDD61E"/>
<stop offset="11.07%" style="stop-color:#F0DA1A"/>
<stop offset="12.98%" style="stop-color:#FBDD18"/>
<stop offset="15%" style="stop-color:#FFDE17"/>
<stop offset="30%" style="stop-color:#F26522"/>
<stop offset="47%" style="stop-color:#00A14B"/>
<stop offset="64%" style="stop-color:#FFDE17"/>
<stop offset="80.12%" style="stop-color:#F26522"/>
<stop offset="100%" style="stop-color:#00A14B"/>
</linearGradient>
<rect x="69" y="62" fill="url(#SVGID_3_)" width="461" height="59"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="24.6909" y1="760.1406" x2="485.6914" y2="760.1406" gradientTransform="matrix(0 1 -1 0 859.6406 264.3599)">
<stop offset="0" style="stop-color:#231F20"/>
<stop offset="0.0896" style="stop-color:#231F20;stop-opacity:0.9104"/>
<stop offset="1" style="stop-color:#231F20;stop-opacity:0"/>
</linearGradient>
<rect x="70" y="289.051" fill="url(#SVGID_4_)" width="59" height="461"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="24.6909" y1="683.1396" x2="485.6914" y2="683.1396" gradientTransform="matrix(0 1 -1 0 859.6406 264.3599)">
<stop offset="0" style="stop-color:#00A14B"/>
<stop offset="0.0031" style="stop-color:#0BA449"/>
<stop offset="0.0203" style="stop-color:#43B13D"/>
<stop offset="0.038" style="stop-color:#75BD33"/>
<stop offset="0.0559" style="stop-color:#A0C72A"/>
<stop offset="0.074" style="stop-color:#C2CF23"/>
<stop offset="0.0922" style="stop-color:#DDD61E"/>
<stop offset="0.1107" style="stop-color:#F0DA1A"/>
<stop offset="0.1298" style="stop-color:#FBDD18"/>
<stop offset="0.15" style="stop-color:#FFDE17"/>
<stop offset="0.3" style="stop-color:#F26522"/>
<stop offset="0.47" style="stop-color:#00A14B"/>
<stop offset="0.64" style="stop-color:#FFDE17"/>
<stop offset="0.8012" style="stop-color:#F26522"/>
<stop offset="1" style="stop-color:#00A14B"/>
</linearGradient>
<rect x="147.001" y="289.051" fill="url(#SVGID_5_)" width="59" height="461"/>
<radialGradient id="SVGID_6_" cx="368.75" cy="409.5503" r="92.1995" gradientUnits="userSpaceOnUse">
<stop offset="0.1656" style="stop-color:#FFFFFF"/>
<stop offset="0.2576" style="stop-color:#CBCBCB"/>
<stop offset="0.3651" style="stop-color:#969696"/>
<stop offset="0.474" style="stop-color:#686868"/>
<stop offset="0.5821" style="stop-color:#434343"/>
<stop offset="0.6893" style="stop-color:#252525"/>
<stop offset="0.7953" style="stop-color:#111111"/>
<stop offset="0.8995" style="stop-color:#040404"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle fill="url(#SVGID_6_)" cx="368.75" cy="409.55" r="92.2"/>
<radialGradient id="SVGID_7_" cx="368.75" cy="619.5508" r="92.1997" fx="323.3488" fy="618.7006" gradientUnits="userSpaceOnUse">
<stop offset="0.1656" style="stop-color:#FFFFFF"/>
<stop offset="0.2576" style="stop-color:#CBCBCB"/>
<stop offset="0.3651" style="stop-color:#969696"/>
<stop offset="0.474" style="stop-color:#686868"/>
<stop offset="0.5821" style="stop-color:#434343"/>
<stop offset="0.6893" style="stop-color:#252525"/>
<stop offset="0.7953" style="stop-color:#111111"/>
<stop offset="0.8995" style="stop-color:#040404"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle fill="url(#SVGID_7_)" cx="368.75" cy="619.551" r="92.2"/>
</svg>
<canvas id="canvas" width="500" height="1000"></canvas>
<svg id="svg" x="0" y="0" width="300" height="600" version="1.1" xmlns="http://www.w3.org/2000/svg" xlink="http://www.w3.org/1999/xlink">
<linearGradient x1="45" y1="345" x2="255" y2="555" gradientUnits="userSpaceOnUse" id="gradient-2">
<stop offset="0" stop-color="rgb(255, 255, 0)" stop-opacity="0"></stop>
<stop offset="0.5" stop-color="rgb(255, 0, 0)"></stop>
<stop offset="1" stop-color="rgb(0, 0, 0)"></stop>
</linearGradient>
<radialGradient cx="150" cy="150" r="120" gradientUnits="userSpaceOnUse" id="gradient-1">
<stop offset="0" stop-color="rgb(255, 255, 0)" stop-opacity="0"></stop>
<stop offset="0.5" stop-color="rgb(255, 0, 0)"></stop>
<stop offset="1" stop-color="rgb(0, 0, 0)"></stop>
</radialGradient>
<g fill="none" stroke="rgb(0, 0, 0)" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="10" stroke-dasharray="" stroke-dashoffset="0">
<circle cx="150" cy="150" r="120" fill="url(#gradient-1)"></circle>
<rect x="45" y="345" width="210" height="210" transform="rotate(45,150,450)" fill="url(#gradient-2)"></rect>
</g>
</svg>
<canvas id="canvas" width="300" height="600"></canvas>
</body>
</html>

View file

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Gradients</title>
<script type="text/javascript" src="../../dist/paper.js"></script>
<script type="text/paperscript" canvas="canvas">
project.importSVG(document.getElementById('Layer_1'));
</script>
</head>
<body>
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="500" height="1000" enable-background="new 0 0 595.28 841.89" xml:space="preserve">
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="69" y1="239.5" x2="530" y2="239.5">
<stop offset="0" style="stop-color:#231F20"/>
<stop offset="0.0896" style="stop-color:#231F20;stop-opacity:0.9104"/>
<stop offset="1" style="stop-color:#231F20;stop-opacity:0"/>
</linearGradient>
<rect x="69" y="210" fill="url(#SVGID_1_)" width="461" height="59"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="69" y1="162.5" x2="530" y2="162.5">
<stop offset="0" style="stop-color:#00A14B"/>
<stop offset="0.0031" style="stop-color:#0BA449"/>
<stop offset="0.0203" style="stop-color:#43B13D"/>
<stop offset="0.038" style="stop-color:#75BD33"/>
<stop offset="0.0559" style="stop-color:#A0C72A"/>
<stop offset="0.074" style="stop-color:#C2CF23"/>
<stop offset="0.0922" style="stop-color:#DDD61E"/>
<stop offset="0.1107" style="stop-color:#F0DA1A"/>
<stop offset="0.1298" style="stop-color:#FBDD18"/>
<stop offset="0.15" style="stop-color:#FFDE17"/>
<stop offset="0.3" style="stop-color:#F26522"/>
<stop offset="0.47" style="stop-color:#00A14B"/>
<stop offset="0.64" style="stop-color:#FFDE17"/>
<stop offset="0.8012" style="stop-color:#F26522"/>
<stop offset="1" style="stop-color:#00A14B"/>
</linearGradient>
<rect x="69" y="133" fill="url(#SVGID_2_)" width="461" height="59"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="69" y1="91.5" x2="530" y2="91.5">
<stop offset="0%" style="stop-color:#00A14B"/>
<stop offset="0.31%" style="stop-color:#0BA449"/>
<stop offset="2%" style="stop-color:#43B13D"/>
<stop offset="3.8%" style="stop-color:#75BD33"/>
<stop offset="5.59%" style="stop-color:#A0C72A"/>
<stop offset="7.4%" style="stop-color:#C2CF23"/>
<stop offset="9.22%" style="stop-color:#DDD61E"/>
<stop offset="11.07%" style="stop-color:#F0DA1A"/>
<stop offset="12.98%" style="stop-color:#FBDD18"/>
<stop offset="15%" style="stop-color:#FFDE17"/>
<stop offset="30%" style="stop-color:#F26522"/>
<stop offset="47%" style="stop-color:#00A14B"/>
<stop offset="64%" style="stop-color:#FFDE17"/>
<stop offset="80.12%" style="stop-color:#F26522"/>
<stop offset="100%" style="stop-color:#00A14B"/>
</linearGradient>
<rect x="69" y="62" fill="url(#SVGID_3_)" width="461" height="59"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="24.6909" y1="760.1406" x2="485.6914" y2="760.1406" gradientTransform="matrix(0 1 -1 0 859.6406 264.3599)">
<stop offset="0" style="stop-color:#231F20"/>
<stop offset="0.0896" style="stop-color:#231F20;stop-opacity:0.9104"/>
<stop offset="1" style="stop-color:#231F20;stop-opacity:0"/>
</linearGradient>
<rect x="70" y="289.051" fill="url(#SVGID_4_)" width="59" height="461"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="24.6909" y1="683.1396" x2="485.6914" y2="683.1396" gradientTransform="matrix(0 1 -1 0 859.6406 264.3599)">
<stop offset="0" style="stop-color:#00A14B"/>
<stop offset="0.0031" style="stop-color:#0BA449"/>
<stop offset="0.0203" style="stop-color:#43B13D"/>
<stop offset="0.038" style="stop-color:#75BD33"/>
<stop offset="0.0559" style="stop-color:#A0C72A"/>
<stop offset="0.074" style="stop-color:#C2CF23"/>
<stop offset="0.0922" style="stop-color:#DDD61E"/>
<stop offset="0.1107" style="stop-color:#F0DA1A"/>
<stop offset="0.1298" style="stop-color:#FBDD18"/>
<stop offset="0.15" style="stop-color:#FFDE17"/>
<stop offset="0.3" style="stop-color:#F26522"/>
<stop offset="0.47" style="stop-color:#00A14B"/>
<stop offset="0.64" style="stop-color:#FFDE17"/>
<stop offset="0.8012" style="stop-color:#F26522"/>
<stop offset="1" style="stop-color:#00A14B"/>
</linearGradient>
<rect x="147.001" y="289.051" fill="url(#SVGID_5_)" width="59" height="461"/>
<radialGradient id="SVGID_6_" cx="368.75" cy="409.5503" r="92.1995" gradientUnits="userSpaceOnUse">
<stop offset="0.1656" style="stop-color:#FFFFFF"/>
<stop offset="0.2576" style="stop-color:#CBCBCB"/>
<stop offset="0.3651" style="stop-color:#969696"/>
<stop offset="0.474" style="stop-color:#686868"/>
<stop offset="0.5821" style="stop-color:#434343"/>
<stop offset="0.6893" style="stop-color:#252525"/>
<stop offset="0.7953" style="stop-color:#111111"/>
<stop offset="0.8995" style="stop-color:#040404"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle fill="url(#SVGID_6_)" cx="368.75" cy="409.55" r="92.2"/>
<radialGradient id="SVGID_7_" cx="368.75" cy="619.5508" r="92.1997" fx="323.3488" fy="618.7006" gradientUnits="userSpaceOnUse">
<stop offset="0.1656" style="stop-color:#FFFFFF"/>
<stop offset="0.2576" style="stop-color:#CBCBCB"/>
<stop offset="0.3651" style="stop-color:#969696"/>
<stop offset="0.474" style="stop-color:#686868"/>
<stop offset="0.5821" style="stop-color:#434343"/>
<stop offset="0.6893" style="stop-color:#252525"/>
<stop offset="0.7953" style="stop-color:#111111"/>
<stop offset="0.8995" style="stop-color:#040404"/>
<stop offset="1" style="stop-color:#000000"/>
</radialGradient>
<circle fill="url(#SVGID_7_)" cx="368.75" cy="619.551" r="92.2"/>
</svg>
<canvas id="canvas" width="500" height="1000"></canvas>
</body>
</html>

2
lib/acorn-min.js vendored

File diff suppressed because one or more lines are too long

View file

@ -20,12 +20,16 @@
// [dammit]: acorn_loose.js
// [walk]: util/walk.js
(function(exports) {
(function(mod) {
if (typeof exports == "object" && typeof module == "object") return mod(exports); // CommonJS
if (typeof define == "function" && define.amd) return define(["exports"], mod); // AMD
mod(this.acorn || (this.acorn = {})); // Plain browser env
})(function(exports) {
"use strict";
exports.version = "0.1.01";
exports.version = "0.2.01";
// The main exported interface (under `self.acorn` when in the
// The main exported interface (under `this.acorn` when in the
// browser) is a `parse` function that takes a code string and
// returns an abstract syntax tree as specified by [Mozilla parser
// API][api], with the caveat that the SpiderMonkey-specific syntax
@ -418,17 +422,17 @@
// Test whether a given character code starts an identifier.
function isIdentifierStart(code) {
var isIdentifierStart = exports.isIdentifierStart = function(code) {
if (code < 65) return code === 36;
if (code < 91) return true;
if (code < 97) return code === 95;
if (code < 123)return true;
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}
};
// Test whether a given character is part of an identifier.
function isIdentifierChar(code) {
var isIdentifierChar = exports.isIdentifierChar = function(code) {
if (code < 48) return code === 36;
if (code < 58) return true;
if (code < 65) return false;
@ -436,7 +440,7 @@
if (code < 97) return code === 95;
if (code < 123)return true;
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}
};
// ## Tokenizer
@ -679,7 +683,8 @@
}
function readToken(forceRegexp) {
tokStart = tokPos;
if (!forceRegexp) tokStart = tokPos;
else tokPos = tokStart + 1;
if (options.locations) tokStartLoc = new line_loc_t;
if (forceRegexp) return readRegexp();
if (tokPos >= inputLen) return finishToken(_eof);
@ -821,7 +826,7 @@
case 85: out += String.fromCharCode(readHexChar(8)); break; // 'U'
case 116: out += "\t"; break; // 't' -> '\t'
case 98: out += "\b"; break; // 'b' -> '\b'
case 118: out += "\v"; break; // 'v' -> '\u000b'
case 118: out += "\u000b"; break; // 'v' -> '\u000b'
case 102: out += "\f"; break; // 'f' -> '\f'
case 48: out += "\0"; break; // 0 -> '\0'
case 13: if (input.charCodeAt(tokPos) === 10) ++tokPos; // '\r\n'
@ -940,6 +945,10 @@
function setStrict(strct) {
strict = strct;
tokPos = lastEnd;
while (tokPos < tokLineStart) {
tokLineStart = input.lastIndexOf("\n", tokLineStart - 2) + 1;
--tokCurLine;
}
skipSpace();
readToken();
}
@ -1226,8 +1235,8 @@
case _try:
next();
node.block = parseBlock();
node.handlers = [];
while (tokType === _catch) {
node.handler = null;
if (tokType === _catch) {
var clause = startNode();
next();
expect(_parenL);
@ -1237,10 +1246,10 @@
expect(_parenR);
clause.guard = null;
clause.body = parseBlock();
node.handlers.push(finishNode(clause, "CatchClause"));
node.handler = finishNode(clause, "CatchClause");
}
node.finalizer = eat(_finally) ? parseBlock() : null;
if (!node.handlers.length && !node.finalizer)
if (!node.handler && !node.finalizer)
raise(node.start, "Missing catch or finally clause");
return finishNode(node, "TryStatement");
@ -1707,4 +1716,4 @@
return finishNode(node, "Identifier");
}
})(typeof exports === "undefined" ? (self.acorn = {}) : exports);
});

25
lib/bootstrap.js → lib/straps.js Normal file → Executable file
View file

@ -1,14 +1,21 @@
/**
* Bootstrap.js JavaScript Inheritance Microframework
* Straps.js - Inheritance library with support for bean-style accessors and
* AOP patterns.
*
* Copyright (c) 2006 - 2013 Juerg Lehni
* http://lehni.org/
*
* Distributed under the MIT license.
*
* straps.js was created by extracting and simplifying the inheritance code from
* boostrap.js, a JavaScript DOM library, also published by Juerg Lehni:
* https://github.com/lehni/bootstrap.js
* The name was changed due to Twitter's introduction of their CSS framework
* with the same name.
*
* Inspirations:
* http://dean.edwards.name/weblog/2006/03/base/
* http://dev.helma.org/Wiki/JavaScript+Inheritance+Sugar/
* http://prototypejs.org/
*/
var Base = new function() { // Bootstrap scope
@ -36,7 +43,7 @@ var Base = new function() { // Bootstrap scope
// supports the first parameter (in the emulation):
create = Object.create || function(proto) {
// From all browsers that do not offer Object.create(), we only
// support Firefox 3.5 & 3.5, but luckily this hack works there:
// support Firefox 3.5 & 3.5, and this hack works there:
return { __proto__: proto };
},
_define = Object.defineProperty,
@ -55,8 +62,8 @@ var Base = new function() { // Bootstrap scope
} catch (e) {}
}
if ((desc.get || desc.set) && obj.__defineGetter__) {
desc.get && obj.__defineGetter__(name, desc.get);
desc.set && obj.__defineSetter__(name, desc.set);
if (desc.get) obj.__defineGetter__(name, desc.get);
if (desc.set) obj.__defineSetter__(name, desc.set);
} else {
obj[name] = desc.value;
}
@ -97,8 +104,12 @@ var Base = new function() { // Bootstrap scope
// This does even work for prop: 0, as it will just be looked up
// again through describe.
var val = val || (val = describe(src, name))
&& (val.get ? val : val.value),
func = typeof val === 'function',
&& (val.get ? val : val.value);
// Allow aliases to properties with different names, by having
// string values starting with '#'
if (typeof val === 'string' && val[0] === '#')
val = src[val.substring(1)] || val;
var func = typeof val === 'function',
res = val,
// Only lookup previous value if we preserve or define a
// function that might need it for this.base(). If we're

View file

@ -1,70 +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.
*/
var fs = require('fs'),
vm = require('vm'),
path = require('path'),
Canvas = require('canvas');
__dirname = path.resolve(__dirname, '../src/');
// Create the context within which we will run the source files:
var context = vm.createContext({
options: {
server: true,
svg: true,
parser: 'acorn',
version: 'dev'
},
fs: fs,
// Node Canvas library: https://github.com/learnboost/node-canvas
Canvas: Canvas,
HTMLCanvasElement: Canvas,
Image: Canvas.Image,
// Copy over global variables:
console: console,
require: require,
__dirname: __dirname,
__filename: __filename,
// Used to load and run source files within the same context:
include: function(uri) {
var source = fs.readFileSync(path.resolve(__dirname, uri), 'utf8');
// For relative includes, we save the current directory and then
// add the uri directory to __dirname:
var oldDirname = __dirname;
__dirname = path.resolve(__dirname, path.dirname(uri));
vm.runInContext(source, context, uri);
__dirname = oldDirname;
}
});
// Load Paper.js library files:
context.include('paper.js');
// Export all classes through PaperScope:
context.Base.each(context, function(val, key) {
if (val && val.prototype instanceof context.Base)
context.PaperScope.prototype[key] = val;
});
context.PaperScope.prototype['Canvas'] = context.Canvas;
require.extensions['.pjs'] = function(module, uri) {
var source = context.PaperScript.compile(fs.readFileSync(uri, 'utf8'));
var envVars = 'var __dirname = \'' + path.dirname(uri) + '\';' +
'var __filename = \'' + uri + '\';';
vm.runInContext(envVars, context);
var scope = new context.PaperScope();
context.PaperScript.evaluate(source, scope);
module.exports = scope;
};
module.exports = new context.PaperScope();

2
node_modules/.gitignore generated vendored Normal file
View file

@ -0,0 +1,2 @@
canvas
jsdom

1
node_modules/paper generated vendored Symbolic link
View file

@ -0,0 +1 @@
../

View file

@ -1,20 +1,18 @@
{
"name": "paper",
"description": "Vector graphics scripting framework",
"version": "0.2.2",
"contributors": [{
"name" : "Jürg Lehni",
"url" : "http://lehni.org"
}, {
"name" : "Jonathan Puckey",
"url" : "http://jonathanpuckey.com"
}],
"homepage": "http://paperjs.org",
"keywords": ["canvas", "graphic", "graphics", "vector", "paper.js"],
"repository": "git://github.com/paperjs/paper.js/",
"dependencies": {
"canvas": ">= 0.7.0"
},
"version": "0.8.3",
"main": "./src/node/index.js",
"engines": { "node": ">= 0.4.0" },
"main": "./node.js/index.js"
}
"dependencies": {
"canvas": ">= 0.7.0",
"jsdom": ">= 0.6.0"
},
"description": "The Swiss Army Knife of Vector Graphics Scripting",
"contributors": [
"Jürg Lehni <juerg@lehni.org> (http://lehni.org)",
"Jonathan Puckey <jonathan@studiomoniker.com> (http://studiomoniker.com)"
],
"homepage": "http://paperjs.org",
"repository": "git://github.com/paperjs/paper.js",
"keywords": ["vector", "graphic", "graphics", "bezier", "curve", "curves", "canvas", "svg", "paper.js"]
}

View file

@ -18,9 +18,6 @@
// jsdoc-toolkit will have its own project file
"folder_exclude_patterns": ["jsdoc-toolkit"]
},
{
"path": "../node.js"
},
{
"path": "..",
"name": "root",

View file

@ -265,7 +265,7 @@ var Matrix = this.Matrix = Base.extend(/** @lends Matrix# */{
// Do not modify point, center, since that would arguments of which
// we're reading from!
var _point = Point.read(arguments),
_center = Point.read(arguments);
_center = Point.read(arguments, 0, 0, false, true); // readNull
if (_center)
this.translate(_center);
var a = this._a,

View file

@ -16,7 +16,7 @@
* @private
*/
// Extend Base with utility functions used across the library. Also set
// this.Base on the injection scope, since bootstrap.js ommits that.
// this.Base on the injection scope, since straps.js ommits that.
this.Base = Base.inject(/** @lends Base# */{
// Have generics versions of #clone() and #toString():
generics: true,

View file

@ -13,6 +13,7 @@
/**
* @name Callback
* @namespace
* @private
*/
var Callback = {
attach: function(type, func) {
@ -63,6 +64,13 @@ var Callback = {
}
},
once: function(type, func) {
this.attach(type, function() {
func.apply(this, arguments);
this.detach(type, func);
});
},
fire: function(type, event) {
// Returns true if fired, false otherwise
var handlers = this._handlers && this._handlers[type];
@ -82,7 +90,14 @@ var Callback = {
return !!(this._handlers && this._handlers[type]);
},
// Install jQuery-style aliases to our event handler methods
on: '#attach',
off: '#detach',
trigger: '#fire',
statics: {
// Override inject() so that sub-classes automatically add the accessors
// for the event handler functions (e.g. #onMouseDown) for each property
inject: function(/* src, ... */) {
for (var i = 0, l = arguments.length; i < l; i++) {
var src = arguments[i],

View file

@ -1553,9 +1553,7 @@ var Item = this.Item = Base.extend(Callback, {
* @param {Item} item The item to be appended as a child
* @deprecated use {@link #addChild(item)} instead.
*/
appendTop: function(item) {
return this.addChild(item);
},
appendTop: '#addChild',
/**
* Inserts the specified item as a child of this item by appending it to
@ -1576,9 +1574,7 @@ var Item = this.Item = Base.extend(Callback, {
* @return {Boolean} {@true it was moved}
* @deprecated use {@link #insertAbove(item)} instead.
*/
moveAbove: function(item) {
return this.insertAbove(item);
},
moveAbove: '#insertAbove',
/**
* Moves the item below the specified item.
@ -1587,9 +1583,7 @@ var Item = this.Item = Base.extend(Callback, {
* @return {Boolean} {@true it was moved}
* @deprecated use {@link #insertBelow(item)} instead.
*/
moveBelow: function(item) {
return this.insertBelow(item);
},
moveBelow: '#insertBelow',
/**
* Removes the item from its parent's named children list.
@ -2660,7 +2654,7 @@ var Item = this.Item = Base.extend(Callback, {
*
* Attach an event handler to the item.
*
* @name Item#attach
* @name Item#on
* @function
* @param {String('mousedown', 'mouseup', 'mousedrag', 'click',
* 'doubleclick', 'mousemove', 'mouseenter', 'mouseleave')} type the event
@ -2680,19 +2674,19 @@ var Item = this.Item = Base.extend(Callback, {
* });
*
* // When the mouse enters the item, set its fill color to red:
* path.attach('mouseenter', function() {
* path.on('mouseenter', function() {
* this.fillColor = 'red';
* });
*
* // When the mouse leaves the item, set its fill color to black:
* path.attach('mouseleave', function() {
* path.on('mouseleave', function() {
* this.fillColor = 'black';
* });
*/
/**
* Attach one or more event handlers to the item.
*
* @name Item#attach^2
* @name Item#on^2
* @function
* @param {Object} param An object literal containing one or more of the
* following properties: {@code mousedown, mouseup, mousedrag, click,
@ -2710,7 +2704,7 @@ var Item = this.Item = Base.extend(Callback, {
* path.fillColor = 'black';
*
* // When the mouse enters the item, set its fill color to red:
* path.attach({
* path.on({
* mouseenter: function(event) {
* this.fillColor = 'red';
* },
@ -2742,7 +2736,7 @@ var Item = this.Item = Base.extend(Callback, {
* });
*
* // Attach the handers inside the object literal to the path:
* path.attach(pathHandlers);
* path.on(pathHandlers);
* }
*/

127
src/node/index.js Normal file
View file

@ -0,0 +1,127 @@
/*
* 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.
*/
var fs = require('fs'),
vm = require('vm'),
path = require('path'),
// Node Canvas library: https://github.com/learnboost/node-canvas
Canvas = require('canvas'),
jsdom = require('jsdom'),
domToHtml = require('jsdom/lib/jsdom/browser/domtohtml').domToHtml,
json = require('../../package.json');
var options = {
server: true,
svg: true,
parser: 'acorn',
// Use 'dev' for on-the fly compilation of separate files ,but update after.
version: 'dev'
};
// Create a document and a window using jsdom, e.g. for exportSVG()
var doc = jsdom.jsdom("<html><body></body></html>"),
win = doc.createWindow();
// Define XMLSerializer.
// TODO: Put this into a simple node module, with dependency on jsdom
function XMLSerializer() {
}
XMLSerializer.prototype.serializeToString = function(node) {
var text = domToHtml(node);
// Fix a jsdom issue where linearGradient gets converted to lineargradient:
// https://github.com/tmpvar/jsdom/issues/620
return text.replace(/(linear|radial)(gradient)/g, function(all, type) {
return type + 'Gradient';
});
};
function DOMParser() {
}
DOMParser.prototype.parseFromString = function(string, contenType) {
var div = doc.createElement('div');
div.innerHTML = string;
return div.firstChild;
};
// Create the context within which we will run the source files:
var dirname = path.resolve(__dirname, '..');
var context = vm.createContext({
// Used to load and run source files within the same context:
include: function(uri) {
var source = fs.readFileSync(path.resolve(dirname, uri), 'utf8'),
// For relative includes, we save the current directory and then
// add the uri directory to dirname:
prevDirname = dirname;
dirname = path.resolve(dirname, path.dirname(uri));
vm.runInContext(source, context, uri);
dirname = prevDirname;
},
// Expose core methods and values
__dirname: dirname,
require: require,
options: options,
// Expose node modules
fs: fs,
Canvas: Canvas,
// Expose global browser variables:
HTMLCanvasElement: Canvas,
XMLSerializer: XMLSerializer,
DOMParser: DOMParser,
Image: Canvas.Image,
window: win,
document: doc,
navigator: win.navigator,
console: console
});
// Load Paper.js library files:
context.include('paper.js');
// Fix version now. Remove 2nd dot, so we can make a float out of it:
options.version = parseFloat(json.version.replace(/(.)(\d)$/, '$2'));
// Since the created context fo Paper.js compilation, and the context in which
// Node.js scripts are executed do not share the definition of Object and Array,
// we need to redefine Base.isPlainObject() here.
// Object(obj) === obj is a trick from underscore, but also returns true for all
// Base objects. So we are filtering these out with an instanceof check, but
// Include Base instances since we're using them as hashes.
// TODO: Benchmark the speed and consider this implementation instead of the
// current one.
var Base = context.Base;
Base.isPlainObject = function(obj) {
return Object(obj) === obj && !Array.isArray(obj) && (!(obj instanceof Base)
|| Object.getPrototypeOf(obj) === Base.prototype);
};
// Expose the Canvas, XMLSerializer to paper scopes:
Base.each({
Canvas: Canvas,
XMLSerializer: XMLSerializer,
DOMParser: DOMParser
}, function(value, key) {
this[key] = value;
}, context.PaperScope.prototype);
require.extensions['.pjs'] = function(module, uri) {
var source = context.PaperScript.compile(fs.readFileSync(uri, 'utf8'));
// Temporarily override __dirname and __filename
var envVars = 'var __dirname = \'' + path.dirname(uri) + '\';'
+ 'var __filename = \'' + uri + '\';';
vm.runInContext(envVars, context);
var scope = new context.PaperScope();
context.PaperScript.evaluate(source, scope);
module.exports = scope;
};
module.exports = new context.PaperScope();

View file

@ -13,7 +13,9 @@
*
***
*
* Bootstrap.js JavaScript Inheritance Micro-Framework
* Straps.js - Inheritance library with support for bean-style accessors and
* AOP patterns.
*
* Copyright (c) 2006 - 2013 Juerg Lehni
* http://lehni.org/
*
@ -31,7 +33,7 @@
var paper = new function() {
// Inline Bootstrap core (the Base class) inside the paper scope first:
/*#*/ include('../lib/bootstrap.js');
/*#*/ include('../lib/straps.js');
/*#*/ if (options.version == 'dev') {
/*#*/ include('constants.js');
@ -90,10 +92,8 @@ var paper = new function() {
/*#*/ include('style/GradientStop.js');
/*#*/ include('style/Style.js');
/*#*/ if (options.browser) {
/*#*/ include('browser/DomElement.js');
/*#*/ include('browser/DomEvent.js');
/*#*/ } // options.browser
/*#*/ include('dom/DomElement.js');
/*#*/ include('dom/DomEvent.js');
/*#*/ include('ui/View.js');
/*#*/ include('ui/CanvasView.js');
@ -119,6 +119,7 @@ var paper = new function() {
/*#*/ if (options.svg) {
/*#*/ include('svg/SVGStyles.js');
/*#*/ include('svg/SVGNamespaces.js');
/*#*/ include('svg/SVGExport.js');
/*#*/ include('svg/SVGImport.js');
/*#*/ } // options.svg

View file

@ -907,6 +907,44 @@ statics: {
getLocationOf: function(point) {
var t = this.getParameterOf.apply(this, arguments);
return t != null ? new CurveLocation(this, t) : null;
},
getNearestLocation: function(point) {
point = Point.read(arguments);
var values = this.getValues(),
step = 1 / 100,
tolerance = Numerical.TOLERANCE,
minDist = Infinity,
minT = 0,
max = 1 + tolerance; // Accomodate imprecision
function refine(t) {
if (t >= 0 && t <= 1) {
var dist = point.getDistance(
Curve.evaluate(values, t, true, 0), true);
if (dist < minDist) {
minDist = dist;
minT = t;
return true;
}
}
}
for (var t = 0; t <= max; t += step)
refine(t);
// Now iteratively refine solution until we reach desired precision.
step /= 2;
while (step > tolerance) {
if (!refine(minT - step) && !refine(minT + step))
step /= 2;
}
var pt = Curve.evaluate(values, minT, true, 0);
return new CurveLocation(this, minT, pt, null, point.getDistance(pt));
},
getNearestPoint: function(point) {
return this.getNearestLocation.apply(this, arguments).getPoint();
}
/**
@ -1061,193 +1099,4 @@ new function() { // Scope for methods that require numerical integration
a, b, 16, /*#=*/ Numerical.TOLERANCE);
}
};
}, new function() { // Scope for nearest point on curve problem
// Solving the Nearest Point-on-Curve Problem and A Bezier-Based Root-Finder
// by Philip J. Schneider from "Graphics Gems", Academic Press, 1990
// Optimised for Paper.js
var maxDepth = 32,
epsilon = Math.pow(2, -maxDepth - 1);
var zCubic = [
[1.0, 0.6, 0.3, 0.1],
[0.4, 0.6, 0.6, 0.4],
[0.1, 0.3, 0.6, 1.0]
];
var xAxis = new Line(new Point(0, 0), new Point(1, 0));
/**
* Given a point and a Bezier curve, generate a 5th-degree Bezier-format
* equation whose solution finds the point on the curve nearest the
* user-defined point.
*/
function toBezierForm(v, point) {
var n = 3, // degree of B(t)
degree = 5, // degree of B(t) . P
c = [],
d = [],
cd = [],
w = [];
for(var i = 0; i <= n; i++) {
// Determine the c's -- these are vectors created by subtracting
// point point from each of the control points
c[i] = v[i].subtract(point);
// Determine the d's -- these are vectors created by subtracting
// each control point from the next
if (i < n)
d[i] = v[i + 1].subtract(v[i]).multiply(n);
}
// Create the c,d table -- this is a table of dot products of the
// c's and d's
for (var row = 0; row < n; row++) {
cd[row] = [];
for (var column = 0; column <= n; column++)
cd[row][column] = d[row].dot(c[column]);
}
// Now, apply the z's to the dot products, on the skew diagonal
// Also, set up the x-values, making these "points"
for (var i = 0; i <= degree; i++)
w[i] = new Point(i / degree, 0);
for (var k = 0; k <= degree; k++) {
var lb = Math.max(0, k - n + 1),
ub = Math.min(k, n);
for (var i = lb; i <= ub; i++) {
var j = k - i;
w[k].y += cd[j][i] * zCubic[j][i];
}
}
return w;
}
/**
* Given a 5th-degree equation in Bernstein-Bezier form, find all of the
* roots in the interval [0, 1]. Return the number of roots found.
*/
function findRoots(w, depth) {
switch (countCrossings(w)) {
case 0:
// No solutions here
return [];
case 1:
// Unique solution
// Stop recursion when the tree is deep enough
// if deep enough, return 1 solution at midpoint
if (depth >= maxDepth)
return [0.5 * (w[0].x + w[5].x)];
// Compute intersection of chord from first control point to last
// with x-axis.
if (isFlatEnough(w)) {
var line = new Line(w[0], w[5], true);
return [ Numerical.isZero(line.vector.getLength(true))
? line.point.x
: xAxis.intersect(line).x ];
}
}
// Otherwise, solve recursively after
// subdividing control polygon
var p = [[]],
left = [],
right = [];
for (var j = 0; j <= 5; j++)
p[0][j] = new Point(w[j]);
// Triangle computation
for (var i = 1; i <= 5; i++) {
p[i] = [];
for (var j = 0 ; j <= 5 - i; j++)
p[i][j] = p[i - 1][j].add(p[i - 1][j + 1]).multiply(0.5);
}
for (var j = 0; j <= 5; j++) {
left[j] = p[j][0];
right[j] = p[5 - j][j];
}
return findRoots(left, depth + 1).concat(findRoots(right, depth + 1));
}
/**
* Count the number of times a Bezier control polygon crosses the x-axis.
* This number is >= the number of roots.
*/
function countCrossings(v) {
var crossings = 0,
prevSign = null;
for (var i = 0, l = v.length; i < l; i++) {
var sign = v[i].y < 0 ? -1 : 1;
if (prevSign != null && sign != prevSign)
crossings++;
prevSign = sign;
}
return crossings;
}
/**
* Check if the control polygon of a Bezier curve is flat enough for
* recursive subdivision to bottom out.
*/
function isFlatEnough(v) {
// Find the perpendicular distance from each interior control point to
// line connecting v[0] and v[degree]
// Derive the implicit equation for line connecting first
// and last control points
var n = v.length - 1,
a = v[0].y - v[n].y,
b = v[n].x - v[0].x,
c = v[0].x * v[n].y - v[n].x * v[0].y,
maxAbove = 0,
maxBelow = 0;
// Find the largest distance
for (var i = 1; i < n; i++) {
// Compute distance from each of the points to that line
var val = a * v[i].x + b * v[i].y + c,
dist = val * val;
if (val < 0 && dist > maxBelow) {
maxBelow = dist;
} else if (dist > maxAbove) {
maxAbove = dist;
}
}
// Compute intercepts of bounding box
return Math.abs((maxAbove + maxBelow) / (2 * a * (a * a + b * b)))
< epsilon;
}
return {
getNearestLocation: function(point) {
// NOTE: If we allow #matrix on Path, we need to inverse-transform
// point here first.
// point = this._matrix.inverseTransform(point);
var w = toBezierForm(this.getPoints(), point);
// Also look at beginning and end of curve (t = 0 / 1)
var roots = findRoots(w, 0).concat([0, 1]);
var minDist = Infinity,
minT,
minPoint;
// There are always roots, since we add [0, 1] above.
for (var i = 0; i < roots.length; i++) {
var pt = this.getPointAt(roots[i], true),
dist = point.getDistance(pt, true);
// We're comparing squared distances
if (dist < minDist) {
minDist = dist;
minT = roots[i];
minPoint = pt;
}
}
return new CurveLocation(this, minT, minPoint, null,
Math.sqrt(minDist));
},
getNearestPoint: function(point) {
return this.getNearestLocation(point).getPoint();
}
};
});

View file

@ -1539,6 +1539,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
* the specified point
*/
getNearestLocation: function(point) {
point = this._matrix.inverseTransform(Point.read(arguments));
var curves = this.getCurves(),
minDist = Infinity,
minLoc = null;
@ -2104,7 +2105,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
// and (through, to), and intersect them to get the center
var l1 = new Line(from.add(through).divide(2),
through.subtract(from).rotate(90)),
l2 = new Line(through.add(to).divide(2),
l2 = new Line(through.add(to).divide(2),
to.subtract(through).rotate(90)),
center = l1.intersect(l2),
line = new Line(from, to, true),

View file

@ -17,7 +17,7 @@
* performance, and has to be tested heavily for stability.
*
* Supported
* - paperjs Path and CompoundPath objects
* - Path and CompoundPath items
* - Boolean Union
* - Boolean Intersection
* - Boolean Subtraction
@ -97,7 +97,7 @@ PathItem.inject(new function() {
return path;
}
function computeBoolean(path1, path2, operator, subtract, _cache) {
function computeBoolean(path1, path2, operator, subtract) {
// We do not modify the operands themselves
// The result might not belong to the same type
// i.e. subtraction(A:Path, B:Path):CompoundPath etc.
@ -106,13 +106,8 @@ PathItem.inject(new function() {
var path1Clockwise = path1.isClockwise(),
path2Clockwise = path2.isClockwise(),
// Calculate all the intersections
intersections = _cache && _cache.intersections
|| path1.getIntersections(path2);
// If we have an empty _cache object as an operand, skip calculating
// boolean and cache the intersections.
// if (_cache && !_cache.intersections)
// return _cache.intersections = intersections;
// Now split intersections on both paths, by asking the first call to
intersections = path1.getIntersections(path2);
// Split intersections on both paths, by asking the first call to
// collect the intersections on the other path for us and passing the
// result of that on to the second call.
splitPath(splitPath(intersections, true));
@ -143,8 +138,9 @@ PathItem.inject(new function() {
&& (clockwise === path2Clockwise
|| !testOnCurve(path2, midPoint));
if (operator(path === path1, insidePath1, insidePath2)) {
// Mark as invalid, but do not remove yet, so the graph
// structure is preserved.
// The segment is to be discarded. Don't add it to segments,
// and mark it as invalid since it might still be found
// through curves / intersections, see below.
segment._invalid = true;
} else {
segments.push(segment);
@ -160,7 +156,8 @@ PathItem.inject(new function() {
loc = segment._intersection,
intersection = loc && loc.getSegment(true);
if (segment.getPrevious()._invalid)
segment.setHandleIn(intersection ? intersection._handleIn
segment.setHandleIn(intersection
? intersection._handleIn
: Point.create(0, 0));
do {
segment._visited = true;
@ -176,7 +173,8 @@ PathItem.inject(new function() {
segment = segment.getNext();
} while (segment && !segment._visited && segment !== intersection);
// Avoid stray segments and incomplete paths
if (path._segments.length > 2) {
var amount = path._segments.length;
if (amount > 1 && (amount > 2 || !path.isPolygon())) {
path.setClosed(true);
result.addChild(path, true);
} else {
@ -219,11 +217,11 @@ PathItem.inject(new function() {
* @param {PathItem} path the path to unite with
* @return {PathItem} the resulting path item
*/
unite: function(path, _cache) {
unite: function(path) {
return computeBoolean(this, path,
function(isPath1, isInPath1, isInPath2) {
return isInPath1 || isInPath2;
}, false, _cache);
});
},
/**
@ -233,11 +231,11 @@ PathItem.inject(new function() {
* @param {PathItem} path the path to intersect with
* @return {PathItem} the resulting path item
*/
intersect: function(path, _cache) {
intersect: function(path) {
return computeBoolean(this, path,
function(isPath1, isInPath1, isInPath2) {
return !(isInPath1 || isInPath2);
}, false, _cache);
});
},
/**
@ -247,11 +245,11 @@ PathItem.inject(new function() {
* @param {PathItem} path the path to subtract
* @return {PathItem} the resulting path item
*/
subtract: function(path, _cache) {
subtract: function(path) {
return computeBoolean(this, path,
function(isPath1, isInPath1, isInPath2) {
return isPath1 && isInPath2 || !isPath1 && !isInPath1;
}, true, _cache);
}, true);
},
// Compound boolean operators combine the basic boolean operations such

View file

@ -526,6 +526,7 @@ var Color = this.Color = Base.extend(new function() {
? 'hsl'
: 'hsb'
: 'gradient' in arg || 'stops' in arg
|| 'radial' in arg
? 'gradient'
: 'gray' in arg
? 'gray'
@ -580,11 +581,12 @@ var Color = this.Color = Base.extend(new function() {
},
_serialize: function(options, dictionary) {
var components = this.getComponents();
return Base.serialize(
// We can ommit the type for gray and rgb:
/^(gray|rgb)$/.test(this._type)
? this._components
: [this._type].concat(this._components),
? components
: [this._type].concat(components),
options, true, dictionary);
},

View file

@ -15,15 +15,12 @@
* Paper.js DOM to a SVG DOM.
*/
new function() {
var formatter = Formatter.instance,
namespaces = {
href: 'http://www.w3.org/1999/xlink'
};
var formatter = Formatter.instance;
function setAttributes(node, attrs) {
for (var key in attrs) {
var val = attrs[key],
namespace = namespaces[key];
namespace = SVGNamespaces[key];
if (typeof val === 'number')
val = formatter.number(val);
if (namespace) {
@ -346,26 +343,26 @@ new function() {
origin = color.getOrigin().transform(matrix),
destination = color.getDestination().transform(matrix),
attrs;
if (radial) {
attrs = {
cx: origin.x,
cy: origin.y,
r: origin.getDistance(destination)
};
var highlight = color.getHighlight();
if (highlight) {
highlight = highlight.transform(matrix);
attrs.fx = highlight.x;
attrs.fy = highlight.y;
}
} else {
attrs = {
x1: origin.x,
y1: origin.y,
x2: destination.x,
y2: destination.y
};
if (radial) {
attrs = {
cx: origin.x,
cy: origin.y,
r: origin.getDistance(destination)
};
var highlight = color.getHighlight();
if (highlight) {
highlight = highlight.transform(matrix);
attrs.fx = highlight.x;
attrs.fy = highlight.y;
}
} else {
attrs = {
x1: origin.x,
y1: origin.y,
x2: destination.x,
y2: destination.y
};
}
attrs.gradientUnits = 'userSpaceOnUse';
gradientNode = createElement(
(radial ? 'radial' : 'linear') + 'Gradient', attrs);
@ -462,10 +459,11 @@ new function() {
function exportDefinitions(node) {
if (!definitions)
return node;
// We can only use node nodes as defintion containers. Have the loop
// We can only use svg nodes as defintion containers. Have the loop
// produce one if it's a single item of another type (when calling
// #exportSVG() on an item rather than a whole project)
var container = node.nodeName == 'svg' && node,
// jsdom in Node.js uses uppercase values for nodeName...
var container = node.nodeName.toLowerCase() === 'svg' && node,
firstChild = container ? container.firstChild : node;
for (var i in definitions.svgs) {
if (!container) {
@ -513,10 +511,19 @@ new function() {
*/
exportSVG: function() {
var node = createElement('svg'),
layers = this.layers;
layers = this.layers,
size = this.view.getSize();
for (var i = 0, l = layers.length; i < l; i++)
node.appendChild(exportSVG(layers[i]));
return exportDefinitions(node);
return setAttributes(exportDefinitions(node), {
x: 0,
y: 0,
width: size.width,
height: size.height,
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg',
xlink: 'http://www.w3.org/1999/xlink'
});
}
});
};

View file

@ -20,22 +20,22 @@ new function() {
// index is option, and if passed, causes a lookup in a list.
function getValue(node, key, allowNull, index) {
// node[key].baseVal will even be set if the node did not define the
// attribute, so if allowNull is true, we need to also check
// node.getAttribute(key) == null
var base = (!allowNull || node.getAttribute(key) != null)
&& node[key] && node[key].baseVal;
var namespace = SVGNamespaces[key];
var value = namespace
? node.getAttributeNS(namespace, key)
: node.getAttribute(key);
// Note: String values are unfortunately not stored in base.value, but
// in base directly, so we need to check both, also on item lists, using
// Base.pick(base.value, base)
return base
? index !== undefined
// Item list? Look up by index:
? index < base.numberOfItems
? Base.pick((base = base.getItem(index)).value, base)
: null
: Base.pick(base.value, base)
: null;
if (index != null && value != null) {
var values = value.split(',');
value = values[index];
if (value == null)
value = values[values.length - 1];
}
if (/^[\d.+-]/.test(value))
value = parseFloat(value);
return value;
}
function getPoint(node, x, y, allowNull, index) {
@ -68,7 +68,7 @@ new function() {
function importGroup(node, type) {
var nodes = node.childNodes,
clip = type === 'clipPath',
clip = type === 'clippath',
item = clip ? new CompoundPath() : new Group(),
project = item._project,
currentStyle = project._currentStyle;
@ -142,7 +142,7 @@ new function() {
if (child.nodeType == 1)
stops.push(applyAttributes(new GradientStop(), child));
}
var isRadial = type === 'radialGradient',
var isRadial = type === 'radialgradient',
gradient = new Gradient(stops, isRadial),
origin, destination, highlight;
if (isRadial) {
@ -160,12 +160,14 @@ new function() {
return null;
}
// NOTE: All importers are lowercase, since jsdom is using uppercase
// nodeNames still.
var importers = {
// http://www.w3.org/TR/SVG/struct.html#Groups
g: importGroup,
// http://www.w3.org/TR/SVG/struct.html#NewDocument
svg: importGroup,
clipPath: importGroup,
clippath: importGroup,
// http://www.w3.org/TR/SVG/shapes.html#PolygonElement
polygon: importPoly,
// http://www.w3.org/TR/SVG/shapes.html#PolylineElement
@ -173,9 +175,9 @@ new function() {
// http://www.w3.org/TR/SVG/paths.html
path: importPath,
// http://www.w3.org/TR/SVG/pservers.html#LinearGradients
linearGradient: importGradient,
lineargradient: importGradient,
// http://www.w3.org/TR/SVG/pservers.html#RadialGradients
radialGradient: importGradient,
radialgradient: importGradient,
// http://www.w3.org/TR/SVG/struct.html#ImageElement
image: function (node) {
@ -271,12 +273,42 @@ new function() {
function applyTransform(item, value, name, node) {
// http://www.w3.org/TR/SVG/types.html#DataTypeTransformList
var transforms = node[name].baseVal,
// Parse SVG transform string. First we split at /)\s*/, to separate
// commands
var transforms = (node.getAttribute(name) || '').split(/\)\s*/g),
matrix = new Matrix();
for (var i = 0, l = transforms.numberOfItems; i < l; i++) {
var mx = transforms.getItem(i).matrix;
matrix.concatenate(
new Matrix(mx.a, mx.b, mx.c, mx.d, mx.e, mx.f));
for (var i = 0, l = transforms.length; i < l; i++) {
var transform = transforms[i];
if (!transform)
break;
// Command come before the '(', values after
var parts = transform.split('('),
command = parts[0],
v = parts[1].split(/[\s,]+/g);
// Convert values to floats
for (var j = 0, m = v.length; j < m; j++)
v[j] = parseFloat(v[j]);
switch (command) {
case 'matrix':
matrix.concatenate(
new Matrix(v[0], v[2], v[1], v[3], v[4], v[5]));
break;
case 'rotate':
matrix.rotate(v[0], v[1], v[2]);
break;
case 'translate':
matrix.translate(v[0], v[1]);
break;
case 'scale':
matrix.scale(v);
break;
case 'skewX':
case 'skewY':
var value = Math.tan(v[0] * Math.PI / 180),
isX = command == 'skewX';
matrix.shear(isX ? value : 0, isX ? 0 : value);
break;
}
}
item.transform(matrix);
}
@ -290,12 +322,15 @@ new function() {
color.setAlpha(parseFloat(value));
}
// Create apply-functions for attributes, and merge in those for SVGStlyes:
var attributes = Base.each(SVGStyles, function(entry) {
// Create apply-functions for attributes, and merge in those for SVGStlyes.
// We need to define style attributes first, and merge in all others after,
// since transform needs to be applied after fill color, as transformations
// can affect gradient fills.
var attributes = Base.merge(Base.each(SVGStyles, function(entry) {
this[entry.attribute] = function(item, value, name, node) {
item._style[entry.set](convertValue(value, entry.type));
};
}, {
}, {}), {
id: function(item, value) {
definitions[value] = item;
if (item.setName)
@ -359,7 +394,9 @@ new function() {
offset: function(item, value) {
// http://www.w3.org/TR/SVG/pservers.html#StopElementOffsetAttribute
var percentage = value.match(/(.*)%$/);
item.setRampPoint(percentage ? percentage[1] / 100 : value);
item.setRampPoint(percentage
? percentage[1] / 100
: parseFloat(value));
},
viewBox: function(item, value, name, node, styles) {
@ -449,7 +486,10 @@ new function() {
}
function importSVG(node, clearDefs) {
var type = node.nodeName,
if (typeof node === 'string')
node = new DOMParser().parseFromString(node, 'image/svg+xml');
// jsdom in Node.js uses uppercase values for nodeName...
var type = node.nodeName.toLowerCase(),
importer = importers[type],
item = importer && importer(node, type),
data = node.getAttribute('data-paper-data');

16
src/svg/SVGNamespaces.js Normal file
View file

@ -0,0 +1,16 @@
/*
* 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.
*/
var SVGNamespaces = {
href: 'http://www.w3.org/1999/xlink',
xlink: 'http://www.w3.org/2000/xmlns'
};

View file

@ -100,23 +100,13 @@ var TextItem = this.TextItem = Item.extend(/** @lends TextItem# */{
* @private
* @deprecated use {@link #getStyle()} instead.
*/
getCharacterStyle: function() {
return this.getStyle();
},
setCharacterStyle: function(style) {
this.setStyle(style);
},
getCharacterStyle: '#getStyle',
setCharacterStyle: '#setStyle',
/**
* @private
* @deprecated use {@link #getStyle()} instead.
*/
getParagraphStyle: function() {
return this.getStyle();
},
setParagraphStyle: function(style) {
this.setStyle(style);
}
getParagraphStyle: '#getStyle',
setParagraphStyle: '#setStyle'
});

View file

@ -414,7 +414,7 @@ var Tool = this.Tool = PaperScopeItem.extend(/** @lends Tool# */{
*
* Attach an event handler to the tool.
*
* @name Tool#attach
* @name Tool#on
* @function
* @param {String('mousedown', 'mouseup', 'mousedrag', 'mousemove',
* 'keydown', 'keyup')} type the event type
@ -424,7 +424,7 @@ var Tool = this.Tool = PaperScopeItem.extend(/** @lends Tool# */{
/**
* Attach one or more event handlers to the tool.
*
* @name Tool#attach^2
* @name Tool#on^2
* @function
* @param {Object} param An object literal containing one or more of the
* following properties: {@code mousedown, mouseup, mousedrag, mousemove,

View file

@ -172,7 +172,6 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
/*#*/ if (options.server) {
// Node.js server based image exporting code.
CanvasView.inject(new function() {
var path = require('path');
// Utility function that converts a number to a string with
// x amount of padded 0 digits:
function toPaddedString(number, length) {
@ -196,7 +195,8 @@ CanvasView.inject(new function() {
var view = this,
count = 0,
frameDuration = 1 / param.fps,
lastTime = startTime = Date.now();
startTime = Date.now(),
lastTime = startTime;
// Start exporting frames by exporting the first frame:
exportFrame(param);
@ -204,8 +204,8 @@ CanvasView.inject(new function() {
function exportFrame(param) {
count++;
var filename = param.prefix + toPaddedString(count, 6) + '.png',
uri = param.directory + '/' + filename;
var out = view.exportImage(uri, function() {
path = param.directory + '/' + filename;
var out = view.exportImage(path, function() {
// When the file has been closed, export the next fame:
var then = Date.now();
if (param.onProgress) {
@ -237,11 +237,11 @@ CanvasView.inject(new function() {
}
}
},
// DOCS: View#exportImage(uri, callback);
exportImage: function(uri, callback) {
// DOCS: View#exportImage(path, callback);
exportImage: function(path, callback) {
this.draw();
// TODO: is it necessary to resolve the path?
var out = fs.createWriteStream(path.resolve(__dirname, uri)),
var out = fs.createWriteStream(path),
stream = this._element.createPNGStream();
// Pipe the png stream to the write stream:
stream.pipe(out);

View file

@ -314,8 +314,8 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
* @type Size
* @bean
*/
getSize: function() {
return this.getBounds().getSize();
getSize: function(/* dontLink */) {
return this.getBounds().getSize(arguments[0]);
},
/**
@ -324,8 +324,8 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
* @type Point
* @bean
*/
getCenter: function() {
return this.getBounds().getCenter();
getCenter: function(/* dontLink */) {
return this.getBounds().getCenter(arguments[0]);
},
setCenter: function(center) {
@ -455,7 +455,7 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
*
* Attach an event handler to the view.
*
* @name View#attach
* @name View#on
* @function
* @param {String('frame', 'resize')} type the event type
* @param {Function} function The function to be called when the event
@ -472,12 +472,12 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
* path.rotate(3);
* };
*
* view.attach('frame', frameHandler);
* view.on('frame', frameHandler);
*/
/**
* Attach one or more event handlers to the view.
*
* @name View#attach^2
* @name View#on^2
* @function
* @param {Object} param An object literal containing one or more of the
* following properties: {@code frame, resize}.
@ -491,7 +491,7 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
* path.rotate(3);
* };
*
* view.attach({
* view.on({
* frame: frameHandler
* });
*/
@ -515,7 +515,7 @@ var View = this.View = Base.extend(Callback, /** @lends View# */{
* path.rotate(3);
* };
*
* view.attach({
* view.on({
* frame: frameHandler
* });
*

View file

@ -203,3 +203,9 @@ test('Item#data', function() {
testExportImportJSON(paper.project);
});
test('Color', function() {
var path = new Path({
fillColor: new Color(1, 1, 0, 0.5)
});
testExportImportJSON(paper.project);
});