mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Merge branch 'unified-version' into develop
This commit is contained in:
commit
9ad63a7231
34 changed files with 459 additions and 13870 deletions
13375
dist/paper-core.js
vendored
13375
dist/paper-core.js
vendored
File diff suppressed because it is too large
Load diff
1
dist/paper-core.js
vendored
Symbolic link
1
dist/paper-core.js
vendored
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../src/load.js
|
1
dist/paper-node.js
vendored
1
dist/paper-node.js
vendored
|
@ -1 +0,0 @@
|
||||||
../src/load.js
|
|
|
@ -1,5 +1,5 @@
|
||||||
var paper = require('paper');
|
var paper = require('paper');
|
||||||
paper.setup(new paper.Canvas(1024, 768));
|
paper.setup(new paper.Size(1024, 768));
|
||||||
|
|
||||||
var layer = paper.project.activeLayer;
|
var layer = paper.project.activeLayer;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ var http = require('http');
|
||||||
var paper = require('paper');
|
var paper = require('paper');
|
||||||
|
|
||||||
http.createServer(function(request, response) {
|
http.createServer(function(request, response) {
|
||||||
var canvas = new paper.Canvas(800, 800);
|
var canvas = paper.createCanvas(800, 800);
|
||||||
paper.setup(canvas);
|
paper.setup(canvas);
|
||||||
with(paper) {
|
with(paper) {
|
||||||
var style = {
|
var style = {
|
||||||
|
@ -30,4 +30,4 @@ http.createServer(function(request, response) {
|
||||||
});
|
});
|
||||||
}).listen(3000);
|
}).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'),
|
path = require('path'),
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
|
|
||||||
var canvas = new paper.Canvas(612, 792, 'pdf');
|
var canvas = paper.createCanvas(612, 792, 'pdf');
|
||||||
paper.setup(canvas);
|
paper.setup(canvas);
|
||||||
with (paper) {
|
with (paper) {
|
||||||
fs.readFile('./in.json', { encoding: 'utf8' }, function (err, data) {
|
fs.readFile('./in.json', { encoding: 'utf8' }, function (err, data) {
|
||||||
if (err)
|
if (err)
|
||||||
throw err;
|
throw err;
|
||||||
project.importJSON(data);
|
project.importJSON(data);
|
||||||
view.update();
|
view.update();
|
||||||
fs.writeFile(path.resolve(__dirname, 'out.pdf'), canvas.toBuffer(), function (err) {
|
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 paper = require('paper');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
var canvas = new paper.Canvas(800, 600);
|
var canvas = paper.createCanvas(800, 600);
|
||||||
paper.setup(canvas);
|
paper.setup(canvas);
|
||||||
|
|
||||||
var url = 'http://assets.paperjs.org/images/marilyn.jpg';
|
var url = 'http://assets.paperjs.org/images/marilyn.jpg';
|
||||||
|
@ -13,7 +13,7 @@ raster.onLoad = function() {
|
||||||
|
|
||||||
// Saving the canvas to a file.
|
// Saving the canvas to a file.
|
||||||
out = fs.createWriteStream(__dirname + '/canvas.png');
|
out = fs.createWriteStream(__dirname + '/canvas.png');
|
||||||
stream = canvas.pngStream();
|
stream = canvas.createPNGStream();
|
||||||
|
|
||||||
stream.on('data', function(chunk) {
|
stream.on('data', function(chunk) {
|
||||||
out.write(chunk);
|
out.write(chunk);
|
||||||
|
|
|
@ -2,8 +2,8 @@ var paper = require('paper'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
|
|
||||||
paper.setup(new paper.Canvas(300, 600));
|
|
||||||
with (paper) {
|
with (paper) {
|
||||||
|
paper.setup(new Size(300, 600));
|
||||||
var stops = [new Color(1, 1, 0, 0), 'red', 'black'];
|
var stops = [new Color(1, 1, 0, 0), 'red', 'black'];
|
||||||
|
|
||||||
var radius = view.bounds.width * 0.4,
|
var radius = view.bounds.width * 0.4,
|
||||||
|
|
|
@ -2,12 +2,9 @@ var paper = require('paper'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
fs = require('fs');
|
fs = require('fs');
|
||||||
|
|
||||||
paper.setup(new paper.Canvas(300, 600));
|
paper.setup(new paper.Size(300, 600));
|
||||||
with (paper) {
|
paper.project.importSVG('file://' + path.resolve(__dirname, 'in.svg'), {
|
||||||
fs.readFile('./in.svg', { encoding: 'utf8' }, function (err, data) {
|
onLoad: function(item) {
|
||||||
if (err)
|
|
||||||
throw err;
|
|
||||||
project.importSVG(data);
|
|
||||||
paper.view.exportFrames({
|
paper.view.exportFrames({
|
||||||
amount: 1,
|
amount: 1,
|
||||||
directory: __dirname,
|
directory: __dirname,
|
||||||
|
@ -18,5 +15,5 @@ with (paper) {
|
||||||
console.log(event.percentage + '% complete, frame took: ' + event.delta);
|
console.log(event.percentage + '% complete, frame took: ' + event.delta);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
}
|
});
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -19,7 +19,10 @@
|
||||||
var scale = (Math.sin(event.time * 2) + 1) / 2;
|
var scale = (Math.sin(event.time * 2) + 1) / 2;
|
||||||
raster.scale(scale / lastScale);
|
raster.scale(scale / lastScale);
|
||||||
lastScale = scale;
|
lastScale = scale;
|
||||||
raster.position = center + [Math.sin(event.time * 3) * 256, Math.sin(event.time * 2.5) * 256];
|
raster.position = center + [
|
||||||
|
Math.sin(event.time * 3) * 256,
|
||||||
|
Math.sin(event.time * 2.5) * 256
|
||||||
|
];
|
||||||
raster.rotate(event.delta * 120);
|
raster.rotate(event.delta * 120);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -23,8 +23,7 @@ var gulp = require('gulp'),
|
||||||
// object, merged in with the options required above.
|
// object, merged in with the options required above.
|
||||||
var buildOptions = {
|
var buildOptions = {
|
||||||
full: { paperScript: true },
|
full: { paperScript: true },
|
||||||
core: { paperScript: false },
|
core: { paperScript: false }
|
||||||
node: { environment: 'node', paperScript: true }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var buildNames = Object.keys(buildOptions);
|
var buildNames = Object.keys(buildOptions);
|
||||||
|
@ -32,9 +31,13 @@ var buildNames = Object.keys(buildOptions);
|
||||||
gulp.task('build',
|
gulp.task('build',
|
||||||
buildNames.map(function(name) {
|
buildNames.map(function(name) {
|
||||||
return 'build:' + name;
|
return 'build:' + name;
|
||||||
})
|
}).concat(['build:copy'])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gulp.task('build:copy', function() {
|
||||||
|
gulp.src(['src/node/*.js']).pipe(gulp.dest('dist/node'));
|
||||||
|
});
|
||||||
|
|
||||||
buildNames.forEach(function(name) {
|
buildNames.forEach(function(name) {
|
||||||
gulp.task('build:' + name, ['clean:build:' + name, 'minify:acorn'], function() {
|
gulp.task('build:' + name, ['clean:build:' + name, 'minify:acorn'], function() {
|
||||||
return gulp.src('src/paper.js')
|
return gulp.src('src/paper.js')
|
||||||
|
|
|
@ -17,12 +17,9 @@ var gulp = require('gulp'),
|
||||||
gulp.task('load', ['clean:load'], function() {
|
gulp.task('load', ['clean:load'], function() {
|
||||||
return gulp.src('src/load.js')
|
return gulp.src('src/load.js')
|
||||||
.pipe(symlink('dist/paper-full.js'))
|
.pipe(symlink('dist/paper-full.js'))
|
||||||
.pipe(symlink('dist/paper-node.js'));
|
.pipe(symlink('dist/paper-core.js'));
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('clean:load', function() {
|
gulp.task('clean:load', function() {
|
||||||
return del([
|
return del([ 'dist/paper-full.js', 'dist/paper-core.js', 'dist/node/**' ]);
|
||||||
'dist/paper-full.js',
|
|
||||||
'dist/paper-node.js'
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
10
package.json
10
package.json
|
@ -13,8 +13,7 @@
|
||||||
"Jürg Lehni <juerg@scratchdisk.com> (http://scratchdisk.com)",
|
"Jürg Lehni <juerg@scratchdisk.com> (http://scratchdisk.com)",
|
||||||
"Jonathan Puckey <jonathan@studiomoniker.com> (http://studiomoniker.com)"
|
"Jonathan Puckey <jonathan@studiomoniker.com> (http://studiomoniker.com)"
|
||||||
],
|
],
|
||||||
"main": "dist/paper-node.js",
|
"main": "dist/paper-full.js",
|
||||||
"browser": "dist/paper-full.js",
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "jshint src"
|
"lint": "jshint src"
|
||||||
},
|
},
|
||||||
|
@ -29,12 +28,11 @@
|
||||||
"node": ">=0.8.0 <5.0.0"
|
"node": ">=0.8.0 <5.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsdom": ">=3.1.2 <8.0.0",
|
"jsdom": "git://github.com/lehni/jsdom.git#3d55789d0f4d55392721b1e22890837fde472375",
|
||||||
"mime": "^1.3.0",
|
"source-map-support": "^0.4.0"
|
||||||
"request": "^2.61.0"
|
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"canvas": "^1.2.9"
|
"canvas": "^1.3.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"acorn": "~0.5.0",
|
"acorn": "~0.5.0",
|
||||||
|
|
|
@ -25,12 +25,8 @@ var CanvasProvider = {
|
||||||
if (this.canvases.length) {
|
if (this.canvases.length) {
|
||||||
canvas = this.canvases.pop();
|
canvas = this.canvases.pop();
|
||||||
} else {
|
} else {
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
canvas = document.createElement('canvas');
|
canvas = document.createElement('canvas');
|
||||||
/*#*/ } else { // __options.environment != 'browser'
|
clear = false; // It's already cleared through createElement().
|
||||||
canvas = new Canvas(width, height);
|
|
||||||
clear = false; // It's already cleared through constructor.
|
|
||||||
/*#*/ } // __options.environment != 'browser'
|
|
||||||
}
|
}
|
||||||
var ctx = canvas.getContext('2d');
|
var ctx = canvas.getContext('2d');
|
||||||
// If they are not the same size, we don't need to clear them
|
// If they are not the same size, we don't need to clear them
|
||||||
|
|
|
@ -71,48 +71,40 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
};
|
};
|
||||||
CanvasProvider.release(ctx);
|
CanvasProvider.release(ctx);
|
||||||
}
|
}
|
||||||
|
if (!this.agent) {
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
var user = window.navigator.userAgent.toLowerCase(),
|
||||||
if (!this.browser) {
|
|
||||||
var agent = navigator.userAgent.toLowerCase(),
|
|
||||||
// Detect basic platforms, only mac internally required for now.
|
// Detect basic platforms, only mac internally required for now.
|
||||||
platform = (/(win)/.exec(agent)
|
os = (/(darwin|win|mac|linux|freebsd|sunos)/.exec(user)||[])[0],
|
||||||
|| /(mac)/.exec(agent)
|
platform = os === 'darwin' ? 'mac' : os,
|
||||||
|| /(linux)/.exec(agent)
|
agent = proto.agent = proto.browser = { platform: platform };
|
||||||
|| [])[0],
|
|
||||||
browser = proto.browser = { platform: platform };
|
|
||||||
if (platform)
|
if (platform)
|
||||||
browser[platform] = true;
|
agent[platform] = true;
|
||||||
// Use replace() to get all matches, and deal with Chrome/Webkit
|
// Use replace() to get all matches, and deal with Chrome/Webkit
|
||||||
// overlap:
|
// overlap:
|
||||||
// TODO: Do we need Mozilla next to Firefox? Other than the
|
// TODO: Do we need Mozilla next to Firefox? Other than the
|
||||||
// different treatment of the Chrome/Webkit overlap
|
// different treatment of the Chrome/Webkit overlap
|
||||||
// here: { chrome: true, webkit: false }, Mozilla missing is the
|
// here: { chrome: true, webkit: false }, Mozilla missing is the
|
||||||
// only difference to jQuery.browser
|
// only difference to jQuery.browser
|
||||||
agent.replace(
|
user.replace(
|
||||||
/(opera|chrome|safari|webkit|firefox|msie|trident|atom)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:([.\d]+))?/g,
|
/(opera|chrome|safari|webkit|firefox|msie|trident|atom|node)\/?\s*([.\d]+)(?:.*version\/([.\d]+))?(?:.*rv\:v?([.\d]+))?/g,
|
||||||
function(all, n, v1, v2, rv) {
|
function(all, n, v1, v2, rv) {
|
||||||
// Do not set additional browsers once chrome is detected.
|
// Do not set additional browsers once chrome is detected.
|
||||||
if (!browser.chrome) {
|
if (!agent.chrome) {
|
||||||
var v = n === 'opera' ? v2 : v1;
|
var v = n === 'opera' ? v2 :
|
||||||
if (n === 'trident') {
|
/^(node|trident)$/.test(n) ? rv : v1;
|
||||||
// Use rv: and rename to msie
|
agent.version = v;
|
||||||
v = rv;
|
agent.versionNumber = parseFloat(v);
|
||||||
n = 'msie';
|
n = n === 'trident' ? 'msie' : n;
|
||||||
}
|
agent.name = n;
|
||||||
browser.version = v;
|
agent[n] = true;
|
||||||
browser.versionNumber = parseFloat(v);
|
|
||||||
browser.name = n;
|
|
||||||
browser[n] = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (browser.chrome)
|
if (agent.chrome)
|
||||||
delete browser.webkit;
|
delete agent.webkit;
|
||||||
if (browser.atom)
|
if (agent.atom)
|
||||||
delete browser.chrome;
|
delete agent.chrome;
|
||||||
}
|
}
|
||||||
/*#*/ } // __options.environment == 'browser'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -261,6 +253,18 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
return this;
|
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
|
* Activates this PaperScope, so all newly created items will be placed
|
||||||
* in its active project.
|
* in its active project.
|
||||||
|
|
|
@ -102,13 +102,14 @@ Base.exports.PaperScript = (function() {
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* @option options.url {String} the url of the source, for source-map
|
* @option options.url {String} the url of the source, for source-map
|
||||||
* debugging
|
* generation
|
||||||
* @option options.source {String} the source to be used for the source-
|
* @option options.source {String} the source to be used for the source-
|
||||||
* mapping, in case the code that's passed in has already been mingled.
|
* mapping, in case the code that's passed in has already been mingled.
|
||||||
*
|
*
|
||||||
* @param {String} code the PaperScript code
|
* @param {String} code the PaperScript code
|
||||||
* @param {Object} [option] the compilation options
|
* @param {Object} [option] the compilation options
|
||||||
* @return {String} the compiled PaperScript translated into JavaScript code
|
* @return {Object} an object holding the compiled PaperScript translated
|
||||||
|
* into JavaScript code along with source-maps and other information.
|
||||||
*/
|
*/
|
||||||
function compile(code, options) {
|
function compile(code, options) {
|
||||||
if (!code)
|
if (!code)
|
||||||
|
@ -261,20 +262,46 @@ Base.exports.PaperScript = (function() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
// Source-map support:
|
// 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 & (32 - 1);
|
||||||
|
value >>= 5;
|
||||||
|
if (value)
|
||||||
|
next |= 32;
|
||||||
|
res += base64[next];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
var url = options.url || '',
|
var url = options.url || '',
|
||||||
browser = paper.browser,
|
agent = paper.agent,
|
||||||
version = browser.versionNumber,
|
version = agent.versionNumber,
|
||||||
sourceMap = null,
|
offsetCode = false,
|
||||||
|
sourceMaps = options.sourceMaps,
|
||||||
|
// 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,
|
lineBreaks = /\r\n|\n|\r/mg,
|
||||||
offset = 0;
|
offset = options.offset || 0,
|
||||||
|
map;
|
||||||
// TODO: Verify these browser versions for source map support, and check
|
// TODO: Verify these browser versions for source map support, and check
|
||||||
// other browsers.
|
// other browsers.
|
||||||
if (browser.chrome && version >= 30
|
if (sourceMaps && (agent.chrome && version >= 30
|
||||||
|| browser.webkit && version >= 537.76 // >= Safari 7.0.4
|
|| agent.webkit && version >= 537.76 // >= Safari 7.0.4
|
||||||
|| browser.firefox && version >= 23) {
|
|| agent.firefox && version >= 23
|
||||||
if (url && window.location.href.indexOf(url) === 0) {
|
|| agent.node)) {
|
||||||
|
if (agent.node) {
|
||||||
|
// -2 required to remove function header:
|
||||||
|
// https://code.google.com/p/chromium/issues/detail?id=331655
|
||||||
|
offset -= 2;
|
||||||
|
} else if (url && window.location.href.indexOf(url) === 0) {
|
||||||
// If the code stems from the actual html page, determine the
|
// If the code stems from the actual html page, determine the
|
||||||
// offset of inlined code.
|
// offset of inlined code.
|
||||||
var html = document.getElementsByTagName('html')[0].innerHTML;
|
var html = document.getElementsByTagName('html')[0].innerHTML;
|
||||||
|
@ -283,17 +310,21 @@ Base.exports.PaperScript = (function() {
|
||||||
offset = html.substr(0, html.indexOf(code) + 1).match(
|
offset = html.substr(0, html.indexOf(code) + 1).match(
|
||||||
lineBreaks).length + 1;
|
lineBreaks).length + 1;
|
||||||
}
|
}
|
||||||
// A hack required by all current browser versions: Instead of
|
// A hack required by older versions of browsers to align inlined
|
||||||
// starting the mappings at the given offset, we have to shift the
|
// code: Instead of starting the mappings at the given offset, we
|
||||||
// actual code down to the place in the original file, as source-map
|
// have to shift the actual code down to the place in the original
|
||||||
// support seems incomplete in these browsers. This has some
|
// file, as source-map support seems incomplete in these browsers.
|
||||||
// advantages too: No code for VLQ encoding is required.
|
offsetCode = offset > 0 && !(
|
||||||
// TODO: Report as bugs?
|
agent.chrome && version >= 36 ||
|
||||||
var mappings = ['AAAA'];
|
agent.safari && version >= 600 ||
|
||||||
// Create empty entries by the amount of lines + 1, so join can be
|
agent.firefox && version >= 40 ||
|
||||||
|
agent.node);
|
||||||
|
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.
|
// 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
|
||||||
sourceMap = {
|
+ (offsetCode ? offset : 0);
|
||||||
|
map = {
|
||||||
version: 3,
|
version: 3,
|
||||||
file: url,
|
file: url,
|
||||||
names:[],
|
names:[],
|
||||||
|
@ -301,32 +332,34 @@ Base.exports.PaperScript = (function() {
|
||||||
// the lines of the original code, all that is required is a
|
// the lines of the original code, all that is required is a
|
||||||
// mappings string that increments by one between each line.
|
// mappings string that increments by one between each line.
|
||||||
// AACA is the instruction to increment the line by one.
|
// AACA is the instruction to increment the line by one.
|
||||||
|
// TODO: Add support for column offsets!
|
||||||
mappings: mappings.join(';AACA'),
|
mappings: mappings.join(';AACA'),
|
||||||
sourceRoot: '',
|
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
|
// Now do the parsing magic
|
||||||
walkAST(parse(code, { ranges: true }));
|
walkAST(parse(code, { ranges: true }));
|
||||||
if (sourceMap) {
|
if (map) {
|
||||||
// Adjust the line offset of the resulting code if required.
|
if (offsetCode) {
|
||||||
// This is part of a browser hack, see above.
|
// Adjust the line offset of the resulting code if required.
|
||||||
code = new Array(offset + 1).join('\n') + code
|
// This is part of a browser hack, see above.
|
||||||
+ "\n//# sourceMappingURL=data:application/json;base64,"
|
code = new Array(offset + 1).join('\n') + code;
|
||||||
+ (btoa(unescape(encodeURIComponent(
|
}
|
||||||
JSON.stringify(sourceMap)))))
|
if (/^(inline|both)$/.test(sourceMaps)) {
|
||||||
+ "\n//# sourceURL=" + (url || 'paperscript');
|
code += "\n//# sourceMappingURL=data:application/json;base64,"
|
||||||
|
+ window.btoa(unescape(encodeURIComponent(
|
||||||
|
JSON.stringify(map))));
|
||||||
|
}
|
||||||
|
code += "\n//# sourceURL=" + (url || 'paperscript');
|
||||||
}
|
}
|
||||||
/*#*/ } else { // __options.environment != 'browser'
|
return {
|
||||||
// Now do the parsing magic
|
url: url,
|
||||||
walkAST(parse(code, { ranges: true }));
|
source: source,
|
||||||
/*#*/ } // __options.environment != 'browser'
|
code: code,
|
||||||
return code;
|
map: map
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -340,14 +373,15 @@ Base.exports.PaperScript = (function() {
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* @option options.url {String} the url of the source, for source-map
|
* @option options.url {String} the url of the source, for source-map
|
||||||
* debugging
|
* generation
|
||||||
* @option options.source {String} the source to be used for the source-
|
* @option options.source {String} the source to be used for the source-
|
||||||
* mapping, in case the code that's passed in has already been mingled.
|
* mapping, in case the code that's passed in has already been mingled.
|
||||||
*
|
*
|
||||||
* @param {String} code the PaperScript code
|
* @param {String} code the PaperScript code
|
||||||
* @param {PaperScope} scope the scope for which the code is executed
|
* @param {PaperScope} scope the scope for which the code is executed
|
||||||
* @param {Object} [option] the compilation options
|
* @param {Object} [option] the compilation options
|
||||||
* @return {String} the compiled PaperScript translated into JavaScript code
|
* @return {Object} an object holding the compiled PaperScript translated
|
||||||
|
* into JavaScript code along with source-maps and other information.
|
||||||
*/
|
*/
|
||||||
function execute(code, scope, options) {
|
function execute(code, scope, options) {
|
||||||
// Set currently active scope.
|
// Set currently active scope.
|
||||||
|
@ -371,8 +405,9 @@ Base.exports.PaperScript = (function() {
|
||||||
// function call.
|
// function call.
|
||||||
params = [],
|
params = [],
|
||||||
args = [],
|
args = [],
|
||||||
func;
|
func,
|
||||||
code = compile(code, options);
|
compiled = typeof code === 'object' ? code : compile(code, options);
|
||||||
|
code = compiled.code;
|
||||||
function expose(scope, hidden) {
|
function expose(scope, hidden) {
|
||||||
// Look through all enumerable properties on the scope and expose
|
// Look through all enumerable properties on the scope and expose
|
||||||
// these too as pseudo-globals, but only if they seem to be in use.
|
// these too as pseudo-globals, but only if they seem to be in use.
|
||||||
|
@ -405,20 +440,19 @@ Base.exports.PaperScript = (function() {
|
||||||
// We need an additional line that returns the handlers in one object.
|
// We need an additional line that returns the handlers in one object.
|
||||||
if (handlers)
|
if (handlers)
|
||||||
code += '\nreturn { ' + handlers + ' };';
|
code += '\nreturn { ' + handlers + ' };';
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
var agent = paper.agent;
|
||||||
var browser = paper.browser;
|
if (agent.chrome || agent.firefox && agent.versionNumber < 40) {
|
||||||
if (browser.chrome || browser.firefox) {
|
// On older Firefox, all error numbers inside dynamically compiled
|
||||||
// On Firefox, all error numbers inside dynamically compiled code
|
// code are relative to the line where the eval / compilation
|
||||||
// are relative to the line where the eval / compilation happened.
|
// happened. To fix this issue, we're temporarily inserting a new
|
||||||
// To fix this issue, we're temporarily inserting a new script
|
// script tag.
|
||||||
// tag. We also use this on Chrome to fix an issue with compiled
|
// We also use this on Chrome to fix issues with compiled functions:
|
||||||
// functions:
|
|
||||||
// https://code.google.com/p/chromium/issues/detail?id=331655
|
// https://code.google.com/p/chromium/issues/detail?id=331655
|
||||||
var script = document.createElement('script'),
|
var script = document.createElement('script'),
|
||||||
head = document.head || document.getElementsByTagName('head')[0];
|
head = document.head || document.getElementsByTagName('head')[0];
|
||||||
// Add a new-line before the code on Firefox since the error
|
// Add a new-line before the code on Firefox since the error
|
||||||
// messages appear to be aligned to line number 0...
|
// messages appear to be aligned to line number 0...
|
||||||
if (browser.firefox)
|
if (agent.firefox)
|
||||||
code = '\n' + code;
|
code = '\n' + code;
|
||||||
script.appendChild(document.createTextNode(
|
script.appendChild(document.createTextNode(
|
||||||
'paper._execute = function(' + params + ') {' + code + '\n}'
|
'paper._execute = function(' + params + ') {' + code + '\n}'
|
||||||
|
@ -430,9 +464,6 @@ Base.exports.PaperScript = (function() {
|
||||||
} else {
|
} else {
|
||||||
func = Function(params, code);
|
func = Function(params, code);
|
||||||
}
|
}
|
||||||
/*#*/ } else { // __options.environment != 'browser'
|
|
||||||
func = Function(params, code);
|
|
||||||
/*#*/ } // __options.environment != 'browser'
|
|
||||||
var res = func.apply(scope, args) || {};
|
var res = func.apply(scope, args) || {};
|
||||||
// Now install the 'global' tool and view handlers, and we're done!
|
// Now install the 'global' tool and view handlers, and we're done!
|
||||||
Base.each(toolHandlers, function(key) {
|
Base.each(toolHandlers, function(key) {
|
||||||
|
@ -454,10 +485,9 @@ Base.exports.PaperScript = (function() {
|
||||||
// Automatically update view at the end.
|
// Automatically update view at the end.
|
||||||
view.update();
|
view.update();
|
||||||
}
|
}
|
||||||
|
return compiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
|
|
||||||
function loadScript(script) {
|
function loadScript(script) {
|
||||||
// Only load this script if it not loaded already.
|
// Only load this script if it not loaded already.
|
||||||
// Support both text/paperscript and text/x-paperscript:
|
// Support both text/paperscript and text/x-paperscript:
|
||||||
|
@ -548,41 +578,6 @@ Base.exports.PaperScript = (function() {
|
||||||
load: load,
|
load: load,
|
||||||
parse: parse
|
parse: parse
|
||||||
};
|
};
|
||||||
|
|
||||||
/*#*/ } 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
|
// Pass on `this` as the binding object, so we can reference Acorn both in
|
||||||
// development and in the built library.
|
// development and in the built library.
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
|
|
@ -22,6 +22,7 @@ var Event = Base.extend(/** @lends Event# */{
|
||||||
|
|
||||||
initialize: function Event(event) {
|
initialize: function Event(event) {
|
||||||
this.event = event;
|
this.event = event;
|
||||||
|
this.type = event.type;
|
||||||
},
|
},
|
||||||
|
|
||||||
prevented: false,
|
prevented: false,
|
||||||
|
|
|
@ -67,8 +67,8 @@ var Key = new function() {
|
||||||
// based on whichever key is used for commands.
|
// based on whichever key is used for commands.
|
||||||
command: {
|
command: {
|
||||||
get: function() {
|
get: function() {
|
||||||
var browser = paper.browser;
|
var agent = paper.agent;
|
||||||
return browser && browser.mac ? this.meta : this.control;
|
return agent && agent.mac ? this.meta : this.control;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -108,8 +108,8 @@ var Key = new function() {
|
||||||
// Detect modifiers and mark them as pressed / released
|
// Detect modifiers and mark them as pressed / released
|
||||||
if (key.length > 1 && (name = Base.camelize(key)) in modifiers) {
|
if (key.length > 1 && (name = Base.camelize(key)) in modifiers) {
|
||||||
modifiers[name] = down;
|
modifiers[name] = down;
|
||||||
var browser = paper.browser;
|
var agent = paper.agent;
|
||||||
if (name === 'meta' && browser && browser.mac) {
|
if (name === 'meta' && agent && agent.mac) {
|
||||||
// Fix a strange behavior on Mac where no keyup events are
|
// Fix a strange behavior on Mac where no keyup events are
|
||||||
// received for any keys pressed while the meta key is down.
|
// received for any keys pressed while the meta key is down.
|
||||||
// Keep track of the normal keys being pressed and trigger keyup
|
// Keep track of the normal keys being pressed and trigger keyup
|
||||||
|
@ -142,14 +142,14 @@ var Key = new function() {
|
||||||
DomEvent.add(document, {
|
DomEvent.add(document, {
|
||||||
keydown: function(event) {
|
keydown: function(event) {
|
||||||
var key = getKey(event),
|
var key = getKey(event),
|
||||||
browser = paper.browser;
|
agent = paper.agent;
|
||||||
// Directly handle any special keys (key.length > 1) in keydown, as
|
// Directly handle any special keys (key.length > 1) in keydown, as
|
||||||
// not all of them will receive keypress events.
|
// not all of them will receive keypress events.
|
||||||
// Chrome doesn't fire keypress events for command and alt keys,
|
// 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.
|
// so we need to handle this in a way that works across all OSes.
|
||||||
if (key.length > 1 || browser && (browser.chrome && (event.altKey
|
if (key.length > 1 || agent && (agent.chrome && (event.altKey
|
||||||
|| browser.mac && event.metaKey
|
|| agent.mac && event.metaKey
|
||||||
|| !browser.mac && event.ctrlKey))) {
|
|| !agent.mac && event.ctrlKey))) {
|
||||||
handleKey(true, key,
|
handleKey(true, key,
|
||||||
charLookup[key] || (key.length > 1 ? '' : key), event);
|
charLookup[key] || (key.length > 1 ? '' : key), event);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
// First add Base and a couple of other objects that are not automatically
|
// First add Base and a couple of other objects that are not automatically
|
||||||
// exported to exports (Numerical, Key, etc), then inject all exports into
|
// exported to exports (Numerical, Key, etc), then inject all exports into
|
||||||
// PaperScope, and create the initial paper object, all in one statement:
|
// PaperScope, and create the initial paper object, all in one statement:
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
|
|
||||||
// NOTE: Do not create local variable `var paper` since it would shield the
|
// NOTE: Do not create local variable `var paper` since it would shield the
|
||||||
// global one in the whole scope.
|
// global one in the whole scope.
|
||||||
|
|
||||||
|
@ -23,9 +21,18 @@ paper = new (PaperScope.inject(Base.exports, {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
Base: Base,
|
Base: Base,
|
||||||
Numerical: Numerical,
|
Numerical: Numerical,
|
||||||
Key: Key
|
Key: Key,
|
||||||
|
// Export jsdom document and window too, for Node.js
|
||||||
|
document: document,
|
||||||
|
window: window
|
||||||
}))();
|
}))();
|
||||||
|
|
||||||
|
// If we're on node, require some additional functionality now before finishing:
|
||||||
|
// - PaperScript support in require() with sourceMaps
|
||||||
|
// - exportFrames / exportImage on CanvasView
|
||||||
|
if (paper.agent.node)
|
||||||
|
require('./node/extend')(paper);
|
||||||
|
|
||||||
// https://github.com/umdjs/umd
|
// https://github.com/umdjs/umd
|
||||||
if (typeof define === 'function' && define.amd) {
|
if (typeof define === 'function' && define.amd) {
|
||||||
// Support AMD (e.g. require.js)
|
// Support AMD (e.g. require.js)
|
||||||
|
@ -39,21 +46,3 @@ if (typeof define === 'function' && define.amd) {
|
||||||
// the Base constructor function after straps.js is included.
|
// the Base constructor function after straps.js is included.
|
||||||
module.exports = paper;
|
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'
|
|
||||||
|
|
21
src/init.js
Normal file
21
src/init.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
|
* http://paperjs.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||||
|
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||||
|
*
|
||||||
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Here we only make sure that there's a window and document object in the node
|
||||||
|
// environment. We can't do this directly in src/paper.js, due to the nature of
|
||||||
|
// how Prepro.js loads the include() files in the various scenarios. E.g. on
|
||||||
|
// Node.js,only the files included in such a way see each other's variables in
|
||||||
|
// their shared scope.
|
||||||
|
|
||||||
|
/* global document:true, window:true */
|
||||||
|
window = window || require('./node/window');
|
||||||
|
var document = window.document;
|
|
@ -145,7 +145,8 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
// Only for external sources, e.g. Raster
|
// Only for external sources, e.g. Raster
|
||||||
onLoad: {}
|
onLoad: {},
|
||||||
|
onError: {}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|
|
@ -221,6 +221,33 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
},
|
},
|
||||||
|
|
||||||
setImage: function(image) {
|
setImage: function(image) {
|
||||||
|
var that = this,
|
||||||
|
loaded = false;
|
||||||
|
|
||||||
|
function emit(event) {
|
||||||
|
var view = that.getView(),
|
||||||
|
type = event && event.type || 'load';
|
||||||
|
if (view && that.responds(type)) {
|
||||||
|
paper = view._scope;
|
||||||
|
that.emit(type, new Event(event));
|
||||||
|
// TODO: Request a redraw in the next animation frame from
|
||||||
|
// update() instead!
|
||||||
|
view.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
// Both canvas and image have width / height attributes. Due to IE,
|
||||||
|
// naturalWidth / Height needs to be checked for a swell, because it
|
||||||
|
// apparently can have width / height set to 0 when the image is
|
||||||
|
// invisible in the document.
|
||||||
|
that._size = new Size(
|
||||||
|
image ? image.naturalWidth || image.width : 0,
|
||||||
|
image ? image.naturalHeight || image.height : 0);
|
||||||
|
that._context = null;
|
||||||
|
that._changed(/*#=*/(Change.GEOMETRY | Change.PIXELS));
|
||||||
|
}
|
||||||
|
|
||||||
if (this._canvas)
|
if (this._canvas)
|
||||||
CanvasProvider.release(this._canvas);
|
CanvasProvider.release(this._canvas);
|
||||||
// Due to similarities, we can handle both canvas and image types here.
|
// Due to similarities, we can handle both canvas and image types here.
|
||||||
|
@ -228,22 +255,30 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
// A canvas object
|
// A canvas object
|
||||||
this._image = null;
|
this._image = null;
|
||||||
this._canvas = image;
|
this._canvas = image;
|
||||||
this._loaded = true;
|
loaded = true;
|
||||||
} else {
|
} else {
|
||||||
// A image object
|
// A image object
|
||||||
this._image = image;
|
this._image = image;
|
||||||
this._canvas = null;
|
this._canvas = null;
|
||||||
this._loaded = image && image.complete;
|
loaded = image && image.complete;
|
||||||
|
}
|
||||||
|
this._loaded = loaded;
|
||||||
|
if (loaded) {
|
||||||
|
// 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.
|
||||||
|
update();
|
||||||
|
setTimeout(emit, 0);
|
||||||
|
} else if (image) {
|
||||||
|
// Trigger the load event on the image once it's loaded
|
||||||
|
DomEvent.add(image, {
|
||||||
|
load: function(event) {
|
||||||
|
that._loaded = true;
|
||||||
|
update();
|
||||||
|
emit(event);
|
||||||
|
},
|
||||||
|
error: emit
|
||||||
|
});
|
||||||
}
|
}
|
||||||
// Both canvas and image have width / height attributes. Due to IE,
|
|
||||||
// naturalWidth / Height needs to be checked for a swell, because it
|
|
||||||
// apparently can have width / height set to 0 when the image is
|
|
||||||
// invisible in the document.
|
|
||||||
this._size = new Size(
|
|
||||||
image ? image.naturalWidth || image.width : 0,
|
|
||||||
image ? image.naturalHeight || image.height : 0);
|
|
||||||
this._context = null;
|
|
||||||
this._changed(/*#=*/(Change.GEOMETRY | Change.PIXELS));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -324,95 +359,19 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
*/
|
*/
|
||||||
getSource: function() {
|
getSource: function() {
|
||||||
var image = this._image;
|
var image = this._image;
|
||||||
/*#*/ if (__options.environment == 'node') {
|
|
||||||
// See #toDataURL()
|
|
||||||
image = image && this._src;
|
|
||||||
/*#*/ } // __options.environment == 'node'
|
|
||||||
return image && image.src || this.toDataURL();
|
return image && image.src || this.toDataURL();
|
||||||
},
|
},
|
||||||
|
|
||||||
setSource: function(src) {
|
setSource: function(src) {
|
||||||
var that = this,
|
var crossOrigin = this._crossOrigin,
|
||||||
crossOrigin = this._crossOrigin,
|
// src can be an URL or a DOM ID to load the image from:
|
||||||
image;
|
image = document.getElementById(src) || new window.Image();
|
||||||
|
|
||||||
function loaded() {
|
|
||||||
var view = that.getView();
|
|
||||||
if (view) {
|
|
||||||
paper = view._scope;
|
|
||||||
that.setImage(image);
|
|
||||||
that.emit('load');
|
|
||||||
view.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*#*/ 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)
|
if (crossOrigin)
|
||||||
image.crossOrigin = crossOrigin;
|
image.crossOrigin = crossOrigin;
|
||||||
// IE has naturalWidth / Height defined, but width / height set to 0
|
// A new image created above? Set the source now.
|
||||||
// when the image is invisible in the document.
|
if (!image.src)
|
||||||
if (image.naturalWidth && image.naturalHeight) {
|
|
||||||
// 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 {
|
|
||||||
// Trigger the load event on the image once it's loaded
|
|
||||||
DomEvent.add(image, { load: loaded });
|
|
||||||
// A new image created above? Set the source now.
|
|
||||||
if (!image.src)
|
|
||||||
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;
|
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);
|
this.setImage(image);
|
||||||
/*#*/ } // __options.environment == 'node'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -500,21 +459,7 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
// See if the linked image is base64 encoded already, if so reuse it,
|
// See if the linked image is base64 encoded already, if so reuse it,
|
||||||
// otherwise try using canvas.toDataURL()
|
// otherwise try using canvas.toDataURL()
|
||||||
var image = this._image,
|
var image = this._image,
|
||||||
src;
|
src = image && 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'
|
|
||||||
if (/^data:/.test(src))
|
if (/^data:/.test(src))
|
||||||
return src;
|
return src;
|
||||||
var canvas = this.getCanvas();
|
var canvas = this.getCanvas();
|
||||||
|
|
22
src/load.js
22
src/load.js
|
@ -14,7 +14,7 @@
|
||||||
// the browser, avoiding the step of having to manually preprocess it after each
|
// the browser, avoiding the step of having to manually preprocess it after each
|
||||||
// change. This is very useful during development of the library itself.
|
// change. This is very useful during development of the library itself.
|
||||||
if (typeof window === 'object') {
|
if (typeof window === 'object') {
|
||||||
// Browser based loading through Prepro.js:
|
// Browser based loading through Prepro.js:
|
||||||
|
|
||||||
/* jshint -W082 */
|
/* jshint -W082 */
|
||||||
function load(src) {
|
function load(src) {
|
||||||
|
@ -28,9 +28,9 @@ if (typeof window === 'object') {
|
||||||
src = scripts[scripts.length - 1].getAttribute('src');
|
src = scripts[scripts.length - 1].getAttribute('src');
|
||||||
// Assume that we're loading from a non-root folder, either through
|
// Assume that we're loading from a non-root folder, either through
|
||||||
// ../../dist/paper-full.js, or directly through ../../src/load.js,
|
// ../../dist/paper-full.js, or directly through ../../src/load.js,
|
||||||
// and match root as all the parts of the path that lead to that folder.
|
// and match root as all the parts of the path that lead to that folder,
|
||||||
// So we basically just want all the leading '.' and '/' characters:
|
// exclude the last bit (dist|src), since that's the sub-folder of paper
|
||||||
var root = src.match(/^([.\/]*)/)[1];
|
var root = src.match(/^(.*\/)\w*\//)[1];
|
||||||
// First load the prepro's browser.js file, which provides the include()
|
// First load the prepro's browser.js file, which provides the include()
|
||||||
// function for the browser.
|
// function for the browser.
|
||||||
load(root + 'node_modules/prepro/lib/browser.js');
|
load(root + 'node_modules/prepro/lib/browser.js');
|
||||||
|
@ -40,23 +40,31 @@ if (typeof window === 'object') {
|
||||||
load(root + 'src/load.js');
|
load(root + 'src/load.js');
|
||||||
} else {
|
} else {
|
||||||
include('options.js');
|
include('options.js');
|
||||||
|
// Load constants.js, required by the on-the-fly preprocessing:
|
||||||
|
include('constants.js');
|
||||||
|
// Automatically load stats.js while developing.
|
||||||
|
include('../node_modules/stats.js/build/stats.min.js');
|
||||||
include('paper.js');
|
include('paper.js');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Node.js based loading through Prepro.js:
|
// Node.js based loading through Prepro.js:
|
||||||
var prepro = require('prepro/lib/node.js'),
|
var prepro = require('prepro/lib/node.js'),
|
||||||
// Load the default browser-based options for further amendments.
|
// Load the default browser-based options for further amendments.
|
||||||
// Step out and back into src, if this is loaded from dist/paper-node.js
|
// Step out and back into src, in case this is loaded from
|
||||||
|
// dist/paper-node.js
|
||||||
options = require('../src/options.js');
|
options = require('../src/options.js');
|
||||||
// Override Node.js specific options.
|
// Override Node.js specific options.
|
||||||
options.version += '-load';
|
options.version += '-load';
|
||||||
options.environment = 'node';
|
|
||||||
options.load = true;
|
options.load = true;
|
||||||
prepro.setup(function() {
|
prepro.setup(function() {
|
||||||
// Return objects to be defined in the preprocess-scope.
|
// Return objects to be defined in the preprocess-scope.
|
||||||
// Note that this would be merge in with already existing objects.
|
// Note that this would be merge in with already existing objects.
|
||||||
return { __options: options };
|
// We're defining window here since the paper-scope argument is only
|
||||||
|
// available in the included scripts when the library is actually built.
|
||||||
|
return { __options: options, window: null };
|
||||||
});
|
});
|
||||||
|
// Load constants.js, required by the on-the-fly preprocessing:
|
||||||
|
prepro.include('../src/constants.js');
|
||||||
// Load Paper.js library files.
|
// Load Paper.js library files.
|
||||||
prepro.include('../src/paper.js');
|
prepro.include('../src/paper.js');
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ var Http = {
|
||||||
request: function(method, url, callback, async) {
|
request: function(method, url, callback, async) {
|
||||||
// Code borrowed from Coffee Script and extended:
|
// Code borrowed from Coffee Script and extended:
|
||||||
async = (async === undefined) ? true : async;
|
async = (async === undefined) ? true : async;
|
||||||
var ctor = window.ActiveXObject || XMLHttpRequest,
|
var ctor = window.ActiveXObject || window.XMLHttpRequest,
|
||||||
xhr = new ctor('Microsoft.XMLHTTP');
|
xhr = new ctor('Microsoft.XMLHTTP');
|
||||||
xhr.open(method.toUpperCase(), url, async);
|
xhr.open(method.toUpperCase(), url, async);
|
||||||
if ('overrideMimeType' in xhr)
|
if ('overrideMimeType' in xhr)
|
||||||
|
|
125
src/node/extend.js
Normal file
125
src/node/extend.js
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
|
||||||
|
* http://paperjs.org/
|
||||||
|
*
|
||||||
|
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||||
|
* http://scratchdisk.com/ & http://jonathanpuckey.com/
|
||||||
|
*
|
||||||
|
* Distributed under the MIT license. See LICENSE file for details.
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var fs = require('fs'),
|
||||||
|
path = require('path');
|
||||||
|
|
||||||
|
module.exports = function(paper) {
|
||||||
|
var sourceMaps = {},
|
||||||
|
sourceMapSupprt = 'require("source-map-support").install(paper.PaperScript.sourceMapSupport);\n';
|
||||||
|
|
||||||
|
paper.PaperScript.sourceMapSupport = {
|
||||||
|
retrieveSourceMap: function(source) {
|
||||||
|
var map = sourceMaps[source];
|
||||||
|
return map ? { url: source, map: map } : null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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'),
|
||||||
|
code = sourceMapSupprt + source,
|
||||||
|
compiled = paper.PaperScript.compile(code, {
|
||||||
|
url: filename,
|
||||||
|
source: source,
|
||||||
|
sourceMaps: true,
|
||||||
|
offset: -1 // remove sourceMapSupprt...
|
||||||
|
}),
|
||||||
|
scope = new paper.PaperScope();
|
||||||
|
// Keep track of sourceMaps so retrieveSourceMap() can link them up
|
||||||
|
scope.setup(canvas);
|
||||||
|
scope.__filename = filename;
|
||||||
|
scope.__dirname = path.dirname(filename);
|
||||||
|
// Expose core methods and values
|
||||||
|
scope.require = require;
|
||||||
|
scope.console = console;
|
||||||
|
sourceMaps[filename] = compiled.map;
|
||||||
|
paper.PaperScript.execute(compiled, scope);
|
||||||
|
return scope;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Node.js based image exporting code.
|
||||||
|
paper.CanvasView.inject({
|
||||||
|
// DOCS: CanvasView#exportFrames(param);
|
||||||
|
exportFrames: function(param) {
|
||||||
|
param = new paper.Base({
|
||||||
|
fps: 30,
|
||||||
|
prefix: 'frame-',
|
||||||
|
amount: 1
|
||||||
|
}, param);
|
||||||
|
if (!param.directory) {
|
||||||
|
throw new Error('Missing param.directory');
|
||||||
|
}
|
||||||
|
var view = this,
|
||||||
|
count = 0,
|
||||||
|
frameDuration = 1 / param.fps,
|
||||||
|
startTime = Date.now(),
|
||||||
|
lastTime = startTime;
|
||||||
|
|
||||||
|
// Start exporting frames by exporting the first frame:
|
||||||
|
exportFrame(param);
|
||||||
|
|
||||||
|
function exportFrame(param) {
|
||||||
|
var file = path.join(param.directory,
|
||||||
|
param.prefix + ('000000' + count).slice(-6) + '.png');
|
||||||
|
var out = view.exportImage(file, function() {
|
||||||
|
// When the file has been closed, export the next fame:
|
||||||
|
var then = Date.now();
|
||||||
|
if (param.onProgress) {
|
||||||
|
param.onProgress({
|
||||||
|
count: count,
|
||||||
|
amount: param.amount,
|
||||||
|
percentage: Math.round(count / param.amount
|
||||||
|
* 10000) / 100,
|
||||||
|
time: then - startTime,
|
||||||
|
delta: then - lastTime
|
||||||
|
});
|
||||||
|
}
|
||||||
|
lastTime = then;
|
||||||
|
if (count < param.amount) {
|
||||||
|
exportFrame(param);
|
||||||
|
} else {
|
||||||
|
// Call onComplete handler when finished:
|
||||||
|
if (param.onComplete) {
|
||||||
|
param.onComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Convert to a Base object, for #toString()
|
||||||
|
view.emit('frame', new paper.Base({
|
||||||
|
delta: frameDuration,
|
||||||
|
time: frameDuration * count,
|
||||||
|
count: count
|
||||||
|
}));
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// DOCS: CanvasView#exportImage(path, callback);
|
||||||
|
exportImage: function(path, callback) {
|
||||||
|
this.draw();
|
||||||
|
var out = fs.createWriteStream(path),
|
||||||
|
stream = this._element.createPNGStream();
|
||||||
|
// Pipe the png stream to the write stream:
|
||||||
|
stream.pipe(out);
|
||||||
|
if (callback) {
|
||||||
|
out.on('close', callback);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
|
@ -10,22 +10,30 @@
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Node.js emulation layer of browser based environment, based on node-canvas
|
// Node.js emulation layer of browser environment, based on jsdom with node-
|
||||||
// and jsdom.
|
// canvas integration.
|
||||||
|
|
||||||
/* global document:true, window:true, navigator:true, HTMLCanvasElement:true,
|
|
||||||
Image:true */
|
|
||||||
|
|
||||||
var jsdom = require('jsdom'),
|
var jsdom = require('jsdom'),
|
||||||
// Node Canvas library: https://github.com/learnboost/node-canvas
|
idlUtils = require('jsdom/lib/jsdom/living/generated/utils');
|
||||||
Canvas = require('canvas'),
|
|
||||||
// Expose global browser variables and create a document and a window using
|
// Create our document and window objects through jsdom.
|
||||||
// jsdom, e.g. for import/exportSVG()
|
/* global document:true, window:true */
|
||||||
document = jsdom.jsdom('<html><body></body></html>'),
|
var document = jsdom.jsdom('<html><body></body></html>', {
|
||||||
window = document.defaultView,
|
features: {
|
||||||
navigator = window.navigator,
|
FetchExternalResources : ['img', 'script']
|
||||||
HTMLCanvasElement = Canvas,
|
}
|
||||||
Image = Canvas.Image;
|
}),
|
||||||
|
window = document.defaultView;
|
||||||
|
|
||||||
|
['pngStream', 'createPNGStream', 'jpgStream', 'createJPGStream'].forEach(
|
||||||
|
function(key) {
|
||||||
|
this[key] = function() {
|
||||||
|
var impl = this._canvas ? this : idlUtils.implForWrapper(this),
|
||||||
|
canvas = impl && impl._canvas;
|
||||||
|
return canvas[key].apply(canvas, arguments);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
window.HTMLCanvasElement.prototype);
|
||||||
|
|
||||||
// Define XMLSerializer and DOMParser shims, to emulate browser behavior.
|
// Define XMLSerializer and DOMParser shims, to emulate browser behavior.
|
||||||
// TODO: Put this into a simple node module, with dependency on jsdom?
|
// TODO: Put this into a simple node module, with dependency on jsdom?
|
||||||
|
@ -56,3 +64,8 @@ DOMParser.prototype.parseFromString = function(string, contenType) {
|
||||||
div.innerHTML = string;
|
div.innerHTML = string;
|
||||||
return div.firstChild;
|
return div.firstChild;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
window.XMLSerializer = XMLSerializer;
|
||||||
|
window.DOMParser = DOMParser;
|
||||||
|
|
||||||
|
module.exports = window;
|
|
@ -23,7 +23,6 @@ var load = typeof window === 'object';
|
||||||
|
|
||||||
var __options = {
|
var __options = {
|
||||||
version: version + (load ? '-load' : ''),
|
version: version + (load ? '-load' : ''),
|
||||||
environment: 'browser',
|
|
||||||
load: load,
|
load: load,
|
||||||
parser: 'acorn',
|
parser: 'acorn',
|
||||||
svg: true,
|
svg: true,
|
||||||
|
|
39
src/paper.js
39
src/paper.js
|
@ -32,17 +32,10 @@
|
||||||
|
|
||||||
// Allow the minification of the undefined variable by defining it as a local
|
// Allow the minification of the undefined variable by defining it as a local
|
||||||
// parameter inside the paper scope.
|
// parameter inside the paper scope.
|
||||||
var paper = new function(undefined) {
|
var paper = function(window, undefined) {
|
||||||
|
/*#*/ include('init.js');
|
||||||
// Inline Straps.js core (the Base class) inside the paper scope first:
|
// Inline Straps.js core (the Base class) inside the paper scope first:
|
||||||
/*#*/ include('../node_modules/straps/straps.js', { exports: false });
|
/*#*/ include('../node_modules/straps/straps.js');
|
||||||
|
|
||||||
/*#*/ if (__options.load && __options.environment == 'browser') {
|
|
||||||
/*#*/ include('../node_modules/stats.js/build/stats.min.js');
|
|
||||||
/*#*/ }
|
|
||||||
|
|
||||||
/*#*/ if (__options.load) {
|
|
||||||
/*#*/ include('constants.js');
|
|
||||||
/*#*/ }
|
|
||||||
|
|
||||||
/*#*/ include('core/Base.js');
|
/*#*/ include('core/Base.js');
|
||||||
/*#*/ include('core/Emitter.js');
|
/*#*/ include('core/Emitter.js');
|
||||||
|
@ -96,29 +89,21 @@ var paper = new function(undefined) {
|
||||||
/*#*/ include('style/GradientStop.js');
|
/*#*/ include('style/GradientStop.js');
|
||||||
/*#*/ include('style/Style.js');
|
/*#*/ include('style/Style.js');
|
||||||
|
|
||||||
/*#*/ if (__options.environment == 'node') {
|
|
||||||
/*#*/ include('dom/node.js');
|
|
||||||
/*#*/ }
|
|
||||||
/*#*/ include('dom/DomElement.js');
|
/*#*/ include('dom/DomElement.js');
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
/*#*/ include('dom/DomEvent.js');
|
||||||
// DomEvent doesn't make sense outside of the browser (yet)
|
|
||||||
/*#*/ include('dom/DomEvent.js');
|
|
||||||
/*#*/ }
|
|
||||||
|
|
||||||
/*#*/ include('view/View.js');
|
/*#*/ include('view/View.js');
|
||||||
/*#*/ include('view/CanvasView.js');
|
/*#*/ include('view/CanvasView.js');
|
||||||
|
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
/*#*/ include('event/Event.js');
|
||||||
/*#*/ include('event/Event.js');
|
/*#*/ include('event/KeyEvent.js');
|
||||||
/*#*/ include('event/KeyEvent.js');
|
/*#*/ include('event/Key.js');
|
||||||
/*#*/ include('event/Key.js');
|
/*#*/ include('event/MouseEvent.js');
|
||||||
/*#*/ include('event/MouseEvent.js');
|
|
||||||
|
|
||||||
/*#*/ include('tool/ToolEvent.js');
|
/*#*/ include('tool/ToolEvent.js');
|
||||||
/*#*/ include('tool/Tool.js');
|
/*#*/ include('tool/Tool.js');
|
||||||
|
|
||||||
/*#*/ include('net/Http.js');
|
/*#*/ include('net/Http.js');
|
||||||
/*#*/ }
|
|
||||||
|
|
||||||
/*#*/ include('canvas/CanvasProvider.js');
|
/*#*/ include('canvas/CanvasProvider.js');
|
||||||
/*#*/ include('canvas/BlendMode.js');
|
/*#*/ include('canvas/BlendMode.js');
|
||||||
|
@ -139,4 +124,4 @@ var paper = new function(undefined) {
|
||||||
|
|
||||||
/*#*/ include('export.js');
|
/*#*/ include('export.js');
|
||||||
return paper;
|
return paper;
|
||||||
};
|
}(this.window);
|
||||||
|
|
|
@ -380,7 +380,7 @@ new function() {
|
||||||
definitions = null;
|
definitions = null;
|
||||||
}
|
}
|
||||||
return options.asString
|
return options.asString
|
||||||
? new XMLSerializer().serializeToString(svg)
|
? new window.XMLSerializer().serializeToString(svg)
|
||||||
: svg;
|
: svg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -566,7 +566,6 @@ new function() {
|
||||||
// as this is how SVG works too.
|
// as this is how SVG works too.
|
||||||
// See if it's a string but handle markup separately
|
// See if it's a string but handle markup separately
|
||||||
if (typeof source === 'string' && !/^.*</.test(source)) {
|
if (typeof source === 'string' && !/^.*</.test(source)) {
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
// First see if we're meant to import an element with the given
|
// First see if we're meant to import an element with the given
|
||||||
// id.
|
// id.
|
||||||
node = document.getElementById(source);
|
node = document.getElementById(source);
|
||||||
|
@ -577,9 +576,6 @@ new function() {
|
||||||
} else {
|
} else {
|
||||||
return Http.request('get', source, onLoadCallback);
|
return Http.request('get', source, onLoadCallback);
|
||||||
}
|
}
|
||||||
/*#*/ } else if (__options.environment == 'node') {
|
|
||||||
// TODO: Implement!
|
|
||||||
/*#*/ } // __options.environment == 'node'
|
|
||||||
} else if (typeof File !== 'undefined' && source instanceof File) {
|
} else if (typeof File !== 'undefined' && source instanceof File) {
|
||||||
// Load local file through FileReader
|
// Load local file through FileReader
|
||||||
var reader = new FileReader();
|
var reader = new FileReader();
|
||||||
|
@ -591,7 +587,8 @@ new function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof source === 'string')
|
if (typeof source === 'string')
|
||||||
node = new DOMParser().parseFromString(source, 'image/svg+xml');
|
node = new window.DOMParser().parseFromString(source,
|
||||||
|
'image/svg+xml');
|
||||||
if (!node.nodeName)
|
if (!node.nodeName)
|
||||||
throw new Error('Unsupported SVG source: ' + source);
|
throw new Error('Unsupported SVG source: ' + source);
|
||||||
// jsdom in Node.js uses uppercase values for nodeName...
|
// jsdom in Node.js uses uppercase values for nodeName...
|
||||||
|
|
|
@ -33,7 +33,7 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
*/
|
*/
|
||||||
initialize: function CanvasView(project, canvas) {
|
initialize: function CanvasView(project, canvas) {
|
||||||
// Handle canvas argument
|
// Handle canvas argument
|
||||||
if (!(canvas instanceof HTMLCanvasElement)) {
|
if (!(canvas instanceof window.HTMLCanvasElement)) {
|
||||||
// See if the arguments describe the view size:
|
// See if the arguments describe the view size:
|
||||||
var size = Size.read(arguments, 1);
|
var size = Size.read(arguments, 1);
|
||||||
if (size.isZero())
|
if (size.isZero())
|
||||||
|
@ -44,7 +44,6 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
}
|
}
|
||||||
this._context = canvas.getContext('2d');
|
this._context = canvas.getContext('2d');
|
||||||
this._pixelRatio = 1;
|
this._pixelRatio = 1;
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) {
|
if (!/^off|false$/.test(PaperScope.getAttribute(canvas, 'hidpi'))) {
|
||||||
// Hi-DPI Canvas support based on:
|
// Hi-DPI Canvas support based on:
|
||||||
// http://www.html5rocks.com/en/tutorials/canvas/hidpi/
|
// http://www.html5rocks.com/en/tutorials/canvas/hidpi/
|
||||||
|
@ -53,19 +52,15 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
'backingStorePixelRatio') || 1;
|
'backingStorePixelRatio') || 1;
|
||||||
this._pixelRatio = deviceRatio / backingStoreRatio;
|
this._pixelRatio = deviceRatio / backingStoreRatio;
|
||||||
}
|
}
|
||||||
/*#*/ } // __options.environment == 'browser'
|
|
||||||
View.call(this, project, canvas);
|
View.call(this, project, canvas);
|
||||||
},
|
},
|
||||||
|
|
||||||
_setViewSize: function(size) {
|
_setViewSize: function _setViewSize(width, height) {
|
||||||
var element = this._element,
|
var pixelRatio = this._pixelRatio;
|
||||||
pixelRatio = this._pixelRatio,
|
|
||||||
width = size.width,
|
|
||||||
height = size.height;
|
|
||||||
// Upscale the canvas if the pixel ratio is more than 1.
|
// Upscale the canvas if the pixel ratio is more than 1.
|
||||||
element.width = width * pixelRatio;
|
_setViewSize.base.call(this, width * pixelRatio, height * pixelRatio);
|
||||||
element.height = height * pixelRatio;
|
|
||||||
if (pixelRatio !== 1) {
|
if (pixelRatio !== 1) {
|
||||||
|
var element = this._element;
|
||||||
// We need to set the correct size on non-resizable canvases through
|
// We need to set the correct size on non-resizable canvases through
|
||||||
// their style when HiDPI is active, as otherwise they would appear
|
// their style when HiDPI is active, as otherwise they would appear
|
||||||
// too big.
|
// too big.
|
||||||
|
@ -85,9 +80,9 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
* pixels.
|
* pixels.
|
||||||
*/
|
*/
|
||||||
getPixelSize: function(size) {
|
getPixelSize: function(size) {
|
||||||
var browser = paper.browser,
|
var agent = paper.agent,
|
||||||
pixels;
|
pixels;
|
||||||
if (browser && browser.firefox) {
|
if (agent && agent.firefox) {
|
||||||
// Firefox doesn't appear to convert context.font sizes to pixels,
|
// Firefox doesn't appear to convert context.font sizes to pixels,
|
||||||
// while other browsers do. Workaround:
|
// while other browsers do. Workaround:
|
||||||
var parent = this._element.parentNode,
|
var parent = this._element.parentNode,
|
||||||
|
@ -132,9 +127,6 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
var project = this._project;
|
var project = this._project;
|
||||||
if (!project || !force && !project._needsUpdate)
|
if (!project || !force && !project._needsUpdate)
|
||||||
return false;
|
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,
|
var ctx = this._context,
|
||||||
size = this._viewSize;
|
size = this._viewSize;
|
||||||
ctx.clearRect(0, 0, size.width + 1, size.height + 1);
|
ctx.clearRect(0, 0, size.width + 1, size.height + 1);
|
||||||
|
@ -143,90 +135,3 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/*#*/ if (__options.environment == 'node') {
|
|
||||||
// Node.js based image exporting code.
|
|
||||||
CanvasView.inject(new function() {
|
|
||||||
// Utility function that converts a number to a string with
|
|
||||||
// x amount of padded 0 digits:
|
|
||||||
function toPaddedString(number, length) {
|
|
||||||
var str = number.toString(10);
|
|
||||||
for (var i = 0, l = length - str.length; i < l; i++) {
|
|
||||||
str = '0' + str;
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
var fs = require('fs');
|
|
||||||
|
|
||||||
return {
|
|
||||||
// DOCS: CanvasView#exportFrames(param);
|
|
||||||
exportFrames: function(param) {
|
|
||||||
param = new Base({
|
|
||||||
fps: 30,
|
|
||||||
prefix: 'frame-',
|
|
||||||
amount: 1
|
|
||||||
}, param);
|
|
||||||
if (!param.directory) {
|
|
||||||
throw new Error('Missing param.directory');
|
|
||||||
}
|
|
||||||
var view = this,
|
|
||||||
count = 0,
|
|
||||||
frameDuration = 1 / param.fps,
|
|
||||||
startTime = Date.now(),
|
|
||||||
lastTime = startTime;
|
|
||||||
|
|
||||||
// Start exporting frames by exporting the first frame:
|
|
||||||
exportFrame(param);
|
|
||||||
|
|
||||||
function exportFrame(param) {
|
|
||||||
var filename = param.prefix + toPaddedString(count, 6) + '.png',
|
|
||||||
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) {
|
|
||||||
param.onProgress({
|
|
||||||
count: count,
|
|
||||||
amount: param.amount,
|
|
||||||
percentage: Math.round(count / param.amount
|
|
||||||
* 10000) / 100,
|
|
||||||
time: then - startTime,
|
|
||||||
delta: then - lastTime
|
|
||||||
});
|
|
||||||
}
|
|
||||||
lastTime = then;
|
|
||||||
if (count < param.amount) {
|
|
||||||
exportFrame(param);
|
|
||||||
} else {
|
|
||||||
// Call onComplete handler when finished:
|
|
||||||
if (param.onComplete) {
|
|
||||||
param.onComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Use new Base() to convert into a Base object, for #toString()
|
|
||||||
view.emit('frame', new Base({
|
|
||||||
delta: frameDuration,
|
|
||||||
time: frameDuration * count,
|
|
||||||
count: count
|
|
||||||
}));
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// DOCS: CanvasView#exportImage(path, callback);
|
|
||||||
exportImage: function(path, callback) {
|
|
||||||
this.draw();
|
|
||||||
var out = fs.createWriteStream(path),
|
|
||||||
stream = this._element.createPNGStream();
|
|
||||||
// Pipe the png stream to the write stream:
|
|
||||||
stream.pipe(out);
|
|
||||||
if (callback) {
|
|
||||||
out.on('close', callback);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
/*#*/ } // __options.environment == 'node'
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
* center, both useful for constructing artwork that should appear centered on
|
* center, both useful for constructing artwork that should appear centered on
|
||||||
* screen.
|
* screen.
|
||||||
*/
|
*/
|
||||||
/* jshint -W082 */// Do not complain about functions inside Prepro.js statements
|
|
||||||
var View = Base.extend(Emitter, /** @lends View# */{
|
var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
_class: 'View',
|
_class: 'View',
|
||||||
|
|
||||||
|
@ -29,8 +28,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
this._project = project;
|
this._project = project;
|
||||||
this._scope = project._scope;
|
this._scope = project._scope;
|
||||||
this._element = element;
|
this._element = element;
|
||||||
var size;
|
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
// Sub-classes may set _pixelRatio first
|
// Sub-classes may set _pixelRatio first
|
||||||
if (!this._pixelRatio)
|
if (!this._pixelRatio)
|
||||||
this._pixelRatio = window.devicePixelRatio || 1;
|
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
|
// 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.
|
// default internal size (300x150 on WebKit) and scale up the pixels.
|
||||||
// We also need this call here for HiDPI support.
|
// 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:
|
// TODO: Test this on IE:
|
||||||
if (PaperScope.hasAttribute(element, 'stats')
|
if (PaperScope.hasAttribute(element, 'stats')
|
||||||
&& typeof Stats !== 'undefined') {
|
&& typeof Stats !== 'undefined') {
|
||||||
|
@ -94,19 +92,10 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
style.top = offset.y + 'px';
|
style.top = offset.y + 'px';
|
||||||
document.body.appendChild(stats);
|
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
|
// Keep track of views internally
|
||||||
View._views.push(this);
|
View._views.push(this);
|
||||||
// Link this id to our view
|
// Link this id to our view
|
||||||
View._viewsById[this._id] = this;
|
View._viewsById[this._id] = this;
|
||||||
this._viewSize = size;
|
|
||||||
(this._matrix = new Matrix())._owner = this;
|
(this._matrix = new Matrix())._owner = this;
|
||||||
this._zoom = 1;
|
this._zoom = 1;
|
||||||
// Make sure the first view is focused for keyboard input straight away
|
// 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;
|
var project = this._project;
|
||||||
if (project._view === this)
|
if (project._view === this)
|
||||||
project._view = null;
|
project._view = null;
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
// Uninstall event handlers again for this view.
|
// Uninstall event handlers again for this view.
|
||||||
DomEvent.remove(this._element, this._viewEvents);
|
DomEvent.remove(this._element, this._viewEvents);
|
||||||
DomEvent.remove(window, this._windowEvents);
|
DomEvent.remove(window, this._windowEvents);
|
||||||
/*#*/ } // __options.environment == 'browser'
|
|
||||||
this._element = this._project = null;
|
this._element = this._project = null;
|
||||||
// Remove all onFrame handlers.
|
// Remove all onFrame handlers.
|
||||||
// TODO: Shouldn't we remove all handlers, automatically
|
// TODO: Shouldn't we remove all handlers, automatically
|
||||||
|
@ -174,7 +161,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
_count: 0,
|
_count: 0,
|
||||||
|
|
||||||
_requestFrame: function() {
|
_requestFrame: function() {
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
var that = this;
|
var that = this;
|
||||||
DomEvent.requestAnimationFrame(function() {
|
DomEvent.requestAnimationFrame(function() {
|
||||||
that._requested = false;
|
that._requested = false;
|
||||||
|
@ -186,7 +172,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
that._handleFrame();
|
that._handleFrame();
|
||||||
}, this._element);
|
}, this._element);
|
||||||
this._requested = true;
|
this._requested = true;
|
||||||
/*#*/ } // __options.environment == 'browser'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleFrame: function() {
|
_handleFrame: function() {
|
||||||
|
@ -319,11 +304,13 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
|
|
||||||
setViewSize: function(/* size */) {
|
setViewSize: function(/* size */) {
|
||||||
var size = Size.read(arguments),
|
var size = Size.read(arguments),
|
||||||
|
width = size.width,
|
||||||
|
height = size.height,
|
||||||
delta = size.subtract(this._viewSize);
|
delta = size.subtract(this._viewSize);
|
||||||
if (delta.isZero())
|
if (delta.isZero())
|
||||||
return;
|
return;
|
||||||
this._viewSize.set(size.width, size.height);
|
this._viewSize.set(width, height);
|
||||||
this._setViewSize(size);
|
this._setViewSize(width, height);
|
||||||
// Call onResize handler on any size change
|
// Call onResize handler on any size change
|
||||||
this.emit('resize', {
|
this.emit('resize', {
|
||||||
size: size,
|
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;
|
var element = this._element;
|
||||||
element.width = size.width;
|
if (element.width !== width)
|
||||||
element.height = size.height;
|
element.width = width;
|
||||||
|
if (element.height !== height)
|
||||||
|
element.height = height;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -556,12 +545,10 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
*/
|
*/
|
||||||
play: function() {
|
play: function() {
|
||||||
this._animate = true;
|
this._animate = true;
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
// Request a frame handler straight away to initialize the
|
// Request a frame handler straight away to initialize the
|
||||||
// sequence of onFrame calls.
|
// sequence of onFrame calls.
|
||||||
if (!this._requested)
|
if (!this._requested)
|
||||||
this._requestFrame();
|
this._requestFrame();
|
||||||
/*#*/ } // __options.environment == 'browser'
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -806,10 +793,8 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
_id: 0,
|
_id: 0,
|
||||||
|
|
||||||
create: function(project, element) {
|
create: function(project, element) {
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
if (typeof element === 'string')
|
if (typeof element === 'string')
|
||||||
element = document.getElementById(element);
|
element = document.getElementById(element);
|
||||||
/*#*/ } // __options.environment == 'browser'
|
|
||||||
// Factory to provide the right View subclass for a given element.
|
// Factory to provide the right View subclass for a given element.
|
||||||
// Produces only CanvasViews for now:
|
// Produces only CanvasViews for now:
|
||||||
return new CanvasView(project, element);
|
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
|
new function() { // Injection scope for mouse events on the browser
|
||||||
/*#*/ if (__options.environment == 'browser') {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Native event handling, coordinate conversion, focus handling and
|
* Native event handling, coordinate conversion, focus handling and
|
||||||
* delegation to view and tool objects.
|
* delegation to view and tool objects.
|
||||||
|
@ -1227,5 +1210,4 @@ new function() { // Injection scope for mouse events on the browser
|
||||||
updateFocus: updateFocus
|
updateFocus: updateFocus
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/*#*/ } // __options.environment == 'browser'
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -35,7 +35,7 @@ var errorHandler = console.error;
|
||||||
console.error = function() {
|
console.error = function() {
|
||||||
QUnit.pushFailure([].join.call(arguments, ' '), QUnit.config.current.stack);
|
QUnit.pushFailure([].join.call(arguments, ' '), QUnit.config.current.stack);
|
||||||
errorHandler.apply(this, arguments);
|
errorHandler.apply(this, arguments);
|
||||||
}
|
};
|
||||||
|
|
||||||
// Register a jsDump parser for Base.
|
// Register a jsDump parser for Base.
|
||||||
QUnit.jsDump.setParser('Base', function (obj, stack) {
|
QUnit.jsDump.setParser('Base', function (obj, stack) {
|
||||||
|
@ -75,14 +75,14 @@ function compareItem(actual, expected, message, options, properties) {
|
||||||
|
|
||||||
function getImageTag(raster) {
|
function getImageTag(raster) {
|
||||||
return '<img width="' + raster.width + '" height="' + raster.height
|
return '<img width="' + raster.width + '" height="' + raster.height
|
||||||
+ '" src="' + raster.source + '">'
|
+ '" src="' + raster.source + '">';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options && options.rasterize) {
|
if (options && options.rasterize) {
|
||||||
// In order to properly compare pixel by pixel, we need to put each item
|
// In order to properly compare pixel by pixel, we need to put each item
|
||||||
// into a group with a white background of the united dimensions of the
|
// into a group with a white background of the united dimensions of the
|
||||||
// bounds of both items before rasterizing.
|
// bounds of both items before rasterizing.
|
||||||
var resolution = options.rasterize == true ? 72 : options.rasterize,
|
var resolution = options.rasterize === true ? 72 : options.rasterize,
|
||||||
actualBounds = actual.strokeBounds,
|
actualBounds = actual.strokeBounds,
|
||||||
expecedBounds = expected.strokeBounds,
|
expecedBounds = expected.strokeBounds,
|
||||||
bounds = actualBounds.isEmpty()
|
bounds = actualBounds.isEmpty()
|
||||||
|
@ -120,7 +120,7 @@ function compareItem(actual, expected, message, options, properties) {
|
||||||
.onComplete(function(data) { result = data; });
|
.onComplete(function(data) { result = data; });
|
||||||
var identical = result ? 100 - result.misMatchPercentage : 0,
|
var identical = result ? 100 - result.misMatchPercentage : 0,
|
||||||
ok = identical == 100,
|
ok = identical == 100,
|
||||||
text = identical.toFixed(2) + '% identical'
|
text = identical.toFixed(2) + '% identical';
|
||||||
QUnit.push(ok, text, '100.00% identical', message);
|
QUnit.push(ok, text, '100.00% identical', message);
|
||||||
if (!ok && result) {
|
if (!ok && result) {
|
||||||
// Get the right entry for this unit test and assertion, and
|
// Get the right entry for this unit test and assertion, and
|
||||||
|
@ -407,7 +407,7 @@ function createSVG(str, attrs) {
|
||||||
node.setAttribute(key, attrs[key]);
|
node.setAttribute(key, attrs[key]);
|
||||||
return node;
|
return node;
|
||||||
} else {
|
} else {
|
||||||
return new DOMParser().parseFromString(
|
return new window.DOMParser().parseFromString(
|
||||||
'<svg xmlns="http://www.w3.org/2000/svg">' + str + '</svg>',
|
'<svg xmlns="http://www.w3.org/2000/svg">' + str + '</svg>',
|
||||||
'text/xml');
|
'text/xml');
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue