mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-28 17:02:24 -05:00
parent
1dcb19ec3b
commit
c479ec9272
21 changed files with 220 additions and 302 deletions
|
@ -1,5 +1,5 @@
|
|||
var paper = require('paper');
|
||||
paper.setup(new paper.Canvas(1024, 768));
|
||||
paper.setup(new paper.Size(1024, 768));
|
||||
|
||||
var layer = paper.project.activeLayer;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ var http = require('http');
|
|||
var paper = require('paper');
|
||||
|
||||
http.createServer(function(request, response) {
|
||||
var canvas = new paper.Canvas(800, 800);
|
||||
var canvas = paper.createCanvas(800, 800);
|
||||
paper.setup(canvas);
|
||||
with(paper) {
|
||||
var style = {
|
||||
|
@ -30,4 +30,4 @@ http.createServer(function(request, response) {
|
|||
});
|
||||
}).listen(3000);
|
||||
|
||||
console.log('Server running at http://127.0.0.1:3000/');
|
||||
console.log('Server running at http://127.0.0.1:3000/');
|
||||
|
|
|
@ -2,12 +2,12 @@ var paper = require('paper'),
|
|||
path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
var canvas = new paper.Canvas(612, 792, 'pdf');
|
||||
var canvas = paper.createCanvas(612, 792, 'pdf');
|
||||
paper.setup(canvas);
|
||||
with (paper) {
|
||||
fs.readFile('./in.json', { encoding: 'utf8' }, function (err, data) {
|
||||
if (err)
|
||||
throw err;
|
||||
throw err;
|
||||
project.importJSON(data);
|
||||
view.update();
|
||||
fs.writeFile(path.resolve(__dirname, 'out.pdf'), canvas.toBuffer(), function (err) {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,7 @@
|
|||
var paper = require('paper');
|
||||
var fs = require('fs');
|
||||
|
||||
var canvas = new paper.Canvas(800, 600);
|
||||
var canvas = paper.createCanvas(800, 600);
|
||||
paper.setup(canvas);
|
||||
|
||||
var url = 'http://assets.paperjs.org/images/marilyn.jpg';
|
||||
|
@ -13,7 +13,7 @@ raster.onLoad = function() {
|
|||
|
||||
// Saving the canvas to a file.
|
||||
out = fs.createWriteStream(__dirname + '/canvas.png');
|
||||
stream = canvas.pngStream();
|
||||
stream = canvas.createPNGStream();
|
||||
|
||||
stream.on('data', function(chunk) {
|
||||
out.write(chunk);
|
||||
|
|
|
@ -2,8 +2,8 @@ var paper = require('paper'),
|
|||
path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
paper.setup(new paper.Canvas(300, 600));
|
||||
with (paper) {
|
||||
paper.setup(new Size(300, 600));
|
||||
var stops = [new Color(1, 1, 0, 0), 'red', 'black'];
|
||||
|
||||
var radius = view.bounds.width * 0.4,
|
||||
|
|
|
@ -2,12 +2,9 @@ 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.setup(new paper.Size(300, 600));
|
||||
paper.project.importSVG('file://' + path.resolve(__dirname, 'in.svg'), {
|
||||
onLoad: function(item) {
|
||||
paper.view.exportFrames({
|
||||
amount: 1,
|
||||
directory: __dirname,
|
||||
|
@ -18,5 +15,5 @@ with (paper) {
|
|||
console.log(event.percentage + '% complete, frame took: ' + event.delta);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -29,9 +29,8 @@
|
|||
"node": ">=0.8.0 <5.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsdom": ">=3.1.2 <8.0.0",
|
||||
"mime": "^1.3.0",
|
||||
"request": "^2.61.0"
|
||||
"jsdom": "git://github.com/lehni/jsdom.git#45c5ad551ff7d12efacac06bea5b29cc3aeadb20",
|
||||
"source-map-support": "^0.4.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"canvas": "^1.2.9"
|
||||
|
|
|
@ -25,12 +25,8 @@ var CanvasProvider = {
|
|||
if (this.canvases.length) {
|
||||
canvas = this.canvases.pop();
|
||||
} else {
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
canvas = document.createElement('canvas');
|
||||
/*#*/ } else { // __options.environment != 'browser'
|
||||
canvas = new Canvas(width, height);
|
||||
clear = false; // It's already cleared through constructor.
|
||||
/*#*/ } // __options.environment != 'browser'
|
||||
clear = false; // It's already cleared through createElement().
|
||||
}
|
||||
var ctx = canvas.getContext('2d');
|
||||
// If they are not the same size, we don't need to clear them
|
||||
|
|
|
@ -71,48 +71,40 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
};
|
||||
CanvasProvider.release(ctx);
|
||||
}
|
||||
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
if (!this.browser) {
|
||||
var agent = navigator.userAgent.toLowerCase(),
|
||||
if (!this.agent) {
|
||||
var user = navigator.userAgent.toLowerCase(),
|
||||
// Detect basic platforms, only mac internally required for now.
|
||||
platform = (/(win)/.exec(agent)
|
||||
|| /(mac)/.exec(agent)
|
||||
|| /(linux)/.exec(agent)
|
||||
|| [])[0],
|
||||
browser = proto.browser = { platform: platform };
|
||||
os = (/(darwin|win|mac|linux|freebsd|sunos)/.exec(user)||[])[0],
|
||||
platform = os === 'darwin' ? 'mac' : os,
|
||||
agent = proto.agent = proto.browser = { platform: platform };
|
||||
if (platform)
|
||||
browser[platform] = true;
|
||||
agent[platform] = true;
|
||||
// Use replace() to get all matches, and deal with Chrome/Webkit
|
||||
// overlap:
|
||||
// TODO: Do we need Mozilla next to Firefox? Other than the
|
||||
// different treatment of the Chrome/Webkit overlap
|
||||
// here: { chrome: true, webkit: false }, Mozilla missing is the
|
||||
// only difference to jQuery.browser
|
||||
agent.replace(
|
||||
/(opera|chrome|safari|webkit|firefox|msie|trident|atom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:([.\d]+))?/g,
|
||||
user.replace(
|
||||
/(opera|chrome|safari|webkit|firefox|msie|trident|atom|node)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g,
|
||||
function(all, n, v1, v2, rv) {
|
||||
// Do not set additional browsers once chrome is detected.
|
||||
if (!browser.chrome) {
|
||||
var v = n === 'opera' ? v2 : v1;
|
||||
if (n === 'trident') {
|
||||
// Use rv: and rename to msie
|
||||
v = rv;
|
||||
n = 'msie';
|
||||
}
|
||||
browser.version = v;
|
||||
browser.versionNumber = parseFloat(v);
|
||||
browser.name = n;
|
||||
browser[n] = true;
|
||||
if (!agent.chrome) {
|
||||
var v = n === 'opera' ? v2 :
|
||||
/^(node|trident)$/.test(n) ? rv : v1;
|
||||
agent.version = v;
|
||||
agent.versionNumber = parseFloat(v);
|
||||
n = n === 'trident' ? 'msie' : n;
|
||||
agent.name = n;
|
||||
agent[n] = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
if (browser.chrome)
|
||||
delete browser.webkit;
|
||||
if (browser.atom)
|
||||
delete browser.chrome;
|
||||
if (agent.chrome)
|
||||
delete agent.webkit;
|
||||
if (agent.atom)
|
||||
delete agent.chrome;
|
||||
}
|
||||
/*#*/ } // __options.environment == 'browser'
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -261,6 +253,18 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
|||
return this;
|
||||
},
|
||||
|
||||
createCanvas: function(width, height, type) {
|
||||
if (type) {
|
||||
// TODO: Support 'pdf' on node.js!
|
||||
}
|
||||
return CanvasProvider.getCanvas(width, height);
|
||||
},
|
||||
|
||||
/**
|
||||
* @deprecated, use use {@link #createCanvas(width, height)} instead.
|
||||
*/
|
||||
Canvas: '#createCanvas',
|
||||
|
||||
/**
|
||||
* Activates this PaperScope, so all newly created items will be placed
|
||||
* in its active project.
|
||||
|
|
|
@ -95,6 +95,8 @@ Base.exports.PaperScript = (function() {
|
|||
return scope.acorn.parse(code, options);
|
||||
}
|
||||
|
||||
var sourceMaps = {};
|
||||
|
||||
/**
|
||||
* Compiles PaperScript code into JavaScript code.
|
||||
*
|
||||
|
@ -261,20 +263,44 @@ Base.exports.PaperScript = (function() {
|
|||
break;
|
||||
}
|
||||
}
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
|
||||
// Source-map support:
|
||||
// Encodes a Variable Length Quantity as a Base64 string.
|
||||
// See: http://www.html5rocks.com/en/tutorials/developertools/sourcemaps
|
||||
function encodeVLQ(value) {
|
||||
var res = '',
|
||||
base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
||||
value = (Math.abs(value) << 1) + (value < 0 ? 1 : 0);
|
||||
while (value || !res) {
|
||||
var next = value & ((1 << 5) - 1);
|
||||
value >>= 5;
|
||||
if (value)
|
||||
next |= (1 << 5);
|
||||
res += base64[next];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
var url = options.url || '',
|
||||
browser = paper.browser,
|
||||
version = browser.versionNumber,
|
||||
agent = paper.agent,
|
||||
version = agent.versionNumber,
|
||||
offsetCode = false,
|
||||
sourceMap = null,
|
||||
// Include the original code in the sourceMap if there is no linked
|
||||
// source file so the debugger can still display it correctly.
|
||||
source = options.source || code,
|
||||
lineBreaks = /\r\n|\n|\r/mg,
|
||||
offset = 0;
|
||||
// TODO: Verify these browser versions for source map support, and check
|
||||
// other browsers.
|
||||
if (browser.chrome && version >= 30
|
||||
|| browser.webkit && version >= 537.76 // >= Safari 7.0.4
|
||||
|| browser.firefox && version >= 23) {
|
||||
if (url && window.location.href.indexOf(url) === 0) {
|
||||
if (agent.chrome && version >= 30
|
||||
|| agent.webkit && version >= 537.76 // >= Safari 7.0.4
|
||||
|| agent.firefox && version >= 23
|
||||
|| agent.node) {
|
||||
if (agent.node) {
|
||||
code = 'require("source-map-support").install(paper.PaperScript.sourceMapSupport);\n' + code;
|
||||
offset = -3; // -2 for function body, - 1 for require("source-map-support")
|
||||
} else if (url && window.location.href.indexOf(url) === 0) {
|
||||
// If the code stems from the actual html page, determine the
|
||||
// offset of inlined code.
|
||||
var html = document.getElementsByTagName('html')[0].innerHTML;
|
||||
|
@ -283,16 +309,17 @@ Base.exports.PaperScript = (function() {
|
|||
offset = html.substr(0, html.indexOf(code) + 1).match(
|
||||
lineBreaks).length + 1;
|
||||
}
|
||||
// A hack required by all current browser versions: Instead of
|
||||
// starting the mappings at the given offset, we have to shift the
|
||||
// actual code down to the place in the original file, as source-map
|
||||
// support seems incomplete in these browsers. This has some
|
||||
// advantages too: No code for VLQ encoding is required.
|
||||
// A hack required by most versions of browsers except chrome 36+:
|
||||
// Instead of starting the mappings at the given offset, we have to
|
||||
// shift the actual code down to the place in the original file, as
|
||||
// source-map support seems incomplete in these browsers.
|
||||
// TODO: Report as bugs?
|
||||
var mappings = ['AAAA'];
|
||||
// Create empty entries by the amount of lines + 1, so join can be
|
||||
offsetCode = offset > 0 && (!browser.chrome || version < 36);
|
||||
var mappings = ['AA' + encodeVLQ(offsetCode ? 0 : offset) + 'A'];
|
||||
// Create empty entries by the amount of lines + 1, so join can be
|
||||
// used below to produce the actual instructions that many times.
|
||||
mappings.length = (code.match(lineBreaks) || []).length + 1 + offset;
|
||||
mappings.length = (code.match(lineBreaks) || []).length + 1
|
||||
+ (offsetCode ? offset : 0);
|
||||
sourceMap = {
|
||||
version: 3,
|
||||
file: url,
|
||||
|
@ -303,29 +330,24 @@ Base.exports.PaperScript = (function() {
|
|||
// AACA is the instruction to increment the line by one.
|
||||
mappings: mappings.join(';AACA'),
|
||||
sourceRoot: '',
|
||||
sources: [url]
|
||||
sources: [url],
|
||||
sourcesContent: [source]
|
||||
};
|
||||
// Include the original code in the sourceMap if there is no linked
|
||||
// source file so the debugger can still display it correctly.
|
||||
var source = options.source || !url && code;
|
||||
if (source)
|
||||
sourceMap.sourcesContent = [source];
|
||||
}
|
||||
// Now do the parsing magic
|
||||
walkAST(parse(code, { ranges: true }));
|
||||
if (sourceMap) {
|
||||
// Adjust the line offset of the resulting code if required.
|
||||
// This is part of a browser hack, see above.
|
||||
code = new Array(offset + 1).join('\n') + code
|
||||
+ "\n//# sourceMappingURL=data:application/json;base64,"
|
||||
+ (btoa(unescape(encodeURIComponent(
|
||||
JSON.stringify(sourceMap)))))
|
||||
if (offsetCode)
|
||||
code = new Array(offset + 1).join('\n') + code;
|
||||
code += "\n//# sourceMappingURL=data:application/json;base64,"
|
||||
+ window.btoa(unescape(encodeURIComponent(
|
||||
JSON.stringify(sourceMap))))
|
||||
+ "\n//# sourceURL=" + (url || 'paperscript');
|
||||
if (url)
|
||||
sourceMaps[url] = sourceMap;
|
||||
}
|
||||
/*#*/ } else { // __options.environment != 'browser'
|
||||
// Now do the parsing magic
|
||||
walkAST(parse(code, { ranges: true }));
|
||||
/*#*/ } // __options.environment != 'browser'
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -405,9 +427,8 @@ Base.exports.PaperScript = (function() {
|
|||
// We need an additional line that returns the handlers in one object.
|
||||
if (handlers)
|
||||
code += '\nreturn { ' + handlers + ' };';
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
var browser = paper.browser;
|
||||
if (browser.chrome || browser.firefox) {
|
||||
var agent = paper.agent;
|
||||
if (agent.chrome || agent.firefox) {
|
||||
// On Firefox, all error numbers inside dynamically compiled code
|
||||
// are relative to the line where the eval / compilation happened.
|
||||
// To fix this issue, we're temporarily inserting a new script
|
||||
|
@ -418,7 +439,7 @@ Base.exports.PaperScript = (function() {
|
|||
head = document.head || document.getElementsByTagName('head')[0];
|
||||
// Add a new-line before the code on Firefox since the error
|
||||
// messages appear to be aligned to line number 0...
|
||||
if (browser.firefox)
|
||||
if (agent.firefox)
|
||||
code = '\n' + code;
|
||||
script.appendChild(document.createTextNode(
|
||||
'paper._execute = function(' + params + ') {' + code + '\n}'
|
||||
|
@ -430,9 +451,6 @@ Base.exports.PaperScript = (function() {
|
|||
} else {
|
||||
func = Function(params, code);
|
||||
}
|
||||
/*#*/ } else { // __options.environment != 'browser'
|
||||
func = Function(params, code);
|
||||
/*#*/ } // __options.environment != 'browser'
|
||||
var res = func.apply(scope, args) || {};
|
||||
// Now install the 'global' tool and view handlers, and we're done!
|
||||
Base.each(toolHandlers, function(key) {
|
||||
|
@ -456,8 +474,6 @@ Base.exports.PaperScript = (function() {
|
|||
}
|
||||
}
|
||||
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
|
||||
function loadScript(script) {
|
||||
// Only load this script if it not loaded already.
|
||||
// Support both text/paperscript and text/x-paperscript:
|
||||
|
@ -546,43 +562,14 @@ Base.exports.PaperScript = (function() {
|
|||
compile: compile,
|
||||
execute: execute,
|
||||
load: load,
|
||||
parse: parse
|
||||
parse: parse,
|
||||
sourceMapSupport: {
|
||||
retrieveSourceMap: function(source) {
|
||||
var map = sourceMaps[source];
|
||||
return map ? { url: source, map: map } : null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*#*/ } else { // __options.environment != 'browser'
|
||||
/*#*/ if (__options.environment == 'node') {
|
||||
|
||||
// Register the .pjs extension for automatic compilation as PaperScript
|
||||
var fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
require.extensions['.pjs'] = function(module, uri) {
|
||||
// Requiring a PaperScript on Node.js returns an initialize method which
|
||||
// needs to receive a Canvas object when called and returns the
|
||||
// PaperScope.
|
||||
module.exports = function(canvas) {
|
||||
var source = compile(fs.readFileSync(uri, 'utf8')),
|
||||
scope = new PaperScope();
|
||||
scope.setup(canvas);
|
||||
scope.__filename = uri;
|
||||
scope.__dirname = path.dirname(uri);
|
||||
// Expose core methods and values
|
||||
scope.require = require;
|
||||
scope.console = console;
|
||||
execute(source, scope);
|
||||
return scope;
|
||||
};
|
||||
};
|
||||
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
|
||||
return {
|
||||
compile: compile,
|
||||
execute: execute,
|
||||
parse: parse
|
||||
};
|
||||
|
||||
/*#*/ } // __options.environment != 'browser'
|
||||
// Pass on `this` as the binding object, so we can reference Acorn both in
|
||||
// development and in the built library.
|
||||
}).call(this);
|
||||
|
|
|
@ -67,8 +67,8 @@ var Key = new function() {
|
|||
// based on whichever key is used for commands.
|
||||
command: {
|
||||
get: function() {
|
||||
var browser = paper.browser;
|
||||
return browser && browser.mac ? this.meta : this.control;
|
||||
var agent = paper.agent;
|
||||
return agent && agent.mac ? this.meta : this.control;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -108,8 +108,8 @@ var Key = new function() {
|
|||
// Detect modifiers and mark them as pressed / released
|
||||
if (key.length > 1 && (name = Base.camelize(key)) in modifiers) {
|
||||
modifiers[name] = down;
|
||||
var browser = paper.browser;
|
||||
if (name === 'meta' && browser && browser.mac) {
|
||||
var agent = paper.agent;
|
||||
if (name === 'meta' && agent && agent.mac) {
|
||||
// Fix a strange behavior on Mac where no keyup events are
|
||||
// received for any keys pressed while the meta key is down.
|
||||
// Keep track of the normal keys being pressed and trigger keyup
|
||||
|
@ -142,14 +142,14 @@ var Key = new function() {
|
|||
DomEvent.add(document, {
|
||||
keydown: function(event) {
|
||||
var key = getKey(event),
|
||||
browser = paper.browser;
|
||||
agent = paper.agent;
|
||||
// Directly handle any special keys (key.length > 1) in keydown, as
|
||||
// not all of them will receive keypress events.
|
||||
// Chrome doesn't fire keypress events for command and alt keys,
|
||||
// so we need to handle this in a way that works across all OSes.
|
||||
if (key.length > 1 || browser && (browser.chrome && (event.altKey
|
||||
|| browser.mac && event.metaKey
|
||||
|| !browser.mac && event.ctrlKey))) {
|
||||
if (key.length > 1 || agent && (agent.chrome && (event.altKey
|
||||
|| agent.mac && event.metaKey
|
||||
|| !agent.mac && event.ctrlKey))) {
|
||||
handleKey(true, key,
|
||||
charLookup[key] || (key.length > 1 ? '' : key), event);
|
||||
} else {
|
||||
|
|
|
@ -26,6 +26,24 @@ paper = new (PaperScope.inject(Base.exports, {
|
|||
Key: Key
|
||||
}))();
|
||||
|
||||
/*#*/ } else if (__options.environment == 'node') {
|
||||
|
||||
paper = new (PaperScope.inject(Base.exports, {
|
||||
// Mark fields as enumerable so PaperScope.inject can pick them up
|
||||
enumerable: true,
|
||||
Base: Base,
|
||||
Numerical: Numerical,
|
||||
// Export dom/node.js stuff too
|
||||
XMLSerializer: XMLSerializer,
|
||||
DOMParser: DOMParser,
|
||||
HTMLCanvasElement: HTMLCanvasElement,
|
||||
Image: Image,
|
||||
document: document,
|
||||
window: window
|
||||
}))();
|
||||
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
|
||||
// https://github.com/umdjs/umd
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// Support AMD (e.g. require.js)
|
||||
|
@ -39,21 +57,3 @@ if (typeof define === 'function' && define.amd) {
|
|||
// the Base constructor function after straps.js is included.
|
||||
module.exports = paper;
|
||||
}
|
||||
|
||||
/*#*/ } else if (__options.environment == 'node') {
|
||||
|
||||
paper = new (PaperScope.inject(Base.exports, {
|
||||
// Mark fields as enumerable so PaperScope.inject can pick them up
|
||||
enumerable: true,
|
||||
Base: Base,
|
||||
Numerical: Numerical,
|
||||
// Export dom/node.js stuff too
|
||||
XMLSerializer: XMLSerializer,
|
||||
DOMParser: DOMParser,
|
||||
Canvas: Canvas
|
||||
}))();
|
||||
|
||||
// Export the paper scope.
|
||||
module.exports = paper;
|
||||
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
|
|
|
@ -324,10 +324,6 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
*/
|
||||
getSource: function() {
|
||||
var image = this._image;
|
||||
/*#*/ if (__options.environment == 'node') {
|
||||
// See #toDataURL()
|
||||
image = image && this._src;
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
return image && image.src || this.toDataURL();
|
||||
},
|
||||
|
||||
|
@ -346,14 +342,11 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
}
|
||||
}
|
||||
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
// src can be an URL or a DOM ID to load the image from
|
||||
image = document.getElementById(src) || new Image();
|
||||
if (crossOrigin)
|
||||
image.crossOrigin = crossOrigin;
|
||||
// IE has naturalWidth / Height defined, but width / height set to 0
|
||||
// when the image is invisible in the document.
|
||||
if (image.naturalWidth && image.naturalHeight) {
|
||||
if (image.complete) {
|
||||
// Emit load event with a delay, so behavior is the same as when
|
||||
// it's actually loaded and we give the code time to install event.
|
||||
setTimeout(loaded, 0);
|
||||
|
@ -365,54 +358,6 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
image.src = src;
|
||||
}
|
||||
this.setImage(image);
|
||||
/*#*/ } else if (__options.environment == 'node') {
|
||||
image = new Image();
|
||||
if (crossOrigin)
|
||||
image.crossOrigin = crossOrigin;
|
||||
// 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._src since canvas-node eats it.
|
||||
image.src = src;
|
||||
this._src = { src: src, data: src };
|
||||
// Emit load event with a delay, so behavior is the same as when
|
||||
// it's actually loaded and we give the code time to install event.
|
||||
setTimeout(loaded, 0);
|
||||
} else if (/^https?:\/\//.test(src)) {
|
||||
// Load it from remote location:
|
||||
require('request').get({
|
||||
url: src,
|
||||
encoding: null // So the response data is a Buffer
|
||||
}, function (err, response, buffer) {
|
||||
if (err)
|
||||
throw err;
|
||||
if (response.statusCode == 200) {
|
||||
image.src = buffer;
|
||||
that._src = {
|
||||
src: src,
|
||||
buffer: buffer,
|
||||
type: response.headers['content-type']
|
||||
};
|
||||
loaded();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Load it from disk:
|
||||
src = (src.match(/^file:\/\/(.*)$/) || [null, src])[1];
|
||||
require('fs').readFile(src, function (err, buffer) {
|
||||
if (err)
|
||||
throw err;
|
||||
image.src = buffer;
|
||||
that._src = {
|
||||
src: 'file://' + src,
|
||||
buffer: buffer,
|
||||
type: require('mime').lookup(src)
|
||||
};
|
||||
loaded();
|
||||
});
|
||||
}
|
||||
this.setImage(image);
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -500,21 +445,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
|||
// See if the linked image is base64 encoded already, if so reuse it,
|
||||
// otherwise try using canvas.toDataURL()
|
||||
var image = this._image,
|
||||
src;
|
||||
/*#*/ if (__options.environment == 'node') {
|
||||
// Only use the information stored in _src if we still use the _image
|
||||
// that goes with it.
|
||||
var obj = image && this._src;
|
||||
if (obj) {
|
||||
if (!obj.data) {
|
||||
obj.data = 'data:' + obj.type + ';base64,' +
|
||||
obj.buffer.toString('base64');
|
||||
}
|
||||
src = obj.data;
|
||||
}
|
||||
/*#*/ } else {
|
||||
src = image && image.src;
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
src = image && image.src;
|
||||
if (/^data:/.test(src))
|
||||
return src;
|
||||
var canvas = this.getCanvas();
|
||||
|
|
|
@ -14,7 +14,7 @@ var Http = {
|
|||
request: function(method, url, callback, async) {
|
||||
// Code borrowed from Coffee Script and extended:
|
||||
async = (async === undefined) ? true : async;
|
||||
var ctor = window.ActiveXObject || XMLHttpRequest,
|
||||
var ctor = window.ActiveXObject || window.XMLHttpRequest,
|
||||
xhr = new ctor('Microsoft.XMLHTTP');
|
||||
xhr.open(method.toUpperCase(), url, async);
|
||||
if ('overrideMimeType' in xhr)
|
||||
|
|
|
@ -17,15 +17,32 @@
|
|||
Image:true */
|
||||
|
||||
var jsdom = require('jsdom'),
|
||||
// Node Canvas library: https://github.com/learnboost/node-canvas
|
||||
Canvas = require('canvas'),
|
||||
// Expose global browser variables and create a document and a window using
|
||||
// jsdom, e.g. for import/exportSVG()
|
||||
document = jsdom.jsdom('<html><body></body></html>'),
|
||||
idlUtils = require('jsdom/lib/jsdom/living/generated/utils'),
|
||||
fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
// Expose global browser variables and create a document and a window using
|
||||
// jsdom.
|
||||
var document = jsdom.jsdom('<html><body></body></html>', {
|
||||
features: {
|
||||
FetchExternalResources : ['img', 'script']
|
||||
}
|
||||
}),
|
||||
window = document.defaultView,
|
||||
navigator = window.navigator,
|
||||
HTMLCanvasElement = Canvas,
|
||||
Image = Canvas.Image;
|
||||
HTMLCanvasElement = window.HTMLCanvasElement,
|
||||
Image = window.Image;
|
||||
|
||||
Base.each(
|
||||
['pngStream', 'createPNGStream', 'jpgStream', 'createJPGStream'],
|
||||
function(key) {
|
||||
this[key] = function() {
|
||||
var impl = idlUtils.implForWrapper(this),
|
||||
canvas = impl && impl._canvas;
|
||||
return canvas[key].apply(canvas, arguments);
|
||||
};
|
||||
},
|
||||
HTMLCanvasElement.prototype);
|
||||
|
||||
// Define XMLSerializer and DOMParser shims, to emulate browser behavior.
|
||||
// TODO: Put this into a simple node module, with dependency on jsdom?
|
||||
|
@ -56,3 +73,24 @@ DOMParser.prototype.parseFromString = function(string, contenType) {
|
|||
div.innerHTML = string;
|
||||
return div.firstChild;
|
||||
};
|
||||
|
||||
// Register the .pjs extension for automatic compilation as PaperScript
|
||||
require.extensions['.pjs'] = function(module, filename) {
|
||||
// Requiring a PaperScript on Node.js returns an initialize method which
|
||||
// needs to receive a Canvas object when called and returns the
|
||||
// PaperScope.
|
||||
module.exports = function(canvas) {
|
||||
var source = fs.readFileSync(filename, 'utf8');
|
||||
scope = new paper.PaperScope();
|
||||
scope.setup(canvas);
|
||||
scope.__filename = filename;
|
||||
scope.__dirname = path.dirname(filename);
|
||||
// Expose core methods and values
|
||||
scope.require = require;
|
||||
scope.console = console;
|
||||
paper.PaperScript.execute(source, scope, {
|
||||
url: filename
|
||||
});
|
||||
return scope;
|
||||
};
|
||||
};
|
30
src/paper.js
30
src/paper.js
|
@ -44,6 +44,10 @@ var paper = new function(undefined) {
|
|||
/*#*/ include('constants.js');
|
||||
/*#*/ }
|
||||
|
||||
/*#*/ if (__options.environment == 'node') {
|
||||
/*#*/ include('node.js');
|
||||
/*#*/ }
|
||||
|
||||
/*#*/ include('core/Base.js');
|
||||
/*#*/ include('core/Emitter.js');
|
||||
/*#*/ include('core/PaperScope.js');
|
||||
|
@ -64,7 +68,7 @@ var paper = new function(undefined) {
|
|||
/*#*/ include('basic/Line.js');
|
||||
|
||||
/*#*/ include('project/Project.js');
|
||||
/*#*/ include('project/Symbol.js');
|
||||
// /*#*/ include('project/Symbol.js');
|
||||
|
||||
/*#*/ include('item/Item.js');
|
||||
/*#*/ include('item/Group.js');
|
||||
|
@ -96,29 +100,21 @@ var paper = new function(undefined) {
|
|||
/*#*/ include('style/GradientStop.js');
|
||||
/*#*/ include('style/Style.js');
|
||||
|
||||
/*#*/ if (__options.environment == 'node') {
|
||||
/*#*/ include('dom/node.js');
|
||||
/*#*/ }
|
||||
/*#*/ include('dom/DomElement.js');
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
// DomEvent doesn't make sense outside of the browser (yet)
|
||||
/*#*/ include('dom/DomEvent.js');
|
||||
/*#*/ }
|
||||
/*#*/ include('dom/DomEvent.js');
|
||||
|
||||
/*#*/ include('view/View.js');
|
||||
/*#*/ include('view/CanvasView.js');
|
||||
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
/*#*/ include('event/Event.js');
|
||||
/*#*/ include('event/KeyEvent.js');
|
||||
/*#*/ include('event/Key.js');
|
||||
/*#*/ include('event/MouseEvent.js');
|
||||
/*#*/ include('event/Event.js');
|
||||
/*#*/ include('event/KeyEvent.js');
|
||||
/*#*/ include('event/Key.js');
|
||||
/*#*/ include('event/MouseEvent.js');
|
||||
|
||||
/*#*/ include('tool/ToolEvent.js');
|
||||
/*#*/ include('tool/Tool.js');
|
||||
/*#*/ include('tool/ToolEvent.js');
|
||||
/*#*/ include('tool/Tool.js');
|
||||
|
||||
/*#*/ include('net/Http.js');
|
||||
/*#*/ }
|
||||
/*#*/ include('net/Http.js');
|
||||
|
||||
/*#*/ include('canvas/CanvasProvider.js');
|
||||
/*#*/ include('canvas/BlendMode.js');
|
||||
|
|
|
@ -566,7 +566,6 @@ new function() {
|
|||
// as this is how SVG works too.
|
||||
// See if it's a string but handle markup separately
|
||||
if (typeof source === 'string' && !/^.*</.test(source)) {
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
// First see if we're meant to import an element with the given
|
||||
// id.
|
||||
node = document.getElementById(source);
|
||||
|
@ -577,9 +576,6 @@ new function() {
|
|||
} else {
|
||||
return Http.request('get', source, onLoadCallback);
|
||||
}
|
||||
/*#*/ } else if (__options.environment == 'node') {
|
||||
// TODO: Implement!
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
} else if (typeof File !== 'undefined' && source instanceof File) {
|
||||
// Load local file through FileReader
|
||||
var reader = new FileReader();
|
||||
|
|
|
@ -44,7 +44,6 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
|||
}
|
||||
this._context = canvas.getContext('2d');
|
||||
this._pixelRatio = 1;
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) {
|
||||
// Hi-DPI Canvas support based on:
|
||||
// http://www.html5rocks.com/en/tutorials/canvas/hidpi/
|
||||
|
@ -53,19 +52,15 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
|||
'backingStorePixelRatio') || 1;
|
||||
this._pixelRatio = deviceRatio / backingStoreRatio;
|
||||
}
|
||||
/*#*/ } // __options.environment == 'browser'
|
||||
View.call(this, project, canvas);
|
||||
},
|
||||
|
||||
_setViewSize: function(size) {
|
||||
var element = this._element,
|
||||
pixelRatio = this._pixelRatio,
|
||||
width = size.width,
|
||||
height = size.height;
|
||||
_setViewSize: function _setViewSize(width, height) {
|
||||
var pixelRatio = this._pixelRatio;
|
||||
// Upscale the canvas if the pixel ratio is more than 1.
|
||||
element.width = width * pixelRatio;
|
||||
element.height = height * pixelRatio;
|
||||
_setViewSize.base.call(this, width * pixelRatio, height * pixelRatio);
|
||||
if (pixelRatio !== 1) {
|
||||
var element = this._element;
|
||||
// We need to set the correct size on non-resizable canvases through
|
||||
// their style when HiDPI is active, as otherwise they would appear
|
||||
// too big.
|
||||
|
@ -85,9 +80,9 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
|||
* pixels.
|
||||
*/
|
||||
getPixelSize: function(size) {
|
||||
var browser = paper.browser,
|
||||
var agent = paper.agent,
|
||||
pixels;
|
||||
if (browser && browser.firefox) {
|
||||
if (agent && agent.firefox) {
|
||||
// Firefox doesn't appear to convert context.font sizes to pixels,
|
||||
// while other browsers do. Workaround:
|
||||
var parent = this._element.parentNode,
|
||||
|
@ -132,9 +127,6 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
|||
var project = this._project;
|
||||
if (!project || !force && !project._needsUpdate)
|
||||
return false;
|
||||
// Initial tests conclude that clearing the canvas using clearRect
|
||||
// is always faster than setting canvas.width = canvas.width
|
||||
// http://jsperf.com/clearrect-vs-setting-width/7
|
||||
var ctx = this._context,
|
||||
size = this._viewSize;
|
||||
ctx.clearRect(0, 0, size.width + 1, size.height + 1);
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
* center, both useful for constructing artwork that should appear centered on
|
||||
* screen.
|
||||
*/
|
||||
/* jshint -W082 */// Do not complain about functions inside Prepro.js statements
|
||||
var View = Base.extend(Emitter, /** @lends View# */{
|
||||
_class: 'View',
|
||||
|
||||
|
@ -29,8 +28,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
this._project = project;
|
||||
this._scope = project._scope;
|
||||
this._element = element;
|
||||
var size;
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
// Sub-classes may set _pixelRatio first
|
||||
if (!this._pixelRatio)
|
||||
this._pixelRatio = window.devicePixelRatio || 1;
|
||||
|
@ -80,7 +77,8 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
// it might have been set to a % size, in which case it would use some
|
||||
// default internal size (300x150 on WebKit) and scale up the pixels.
|
||||
// We also need this call here for HiDPI support.
|
||||
this._setViewSize(size = getCanvasSize());
|
||||
var size = this._viewSize = getCanvasSize();
|
||||
this._setViewSize(size.width, size.height);
|
||||
// TODO: Test this on IE:
|
||||
if (PaperScope.hasAttribute(element, 'stats')
|
||||
&& typeof Stats !== 'undefined') {
|
||||
|
@ -94,19 +92,10 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
style.top = offset.y + 'px';
|
||||
document.body.appendChild(stats);
|
||||
}
|
||||
/*#*/ } else if (__options.environment == 'node') {
|
||||
// Sub-classes may set _pixelRatio first
|
||||
if (!this._pixelRatio)
|
||||
this._pixelRatio = 1;
|
||||
// Generate an id for this view
|
||||
this._id = 'view-' + View._id++;
|
||||
size = new Size(element.width, element.height);
|
||||
/*#*/ } // __options.environment == 'node'
|
||||
// Keep track of views internally
|
||||
View._views.push(this);
|
||||
// Link this id to our view
|
||||
View._viewsById[this._id] = this;
|
||||
this._viewSize = size;
|
||||
(this._matrix = new Matrix())._owner = this;
|
||||
this._zoom = 1;
|
||||
// Make sure the first view is focused for keyboard input straight away
|
||||
|
@ -135,11 +124,9 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
var project = this._project;
|
||||
if (project._view === this)
|
||||
project._view = null;
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
// Uninstall event handlers again for this view.
|
||||
DomEvent.remove(this._element, this._viewEvents);
|
||||
DomEvent.remove(window, this._windowEvents);
|
||||
/*#*/ } // __options.environment == 'browser'
|
||||
this._element = this._project = null;
|
||||
// Remove all onFrame handlers.
|
||||
// TODO: Shouldn't we remove all handlers, automatically
|
||||
|
@ -174,7 +161,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
_count: 0,
|
||||
|
||||
_requestFrame: function() {
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
var that = this;
|
||||
DomEvent.requestAnimationFrame(function() {
|
||||
that._requested = false;
|
||||
|
@ -186,7 +172,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
that._handleFrame();
|
||||
}, this._element);
|
||||
this._requested = true;
|
||||
/*#*/ } // __options.environment == 'browser'
|
||||
},
|
||||
|
||||
_handleFrame: function() {
|
||||
|
@ -319,11 +304,13 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
|
||||
setViewSize: function(/* size */) {
|
||||
var size = Size.read(arguments),
|
||||
width = size.width,
|
||||
height = size.height,
|
||||
delta = size.subtract(this._viewSize);
|
||||
if (delta.isZero())
|
||||
return;
|
||||
this._viewSize.set(size.width, size.height);
|
||||
this._setViewSize(size);
|
||||
this._viewSize.set(width, height);
|
||||
this._setViewSize(width, height);
|
||||
// Call onResize handler on any size change
|
||||
this.emit('resize', {
|
||||
size: size,
|
||||
|
@ -334,12 +321,14 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* Private method, overriden in CanvasView for HiDPI support.
|
||||
* Private method, overridden in CanvasView for HiDPI support.
|
||||
*/
|
||||
_setViewSize: function(size) {
|
||||
_setViewSize: function(width, height) {
|
||||
var element = this._element;
|
||||
element.width = size.width;
|
||||
element.height = size.height;
|
||||
if (element.width !== width)
|
||||
element.width = width;
|
||||
if (element.height !== height)
|
||||
element.height = height;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -556,12 +545,10 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
*/
|
||||
play: function() {
|
||||
this._animate = true;
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
// Request a frame handler straight away to initialize the
|
||||
// sequence of onFrame calls.
|
||||
if (!this._requested)
|
||||
this._requestFrame();
|
||||
/*#*/ } // __options.environment == 'browser'
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -806,10 +793,8 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
_id: 0,
|
||||
|
||||
create: function(project, element) {
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
if (typeof element === 'string')
|
||||
element = document.getElementById(element);
|
||||
/*#*/ } // __options.environment == 'browser'
|
||||
// Factory to provide the right View subclass for a given element.
|
||||
// Produces only CanvasViews for now:
|
||||
return new CanvasView(project, element);
|
||||
|
@ -817,8 +802,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
}
|
||||
},
|
||||
new function() { // Injection scope for mouse events on the browser
|
||||
/*#*/ if (__options.environment == 'browser') {
|
||||
|
||||
/**
|
||||
* Native event handling, coordinate conversion, focus handling and
|
||||
* delegation to view and tool objects.
|
||||
|
@ -1227,5 +1210,4 @@ new function() { // Injection scope for mouse events on the browser
|
|||
updateFocus: updateFocus
|
||||
}
|
||||
};
|
||||
/*#*/ } // __options.environment == 'browser'
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue