mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-28 17:02:24 -05:00
parent
74d188967c
commit
8fb7c41537
15 changed files with 272 additions and 135 deletions
53
examples/Worker/Main.html
Normal file
53
examples/Worker/Main.html
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Shapes</title>
|
||||||
|
<link rel="stylesheet" href="../css/style.css">
|
||||||
|
<script type="text/javascript" src="../../dist/paper-full.js"></script>
|
||||||
|
<script type="text/paperscript" canvas="canvas">
|
||||||
|
if (window.Worker) { // Check if Browser supports the Worker API.
|
||||||
|
var worker = new Worker("Worker.js");
|
||||||
|
|
||||||
|
// Create two paths, and send them to the worker to perform a boolean
|
||||||
|
// operation on them.
|
||||||
|
|
||||||
|
var circle = new Path.Circle({
|
||||||
|
center: [200, 200],
|
||||||
|
radius: 100,
|
||||||
|
fillColor: 'red'
|
||||||
|
});
|
||||||
|
|
||||||
|
var rectangle = new Path.Rectangle({
|
||||||
|
point: [200, 200],
|
||||||
|
size: [200, 200],
|
||||||
|
fillColor: 'blue'
|
||||||
|
});
|
||||||
|
|
||||||
|
var data = [
|
||||||
|
circle.exportJSON(),
|
||||||
|
rectangle.exportJSON()
|
||||||
|
];
|
||||||
|
console.log('Sent', data);
|
||||||
|
worker.postMessage(data);
|
||||||
|
|
||||||
|
// The worker sends the result back in a message, from which we can then
|
||||||
|
// create a new path item and siplay it.
|
||||||
|
worker.onmessage = function(event) {
|
||||||
|
var data = event.data;
|
||||||
|
if (data) {
|
||||||
|
console.log('Received', data);
|
||||||
|
var result = project.activeLayer.importJSON(data);
|
||||||
|
result.fillColor = 'yellow';
|
||||||
|
result.fillColor.alpha = 0.5;
|
||||||
|
result.position += [400, 0];
|
||||||
|
result.fullySelected = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas" resize></canvas>
|
||||||
|
</body>
|
||||||
|
</html>
|
14
examples/Worker/Worker.js
Normal file
14
examples/Worker/Worker.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
importScripts('../../dist/paper-full.js');
|
||||||
|
paper.install(this);
|
||||||
|
paper.setup([640, 480]);
|
||||||
|
|
||||||
|
onmessage = function(event) {
|
||||||
|
var data = event.data;
|
||||||
|
if (data) {
|
||||||
|
var path1 = project.importJSON(data[0]);
|
||||||
|
var path2 = project.importJSON(data[1]);
|
||||||
|
console.log(path1, path2);
|
||||||
|
var result = path1.unite(path2);
|
||||||
|
postMessage(result.exportJSON());
|
||||||
|
}
|
||||||
|
};
|
|
@ -45,7 +45,7 @@
|
||||||
"gulp-cached": "^1.1.0",
|
"gulp-cached": "^1.1.0",
|
||||||
"gulp-git-streamed": "^1.0.0",
|
"gulp-git-streamed": "^1.0.0",
|
||||||
"gulp-jshint": "^2.0.0",
|
"gulp-jshint": "^2.0.0",
|
||||||
"gulp-prepro": "^2.2.0",
|
"gulp-prepro": "^2.3.0",
|
||||||
"gulp-qunits": "^2.0.1",
|
"gulp-qunits": "^2.0.1",
|
||||||
"gulp-rename": "^1.2.2",
|
"gulp-rename": "^1.2.2",
|
||||||
"gulp-shell": "^0.5.2",
|
"gulp-shell": "^0.5.2",
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
"jshint": "2.8.x",
|
"jshint": "2.8.x",
|
||||||
"jshint-summary": "^0.4.0",
|
"jshint-summary": "^0.4.0",
|
||||||
"merge-stream": "^1.0.0",
|
"merge-stream": "^1.0.0",
|
||||||
"prepro": "^2.2.0",
|
"prepro": "^2.3.0",
|
||||||
"qunitjs": "^1.20.0",
|
"qunitjs": "^1.20.0",
|
||||||
"require-dir": "^0.3.0",
|
"require-dir": "^0.3.0",
|
||||||
"resemblejs": "^2.1.0",
|
"resemblejs": "^2.1.0",
|
||||||
|
|
|
@ -229,29 +229,33 @@ var BlendMode = new function() {
|
||||||
// is sticky is not enough, as Chome 27 pretends for blend-modes to work,
|
// is sticky is not enough, as Chome 27 pretends for blend-modes to work,
|
||||||
// but does not actually apply them.
|
// but does not actually apply them.
|
||||||
var ctx = CanvasProvider.getContext(1, 1);
|
var ctx = CanvasProvider.getContext(1, 1);
|
||||||
Base.each(modes, function(func, mode) {
|
if (ctx) {
|
||||||
// Blend #330000 (51) and #aa0000 (170):
|
Base.each(modes, function(func, mode) {
|
||||||
// Multiplying should lead to #220000 (34)
|
// Blend #330000 (51) and #aa0000 (170):
|
||||||
// For darken we need to reverse color parameters in order to test mode.
|
// Multiplying should lead to #220000 (34)
|
||||||
var darken = mode === 'darken',
|
var darken = mode === 'darken',
|
||||||
ok = false;
|
ok = false;
|
||||||
ctx.save();
|
ctx.save();
|
||||||
// FF 3.6 throws exception when setting globalCompositeOperation to
|
// FF 3.6 throws exception when setting globalCompositeOperation to
|
||||||
// unsupported values.
|
// unsupported values.
|
||||||
try {
|
try {
|
||||||
ctx.fillStyle = darken ? '#300' : '#a00';
|
// For darken we need to reverse color parameters in order to
|
||||||
ctx.fillRect(0, 0, 1, 1);
|
// test mode.
|
||||||
ctx.globalCompositeOperation = mode;
|
ctx.fillStyle = darken ? '#300' : '#a00';
|
||||||
if (ctx.globalCompositeOperation === mode) {
|
|
||||||
ctx.fillStyle = darken ? '#a00' : '#300';
|
|
||||||
ctx.fillRect(0, 0, 1, 1);
|
ctx.fillRect(0, 0, 1, 1);
|
||||||
ok = ctx.getImageData(0, 0, 1, 1).data[0] !== darken ? 170 : 51;
|
ctx.globalCompositeOperation = mode;
|
||||||
}
|
if (ctx.globalCompositeOperation === mode) {
|
||||||
} catch (e) {}
|
ctx.fillStyle = darken ? '#a00' : '#300';
|
||||||
ctx.restore();
|
ctx.fillRect(0, 0, 1, 1);
|
||||||
nativeModes[mode] = ok;
|
ok = ctx.getImageData(0, 0, 1, 1).data[0] !== darken
|
||||||
});
|
? 170 : 51;
|
||||||
CanvasProvider.release(ctx);
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
ctx.restore();
|
||||||
|
nativeModes[mode] = ok;
|
||||||
|
});
|
||||||
|
CanvasProvider.release(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
this.process = function(mode, srcContext, dstContext, alpha, offset) {
|
this.process = function(mode, srcContext, dstContext, alpha, offset) {
|
||||||
var srcCanvas = srcContext.canvas,
|
var srcCanvas = srcContext.canvas,
|
||||||
|
|
|
@ -16,6 +16,8 @@ var CanvasProvider = {
|
||||||
canvases: [],
|
canvases: [],
|
||||||
|
|
||||||
getCanvas: function(width, height) {
|
getCanvas: function(width, height) {
|
||||||
|
if (!window)
|
||||||
|
return null;
|
||||||
var canvas,
|
var canvas,
|
||||||
clear = true;
|
clear = true;
|
||||||
if (typeof width === 'object') {
|
if (typeof width === 'object') {
|
||||||
|
@ -49,14 +51,17 @@ var CanvasProvider = {
|
||||||
},
|
},
|
||||||
|
|
||||||
getContext: function(width, height) {
|
getContext: function(width, height) {
|
||||||
return this.getCanvas(width, height).getContext('2d');
|
var canvas = this.getCanvas(width, height);
|
||||||
|
return canvas ? canvas.getContext('2d') : null;
|
||||||
},
|
},
|
||||||
|
|
||||||
// release can receive either a canvas or a context.
|
// release can receive either a canvas or a context.
|
||||||
release: function(obj) {
|
release: function(obj) {
|
||||||
var canvas = obj.canvas ? obj.canvas : obj;
|
var canvas = obj && obj.canvas ? obj.canvas : obj;
|
||||||
// We restore contexts on release(), see getCanvas()
|
if (canvas && canvas.getContext) {
|
||||||
canvas.getContext('2d').restore();
|
// We restore contexts on release(), see getCanvas()
|
||||||
this.canvases.push(canvas);
|
canvas.getContext('2d').restore();
|
||||||
|
this.canvases.push(canvas);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -64,7 +64,7 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
if (!this.support) {
|
if (!this.support) {
|
||||||
// Set up paper.support, as an object containing properties that
|
// Set up paper.support, as an object containing properties that
|
||||||
// describe the support of various features.
|
// describe the support of various features.
|
||||||
var ctx = CanvasProvider.getContext(1, 1);
|
var ctx = CanvasProvider.getContext(1, 1) || {};
|
||||||
proto.support = {
|
proto.support = {
|
||||||
nativeDash: 'setLineDash' in ctx || 'mozDash' in ctx,
|
nativeDash: 'setLineDash' in ctx || 'mozDash' in ctx,
|
||||||
nativeBlendModes: BlendMode.nativeModes
|
nativeBlendModes: BlendMode.nativeModes
|
||||||
|
@ -72,7 +72,8 @@ var PaperScope = Base.extend(/** @lends PaperScope# */{
|
||||||
CanvasProvider.release(ctx);
|
CanvasProvider.release(ctx);
|
||||||
}
|
}
|
||||||
if (!this.agent) {
|
if (!this.agent) {
|
||||||
var user = window.navigator.userAgent.toLowerCase(),
|
// Use self.instead of window, to cover handle web-workers too.
|
||||||
|
var user = self.navigator.userAgent.toLowerCase(),
|
||||||
// Detect basic platforms, only mac internally required for now.
|
// Detect basic platforms, only mac internally required for now.
|
||||||
os = (/(darwin|win|mac|linux|freebsd|sunos)/.exec(user)||[])[0],
|
os = (/(darwin|win|mac|linux|freebsd|sunos)/.exec(user)||[])[0],
|
||||||
platform = os === 'darwin' ? 'mac' : os,
|
platform = os === 'darwin' ? 'mac' : os,
|
||||||
|
|
|
@ -300,7 +300,7 @@ Base.exports.PaperScript = (function() {
|
||||||
// -2 required to remove function header:
|
// -2 required to remove function header:
|
||||||
// https://code.google.com/p/chromium/issues/detail?id=331655
|
// https://code.google.com/p/chromium/issues/detail?id=331655
|
||||||
offset -= 2;
|
offset -= 2;
|
||||||
} else if (url && window.location.href.indexOf(url) === 0) {
|
} else if (window && url && !window.location.href.indexOf(url)) {
|
||||||
// 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;
|
||||||
|
@ -440,7 +440,8 @@ Base.exports.PaperScript = (function() {
|
||||||
if (handlers)
|
if (handlers)
|
||||||
code += '\nreturn { ' + handlers + ' };';
|
code += '\nreturn { ' + handlers + ' };';
|
||||||
var agent = paper.agent;
|
var agent = paper.agent;
|
||||||
if (agent.chrome || agent.firefox && agent.versionNumber < 40) {
|
if (document && (agent.chrome
|
||||||
|
|| agent.firefox && agent.versionNumber < 40)) {
|
||||||
// On older Firefox, all error numbers inside dynamically compiled
|
// On older Firefox, all error numbers inside dynamically compiled
|
||||||
// code are relative to the line where the eval / compilation
|
// code are relative to the line where the eval / compilation
|
||||||
// happened. To fix this issue, we're temporarily inserting a new
|
// happened. To fix this issue, we're temporarily inserting a new
|
||||||
|
@ -536,7 +537,8 @@ Base.exports.PaperScript = (function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadAll() {
|
function loadAll() {
|
||||||
Base.each(document.getElementsByTagName('script'), loadScript);
|
Base.each(document && document.getElementsByTagName('script'),
|
||||||
|
loadScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -560,13 +562,15 @@ Base.exports.PaperScript = (function() {
|
||||||
return script ? loadScript(script) : loadAll();
|
return script ? loadScript(script) : loadAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catch cases where paper.js is loaded after the browser event has already
|
if (window) {
|
||||||
// occurred.
|
// Catch cases where paper.js is loaded after the browser event has
|
||||||
if (document.readyState === 'complete') {
|
// already occurred.
|
||||||
// Handle it asynchronously
|
if (document.readyState === 'complete') {
|
||||||
setTimeout(loadAll);
|
// Handle it asynchronously
|
||||||
} else {
|
setTimeout(loadAll);
|
||||||
DomEvent.add(window, { load: loadAll });
|
} else {
|
||||||
|
DomEvent.add(window, { load: loadAll });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -113,7 +113,7 @@ var DomElement = new function() {
|
||||||
* prefix variants.
|
* prefix variants.
|
||||||
*/
|
*/
|
||||||
getPrefixed: function(el, name) {
|
getPrefixed: function(el, name) {
|
||||||
return handlePrefix(el, name);
|
return el && handlePrefix(el, name);
|
||||||
},
|
},
|
||||||
|
|
||||||
setPrefixed: function(el, name, value) {
|
setPrefixed: function(el, name, value) {
|
||||||
|
|
|
@ -17,20 +17,27 @@
|
||||||
*/
|
*/
|
||||||
var DomEvent = /** @lends DomEvent */{
|
var DomEvent = /** @lends DomEvent */{
|
||||||
add: function(el, events) {
|
add: function(el, events) {
|
||||||
for (var type in events) {
|
// Do not fail if el is not defined, that way we can keep the code that
|
||||||
var func = events[type],
|
// should not fail in web-workers to a minimum.
|
||||||
parts = type.split(/[\s,]+/g);
|
if (el) {
|
||||||
for (var i = 0, l = parts.length; i < l; i++)
|
for (var type in events) {
|
||||||
el.addEventListener(parts[i], func, false);
|
var func = events[type],
|
||||||
|
parts = type.split(/[\s,]+/g);
|
||||||
|
for (var i = 0, l = parts.length; i < l; i++)
|
||||||
|
el.addEventListener(parts[i], func, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function(el, events) {
|
remove: function(el, events) {
|
||||||
for (var type in events) {
|
// See DomEvent.add() for an explanation of this check:
|
||||||
var func = events[type],
|
if (el) {
|
||||||
parts = type.split(/[\s,]+/g);
|
for (var type in events) {
|
||||||
for (var i = 0, l = parts.length; i < l; i++)
|
var func = events[type],
|
||||||
el.removeEventListener(parts[i], func, false);
|
parts = type.split(/[\s,]+/g);
|
||||||
|
for (var i = 0, l = parts.length; i < l; i++)
|
||||||
|
el.removeEventListener(parts[i], func, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
13
src/init.js
13
src/init.js
|
@ -17,5 +17,14 @@
|
||||||
// their shared scope.
|
// their shared scope.
|
||||||
|
|
||||||
/* global document:true, window:true */
|
/* global document:true, window:true */
|
||||||
window = window || require('./node/window');
|
// Use typeof self to detect both browsers and web-workers.
|
||||||
var document = window.document;
|
// In workers, window will then be null, so we can use the validity of the
|
||||||
|
// window object to decide if we're in a worker-like context in the rest of
|
||||||
|
// the library.
|
||||||
|
var window = self ? self.window : require('./node/window'),
|
||||||
|
document = window && window.document;
|
||||||
|
// Make sure 'self' always points to a window object, also on Node.js.
|
||||||
|
// NOTE: We're not modifying the global `self` here. We receive its value passed
|
||||||
|
// to the paper.js function scope, and this is the one that is modified here.
|
||||||
|
self = self || window;
|
||||||
|
|
||||||
|
|
|
@ -56,9 +56,9 @@ if (typeof window === 'object') {
|
||||||
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.
|
||||||
// We're defining window here since the paper-scope argument is only
|
// We're defining self here since the paper-scope argument is only
|
||||||
// available in the included scripts when the library is actually built.
|
// available in the included scripts when the library is actually built.
|
||||||
return { __options: options, window: null };
|
return { __options: options, self: undefined };
|
||||||
});
|
});
|
||||||
// Load constants.js, required by the on-the-fly preprocessing:
|
// Load constants.js, required by the on-the-fly preprocessing:
|
||||||
prepro.include('../src/constants.js');
|
prepro.include('../src/constants.js');
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
// 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 = function(window, undefined) {
|
var paper = function(self, undefined) {
|
||||||
/*#*/ include('init.js');
|
/*#*/ 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');
|
/*#*/ include('../node_modules/straps/straps.js');
|
||||||
|
@ -123,4 +123,4 @@ var paper = function(window, undefined) {
|
||||||
|
|
||||||
/*#*/ include('export.js');
|
/*#*/ include('export.js');
|
||||||
return paper;
|
return paper;
|
||||||
}(this.window);
|
}(this.self);
|
||||||
|
|
|
@ -75,7 +75,7 @@ var Color = Base.extend(new function() {
|
||||||
var value = +components[i];
|
var value = +components[i];
|
||||||
components[i] = i < 3 ? value / 255 : value;
|
components[i] = i < 3 ? value / 255 : value;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (window) {
|
||||||
// Named
|
// Named
|
||||||
var cached = colorCache[string];
|
var cached = colorCache[string];
|
||||||
if (!cached) {
|
if (!cached) {
|
||||||
|
@ -102,6 +102,9 @@ var Color = Base.extend(new function() {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
components = cached.slice();
|
components = cached.slice();
|
||||||
|
} else {
|
||||||
|
// Web-workers can't resolve CSS color names, for now.
|
||||||
|
components = [0, 0, 0];
|
||||||
}
|
}
|
||||||
return components;
|
return components;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,16 +42,16 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
+ [].slice.call(arguments, 1));
|
+ [].slice.call(arguments, 1));
|
||||||
canvas = CanvasProvider.getCanvas(size);
|
canvas = CanvasProvider.getCanvas(size);
|
||||||
}
|
}
|
||||||
var context = this._context = canvas.getContext('2d');
|
var ctx = this._context = canvas.getContext('2d');
|
||||||
// Save context right away, and restore in #remove(). Also restore() and
|
// Save context right away, and restore in #remove(). Also restore() and
|
||||||
// save() again in _setViewSize(), to prevent accumulation of scaling.
|
// save() again in _setElementSize() to prevent accumulation of scaling.
|
||||||
context.save();
|
ctx.save();
|
||||||
this._pixelRatio = 1;
|
this._pixelRatio = 1;
|
||||||
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/
|
||||||
var deviceRatio = window.devicePixelRatio || 1,
|
var deviceRatio = window.devicePixelRatio || 1,
|
||||||
backingStoreRatio = DomElement.getPrefixed(context,
|
backingStoreRatio = DomElement.getPrefixed(ctx,
|
||||||
'backingStorePixelRatio') || 1;
|
'backingStorePixelRatio') || 1;
|
||||||
this._pixelRatio = deviceRatio / backingStoreRatio;
|
this._pixelRatio = deviceRatio / backingStoreRatio;
|
||||||
}
|
}
|
||||||
|
@ -63,13 +63,13 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
return remove.base.call(this);
|
return remove.base.call(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
_setViewSize: function _setViewSize(width, height) {
|
_setElementSize: function _setElementSize(width, height) {
|
||||||
var pixelRatio = this._pixelRatio;
|
var pixelRatio = this._pixelRatio;
|
||||||
// Upscale the canvas if the pixel ratio is more than 1.
|
// Upscale the canvas if the pixel ratio is more than 1.
|
||||||
_setViewSize.base.call(this, width * pixelRatio, height * pixelRatio);
|
_setElementSize.base.call(this, width * pixelRatio, height * pixelRatio);
|
||||||
if (pixelRatio !== 1) {
|
if (pixelRatio !== 1) {
|
||||||
var element = this._element,
|
var element = this._element,
|
||||||
context = this._context;
|
ctx = this._context;
|
||||||
// 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.
|
||||||
|
@ -80,9 +80,9 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
}
|
}
|
||||||
// Scale the context to counter the fact that we've manually scaled
|
// Scale the context to counter the fact that we've manually scaled
|
||||||
// our canvas element.
|
// our canvas element.
|
||||||
context.restore();
|
ctx.restore();
|
||||||
context.save();
|
ctx.save();
|
||||||
context.scale(pixelRatio, pixelRatio);
|
ctx.scale(pixelRatio, pixelRatio);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -90,18 +90,13 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
* Converts the provide size in any of the units allowed in the browser to
|
* Converts the provide size in any of the units allowed in the browser to
|
||||||
* pixels.
|
* pixels.
|
||||||
*/
|
*/
|
||||||
getPixelSize: function(size) {
|
getPixelSize: function getPixelSize(size) {
|
||||||
var agent = paper.agent,
|
var agent = paper.agent,
|
||||||
pixels;
|
pixels;
|
||||||
|
// Firefox doesn't appear to convert context.font sizes to pixels,
|
||||||
|
// while other browsers do. Fall-back to View#getPixelSize.
|
||||||
if (agent && agent.firefox) {
|
if (agent && agent.firefox) {
|
||||||
// Firefox doesn't appear to convert context.font sizes to pixels,
|
pixels = getPixelSize.base.call(this, size);
|
||||||
// while other browsers do. Workaround:
|
|
||||||
var parent = this._element.parentNode,
|
|
||||||
temp = document.createElement('div');
|
|
||||||
temp.style.fontSize = size;
|
|
||||||
parent.appendChild(temp);
|
|
||||||
pixels = parseFloat(DomElement.getStyles(temp).fontSize);
|
|
||||||
parent.removeChild(temp);
|
|
||||||
} else {
|
} else {
|
||||||
var ctx = this._context,
|
var ctx = this._context,
|
||||||
prevFont = ctx.font;
|
prevFont = ctx.font;
|
||||||
|
|
156
src/view/View.js
156
src/view/View.js
|
@ -23,29 +23,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
_class: 'View',
|
_class: 'View',
|
||||||
|
|
||||||
initialize: function View(project, element) {
|
initialize: function View(project, element) {
|
||||||
// Store reference to the currently active global paper scope, and the
|
|
||||||
// active project, which will be represented by this view
|
|
||||||
this._project = project;
|
|
||||||
this._scope = project._scope;
|
|
||||||
this._element = element;
|
|
||||||
// Sub-classes may set _pixelRatio first
|
|
||||||
if (!this._pixelRatio)
|
|
||||||
this._pixelRatio = window.devicePixelRatio || 1;
|
|
||||||
// Generate an id for this view / element if it does not have one
|
|
||||||
this._id = element.getAttribute('id');
|
|
||||||
if (this._id == null)
|
|
||||||
element.setAttribute('id', this._id = 'view-' + View._id++);
|
|
||||||
// Install event handlers
|
|
||||||
DomEvent.add(element, this._viewEvents);
|
|
||||||
// Borrowed from Hammer.js:
|
|
||||||
var none = 'none';
|
|
||||||
DomElement.setPrefixed(element.style, {
|
|
||||||
userDrag: none,
|
|
||||||
userSelect: none,
|
|
||||||
touchCallout: none,
|
|
||||||
contentZooming: none,
|
|
||||||
tapHighlightColor: 'rgba(0,0,0,0)'
|
|
||||||
});
|
|
||||||
|
|
||||||
function getSize(name) {
|
function getSize(name) {
|
||||||
return element[name] || parseInt(element.getAttribute(name), 10);
|
return element[name] || parseInt(element.getAttribute(name), 10);
|
||||||
|
@ -63,35 +40,68 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
: size;
|
: size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the element has the resize attribute, listen to resize events and
|
var size;
|
||||||
// update its coordinate space accordingly
|
if (window && element) {
|
||||||
if (PaperScope.hasAttribute(element, 'resize')) {
|
// Generate an id for this view / element if it does not have one
|
||||||
var that = this;
|
this._id = element.getAttribute('id');
|
||||||
DomEvent.add(window, this._windowEvents = {
|
if (this._id == null)
|
||||||
resize: function() {
|
element.setAttribute('id', this._id = 'view-' + View._id++);
|
||||||
that.setViewSize(getCanvasSize());
|
// Install event handlers
|
||||||
}
|
DomEvent.add(element, this._viewEvents);
|
||||||
|
// Borrowed from Hammer.js:
|
||||||
|
var none = 'none';
|
||||||
|
DomElement.setPrefixed(element.style, {
|
||||||
|
userDrag: none,
|
||||||
|
userSelect: none,
|
||||||
|
touchCallout: none,
|
||||||
|
contentZooming: none,
|
||||||
|
tapHighlightColor: 'rgba(0,0,0,0)'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// If the element has the resize attribute, listen to resize events
|
||||||
|
// and update its coordinate space accordingly
|
||||||
|
if (PaperScope.hasAttribute(element, 'resize')) {
|
||||||
|
var that = this;
|
||||||
|
DomEvent.add(window, this._windowEvents = {
|
||||||
|
resize: function() {
|
||||||
|
that.setViewSize(getCanvasSize());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
size = getCanvasSize();
|
||||||
|
|
||||||
|
if (PaperScope.hasAttribute(element, 'stats')
|
||||||
|
&& typeof Stats !== 'undefined') {
|
||||||
|
this._stats = new Stats();
|
||||||
|
// Align top-left to the element
|
||||||
|
var stats = this._stats.domElement,
|
||||||
|
style = stats.style,
|
||||||
|
offset = DomElement.getOffset(element);
|
||||||
|
style.position = 'absolute';
|
||||||
|
style.left = offset.x + 'px';
|
||||||
|
style.top = offset.y + 'px';
|
||||||
|
document.body.appendChild(stats);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For web-workers: Allow calling of `paper.setup(new Size(x, y));`
|
||||||
|
size = new Size(element);
|
||||||
|
element = null;
|
||||||
}
|
}
|
||||||
|
// Store reference to the currently active global paper scope, and the
|
||||||
|
// active project, which will be represented by this view
|
||||||
|
this._project = project;
|
||||||
|
this._scope = project._scope;
|
||||||
|
this._element = element;
|
||||||
|
// Sub-classes may set _pixelRatio first
|
||||||
|
if (!this._pixelRatio)
|
||||||
|
this._pixelRatio = window && window.devicePixelRatio || 1;
|
||||||
// Set canvas size even if we just determined the size from it, since
|
// Set canvas size even if we just determined the size from it, since
|
||||||
// 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.
|
||||||
var size = this._viewSize = getCanvasSize();
|
this._setElementSize(size.width, size.height);
|
||||||
this._setViewSize(size.width, size.height);
|
this._viewSize = size;
|
||||||
// TODO: Test this on IE:
|
|
||||||
if (PaperScope.hasAttribute(element, 'stats')
|
|
||||||
&& typeof Stats !== 'undefined') {
|
|
||||||
this._stats = new Stats();
|
|
||||||
// Align top-left to the element
|
|
||||||
var stats = this._stats.domElement,
|
|
||||||
style = stats.style,
|
|
||||||
offset = DomElement.getOffset(element);
|
|
||||||
style.position = 'absolute';
|
|
||||||
style.left = offset.x + 'px';
|
|
||||||
style.top = offset.y + 'px';
|
|
||||||
document.body.appendChild(stats);
|
|
||||||
}
|
|
||||||
// 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
|
||||||
|
@ -192,14 +202,15 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
* @function
|
* @function
|
||||||
* @return {Boolean} {@true if the view was updated}
|
* @return {Boolean} {@true if the view was updated}
|
||||||
*/
|
*/
|
||||||
// update: function() {
|
update: function() {
|
||||||
// },
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the view if there are changes.
|
* Updates the view if there are changes.
|
||||||
*
|
*
|
||||||
* @deprecated use {@link #update()} instead.
|
* @deprecated use {@link #update()} instead.
|
||||||
*/
|
*/
|
||||||
|
// NOTE: We cannot use draw: '#update'` as that would not work on CanvasView
|
||||||
draw: function() {
|
draw: function() {
|
||||||
this.update();
|
this.update();
|
||||||
},
|
},
|
||||||
|
@ -369,8 +380,8 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
delta = size.subtract(this._viewSize);
|
delta = size.subtract(this._viewSize);
|
||||||
if (delta.isZero())
|
if (delta.isZero())
|
||||||
return;
|
return;
|
||||||
|
this._setElementSize(width, height);
|
||||||
this._viewSize.set(width, height);
|
this._viewSize.set(width, height);
|
||||||
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,
|
||||||
|
@ -384,12 +395,14 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
/**
|
/**
|
||||||
* Private method, overridden in CanvasView for HiDPI support.
|
* Private method, overridden in CanvasView for HiDPI support.
|
||||||
*/
|
*/
|
||||||
_setViewSize: function(width, height) {
|
_setElementSize: function(width, height) {
|
||||||
var element = this._element;
|
var element = this._element;
|
||||||
if (element.width !== width)
|
if (element) {
|
||||||
element.width = width;
|
if (element.width !== width)
|
||||||
if (element.height !== height)
|
element.width = width;
|
||||||
element.height = height;
|
if (element.height !== height)
|
||||||
|
element.height = height;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -482,6 +495,32 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
*/
|
*/
|
||||||
isInserted: function() {
|
isInserted: function() {
|
||||||
return DomElement.isInserted(this._element);
|
return DomElement.isInserted(this._element);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Empty stubs of #getPixelSize() and #getTextWidth(), around so that
|
||||||
|
// web-workers don't fail. Overridden with proper functionality in
|
||||||
|
// CanvasView.
|
||||||
|
getPixelSize: function(size) {
|
||||||
|
var element = this._element,
|
||||||
|
pixels;
|
||||||
|
if (element) {
|
||||||
|
// this code is part of the Firefox workaround in CanvasView, but
|
||||||
|
// also provides a way to determine pixel-size that does not involve
|
||||||
|
// a Canvas. It still does not work in a web-worker though.
|
||||||
|
var parent = element.parentNode,
|
||||||
|
temp = document.createElement('div');
|
||||||
|
temp.style.fontSize = size;
|
||||||
|
parent.appendChild(temp);
|
||||||
|
pixels = parseFloat(DomElement.getStyles(temp).fontSize);
|
||||||
|
parent.removeChild(temp);
|
||||||
|
} else {
|
||||||
|
pixels = parseFloat(pixels);
|
||||||
|
}
|
||||||
|
return pixels;
|
||||||
|
},
|
||||||
|
|
||||||
|
getTextWidth: function(font, lines) {
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) {
|
}, Base.each(['rotate', 'scale', 'shear', 'skew'], function(key) {
|
||||||
var rotate = key === 'rotate';
|
var rotate = key === 'rotate';
|
||||||
|
@ -924,15 +963,18 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
_id: 0,
|
_id: 0,
|
||||||
|
|
||||||
create: function(project, element) {
|
create: function(project, element) {
|
||||||
if (typeof element === 'string')
|
if (document && typeof element === 'string')
|
||||||
element = document.getElementById(element);
|
element = document.getElementById(element);
|
||||||
// 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 CanvasView or View items (for workers) for now:
|
||||||
return new CanvasView(project, element);
|
var ctor = window ? CanvasView : View;
|
||||||
|
return new ctor(project, element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
new function() { // Injection scope for event handling on the browser
|
new function() { // Injection scope for event handling on the browser
|
||||||
|
if (!window)
|
||||||
|
return;
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
|
Loading…
Reference in a new issue