mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-04 03:45:58 -05:00
Merge branch 'develop'
This commit is contained in:
commit
48c8eacf0b
27 changed files with 1670 additions and 1429 deletions
|
@ -41,4 +41,4 @@ script:
|
|||
- gulp minify
|
||||
- gulp test
|
||||
- gulp zip
|
||||
- '[ "${TRAVIS_BRANCH}" = "develop" ] && [ "${TRAVIS_NODE_VERSION}" = "stable" ] && travis/deploy-prebuilt.sh'
|
||||
- '[ "${TRAVIS_BRANCH}" = "develop" ] && [ "${TRAVIS_NODE_VERSION}" = "stable" ] && travis/deploy-prebuilt.sh || true'
|
||||
|
|
16
README.md
16
README.md
|
@ -51,17 +51,17 @@ generally not recommended to install Node.js through OS-supplied package
|
|||
managers, as the its development cycles move fast and these versions are often
|
||||
out-of-date.
|
||||
|
||||
On macOS, [Homebrew](http://brew.sh/) is a good option if one version of
|
||||
Node.js that is kept up to date with `brew upgrade` is enough:
|
||||
<http://treehouse.github.io/installation-guides/mac/node-mac.html>
|
||||
|
||||
[NVM](https://github.com/creationix/nvm) can be used instead to install and
|
||||
maintain multiple versions of Node.js on the same platform, as often required by
|
||||
different projects:
|
||||
<https://nodesource.com/blog/installing-node-js-tutorial-using-nvm-on-mac-os-x-and-ubuntu/>
|
||||
|
||||
on OSX, [Homebrew](http://brew.sh/) is also a good option if one version of
|
||||
Node.js that is kept up to date with `brew update` is enough:
|
||||
<http://treehouse.github.io/installation-guides/mac/node-mac.html>
|
||||
|
||||
Homebrew is recommended on OSX also if you intend to install Paper.js for
|
||||
Node.js, as described in the next paragraph.
|
||||
Homebrew is recommended on macOS also if you intend to install Paper.js with
|
||||
rendering to the Canvas on Node.js, as described in the next paragraph.
|
||||
|
||||
For Linux, see <http://nodejs.org/download/> to locate 32-bit and 64-bit Node.js
|
||||
binaries as well as sources, or use NVM, as described in the paragraph above.
|
||||
|
@ -83,14 +83,14 @@ different one:
|
|||
In order to install `paper-jsdom-canvas`, you need the [Cairo Graphics
|
||||
library](http://cairographics.org/) installed in your system:
|
||||
|
||||
##### Installing Cairo and Pango on OSX:
|
||||
##### Installing Cairo and Pango on macOS:
|
||||
|
||||
The easiest way to install Cairo is through [Homebrew](http://brew.sh/), by
|
||||
issuing the command:
|
||||
|
||||
brew install cairo pango
|
||||
|
||||
Note that currently there is an issue on OSX with Cairo. If the above causes
|
||||
Note that currently there is an issue on macOS with Cairo. If the above causes
|
||||
errors, the following will most likely fix it:
|
||||
|
||||
PKG_CONFIG_PATH=/opt/X11/lib/pkgconfig/ npm install paper
|
||||
|
|
219
dist/paper-core.js
vendored
219
dist/paper-core.js
vendored
|
@ -1,5 +1,5 @@
|
|||
/*!
|
||||
* Paper.js v0.11.2 - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* Paper.js v0.11.3 - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Date: Thu Apr 20 19:14:30 2017 +0200
|
||||
* Date: Sat Apr 22 20:01:34 2017 +0200
|
||||
*
|
||||
***
|
||||
*
|
||||
|
@ -98,12 +98,13 @@ var Base = new function() {
|
|||
&& (bean = name.match(/^([gs]et|is)(([A-Z])(.*))$/)))
|
||||
beansNames[bean[3].toLowerCase() + bean[4]] = bean[2];
|
||||
if (!res || isFunc || !res.get || typeof res.get !== 'function'
|
||||
|| !Base.isPlainObject(res))
|
||||
|| !Base.isPlainObject(res)) {
|
||||
res = { value: res, writable: true };
|
||||
}
|
||||
if ((describe(dest, name)
|
||||
|| { configurable: true }).configurable) {
|
||||
res.configurable = true;
|
||||
res.enumerable = enumerable;
|
||||
res.enumerable = enumerable != null ? enumerable : !bean;
|
||||
}
|
||||
define(dest, name, res);
|
||||
}
|
||||
|
@ -141,7 +142,7 @@ var Base = new function() {
|
|||
preserve = src.preserve;
|
||||
if (statics !== src)
|
||||
inject(this.prototype, src, src.enumerable, beans, preserve);
|
||||
inject(this, statics, true, beans, preserve);
|
||||
inject(this, statics, null, beans, preserve);
|
||||
}
|
||||
for (var i = 1, l = arguments.length; i < l; i++)
|
||||
this.inject(arguments[i]);
|
||||
|
@ -164,13 +165,15 @@ var Base = new function() {
|
|||
proto = ctor.prototype = proto || create(this.prototype);
|
||||
define(proto, 'constructor',
|
||||
{ value: ctor, writable: true, configurable: true });
|
||||
inject(ctor, this, true);
|
||||
inject(ctor, this);
|
||||
if (arguments.length)
|
||||
this.inject.apply(ctor, arguments);
|
||||
ctor.base = base;
|
||||
return ctor;
|
||||
}
|
||||
}, true).inject({
|
||||
}).inject({
|
||||
enumerable: false,
|
||||
|
||||
initialize: Base,
|
||||
|
||||
set: Base,
|
||||
|
@ -230,6 +233,8 @@ if (typeof module !== 'undefined')
|
|||
module.exports = Base;
|
||||
|
||||
Base.inject({
|
||||
enumerable: false,
|
||||
|
||||
toString: function() {
|
||||
return this._id != null
|
||||
? (this._class || 'Object') + (this._name
|
||||
|
@ -265,13 +270,12 @@ Base.inject({
|
|||
if (props)
|
||||
Base.filter(this, props, exclude, this._prioritize);
|
||||
return this;
|
||||
},
|
||||
}
|
||||
}, {
|
||||
|
||||
beans: false,
|
||||
statics: {
|
||||
|
||||
exports: {
|
||||
enumerable: true
|
||||
},
|
||||
exports: {},
|
||||
|
||||
extend: function extend() {
|
||||
var res = extend.base.apply(this, arguments),
|
||||
|
@ -341,6 +345,11 @@ Base.inject({
|
|||
: list) || obj;
|
||||
if (readIndex) {
|
||||
list.__index = begin + obj.__read;
|
||||
var filtered = obj.__filtered;
|
||||
if (filtered) {
|
||||
list.__filtered = filtered;
|
||||
obj.__filtered = undefined;
|
||||
}
|
||||
obj.__read = undefined;
|
||||
}
|
||||
return obj;
|
||||
|
@ -371,14 +380,16 @@ Base.inject({
|
|||
var value = this.getNamed(list, name),
|
||||
hasObject = value !== undefined;
|
||||
if (hasObject) {
|
||||
var filtered = list._filtered;
|
||||
var filtered = list.__filtered;
|
||||
if (!filtered) {
|
||||
filtered = list._filtered = Base.create(list[0]);
|
||||
filtered._unfiltered = list[0];
|
||||
filtered = list.__filtered = Base.create(list[0]);
|
||||
filtered.__unfiltered = list[0];
|
||||
}
|
||||
filtered[name] = undefined;
|
||||
}
|
||||
return this.read(hasObject ? [value] : list, start, options, amount);
|
||||
var l = hasObject ? [value] : list,
|
||||
res = this.read(l, start, options, amount);
|
||||
return res;
|
||||
},
|
||||
|
||||
getNamed: function(list, name) {
|
||||
|
@ -386,7 +397,7 @@ Base.inject({
|
|||
if (list._hasObject === undefined)
|
||||
list._hasObject = list.length === 1 && Base.isPlainObject(arg);
|
||||
if (list._hasObject)
|
||||
return name ? arg[name] : list._filtered || arg;
|
||||
return name ? arg[name] : list.__filtered || arg;
|
||||
},
|
||||
|
||||
hasNamed: function(list, name) {
|
||||
|
@ -416,7 +427,7 @@ Base.inject({
|
|||
processed = keys;
|
||||
}
|
||||
|
||||
Object.keys(source._unfiltered || source).forEach(handleKey);
|
||||
Object.keys(source.__unfiltered || source).forEach(handleKey);
|
||||
return dest;
|
||||
},
|
||||
|
||||
|
@ -462,8 +473,7 @@ Base.inject({
|
|||
} else if (Array.isArray(obj)) {
|
||||
res = [];
|
||||
for (var i = 0, l = obj.length; i < l; i++)
|
||||
res[i] = Base.serialize(obj[i], options, compact,
|
||||
dictionary);
|
||||
res[i] = Base.serialize(obj[i], options, compact, dictionary);
|
||||
} else if (Base.isPlainObject(obj)) {
|
||||
res = {};
|
||||
var keys = Object.keys(obj);
|
||||
|
@ -586,8 +596,7 @@ Base.inject({
|
|||
hyphenate: function(str) {
|
||||
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
}
|
||||
});
|
||||
}});
|
||||
|
||||
var Emitter = {
|
||||
on: function(type, func) {
|
||||
|
@ -769,7 +778,7 @@ var PaperScope = Base.extend({
|
|||
}
|
||||
},
|
||||
|
||||
version: "0.11.2",
|
||||
version: "0.11.3",
|
||||
|
||||
getView: function() {
|
||||
var project = this.project;
|
||||
|
@ -1739,6 +1748,9 @@ var Rectangle = Base.extend({
|
|||
}
|
||||
this._set(x, y, width, height);
|
||||
read = arguments.__index;
|
||||
var filtered = arguments.__filtered;
|
||||
if (filtered)
|
||||
this.__filtered = filtered;
|
||||
}
|
||||
if (this.__read)
|
||||
this.__read = read;
|
||||
|
@ -2262,7 +2274,7 @@ var Matrix = Base.extend({
|
|||
return this.shear(shear, center);
|
||||
},
|
||||
|
||||
append: function(mx) {
|
||||
append: function(mx, _dontNotify) {
|
||||
if (mx) {
|
||||
var a1 = this._a,
|
||||
b1 = this._b,
|
||||
|
@ -2280,12 +2292,13 @@ var Matrix = Base.extend({
|
|||
this._d = b2 * b1 + d2 * d1;
|
||||
this._tx += tx2 * a1 + ty2 * c1;
|
||||
this._ty += tx2 * b1 + ty2 * d1;
|
||||
if (!_dontNotify)
|
||||
this._changed();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
prepend: function(mx) {
|
||||
prepend: function(mx, _dontNotify) {
|
||||
if (mx) {
|
||||
var a1 = this._a,
|
||||
b1 = this._b,
|
||||
|
@ -2305,6 +2318,7 @@ var Matrix = Base.extend({
|
|||
this._d = c2 * c1 + d2 * d1;
|
||||
this._tx = a2 * tx1 + b2 * ty1 + tx2;
|
||||
this._ty = c2 * tx1 + d2 * ty1 + ty2;
|
||||
if (!_dontNotify)
|
||||
this._changed();
|
||||
}
|
||||
return this;
|
||||
|
@ -3236,11 +3250,11 @@ new function() {
|
|||
this._boundsOptions);
|
||||
if (!opts.stroke || this.getStrokeScaling())
|
||||
opts.cacheItem = this;
|
||||
var bounds = this._getCachedBounds(hasMatrix && matrix, opts);
|
||||
var rect = this._getCachedBounds(hasMatrix && matrix, opts).rect;
|
||||
return !arguments.length
|
||||
? new LinkedRectangle(bounds.x, bounds.y, bounds.width,
|
||||
bounds.height, this, 'setBounds')
|
||||
: bounds;
|
||||
? new LinkedRectangle(rect.x, rect.y, rect.width, rect.height,
|
||||
this, 'setBounds')
|
||||
: rect;
|
||||
},
|
||||
|
||||
setBounds: function() {
|
||||
|
@ -3273,29 +3287,49 @@ new function() {
|
|||
return Item._getBounds(children, matrix, options);
|
||||
},
|
||||
|
||||
_getBoundsCacheKey: function(options, internal) {
|
||||
return [
|
||||
options.stroke ? 1 : 0,
|
||||
options.handle ? 1 : 0,
|
||||
internal ? 1 : 0
|
||||
].join('');
|
||||
},
|
||||
|
||||
_getCachedBounds: function(matrix, options, noInternal) {
|
||||
matrix = matrix && matrix._orNullIfIdentity();
|
||||
var internal = options.internal && !noInternal,
|
||||
cacheItem = options.cacheItem,
|
||||
_matrix = internal ? null : this._matrix._orNullIfIdentity(),
|
||||
cacheKey = cacheItem && (!matrix || matrix.equals(_matrix)) && [
|
||||
options.stroke ? 1 : 0,
|
||||
options.handle ? 1 : 0,
|
||||
internal ? 1 : 0
|
||||
].join('');
|
||||
cacheKey = cacheItem && (!matrix || matrix.equals(_matrix))
|
||||
&& this._getBoundsCacheKey(options, internal),
|
||||
bounds = this._bounds;
|
||||
Item._updateBoundsCache(this._parent || this._symbol, cacheItem);
|
||||
if (cacheKey && this._bounds && cacheKey in this._bounds)
|
||||
return this._bounds[cacheKey].rect.clone();
|
||||
var bounds = this._getBounds(matrix || _matrix, options);
|
||||
if (cacheKey && bounds && cacheKey in bounds) {
|
||||
var cached = bounds[cacheKey];
|
||||
return {
|
||||
rect: cached.rect.clone(),
|
||||
nonscaling: cached.nonscaling
|
||||
};
|
||||
}
|
||||
var res = this._getBounds(matrix || _matrix, options),
|
||||
rect = res.rect || res,
|
||||
style = this._style,
|
||||
nonscaling = res.nonscaling || style.hasStroke()
|
||||
&& !style.getStrokeScaling();
|
||||
if (cacheKey) {
|
||||
if (!this._bounds)
|
||||
this._bounds = {};
|
||||
var cached = this._bounds[cacheKey] = {
|
||||
rect: bounds.clone(),
|
||||
if (!bounds) {
|
||||
this._bounds = bounds = {};
|
||||
}
|
||||
var cached = bounds[cacheKey] = {
|
||||
rect: rect.clone(),
|
||||
nonscaling: nonscaling,
|
||||
internal: internal
|
||||
};
|
||||
}
|
||||
return bounds;
|
||||
return {
|
||||
rect: rect,
|
||||
nonscaling: nonscaling
|
||||
};
|
||||
},
|
||||
|
||||
_getStrokeMatrix: function(matrix, options) {
|
||||
|
@ -3340,22 +3374,29 @@ new function() {
|
|||
var x1 = Infinity,
|
||||
x2 = -x1,
|
||||
y1 = x1,
|
||||
y2 = x2;
|
||||
y2 = x2,
|
||||
nonscaling = false;
|
||||
options = options || {};
|
||||
for (var i = 0, l = items.length; i < l; i++) {
|
||||
var item = items[i];
|
||||
if (item._visible && !item.isEmpty()) {
|
||||
var rect = item._getCachedBounds(
|
||||
matrix && matrix.appended(item._matrix), options, true);
|
||||
var bounds = item._getCachedBounds(
|
||||
matrix && matrix.appended(item._matrix), options, true),
|
||||
rect = bounds.rect;
|
||||
x1 = Math.min(rect.x, x1);
|
||||
y1 = Math.min(rect.y, y1);
|
||||
x2 = Math.max(rect.x + rect.width, x2);
|
||||
y2 = Math.max(rect.y + rect.height, y2);
|
||||
if (bounds.nonscaling)
|
||||
nonscaling = true;
|
||||
}
|
||||
}
|
||||
return isFinite(x1)
|
||||
return {
|
||||
rect: isFinite(x1)
|
||||
? new Rectangle(x1, y1, x2 - x1, y2 - y1)
|
||||
: new Rectangle();
|
||||
: new Rectangle(),
|
||||
nonscaling: nonscaling
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3395,8 +3436,18 @@ new function() {
|
|||
var current = this.getScaling(),
|
||||
scaling = Point.read(arguments, 0, { clone: true, readNull: true });
|
||||
if (current && scaling && !current.equals(scaling)) {
|
||||
var decomposed = this._decomposed;
|
||||
this.scale(scaling.x / current.x, scaling.y / current.y);
|
||||
var rotation = this.getRotation(),
|
||||
decomposed = this._decomposed,
|
||||
matrix = new Matrix(),
|
||||
center = this.getPosition(true);
|
||||
matrix.translate(center);
|
||||
if (rotation)
|
||||
matrix.rotate(rotation);
|
||||
matrix.scale(scaling.x / current.x, scaling.y / current.y);
|
||||
if (rotation)
|
||||
matrix.rotate(-rotation);
|
||||
matrix.translate(center.negate());
|
||||
this.transform(matrix);
|
||||
if (decomposed) {
|
||||
decomposed.scaling = scaling;
|
||||
this._decomposed = decomposed;
|
||||
|
@ -4218,8 +4269,6 @@ new function() {
|
|||
|
||||
transform: function(matrix, _applyMatrix, _applyRecursively,
|
||||
_setApplyMatrix) {
|
||||
if (matrix && matrix.isIdentity())
|
||||
matrix = null;
|
||||
var _matrix = this._matrix,
|
||||
transform = matrix && !matrix.isIdentity(),
|
||||
applyMatrix = (_applyMatrix || this._applyMatrix)
|
||||
|
@ -4230,22 +4279,7 @@ new function() {
|
|||
if (transform) {
|
||||
if (!matrix.isInvertible() && _matrix.isInvertible())
|
||||
_matrix._backup = _matrix.getValues();
|
||||
_matrix.prepend(matrix);
|
||||
}
|
||||
if (applyMatrix) {
|
||||
if (this._transformContent(_matrix, _applyRecursively,
|
||||
_setApplyMatrix)) {
|
||||
var pivot = this._pivot;
|
||||
if (pivot)
|
||||
_matrix._transformPoint(pivot, pivot, true);
|
||||
_matrix.reset(true);
|
||||
if (_setApplyMatrix && this._canApplyMatrix)
|
||||
this._applyMatrix = true;
|
||||
} else {
|
||||
applyMatrix = transform = false;
|
||||
}
|
||||
}
|
||||
if (transform) {
|
||||
_matrix.prepend(matrix, true);
|
||||
var style = this._style,
|
||||
fillColor = style.getFillColor(true),
|
||||
strokeColor = style.getStrokeColor(true);
|
||||
|
@ -4254,24 +4288,38 @@ new function() {
|
|||
if (strokeColor)
|
||||
strokeColor.transform(matrix);
|
||||
}
|
||||
if (applyMatrix && (applyMatrix = this._transformContent(_matrix,
|
||||
_applyRecursively, _setApplyMatrix))) {
|
||||
var pivot = this._pivot;
|
||||
if (pivot)
|
||||
_matrix._transformPoint(pivot, pivot, true);
|
||||
_matrix.reset(true);
|
||||
if (_setApplyMatrix && this._canApplyMatrix)
|
||||
this._applyMatrix = true;
|
||||
}
|
||||
var bounds = this._bounds,
|
||||
position = this._position;
|
||||
if (transform || applyMatrix) {
|
||||
this._changed(9);
|
||||
var decomp = bounds && matrix && matrix.decompose();
|
||||
if (decomp && !decomp.shearing && decomp.rotation % 90 === 0) {
|
||||
}
|
||||
var decomp = transform && bounds && matrix.decompose();
|
||||
if (decomp && decomp.skewing.isZero() && decomp.rotation % 90 === 0) {
|
||||
for (var key in bounds) {
|
||||
var cache = bounds[key];
|
||||
if (applyMatrix || !cache.internal) {
|
||||
if (cache.nonscaling) {
|
||||
delete bounds[key];
|
||||
} else if (applyMatrix || !cache.internal) {
|
||||
var rect = cache.rect;
|
||||
matrix._transformBounds(rect, rect);
|
||||
}
|
||||
}
|
||||
var getter = this._boundsGetter,
|
||||
rect = bounds[getter && getter.getBounds || getter || 'getBounds'];
|
||||
if (rect)
|
||||
this._position = rect.getCenter(true);
|
||||
this._bounds = bounds;
|
||||
} else if (matrix && position) {
|
||||
var cached = bounds[this._getBoundsCacheKey(
|
||||
this._boundsOptions || {})];
|
||||
if (cached) {
|
||||
this._position = cached.rect.getCenter(true);
|
||||
}
|
||||
} else if (transform && position && this._pivot) {
|
||||
this._position = matrix._transformPoint(position, position);
|
||||
}
|
||||
return this;
|
||||
|
@ -5483,10 +5531,8 @@ var HitResult = Base.extend({
|
|||
initialize: function HitResult(type, item, values) {
|
||||
this.type = type;
|
||||
this.item = item;
|
||||
if (values) {
|
||||
values.enumerable = true;
|
||||
if (values)
|
||||
this.inject(values);
|
||||
}
|
||||
},
|
||||
|
||||
statics: {
|
||||
|
@ -11016,10 +11062,10 @@ var PointText = TextItem.extend({
|
|||
x = 0;
|
||||
if (justification !== 'left')
|
||||
x -= width / (justification === 'center' ? 2: 1);
|
||||
var bounds = new Rectangle(x,
|
||||
var rect = new Rectangle(x,
|
||||
numLines ? - 0.75 * leading : 0,
|
||||
width, numLines * leading);
|
||||
return matrix ? matrix._transformBounds(bounds, bounds) : bounds;
|
||||
return matrix ? matrix._transformBounds(rect, rect) : rect;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -12694,8 +12740,8 @@ new function() {
|
|||
point, prevPoint)
|
||||
|| hitItem && hitItem !== dragItem
|
||||
&& !hitItem.isDescendant(dragItem)
|
||||
&& emitMouseEvent(hitItem, null, fallbacks[type] || type, event,
|
||||
point, prevPoint, dragItem)
|
||||
&& emitMouseEvent(hitItem, null, type, event, point, prevPoint,
|
||||
dragItem)
|
||||
|| emitMouseEvent(view, dragItem || hitItem || view, type, event,
|
||||
point, prevPoint));
|
||||
}
|
||||
|
@ -13807,9 +13853,9 @@ new function() {
|
|||
if (!Numerical.isZero(scale.x - 1)
|
||||
|| !Numerical.isZero(scale.y - 1))
|
||||
parts.push('scale(' + formatter.point(scale) +')');
|
||||
if (skew && skew.x)
|
||||
if (skew.x)
|
||||
parts.push('skewX(' + formatter.number(skew.x) + ')');
|
||||
if (skew && skew.y)
|
||||
if (skew.y)
|
||||
parts.push('skewY(' + formatter.number(skew.y) + ')');
|
||||
attrs.transform = parts.join(' ');
|
||||
} else {
|
||||
|
@ -13870,8 +13916,9 @@ new function() {
|
|||
if (length > 2) {
|
||||
type = item._closed ? 'polygon' : 'polyline';
|
||||
var parts = [];
|
||||
for(var i = 0; i < length; i++)
|
||||
for (var i = 0; i < length; i++) {
|
||||
parts.push(formatter.point(segments[i]._point));
|
||||
}
|
||||
attrs.points = parts.join(' ');
|
||||
} else {
|
||||
type = 'line';
|
||||
|
@ -14142,6 +14189,7 @@ new function() {
|
|||
? new Rectangle([0, 0], view.getViewSize())
|
||||
: bounds === 'content'
|
||||
? Item._getBounds(children, matrix, { stroke: true })
|
||||
.rect
|
||||
: Rectangle.read([bounds], 0, { readNull: true }),
|
||||
attrs = {
|
||||
version: '1.1',
|
||||
|
@ -14715,7 +14763,6 @@ new function() {
|
|||
};
|
||||
|
||||
paper = new (PaperScope.inject(Base.exports, {
|
||||
enumerable: true,
|
||||
Base: Base,
|
||||
Numerical: Numerical,
|
||||
Key: Key,
|
||||
|
|
219
dist/paper-full.js
vendored
219
dist/paper-full.js
vendored
|
@ -1,5 +1,5 @@
|
|||
/*!
|
||||
* Paper.js v0.11.2 - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* Paper.js v0.11.3 - The Swiss Army Knife of Vector Graphics Scripting.
|
||||
* http://paperjs.org/
|
||||
*
|
||||
* Copyright (c) 2011 - 2016, Juerg Lehni & Jonathan Puckey
|
||||
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Date: Thu Apr 20 19:14:30 2017 +0200
|
||||
* Date: Sat Apr 22 20:01:34 2017 +0200
|
||||
*
|
||||
***
|
||||
*
|
||||
|
@ -98,12 +98,13 @@ var Base = new function() {
|
|||
&& (bean = name.match(/^([gs]et|is)(([A-Z])(.*))$/)))
|
||||
beansNames[bean[3].toLowerCase() + bean[4]] = bean[2];
|
||||
if (!res || isFunc || !res.get || typeof res.get !== 'function'
|
||||
|| !Base.isPlainObject(res))
|
||||
|| !Base.isPlainObject(res)) {
|
||||
res = { value: res, writable: true };
|
||||
}
|
||||
if ((describe(dest, name)
|
||||
|| { configurable: true }).configurable) {
|
||||
res.configurable = true;
|
||||
res.enumerable = enumerable;
|
||||
res.enumerable = enumerable != null ? enumerable : !bean;
|
||||
}
|
||||
define(dest, name, res);
|
||||
}
|
||||
|
@ -141,7 +142,7 @@ var Base = new function() {
|
|||
preserve = src.preserve;
|
||||
if (statics !== src)
|
||||
inject(this.prototype, src, src.enumerable, beans, preserve);
|
||||
inject(this, statics, true, beans, preserve);
|
||||
inject(this, statics, null, beans, preserve);
|
||||
}
|
||||
for (var i = 1, l = arguments.length; i < l; i++)
|
||||
this.inject(arguments[i]);
|
||||
|
@ -164,13 +165,15 @@ var Base = new function() {
|
|||
proto = ctor.prototype = proto || create(this.prototype);
|
||||
define(proto, 'constructor',
|
||||
{ value: ctor, writable: true, configurable: true });
|
||||
inject(ctor, this, true);
|
||||
inject(ctor, this);
|
||||
if (arguments.length)
|
||||
this.inject.apply(ctor, arguments);
|
||||
ctor.base = base;
|
||||
return ctor;
|
||||
}
|
||||
}, true).inject({
|
||||
}).inject({
|
||||
enumerable: false,
|
||||
|
||||
initialize: Base,
|
||||
|
||||
set: Base,
|
||||
|
@ -230,6 +233,8 @@ if (typeof module !== 'undefined')
|
|||
module.exports = Base;
|
||||
|
||||
Base.inject({
|
||||
enumerable: false,
|
||||
|
||||
toString: function() {
|
||||
return this._id != null
|
||||
? (this._class || 'Object') + (this._name
|
||||
|
@ -265,13 +270,12 @@ Base.inject({
|
|||
if (props)
|
||||
Base.filter(this, props, exclude, this._prioritize);
|
||||
return this;
|
||||
},
|
||||
}
|
||||
}, {
|
||||
|
||||
beans: false,
|
||||
statics: {
|
||||
|
||||
exports: {
|
||||
enumerable: true
|
||||
},
|
||||
exports: {},
|
||||
|
||||
extend: function extend() {
|
||||
var res = extend.base.apply(this, arguments),
|
||||
|
@ -341,6 +345,11 @@ Base.inject({
|
|||
: list) || obj;
|
||||
if (readIndex) {
|
||||
list.__index = begin + obj.__read;
|
||||
var filtered = obj.__filtered;
|
||||
if (filtered) {
|
||||
list.__filtered = filtered;
|
||||
obj.__filtered = undefined;
|
||||
}
|
||||
obj.__read = undefined;
|
||||
}
|
||||
return obj;
|
||||
|
@ -371,14 +380,16 @@ Base.inject({
|
|||
var value = this.getNamed(list, name),
|
||||
hasObject = value !== undefined;
|
||||
if (hasObject) {
|
||||
var filtered = list._filtered;
|
||||
var filtered = list.__filtered;
|
||||
if (!filtered) {
|
||||
filtered = list._filtered = Base.create(list[0]);
|
||||
filtered._unfiltered = list[0];
|
||||
filtered = list.__filtered = Base.create(list[0]);
|
||||
filtered.__unfiltered = list[0];
|
||||
}
|
||||
filtered[name] = undefined;
|
||||
}
|
||||
return this.read(hasObject ? [value] : list, start, options, amount);
|
||||
var l = hasObject ? [value] : list,
|
||||
res = this.read(l, start, options, amount);
|
||||
return res;
|
||||
},
|
||||
|
||||
getNamed: function(list, name) {
|
||||
|
@ -386,7 +397,7 @@ Base.inject({
|
|||
if (list._hasObject === undefined)
|
||||
list._hasObject = list.length === 1 && Base.isPlainObject(arg);
|
||||
if (list._hasObject)
|
||||
return name ? arg[name] : list._filtered || arg;
|
||||
return name ? arg[name] : list.__filtered || arg;
|
||||
},
|
||||
|
||||
hasNamed: function(list, name) {
|
||||
|
@ -416,7 +427,7 @@ Base.inject({
|
|||
processed = keys;
|
||||
}
|
||||
|
||||
Object.keys(source._unfiltered || source).forEach(handleKey);
|
||||
Object.keys(source.__unfiltered || source).forEach(handleKey);
|
||||
return dest;
|
||||
},
|
||||
|
||||
|
@ -462,8 +473,7 @@ Base.inject({
|
|||
} else if (Array.isArray(obj)) {
|
||||
res = [];
|
||||
for (var i = 0, l = obj.length; i < l; i++)
|
||||
res[i] = Base.serialize(obj[i], options, compact,
|
||||
dictionary);
|
||||
res[i] = Base.serialize(obj[i], options, compact, dictionary);
|
||||
} else if (Base.isPlainObject(obj)) {
|
||||
res = {};
|
||||
var keys = Object.keys(obj);
|
||||
|
@ -586,8 +596,7 @@ Base.inject({
|
|||
hyphenate: function(str) {
|
||||
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
}
|
||||
});
|
||||
}});
|
||||
|
||||
var Emitter = {
|
||||
on: function(type, func) {
|
||||
|
@ -769,7 +778,7 @@ var PaperScope = Base.extend({
|
|||
}
|
||||
},
|
||||
|
||||
version: "0.11.2",
|
||||
version: "0.11.3",
|
||||
|
||||
getView: function() {
|
||||
var project = this.project;
|
||||
|
@ -1739,6 +1748,9 @@ var Rectangle = Base.extend({
|
|||
}
|
||||
this._set(x, y, width, height);
|
||||
read = arguments.__index;
|
||||
var filtered = arguments.__filtered;
|
||||
if (filtered)
|
||||
this.__filtered = filtered;
|
||||
}
|
||||
if (this.__read)
|
||||
this.__read = read;
|
||||
|
@ -2262,7 +2274,7 @@ var Matrix = Base.extend({
|
|||
return this.shear(shear, center);
|
||||
},
|
||||
|
||||
append: function(mx) {
|
||||
append: function(mx, _dontNotify) {
|
||||
if (mx) {
|
||||
var a1 = this._a,
|
||||
b1 = this._b,
|
||||
|
@ -2280,12 +2292,13 @@ var Matrix = Base.extend({
|
|||
this._d = b2 * b1 + d2 * d1;
|
||||
this._tx += tx2 * a1 + ty2 * c1;
|
||||
this._ty += tx2 * b1 + ty2 * d1;
|
||||
if (!_dontNotify)
|
||||
this._changed();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
prepend: function(mx) {
|
||||
prepend: function(mx, _dontNotify) {
|
||||
if (mx) {
|
||||
var a1 = this._a,
|
||||
b1 = this._b,
|
||||
|
@ -2305,6 +2318,7 @@ var Matrix = Base.extend({
|
|||
this._d = c2 * c1 + d2 * d1;
|
||||
this._tx = a2 * tx1 + b2 * ty1 + tx2;
|
||||
this._ty = c2 * tx1 + d2 * ty1 + ty2;
|
||||
if (!_dontNotify)
|
||||
this._changed();
|
||||
}
|
||||
return this;
|
||||
|
@ -3236,11 +3250,11 @@ new function() {
|
|||
this._boundsOptions);
|
||||
if (!opts.stroke || this.getStrokeScaling())
|
||||
opts.cacheItem = this;
|
||||
var bounds = this._getCachedBounds(hasMatrix && matrix, opts);
|
||||
var rect = this._getCachedBounds(hasMatrix && matrix, opts).rect;
|
||||
return !arguments.length
|
||||
? new LinkedRectangle(bounds.x, bounds.y, bounds.width,
|
||||
bounds.height, this, 'setBounds')
|
||||
: bounds;
|
||||
? new LinkedRectangle(rect.x, rect.y, rect.width, rect.height,
|
||||
this, 'setBounds')
|
||||
: rect;
|
||||
},
|
||||
|
||||
setBounds: function() {
|
||||
|
@ -3273,29 +3287,49 @@ new function() {
|
|||
return Item._getBounds(children, matrix, options);
|
||||
},
|
||||
|
||||
_getBoundsCacheKey: function(options, internal) {
|
||||
return [
|
||||
options.stroke ? 1 : 0,
|
||||
options.handle ? 1 : 0,
|
||||
internal ? 1 : 0
|
||||
].join('');
|
||||
},
|
||||
|
||||
_getCachedBounds: function(matrix, options, noInternal) {
|
||||
matrix = matrix && matrix._orNullIfIdentity();
|
||||
var internal = options.internal && !noInternal,
|
||||
cacheItem = options.cacheItem,
|
||||
_matrix = internal ? null : this._matrix._orNullIfIdentity(),
|
||||
cacheKey = cacheItem && (!matrix || matrix.equals(_matrix)) && [
|
||||
options.stroke ? 1 : 0,
|
||||
options.handle ? 1 : 0,
|
||||
internal ? 1 : 0
|
||||
].join('');
|
||||
cacheKey = cacheItem && (!matrix || matrix.equals(_matrix))
|
||||
&& this._getBoundsCacheKey(options, internal),
|
||||
bounds = this._bounds;
|
||||
Item._updateBoundsCache(this._parent || this._symbol, cacheItem);
|
||||
if (cacheKey && this._bounds && cacheKey in this._bounds)
|
||||
return this._bounds[cacheKey].rect.clone();
|
||||
var bounds = this._getBounds(matrix || _matrix, options);
|
||||
if (cacheKey && bounds && cacheKey in bounds) {
|
||||
var cached = bounds[cacheKey];
|
||||
return {
|
||||
rect: cached.rect.clone(),
|
||||
nonscaling: cached.nonscaling
|
||||
};
|
||||
}
|
||||
var res = this._getBounds(matrix || _matrix, options),
|
||||
rect = res.rect || res,
|
||||
style = this._style,
|
||||
nonscaling = res.nonscaling || style.hasStroke()
|
||||
&& !style.getStrokeScaling();
|
||||
if (cacheKey) {
|
||||
if (!this._bounds)
|
||||
this._bounds = {};
|
||||
var cached = this._bounds[cacheKey] = {
|
||||
rect: bounds.clone(),
|
||||
if (!bounds) {
|
||||
this._bounds = bounds = {};
|
||||
}
|
||||
var cached = bounds[cacheKey] = {
|
||||
rect: rect.clone(),
|
||||
nonscaling: nonscaling,
|
||||
internal: internal
|
||||
};
|
||||
}
|
||||
return bounds;
|
||||
return {
|
||||
rect: rect,
|
||||
nonscaling: nonscaling
|
||||
};
|
||||
},
|
||||
|
||||
_getStrokeMatrix: function(matrix, options) {
|
||||
|
@ -3340,22 +3374,29 @@ new function() {
|
|||
var x1 = Infinity,
|
||||
x2 = -x1,
|
||||
y1 = x1,
|
||||
y2 = x2;
|
||||
y2 = x2,
|
||||
nonscaling = false;
|
||||
options = options || {};
|
||||
for (var i = 0, l = items.length; i < l; i++) {
|
||||
var item = items[i];
|
||||
if (item._visible && !item.isEmpty()) {
|
||||
var rect = item._getCachedBounds(
|
||||
matrix && matrix.appended(item._matrix), options, true);
|
||||
var bounds = item._getCachedBounds(
|
||||
matrix && matrix.appended(item._matrix), options, true),
|
||||
rect = bounds.rect;
|
||||
x1 = Math.min(rect.x, x1);
|
||||
y1 = Math.min(rect.y, y1);
|
||||
x2 = Math.max(rect.x + rect.width, x2);
|
||||
y2 = Math.max(rect.y + rect.height, y2);
|
||||
if (bounds.nonscaling)
|
||||
nonscaling = true;
|
||||
}
|
||||
}
|
||||
return isFinite(x1)
|
||||
return {
|
||||
rect: isFinite(x1)
|
||||
? new Rectangle(x1, y1, x2 - x1, y2 - y1)
|
||||
: new Rectangle();
|
||||
: new Rectangle(),
|
||||
nonscaling: nonscaling
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3395,8 +3436,18 @@ new function() {
|
|||
var current = this.getScaling(),
|
||||
scaling = Point.read(arguments, 0, { clone: true, readNull: true });
|
||||
if (current && scaling && !current.equals(scaling)) {
|
||||
var decomposed = this._decomposed;
|
||||
this.scale(scaling.x / current.x, scaling.y / current.y);
|
||||
var rotation = this.getRotation(),
|
||||
decomposed = this._decomposed,
|
||||
matrix = new Matrix(),
|
||||
center = this.getPosition(true);
|
||||
matrix.translate(center);
|
||||
if (rotation)
|
||||
matrix.rotate(rotation);
|
||||
matrix.scale(scaling.x / current.x, scaling.y / current.y);
|
||||
if (rotation)
|
||||
matrix.rotate(-rotation);
|
||||
matrix.translate(center.negate());
|
||||
this.transform(matrix);
|
||||
if (decomposed) {
|
||||
decomposed.scaling = scaling;
|
||||
this._decomposed = decomposed;
|
||||
|
@ -4218,8 +4269,6 @@ new function() {
|
|||
|
||||
transform: function(matrix, _applyMatrix, _applyRecursively,
|
||||
_setApplyMatrix) {
|
||||
if (matrix && matrix.isIdentity())
|
||||
matrix = null;
|
||||
var _matrix = this._matrix,
|
||||
transform = matrix && !matrix.isIdentity(),
|
||||
applyMatrix = (_applyMatrix || this._applyMatrix)
|
||||
|
@ -4230,22 +4279,7 @@ new function() {
|
|||
if (transform) {
|
||||
if (!matrix.isInvertible() && _matrix.isInvertible())
|
||||
_matrix._backup = _matrix.getValues();
|
||||
_matrix.prepend(matrix);
|
||||
}
|
||||
if (applyMatrix) {
|
||||
if (this._transformContent(_matrix, _applyRecursively,
|
||||
_setApplyMatrix)) {
|
||||
var pivot = this._pivot;
|
||||
if (pivot)
|
||||
_matrix._transformPoint(pivot, pivot, true);
|
||||
_matrix.reset(true);
|
||||
if (_setApplyMatrix && this._canApplyMatrix)
|
||||
this._applyMatrix = true;
|
||||
} else {
|
||||
applyMatrix = transform = false;
|
||||
}
|
||||
}
|
||||
if (transform) {
|
||||
_matrix.prepend(matrix, true);
|
||||
var style = this._style,
|
||||
fillColor = style.getFillColor(true),
|
||||
strokeColor = style.getStrokeColor(true);
|
||||
|
@ -4254,24 +4288,38 @@ new function() {
|
|||
if (strokeColor)
|
||||
strokeColor.transform(matrix);
|
||||
}
|
||||
if (applyMatrix && (applyMatrix = this._transformContent(_matrix,
|
||||
_applyRecursively, _setApplyMatrix))) {
|
||||
var pivot = this._pivot;
|
||||
if (pivot)
|
||||
_matrix._transformPoint(pivot, pivot, true);
|
||||
_matrix.reset(true);
|
||||
if (_setApplyMatrix && this._canApplyMatrix)
|
||||
this._applyMatrix = true;
|
||||
}
|
||||
var bounds = this._bounds,
|
||||
position = this._position;
|
||||
if (transform || applyMatrix) {
|
||||
this._changed(9);
|
||||
var decomp = bounds && matrix && matrix.decompose();
|
||||
if (decomp && !decomp.shearing && decomp.rotation % 90 === 0) {
|
||||
}
|
||||
var decomp = transform && bounds && matrix.decompose();
|
||||
if (decomp && decomp.skewing.isZero() && decomp.rotation % 90 === 0) {
|
||||
for (var key in bounds) {
|
||||
var cache = bounds[key];
|
||||
if (applyMatrix || !cache.internal) {
|
||||
if (cache.nonscaling) {
|
||||
delete bounds[key];
|
||||
} else if (applyMatrix || !cache.internal) {
|
||||
var rect = cache.rect;
|
||||
matrix._transformBounds(rect, rect);
|
||||
}
|
||||
}
|
||||
var getter = this._boundsGetter,
|
||||
rect = bounds[getter && getter.getBounds || getter || 'getBounds'];
|
||||
if (rect)
|
||||
this._position = rect.getCenter(true);
|
||||
this._bounds = bounds;
|
||||
} else if (matrix && position) {
|
||||
var cached = bounds[this._getBoundsCacheKey(
|
||||
this._boundsOptions || {})];
|
||||
if (cached) {
|
||||
this._position = cached.rect.getCenter(true);
|
||||
}
|
||||
} else if (transform && position && this._pivot) {
|
||||
this._position = matrix._transformPoint(position, position);
|
||||
}
|
||||
return this;
|
||||
|
@ -5483,10 +5531,8 @@ var HitResult = Base.extend({
|
|||
initialize: function HitResult(type, item, values) {
|
||||
this.type = type;
|
||||
this.item = item;
|
||||
if (values) {
|
||||
values.enumerable = true;
|
||||
if (values)
|
||||
this.inject(values);
|
||||
}
|
||||
},
|
||||
|
||||
statics: {
|
||||
|
@ -11016,10 +11062,10 @@ var PointText = TextItem.extend({
|
|||
x = 0;
|
||||
if (justification !== 'left')
|
||||
x -= width / (justification === 'center' ? 2: 1);
|
||||
var bounds = new Rectangle(x,
|
||||
var rect = new Rectangle(x,
|
||||
numLines ? - 0.75 * leading : 0,
|
||||
width, numLines * leading);
|
||||
return matrix ? matrix._transformBounds(bounds, bounds) : bounds;
|
||||
return matrix ? matrix._transformBounds(rect, rect) : rect;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -12694,8 +12740,8 @@ new function() {
|
|||
point, prevPoint)
|
||||
|| hitItem && hitItem !== dragItem
|
||||
&& !hitItem.isDescendant(dragItem)
|
||||
&& emitMouseEvent(hitItem, null, fallbacks[type] || type, event,
|
||||
point, prevPoint, dragItem)
|
||||
&& emitMouseEvent(hitItem, null, type, event, point, prevPoint,
|
||||
dragItem)
|
||||
|| emitMouseEvent(view, dragItem || hitItem || view, type, event,
|
||||
point, prevPoint));
|
||||
}
|
||||
|
@ -13807,9 +13853,9 @@ new function() {
|
|||
if (!Numerical.isZero(scale.x - 1)
|
||||
|| !Numerical.isZero(scale.y - 1))
|
||||
parts.push('scale(' + formatter.point(scale) +')');
|
||||
if (skew && skew.x)
|
||||
if (skew.x)
|
||||
parts.push('skewX(' + formatter.number(skew.x) + ')');
|
||||
if (skew && skew.y)
|
||||
if (skew.y)
|
||||
parts.push('skewY(' + formatter.number(skew.y) + ')');
|
||||
attrs.transform = parts.join(' ');
|
||||
} else {
|
||||
|
@ -13870,8 +13916,9 @@ new function() {
|
|||
if (length > 2) {
|
||||
type = item._closed ? 'polygon' : 'polyline';
|
||||
var parts = [];
|
||||
for(var i = 0; i < length; i++)
|
||||
for (var i = 0; i < length; i++) {
|
||||
parts.push(formatter.point(segments[i]._point));
|
||||
}
|
||||
attrs.points = parts.join(' ');
|
||||
} else {
|
||||
type = 'line';
|
||||
|
@ -14142,6 +14189,7 @@ new function() {
|
|||
? new Rectangle([0, 0], view.getViewSize())
|
||||
: bounds === 'content'
|
||||
? Item._getBounds(children, matrix, { stroke: true })
|
||||
.rect
|
||||
: Rectangle.read([bounds], 0, { readNull: true }),
|
||||
attrs = {
|
||||
version: '1.1',
|
||||
|
@ -16413,7 +16461,6 @@ Base.exports.PaperScript = function() {
|
|||
}.call(this);
|
||||
|
||||
paper = new (PaperScope.inject(Base.exports, {
|
||||
enumerable: true,
|
||||
Base: Base,
|
||||
Numerical: Numerical,
|
||||
Key: Key,
|
||||
|
|
|
@ -36,13 +36,15 @@ gulp.task('publish', function() {
|
|||
if (options.branch !== 'develop') {
|
||||
throw new Error('Publishing is only allowed on the develop branch.');
|
||||
}
|
||||
// publish:website comes before publish:release, so paperjs.zip file is gone
|
||||
// before npm publish:
|
||||
return run(
|
||||
'publish:json',
|
||||
'publish:dist',
|
||||
'publish:packages',
|
||||
'publish:commit',
|
||||
'publish:release',
|
||||
'publish:website',
|
||||
'publish:release',
|
||||
'publish:load'
|
||||
);
|
||||
});
|
||||
|
@ -115,8 +117,18 @@ gulp.task('publish:website', function() {
|
|||
}
|
||||
});
|
||||
|
||||
gulp.task('publish:website:build',
|
||||
['publish:website:docs', 'publish:website:zip', 'publish:website:lib']);
|
||||
gulp.task('publish:website:build', [
|
||||
'publish:website:json', 'publish:website:docs',
|
||||
'publish:website:zip', 'publish:website:assets'
|
||||
]);
|
||||
|
||||
gulp.task('publish:website:json', ['publish:version'], function() {
|
||||
return gulp.src([sitePath + '/package.json'])
|
||||
.pipe(jsonEditor({
|
||||
version: options.version
|
||||
}, jsonOptions))
|
||||
.pipe(gulp.dest(sitePath));
|
||||
});
|
||||
|
||||
gulp.task('publish:website:docs:clean', function() {
|
||||
return del([ referencePath + '/*' ], { force: true });
|
||||
|
@ -135,7 +147,10 @@ gulp.task('publish:website:zip', ['publish:version'], function() {
|
|||
.pipe(gulp.dest(downloadPath));
|
||||
});
|
||||
|
||||
gulp.task('publish:website:lib', ['publish:version'], function() {
|
||||
gulp.task('publish:website:assets', function() {
|
||||
// Always delete the old asset first, in case it's a symlink which Gulp
|
||||
// doesn't handle well.
|
||||
fs.unlinkSync(assetPath + '/paper.js');
|
||||
return gulp.src('dist/paper-full.js')
|
||||
.pipe(rename({ basename: 'paper' }))
|
||||
.pipe(gulp.dest(assetPath));
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "paper",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"description": "The Swiss Army Knife of Vector Graphics Scripting",
|
||||
"license": "MIT",
|
||||
"homepage": "http://paperjs.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/paperjs/paper.js"
|
||||
"url": "https://github.com/paperjs/paper.js"
|
||||
},
|
||||
"bugs": "https://github.com/paperjs/paper.js/issues",
|
||||
"contributors": [
|
||||
|
@ -69,7 +69,7 @@
|
|||
"run-sequence": "^1.2.2",
|
||||
"source-map-support": "^0.4.0",
|
||||
"stats.js": "0.16.0",
|
||||
"straps": "^2.1.0"
|
||||
"straps": "^3.0.1"
|
||||
},
|
||||
"browser": {
|
||||
"canvas": false,
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit bab27f25fed8d78f072d8f9a9f68da61e7d1e975
|
||||
Subproject commit fc7ac57828aefadff29f7559a5e39f88d35b0c66
|
|
@ -1 +1 @@
|
|||
Subproject commit 2e257a436e1cfec74ca6ffe4828a761ec058b42f
|
||||
Subproject commit 18feab4d8968339c60d8610584ab3574c49d7a91
|
|
@ -377,7 +377,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
* @param {Matrix} matrix the matrix to append
|
||||
* @return {Matrix} this matrix, modified
|
||||
*/
|
||||
append: function(mx) {
|
||||
append: function(mx, _dontNotify) {
|
||||
if (mx) {
|
||||
var a1 = this._a,
|
||||
b1 = this._b,
|
||||
|
@ -395,6 +395,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
this._d = b2 * b1 + d2 * d1;
|
||||
this._tx += tx2 * a1 + ty2 * c1;
|
||||
this._ty += tx2 * b1 + ty2 * d1;
|
||||
if (!_dontNotify)
|
||||
this._changed();
|
||||
}
|
||||
return this;
|
||||
|
@ -407,7 +408,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
* @param {Matrix} matrix the matrix to prepend
|
||||
* @return {Matrix} this matrix, modified
|
||||
*/
|
||||
prepend: function(mx) {
|
||||
prepend: function(mx, _dontNotify) {
|
||||
if (mx) {
|
||||
var a1 = this._a,
|
||||
b1 = this._b,
|
||||
|
@ -427,6 +428,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
this._d = c2 * c1 + d2 * d1;
|
||||
this._tx = a2 * tx1 + b2 * ty1 + tx2;
|
||||
this._ty = c2 * tx1 + d2 * ty1 + ty2;
|
||||
if (!_dontNotify)
|
||||
this._changed();
|
||||
}
|
||||
return this;
|
||||
|
@ -671,7 +673,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
|
||||
/**
|
||||
* Attempts to decompose the affine transformation described by this matrix
|
||||
* into `scaling`, `rotation` and `shearing`, and returns an object with
|
||||
* into `scaling`, `rotation` and `skewing`, and returns an object with
|
||||
* these properties if it succeeded, `null` otherwise.
|
||||
*
|
||||
* @return {Object} the decomposed matrix, or `null` if decomposition is not
|
||||
|
|
|
@ -141,6 +141,12 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
|
|||
}
|
||||
this._set(x, y, width, height);
|
||||
read = arguments.__index;
|
||||
// arguments.__filtered wouldn't survive the function call even if a
|
||||
// previous arguments list was passed through Function#apply().
|
||||
// Return it on the object instead, see Base.read()
|
||||
var filtered = arguments.__filtered;
|
||||
if (filtered)
|
||||
this.__filtered = filtered;
|
||||
}
|
||||
if (this.__read)
|
||||
this.__read = read;
|
||||
|
|
210
src/core/Base.js
210
src/core/Base.js
|
@ -17,6 +17,8 @@
|
|||
*/
|
||||
// Extend Base with utility functions used across the library.
|
||||
Base.inject(/** @lends Base# */{
|
||||
enumerable: false,
|
||||
|
||||
/**
|
||||
* Renders base objects to strings in object literal notation.
|
||||
*/
|
||||
|
@ -92,14 +94,15 @@ Base.inject(/** @lends Base# */{
|
|||
if (props)
|
||||
Base.filter(this, props, exclude, this._prioritize);
|
||||
return this;
|
||||
},
|
||||
|
||||
}
|
||||
}, /** @lends Base# */{
|
||||
// Mess with indentation in order to get more line-space for the statics below.
|
||||
// Explicitly deactivate the creation of beans, as we have functions here
|
||||
// that look like bean getters but actually read arguments, see getNamed().
|
||||
beans: false,
|
||||
statics: /** @lends Base */{
|
||||
|
||||
// Keep track of all named classes for serialization and exporting.
|
||||
exports: {
|
||||
enumerable: true // For PaperScope.inject() in export.js
|
||||
},
|
||||
exports: {},
|
||||
|
||||
extend: function extend() {
|
||||
// Override Base.extend() to register named classes in Base.exports,
|
||||
|
@ -112,9 +115,9 @@ Base.inject(/** @lends Base# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* Checks if two values or objects are equals to each other, by using
|
||||
* their equals() methods if available, and also comparing elements of
|
||||
* arrays and properties of objects.
|
||||
* Checks if two values or objects are equals to each other, by using their
|
||||
* equals() methods if available, and also comparing elements of arrays and
|
||||
* properties of objects.
|
||||
*/
|
||||
equals: function(obj1, obj2) {
|
||||
if (obj1 === obj2)
|
||||
|
@ -158,26 +161,25 @@ Base.inject(/** @lends Base# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* When called on a subclass of Base, it reads arguments of the type of
|
||||
* the subclass from the passed arguments list or array, at the given
|
||||
* index, up to the specified length.
|
||||
* When called directly on Base, it reads any value without conversion
|
||||
* from the passed arguments list or array.
|
||||
* This is used in argument conversion, e.g. by all basic types (Point,
|
||||
* Size, Rectangle) and also higher classes such as Color and Segment.
|
||||
* When called on a subclass of Base, it reads arguments of the type of the
|
||||
* subclass from the passed arguments list or array, at the given index, up
|
||||
* to the specified length. When called directly on Base, it reads any value
|
||||
* without conversion from the passed arguments list or array. This is used
|
||||
* in argument conversion, e.g. by all basic types (Point, Size, Rectangle)
|
||||
* and also higher classes such as Color and Segment.
|
||||
*
|
||||
* @param {Array} list the list to read from, either an arguments object
|
||||
* or a normal array
|
||||
* @param {Array} list the list to read from, either an arguments object or
|
||||
* a normal array
|
||||
* @param {Number} start the index at which to start reading in the list
|
||||
* @param {Object} options `options.readNull` controls whether null is
|
||||
* returned or converted. `options.clone` controls whether passed
|
||||
* objects should be cloned if they are already provided in the
|
||||
* required type
|
||||
* objects should be cloned if they are already provided in the required
|
||||
* type
|
||||
* @param {Number} length the amount of elements that can be read
|
||||
*/
|
||||
read: function(list, start, options, amount) {
|
||||
// See if it's called directly on Base, and if so, read value and
|
||||
// return without object conversion.
|
||||
// See if it's called directly on Base, and if so, read value and return
|
||||
// without object conversion.
|
||||
if (this === Base) {
|
||||
var value = this.peek(list, start);
|
||||
list.__index++;
|
||||
|
@ -189,9 +191,9 @@ Base.inject(/** @lends Base# */{
|
|||
length = list.length,
|
||||
obj = list[begin];
|
||||
amount = amount || length - begin;
|
||||
// When read() is called on a sub-class of which the object is
|
||||
// already an instance, or when there is only one value in the list
|
||||
// and it's null or undefined, return the obj.
|
||||
// When read() is called on a sub-class of which the object is already
|
||||
// an instance, or when there is only one value in the list and it's
|
||||
// null or undefined, return the obj.
|
||||
if (obj instanceof this
|
||||
|| options && options.readNull && obj == null && amount <= 1) {
|
||||
if (readIndex)
|
||||
|
@ -208,6 +210,14 @@ Base.inject(/** @lends Base# */{
|
|||
: list) || obj;
|
||||
if (readIndex) {
|
||||
list.__index = begin + obj.__read;
|
||||
// This is only in use in Rectangle so far: Nested calls to
|
||||
// `Base.readNamed()` would loose __filtered if it wasn't returned
|
||||
// on the object.
|
||||
var filtered = obj.__filtered;
|
||||
if (filtered) {
|
||||
list.__filtered = filtered;
|
||||
obj.__filtered = undefined;
|
||||
}
|
||||
obj.__read = undefined;
|
||||
}
|
||||
return obj;
|
||||
|
@ -259,20 +269,20 @@ Base.inject(/** @lends Base# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* Allows using of Base.read() mechanism in combination with reading
|
||||
* named arguments form a passed property object literal. Calling
|
||||
* Base.readNamed() can read both from such named properties and normal
|
||||
* unnamed arguments through Base.read(). In use for example for the
|
||||
* various Path.Constructors.
|
||||
* Allows using of Base.read() mechanism in combination with reading named
|
||||
* arguments form a passed property object literal. Calling Base.readNamed()
|
||||
* can read both from such named properties and normal unnamed arguments
|
||||
* through Base.read(). In use for example for the various
|
||||
* Path.Constructors.
|
||||
*
|
||||
* @param {Array} list the list to read from, either an arguments object
|
||||
* or a normal array
|
||||
* @param {Array} list the list to read from, either an arguments object or
|
||||
* a normal array
|
||||
* @param {String} name the property name to read from
|
||||
* @param {Number} start the index at which to start reading in the list
|
||||
* @param {Object} options `options.readNull` controls whether null is
|
||||
* returned or converted. `options.clone` controls whether passed
|
||||
* objects should be cloned if they are already provided in the
|
||||
* required type
|
||||
* objects should be cloned if they are already provided in the required
|
||||
* type
|
||||
* @param {Number} amount the amount of elements that can be read
|
||||
*/
|
||||
readNamed: function(list, name, start, options, amount) {
|
||||
|
@ -281,18 +291,20 @@ Base.inject(/** @lends Base# */{
|
|||
if (hasObject) {
|
||||
// Create a _filtered object that inherits from list[0], and
|
||||
// override all fields that were already read with undefined.
|
||||
var filtered = list._filtered;
|
||||
var filtered = list.__filtered;
|
||||
if (!filtered) {
|
||||
filtered = list._filtered = Base.create(list[0]);
|
||||
filtered = list.__filtered = Base.create(list[0]);
|
||||
// Point _unfiltered to the original so Base#_set() can
|
||||
// execute hasOwnProperty on it.
|
||||
filtered._unfiltered = list[0];
|
||||
filtered.__unfiltered = list[0];
|
||||
}
|
||||
// delete wouldn't work since the masked parent's value would
|
||||
// shine through.
|
||||
filtered[name] = undefined;
|
||||
}
|
||||
return this.read(hasObject ? [value] : list, start, options, amount);
|
||||
var l = hasObject ? [value] : list,
|
||||
res = this.read(l, start, options, amount);
|
||||
return res;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -307,13 +319,12 @@ Base.inject(/** @lends Base# */{
|
|||
list._hasObject = list.length === 1 && Base.isPlainObject(arg);
|
||||
if (list._hasObject)
|
||||
// Return the whole arguments object if no name is provided.
|
||||
return name ? arg[name] : list._filtered || arg;
|
||||
return name ? arg[name] : list.__filtered || arg;
|
||||
},
|
||||
|
||||
/**
|
||||
* Checks if the argument list has a named argument with the given name.
|
||||
* If name is `null`, it returns `true` if there are any named
|
||||
* arguments.
|
||||
* Checks if the argument list has a named argument with the given name. If
|
||||
* name is `null`, it returns `true` if there are any named arguments.
|
||||
*/
|
||||
hasNamed: function(list, name) {
|
||||
return !!this.getNamed(list, name);
|
||||
|
@ -321,18 +332,17 @@ Base.inject(/** @lends Base# */{
|
|||
|
||||
/**
|
||||
* Copies all properties from `source` over to `dest`, supporting
|
||||
* `_filtered` handling as required by {@link Base.readNamed()}
|
||||
* mechanism, as well as a way to exclude and prioritize properties.
|
||||
* `_filtered` handling as required by {@link Base.readNamed()} mechanism,
|
||||
* as well as a way to exclude and prioritize properties.
|
||||
*
|
||||
* @param {Object} dest the destination that is to receive the
|
||||
* properties
|
||||
* @param {Object} source the source from where to retrieve the
|
||||
* properties to be copied
|
||||
* @param {Object} [exclude] an object that can define any properties
|
||||
* as `true` that should be excluded when copying
|
||||
* @param {String[]} [prioritize] a list of keys that should be
|
||||
* prioritized when copying, if they are defined in `source`,
|
||||
* processed in the order of appearance
|
||||
* @param {Object} dest the destination that is to receive the properties
|
||||
* @param {Object} source the source from where to retrieve the properties
|
||||
* to be copied
|
||||
* @param {Object} [exclude] an object that can define any properties as
|
||||
* `true` that should be excluded when copying
|
||||
* @param {String[]} [prioritize] a list of keys that should be prioritized
|
||||
* when copying, if they are defined in `source`, processed in the order
|
||||
* of appearance
|
||||
*/
|
||||
filter: function(dest, source, exclude, prioritize) {
|
||||
var processed;
|
||||
|
@ -362,16 +372,16 @@ Base.inject(/** @lends Base# */{
|
|||
processed = keys;
|
||||
}
|
||||
|
||||
// If source is a filtered object, we get the keys from the
|
||||
// the original object (it's parent / prototype). See _filtered
|
||||
// inheritance trick in the argument reading code.
|
||||
Object.keys(source._unfiltered || source).forEach(handleKey);
|
||||
// If source is a filtered object, we get the keys from the the original
|
||||
// object (it's parent / prototype). See _filtered inheritance trick in
|
||||
// the argument reading code.
|
||||
Object.keys(source.__unfiltered || source).forEach(handleKey);
|
||||
return dest;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if obj is either a plain object or an array, as used by
|
||||
* many argument reading methods.
|
||||
* Returns true if obj is either a plain object or an array, as used by many
|
||||
* argument reading methods.
|
||||
*/
|
||||
isPlainValue: function(obj, asString) {
|
||||
return Base.isPlainObject(obj) || Array.isArray(obj)
|
||||
|
@ -380,7 +390,7 @@ Base.inject(/** @lends Base# */{
|
|||
|
||||
/**
|
||||
* Serializes the passed object into a format that can be passed to
|
||||
* JSON.stringify() for JSON serialization.
|
||||
* `JSON.stringify()` for JSON serialization.
|
||||
*/
|
||||
serialize: function(obj, options, compact, dictionary) {
|
||||
options = options || {};
|
||||
|
@ -389,10 +399,10 @@ Base.inject(/** @lends Base# */{
|
|||
res;
|
||||
if (isRoot) {
|
||||
options.formatter = new Formatter(options.precision);
|
||||
// Create a simple dictionary object that handles all the
|
||||
// storing and retrieving of dictionary definitions and
|
||||
// references, e.g. for symbols and gradients. Items that want
|
||||
// to support this need to define globally unique _id attribute.
|
||||
// Create a simple dictionary object that handles all the storing
|
||||
// and retrieving of dictionary definitions and references, e.g. for
|
||||
// symbols and gradients. Items that want to support this need to
|
||||
// define globally unique _id attribute.
|
||||
/**
|
||||
* @namespace
|
||||
* @private
|
||||
|
@ -402,10 +412,9 @@ Base.inject(/** @lends Base# */{
|
|||
definitions: {},
|
||||
references: {},
|
||||
add: function(item, create) {
|
||||
// See if we have reference entry with the given id
|
||||
// already. If not, call create on the item to allow it
|
||||
// to create the definition, then store the reference
|
||||
// to it and return it.
|
||||
// See if we have reference entry with the given id already.
|
||||
// If not, call create on the item to allow it to create the
|
||||
// definition, then store the reference to it and return it.
|
||||
var id = '#' + item._id,
|
||||
ref = this.references[id];
|
||||
if (!ref) {
|
||||
|
@ -426,11 +435,11 @@ Base.inject(/** @lends Base# */{
|
|||
if (obj && obj._serialize) {
|
||||
res = obj._serialize(options, dictionary);
|
||||
// If we don't serialize to compact form (meaning no type
|
||||
// identifier), see if _serialize didn't already add the class,
|
||||
// e.g. for classes that do not support compact form.
|
||||
// identifier), see if _serialize didn't already add the class, e.g.
|
||||
// for classes that do not support compact form.
|
||||
var name = obj._class;
|
||||
// Enforce class names on root level, except if the class
|
||||
// explicitly asks to be serialized in compact form (Project).
|
||||
// Enforce class names on root level, except if the class explicitly
|
||||
// asks to be serialized in compact form (Project).
|
||||
if (name && !obj._compactSerialize && (isRoot || !compact)
|
||||
&& res[0] !== name) {
|
||||
res.unshift(name);
|
||||
|
@ -438,8 +447,7 @@ Base.inject(/** @lends Base# */{
|
|||
} else if (Array.isArray(obj)) {
|
||||
res = [];
|
||||
for (var i = 0, l = obj.length; i < l; i++)
|
||||
res[i] = Base.serialize(obj[i], options, compact,
|
||||
dictionary);
|
||||
res[i] = Base.serialize(obj[i], options, compact, dictionary);
|
||||
} else if (Base.isPlainObject(obj)) {
|
||||
res = {};
|
||||
var keys = Object.keys(obj);
|
||||
|
@ -461,37 +469,36 @@ Base.inject(/** @lends Base# */{
|
|||
/**
|
||||
* Deserializes from parsed JSON data. A simple convention is followed:
|
||||
* Array values with a string at the first position are links to
|
||||
* deserializable types through Base.exports, and the values following
|
||||
* in the array are the arguments to their initialize function.
|
||||
* Any other value is passed on unmodified.
|
||||
* The passed json data is recoursively traversed and converted, leaves
|
||||
* first
|
||||
* deserializable types through Base.exports, and the values following in
|
||||
* the array are the arguments to their initialize function. Any other value
|
||||
* is passed on unmodified. The passed json data is recoursively traversed
|
||||
* and converted, leaves first.
|
||||
*/
|
||||
deserialize: function(json, create, _data, _setDictionary, _isRoot) {
|
||||
var res = json,
|
||||
isFirst = !_data,
|
||||
hasDictionary = isFirst && json && json.length
|
||||
&& json[0][0] === 'dictionary';
|
||||
// A _data side-car to deserialize that can hold any kind of
|
||||
// 'global' data across a deserialization. It's currently only used
|
||||
// to hold dictionary definitions.
|
||||
// A _data side-car to deserialize that can hold any kind of 'global'
|
||||
// data across a deserialization. It's currently only used to hold
|
||||
// dictionary definitions.
|
||||
_data = _data || {};
|
||||
if (Array.isArray(json)) {
|
||||
// See if it's a serialized type. If so, the rest of the array
|
||||
// are the arguments to #initialize(). Either way, we simply
|
||||
// deserialize all elements of the array.
|
||||
// See if it's a serialized type. If so, the rest of the array are
|
||||
// the arguments to #initialize(). Either way, we simply deserialize
|
||||
// all elements of the array.
|
||||
var type = json[0],
|
||||
// Handle stored dictionary specially, since we need to
|
||||
// keep a lookup table to retrieve referenced items from.
|
||||
// Handle stored dictionary specially, since we need to keep a
|
||||
// lookup table to retrieve referenced items from.
|
||||
isDictionary = type === 'dictionary';
|
||||
// First see if this is perhaps a dictionary reference, and
|
||||
// if so return its definition instead.
|
||||
// First see if this is perhaps a dictionary reference, and if so
|
||||
// return its definition instead.
|
||||
if (json.length == 1 && /^#/.test(type)) {
|
||||
return _data.dictionary[type];
|
||||
}
|
||||
type = Base.exports[type];
|
||||
res = [];
|
||||
// Skip first type entry for arguments
|
||||
// Skip first type entry for arguments.
|
||||
// Pass true for _isRoot in children if we have a dictionary,
|
||||
// in which case we need to shift the root level one down.
|
||||
for (var i = type ? 1 : 0, l = json.length; i < l; i++) {
|
||||
|
@ -502,9 +509,9 @@ Base.inject(/** @lends Base# */{
|
|||
// Create serialized type and pass collected arguments to
|
||||
// constructor().
|
||||
var args = res;
|
||||
// If a create method is provided, handle our own
|
||||
// creation. This is used in #importJSON() to pass
|
||||
// on insert = false to all items except layers.
|
||||
// If a create method is provided, handle our own creation. This
|
||||
// is used in #importJSON() to pass on insert = false to all
|
||||
// items except layers.
|
||||
if (create) {
|
||||
res = create(type, args, isFirst || _isRoot);
|
||||
} else {
|
||||
|
@ -545,10 +552,10 @@ Base.inject(/** @lends Base# */{
|
|||
&& target.constructor === ctor,
|
||||
obj = useTarget ? target
|
||||
: Base.create(ctor.prototype);
|
||||
// NOTE: We don't set insert false for layers since we
|
||||
// want these to be created on the fly in the active
|
||||
// project into which we're importing (except for if
|
||||
// it's a preexisting target layer).
|
||||
// NOTE: We don't set insert false for layers since we want
|
||||
// these to be created on the fly in the active project into
|
||||
// which we're importing (except for if it's a preexisting
|
||||
// target layer).
|
||||
if (args.length === 1 && obj instanceof Item
|
||||
&& (useTarget || !(obj instanceof Layer))) {
|
||||
var arg = args[0];
|
||||
|
@ -566,9 +573,9 @@ Base.inject(/** @lends Base# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* Utility function for adding and removing items from a list of which
|
||||
* each entry keeps a reference to its index in the list in the private
|
||||
* _index property. Used for PaperScope#projects and Item#children.
|
||||
* Utility function for adding and removing items from a list of which each
|
||||
* entry keeps a reference to its index in the list in the private _index
|
||||
* property. Used for PaperScope#projects and Item#children.
|
||||
*/
|
||||
splice: function(list, items, index, remove) {
|
||||
var amount = items && items.length,
|
||||
|
@ -624,5 +631,4 @@ Base.inject(/** @lends Base# */{
|
|||
hyphenate: function(str) {
|
||||
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
||||
}
|
||||
}
|
||||
});
|
||||
}});
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
// global one in the whole scope.
|
||||
|
||||
paper = new (PaperScope.inject(Base.exports, {
|
||||
// Mark fields as enumerable so PaperScope.inject can pick them up
|
||||
enumerable: true,
|
||||
Base: Base,
|
||||
Numerical: Numerical,
|
||||
Key: Key,
|
||||
|
|
|
@ -26,11 +26,8 @@ var HitResult = Base.extend(/** @lends HitResult# */{
|
|||
// Inject passed values, so we can be flexible about the HitResult
|
||||
// properties.
|
||||
// This allows the definition of getters too, e.g. for 'pixel'.
|
||||
if (values) {
|
||||
// Make enumerable so toString() works.
|
||||
values.enumerable = true;
|
||||
if (values)
|
||||
this.inject(values);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
181
src/item/Item.js
181
src/item/Item.js
|
@ -827,14 +827,14 @@ new function() { // Injection scope for various item event handlers
|
|||
opts.cacheItem = this;
|
||||
// If we're caching bounds, pass on this item as cacheItem, so
|
||||
// the children can setup _boundsCache structures for it.
|
||||
var bounds = this._getCachedBounds(hasMatrix && matrix, opts);
|
||||
var rect = this._getCachedBounds(hasMatrix && matrix, opts).rect;
|
||||
// If we're returning '#bounds', create a LinkedRectangle that uses
|
||||
// the setBounds() setter to update the Item whenever the bounds are
|
||||
// changed:
|
||||
return !arguments.length
|
||||
? new LinkedRectangle(bounds.x, bounds.y, bounds.width,
|
||||
bounds.height, this, 'setBounds')
|
||||
: bounds;
|
||||
? new LinkedRectangle(rect.x, rect.y, rect.width, rect.height,
|
||||
this, 'setBounds')
|
||||
: rect;
|
||||
},
|
||||
|
||||
setBounds: function(/* rect */) {
|
||||
|
@ -889,6 +889,14 @@ new function() { // Injection scope for various item event handlers
|
|||
return Item._getBounds(children, matrix, options);
|
||||
},
|
||||
|
||||
_getBoundsCacheKey: function(options, internal) {
|
||||
return [
|
||||
options.stroke ? 1 : 0,
|
||||
options.handle ? 1 : 0,
|
||||
internal ? 1 : 0
|
||||
].join('');
|
||||
},
|
||||
|
||||
/**
|
||||
* Private method that deals with the calling of _getBounds, recursive
|
||||
* matrix concatenation and handles all the complicated caching mechanisms.
|
||||
|
@ -904,29 +912,43 @@ new function() { // Injection scope for various item event handlers
|
|||
cacheItem = options.cacheItem,
|
||||
_matrix = internal ? null : this._matrix._orNullIfIdentity(),
|
||||
// Create a key for caching, reflecting all bounds options.
|
||||
cacheKey = cacheItem && (!matrix || matrix.equals(_matrix)) && [
|
||||
options.stroke ? 1 : 0,
|
||||
options.handle ? 1 : 0,
|
||||
internal ? 1 : 0
|
||||
].join('');
|
||||
cacheKey = cacheItem && (!matrix || matrix.equals(_matrix))
|
||||
&& this._getBoundsCacheKey(options, internal),
|
||||
bounds = this._bounds;
|
||||
// NOTE: This needs to happen before returning cached values, since even
|
||||
// then, _boundsCache needs to be kept up-to-date.
|
||||
Item._updateBoundsCache(this._parent || this._symbol, cacheItem);
|
||||
if (cacheKey && this._bounds && cacheKey in this._bounds)
|
||||
return this._bounds[cacheKey].rect.clone();
|
||||
var bounds = this._getBounds(matrix || _matrix, options);
|
||||
if (cacheKey && bounds && cacheKey in bounds) {
|
||||
var cached = bounds[cacheKey];
|
||||
return {
|
||||
rect: cached.rect.clone(),
|
||||
nonscaling: cached.nonscaling
|
||||
};
|
||||
}
|
||||
var res = this._getBounds(matrix || _matrix, options),
|
||||
// Support two versions of _getBounds(): One that directly returns a
|
||||
// Rectangle, and one that returns a bounds object with nonscaling.
|
||||
rect = res.rect || res,
|
||||
style = this._style,
|
||||
nonscaling = res.nonscaling || style.hasStroke()
|
||||
&& !style.getStrokeScaling();
|
||||
// If we can cache the result, update the _bounds cache structure
|
||||
// before returning
|
||||
if (cacheKey) {
|
||||
if (!this._bounds)
|
||||
this._bounds = {};
|
||||
var cached = this._bounds[cacheKey] = {
|
||||
rect: bounds.clone(),
|
||||
if (!bounds) {
|
||||
this._bounds = bounds = {};
|
||||
}
|
||||
var cached = bounds[cacheKey] = {
|
||||
rect: rect.clone(),
|
||||
nonscaling: nonscaling,
|
||||
// Mark as internal, so Item#transform() won't transform it
|
||||
internal: internal
|
||||
};
|
||||
}
|
||||
return bounds;
|
||||
return {
|
||||
rect: rect,
|
||||
nonscaling: nonscaling
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1005,7 +1027,10 @@ new function() { // Injection scope for various item event handlers
|
|||
var x1 = Infinity,
|
||||
x2 = -x1,
|
||||
y1 = x1,
|
||||
y2 = x2;
|
||||
y2 = x2,
|
||||
nonscaling = false;
|
||||
// NOTE: As soon as one child-item has non-scaling strokes, the full
|
||||
// bounds need to be considered non-scaling for caching purposes.
|
||||
options = options || {};
|
||||
for (var i = 0, l = items.length; i < l; i++) {
|
||||
var item = items[i];
|
||||
|
@ -1013,17 +1038,23 @@ new function() { // Injection scope for various item event handlers
|
|||
// Pass true for noInternal, since even when getting
|
||||
// internal bounds for this item, we need to apply the
|
||||
// matrices to its children.
|
||||
var rect = item._getCachedBounds(
|
||||
matrix && matrix.appended(item._matrix), options, true);
|
||||
var bounds = item._getCachedBounds(
|
||||
matrix && matrix.appended(item._matrix), options, true),
|
||||
rect = bounds.rect;
|
||||
x1 = Math.min(rect.x, x1);
|
||||
y1 = Math.min(rect.y, y1);
|
||||
x2 = Math.max(rect.x + rect.width, x2);
|
||||
y2 = Math.max(rect.y + rect.height, y2);
|
||||
if (bounds.nonscaling)
|
||||
nonscaling = true;
|
||||
}
|
||||
}
|
||||
return isFinite(x1)
|
||||
return {
|
||||
rect: isFinite(x1)
|
||||
? new Rectangle(x1, y1, x2 - x1, y2 - y1)
|
||||
: new Rectangle();
|
||||
: new Rectangle(),
|
||||
nonscaling: nonscaling
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1122,8 +1153,22 @@ new function() { // Injection scope for various item event handlers
|
|||
scaling = Point.read(arguments, 0, { clone: true, readNull: true });
|
||||
if (current && scaling && !current.equals(scaling)) {
|
||||
// See #setRotation() for preservation of _decomposed.
|
||||
var decomposed = this._decomposed;
|
||||
this.scale(scaling.x / current.x, scaling.y / current.y);
|
||||
var rotation = this.getRotation(),
|
||||
decomposed = this._decomposed,
|
||||
matrix = new Matrix(),
|
||||
center = this.getPosition(true);
|
||||
// Create a matrix in which the scaling is applied in the non-
|
||||
// rotated state, so it is always applied before the rotation.
|
||||
// TODO: What about skewing? Do we need separately stored values for
|
||||
// these properties, and apply them separately from the matrix?
|
||||
matrix.translate(center);
|
||||
if (rotation)
|
||||
matrix.rotate(rotation);
|
||||
matrix.scale(scaling.x / current.x, scaling.y / current.y);
|
||||
if (rotation)
|
||||
matrix.rotate(-rotation);
|
||||
matrix.translate(center.negate());
|
||||
this.transform(matrix);
|
||||
if (decomposed) {
|
||||
decomposed.scaling = scaling;
|
||||
this._decomposed = decomposed;
|
||||
|
@ -3376,11 +3421,9 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
// 'lines'. Default: ['objects', 'children']
|
||||
transform: function(matrix, _applyMatrix, _applyRecursively,
|
||||
_setApplyMatrix) {
|
||||
var _matrix = this._matrix,
|
||||
// If no matrix is provided, or the matrix is the identity, we might
|
||||
// still have some work to do in case _applyMatrix is true
|
||||
if (matrix && matrix.isIdentity())
|
||||
matrix = null;
|
||||
var _matrix = this._matrix,
|
||||
transform = matrix && !matrix.isIdentity(),
|
||||
applyMatrix = (_applyMatrix || this._applyMatrix)
|
||||
// Don't apply _matrix if the result of concatenating with
|
||||
|
@ -3398,30 +3441,8 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
// non-invertible. This is then used again in setBounds to restore.
|
||||
if (!matrix.isInvertible() && _matrix.isInvertible())
|
||||
_matrix._backup = _matrix.getValues();
|
||||
_matrix.prepend(matrix);
|
||||
}
|
||||
// Call #_transformContent() now, if we need to directly apply the
|
||||
// internal _matrix transformations to the item's content.
|
||||
// Application is not possible on Raster, PointText, SymbolItem, since
|
||||
// the matrix is where the actual transformation state is stored.
|
||||
if (applyMatrix) {
|
||||
if (this._transformContent(_matrix, _applyRecursively,
|
||||
_setApplyMatrix)) {
|
||||
var pivot = this._pivot;
|
||||
if (pivot)
|
||||
_matrix._transformPoint(pivot, pivot, true);
|
||||
// Reset the internal matrix to the identity transformation if
|
||||
// it was possible to apply it.
|
||||
_matrix.reset(true);
|
||||
// Set the internal _applyMatrix flag to true if we're told to
|
||||
// do so
|
||||
if (_setApplyMatrix && this._canApplyMatrix)
|
||||
this._applyMatrix = true;
|
||||
} else {
|
||||
applyMatrix = transform = false;
|
||||
}
|
||||
}
|
||||
if (transform) {
|
||||
// Pass `true` for _dontNotify, as we're handling this after.
|
||||
_matrix.prepend(matrix, true);
|
||||
// When a new matrix was applied, we also need to transform gradient
|
||||
// color points. These always need transforming, regardless of
|
||||
// #applyMatrix, as they are defined in the parent's coordinate
|
||||
|
@ -3438,39 +3459,65 @@ new function() { // Injection scope for hit-test functions shared with project
|
|||
if (strokeColor)
|
||||
strokeColor.transform(matrix);
|
||||
}
|
||||
// Call #_transformContent() now, if we need to directly apply the
|
||||
// internal _matrix transformations to the item's content.
|
||||
// Application is not possible on Raster, PointText, SymbolItem, since
|
||||
// the matrix is where the actual transformation state is stored.
|
||||
if (applyMatrix && (applyMatrix = this._transformContent(_matrix,
|
||||
_applyRecursively, _setApplyMatrix))) {
|
||||
// Pivot is provided in the parent's coordinate system, so transform
|
||||
// it along too.
|
||||
var pivot = this._pivot;
|
||||
if (pivot)
|
||||
_matrix._transformPoint(pivot, pivot, true);
|
||||
// Reset the internal matrix to the identity transformation if
|
||||
// it was possible to apply it, but do not notify owner of change.
|
||||
_matrix.reset(true);
|
||||
// Set the internal _applyMatrix flag to true if we're told to
|
||||
// do so
|
||||
if (_setApplyMatrix && this._canApplyMatrix)
|
||||
this._applyMatrix = true;
|
||||
}
|
||||
// Calling _changed will clear _bounds and _position, but depending
|
||||
// on matrix we can calculate and set them again, so preserve them.
|
||||
var bounds = this._bounds,
|
||||
position = this._position;
|
||||
// We always need to call _changed since we're caching bounds on all
|
||||
// items, including Group.
|
||||
if (transform || applyMatrix) {
|
||||
this._changed(/*#=*/Change.GEOMETRY);
|
||||
}
|
||||
// Detect matrices that contain only translations and scaling
|
||||
// and transform the cached _bounds and _position without having to
|
||||
// fully recalculate each time.
|
||||
var decomp = bounds && matrix && matrix.decompose();
|
||||
if (decomp && !decomp.shearing && decomp.rotation % 90 === 0) {
|
||||
// Transform the old bound by looping through all the cached bounds
|
||||
// in _bounds and transform each.
|
||||
var decomp = transform && bounds && matrix.decompose();
|
||||
if (decomp && decomp.skewing.isZero() && decomp.rotation % 90 === 0) {
|
||||
// Transform the old bound by looping through all the cached
|
||||
// bounds in _bounds and transform each.
|
||||
for (var key in bounds) {
|
||||
var cache = bounds[key];
|
||||
// If any item involved in the determination of these bounds has
|
||||
// non-scaling strokes, delete the cache now as it can't be
|
||||
// preserved through the transformation.
|
||||
if (cache.nonscaling) {
|
||||
delete bounds[key];
|
||||
} else if (applyMatrix || !cache.internal) {
|
||||
// If these are internal bounds, only transform them if this
|
||||
// item applied its matrix.
|
||||
if (applyMatrix || !cache.internal) {
|
||||
var rect = cache.rect;
|
||||
matrix._transformBounds(rect, rect);
|
||||
}
|
||||
}
|
||||
// If we have cached bounds, update _position again as its
|
||||
// center. We need to take into account _boundsGetter here too, in
|
||||
// case another getter is assigned to it, e.g. 'getStrokeBounds'.
|
||||
var getter = this._boundsGetter,
|
||||
rect = bounds[getter && getter.getBounds || getter || 'getBounds'];
|
||||
if (rect)
|
||||
this._position = rect.getCenter(true);
|
||||
this._bounds = bounds;
|
||||
} else if (matrix && position) {
|
||||
// Transform position as well.
|
||||
// If we have cached bounds, try to determine _position as its
|
||||
// center. Use _boundsOptions do get the cached default bounds.
|
||||
var cached = bounds[this._getBoundsCacheKey(
|
||||
this._boundsOptions || {})];
|
||||
if (cached) {
|
||||
this._position = cached.rect.getCenter(true);
|
||||
}
|
||||
} else if (transform && position && this._pivot) {
|
||||
// If the item has a pivot defined, it means that the default
|
||||
// position defined as the center of the bounds won't shift with
|
||||
// arbitrary transformations and we can therefore update _position:
|
||||
this._position = matrix._transformPoint(position, position);
|
||||
}
|
||||
// Allow chaining here, since transform() is related to Matrix functions
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// The paper.js version.
|
||||
// NOTE: Adjust value here before calling `gulp publish`, which then updates and
|
||||
// publishes the various JSON package files automatically.
|
||||
var version = '0.11.2';
|
||||
var version = '0.11.3';
|
||||
|
||||
// If this file is loaded in the browser, we're in load.js mode.
|
||||
var load = typeof window === 'object';
|
||||
|
|
|
@ -51,9 +51,9 @@ new function() {
|
|||
if (!Numerical.isZero(scale.x - 1)
|
||||
|| !Numerical.isZero(scale.y - 1))
|
||||
parts.push('scale(' + formatter.point(scale) +')');
|
||||
if (skew && skew.x)
|
||||
if (skew.x)
|
||||
parts.push('skewX(' + formatter.number(skew.x) + ')');
|
||||
if (skew && skew.y)
|
||||
if (skew.y)
|
||||
parts.push('skewY(' + formatter.number(skew.y) + ')');
|
||||
attrs.transform = parts.join(' ');
|
||||
} else {
|
||||
|
@ -115,8 +115,9 @@ new function() {
|
|||
if (length > 2) {
|
||||
type = item._closed ? 'polygon' : 'polyline';
|
||||
var parts = [];
|
||||
for(var i = 0; i < length; i++)
|
||||
for (var i = 0; i < length; i++) {
|
||||
parts.push(formatter.point(segments[i]._point));
|
||||
}
|
||||
attrs.points = parts.join(' ');
|
||||
} else {
|
||||
type = 'line';
|
||||
|
@ -416,6 +417,7 @@ new function() {
|
|||
? new Rectangle([0, 0], view.getViewSize())
|
||||
: bounds === 'content'
|
||||
? Item._getBounds(children, matrix, { stroke: true })
|
||||
.rect
|
||||
: Rectangle.read([bounds], 0, { readNull: true }),
|
||||
attrs = {
|
||||
version: '1.1',
|
||||
|
|
|
@ -115,9 +115,9 @@ var PointText = TextItem.extend(/** @lends PointText# */{
|
|||
x -= width / (justification === 'center' ? 2: 1);
|
||||
// Until we don't have baseline measuring, assume 1 / 4 leading as a
|
||||
// rough guess:
|
||||
var bounds = new Rectangle(x,
|
||||
var rect = new Rectangle(x,
|
||||
numLines ? - 0.75 * leading : 0,
|
||||
width, numLines * leading);
|
||||
return matrix ? matrix._transformBounds(bounds, bounds) : bounds;
|
||||
return matrix ? matrix._transformBounds(rect, rect) : rect;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1271,12 +1271,11 @@ new function() { // Injection scope for event handling on the browser
|
|||
point, prevPoint)
|
||||
// Next handle the hit-item, if it's different from the drag-item
|
||||
// and not a descendant of it (in which case it would already have
|
||||
// received an event in the call above). Use fallbacks to translate
|
||||
// mousedrag to mousemove, since drag is handled above.
|
||||
// received an event in the call above).
|
||||
|| hitItem && hitItem !== dragItem
|
||||
&& !hitItem.isDescendant(dragItem)
|
||||
&& emitMouseEvent(hitItem, null, fallbacks[type] || type, event,
|
||||
point, prevPoint, dragItem)
|
||||
&& emitMouseEvent(hitItem, null, type, event, point, prevPoint,
|
||||
dragItem)
|
||||
// Lastly handle the mouse events on the view, if we're still here.
|
||||
|| emitMouseEvent(view, dragItem || hitItem || view, type, event,
|
||||
point, prevPoint));
|
||||
|
|
|
@ -876,3 +876,56 @@ test('Item#pivot', function() {
|
|||
equals(path2.pivot, pivot.add(difference),
|
||||
'Changing position of an item with applyMatrix = true should change pivot');
|
||||
});
|
||||
|
||||
test('Item#position with irregular shape, #pivot and rotation', function() {
|
||||
var path1 = new Path([ [0, 0], [200, 100], [0, 100] ]);
|
||||
var path2 = path1.clone();
|
||||
path2.pivot = path2.position;
|
||||
equals(path1.position, new Point(100, 50),
|
||||
'path1.position, before rotation');
|
||||
path1.rotate(45);
|
||||
equals(path1.position, new Point(64.64466, 50),
|
||||
'path1.position, after rotation');
|
||||
equals(path2.position, new Point(100, 50),
|
||||
'path2.position with pivot, before rotation');
|
||||
path2.rotate(45);
|
||||
equals(path2.position, new Point(100, 50),
|
||||
'path2.position with pivot, after rotation');
|
||||
});
|
||||
|
||||
test('Item#scaling, #rotation', function() {
|
||||
var expected = new Rectangle(100, 50, 100, 200);
|
||||
|
||||
var rect1 = new Path.Rectangle({
|
||||
from: [100, 100],
|
||||
to: [200, 200],
|
||||
applyMatrix: false
|
||||
});
|
||||
var rect2 = rect1.clone();
|
||||
|
||||
rect1.scaling = [2, 1];
|
||||
rect1.rotation = 90;
|
||||
equals(rect1.bounds, expected,
|
||||
'rect1.bounds, setting rect1.scaling before rect1.rotation');
|
||||
|
||||
rect2.rotation = 90;
|
||||
rect2.scaling = [2, 1];
|
||||
equals(rect2.bounds, expected,
|
||||
'rect2.bounds, setting rect2.scaling before rect2.rotation');
|
||||
|
||||
var shape1 = new Shape.Rectangle({
|
||||
from: [100, 100],
|
||||
to: [200, 200]
|
||||
});
|
||||
var shape2 = shape1.clone();
|
||||
|
||||
shape1.scaling = [2, 1];
|
||||
shape1.rotation = 90;
|
||||
equals(shape1.bounds, expected,
|
||||
'shape1.bounds, setting shape1.scaling before shape1.rotation');
|
||||
|
||||
shape2.rotation = 90;
|
||||
shape2.scaling = [2, 1];
|
||||
equals(shape2.bounds, expected,
|
||||
'shape2.bounds, setting shape2.scaling before shape2.rotation');
|
||||
});
|
||||
|
|
|
@ -694,12 +694,15 @@ test('path.strokeBounds with applyMatrix disabled', function() {
|
|||
strokeColor: 'red',
|
||||
strokeWidth: 10
|
||||
});
|
||||
equals(path.strokeBounds, new Rectangle(5, 5, 30, 30), 'path.strokeBounds, applyMatrix enabled');
|
||||
equals(path.strokeBounds, new Rectangle(5, 5, 30, 30),
|
||||
'path.strokeBounds, applyMatrix enabled');
|
||||
path.applyMatrix = false;
|
||||
equals(path.strokeBounds, new Rectangle(5, 5, 30, 30), 'path.strokeBounds, applyMatrix disabled');
|
||||
equals(path.strokeBounds, new Rectangle(5, 5, 30, 30),
|
||||
'path.strokeBounds, applyMatrix disabled');
|
||||
path.scale([4, 2], [0, 0]);
|
||||
var expected = new Rectangle(20, 10, 120, 60);
|
||||
equals(path.strokeBounds, expected, 'path.strokeBounds after scaling, applyMatrix disabled');
|
||||
equals(path.strokeBounds, expected,
|
||||
'path.strokeBounds after scaling, applyMatrix disabled');
|
||||
function testHitResult() {
|
||||
// Hit-testing needs to handle applyMatrix disabled with stroke scaling,
|
||||
// even when hit-testing on "distorted" stroke joins:
|
||||
|
@ -714,10 +717,29 @@ test('path.strokeBounds with applyMatrix disabled', function() {
|
|||
testHitResult();
|
||||
path.applyMatrix = true;
|
||||
expected = new Rectangle(35, 15, 90, 50);
|
||||
equals(path.strokeBounds, expected, 'path.strokeBounds after scaling, applyMatrix enabled');
|
||||
equals(path.strokeBounds, expected,
|
||||
'path.strokeBounds after scaling, applyMatrix enabled');
|
||||
testHitResult();
|
||||
});
|
||||
|
||||
test('TEST', function() {
|
||||
var path = new Path.Rectangle({
|
||||
applyMatrix: false,
|
||||
point: [10, 10],
|
||||
size: [20, 20],
|
||||
strokeScaling: true,
|
||||
strokeColor: 'red',
|
||||
strokeWidth: 10
|
||||
});
|
||||
path.scale([4, 2], [0, 0]);
|
||||
equals(path.strokeBounds, new Rectangle(20, 10, 120, 60),
|
||||
'path.strokeBounds after scaling, applyMatrix disabled');
|
||||
path.applyMatrix = true;
|
||||
equals(path.strokeBounds, new Rectangle(35, 15, 90, 50),
|
||||
'path.strokeBounds after scaling, applyMatrix enabled');
|
||||
|
||||
});
|
||||
|
||||
test('symbolItem.bounds with strokeScaling disabled', function() {
|
||||
var path = new Path.Rectangle({
|
||||
size: [20, 20],
|
||||
|
|
Loading…
Reference in a new issue