Clean up handling of #_set(), #set() and #initialize()

Convention:

- #_set() is for actually setting properties, e.g. on Point, Size, so that derived classes can reuse other parts (e.g. SegmentPoint)
- #set() is a shortcut to #initialize() on all basic types, to offer the same amount of flexibility when setting values.
This commit is contained in:
Jürg Lehni 2016-07-18 20:11:01 +02:00
parent acfe6cddeb
commit 32d8c969fb
21 changed files with 272 additions and 214 deletions

View file

@ -72,7 +72,7 @@
"resemblejs": "^2.2.1", "resemblejs": "^2.2.1",
"run-sequence": "^1.2.2", "run-sequence": "^1.2.2",
"stats.js": "0.16.0", "stats.js": "0.16.0",
"straps": "^1.9.0" "straps": "^2.0.1"
}, },
"browser": { "browser": {
"canvas": false, "canvas": false,

View file

@ -18,9 +18,9 @@
/** /**
* @name Matrix * @name Matrix
* *
* @class An affine transform performs a linear mapping from 2D coordinates * @class An affine transformation matrix performs a linear mapping from 2D
* to other 2D coordinates that preserves the "straightness" and * coordinates to other 2D coordinates that preserves the "straightness" and
* "parallelness" of lines. * "parallelness" of lines.
* *
* Such a coordinate transformation can be represented by a 3 row by 3 * Such a coordinate transformation can be represented by a 3 row by 3
* column matrix with an implied last row of `[ 0 0 1 ]`. This matrix * column matrix with an implied last row of `[ 0 0 1 ]`. This matrix
@ -42,8 +42,15 @@ var Matrix = Base.extend(/** @lends Matrix# */{
_class: 'Matrix', _class: 'Matrix',
/** /**
* Creates a 2D affine transform. * Creates a 2D affine transformation matrix that describes the identity
* transformation.
* *
* @name Matrix#initialize
*/
/**
* Creates a 2D affine transformation matrix.
*
* @name Matrix#initialize
* @param {Number} a the a property of the transform * @param {Number} a the a property of the transform
* @param {Number} c the c property of the transform * @param {Number} c the c property of the transform
* @param {Number} b the b property of the transform * @param {Number} b the b property of the transform
@ -51,16 +58,28 @@ var Matrix = Base.extend(/** @lends Matrix# */{
* @param {Number} tx the tx property of the transform * @param {Number} tx the tx property of the transform
* @param {Number} ty the ty property of the transform * @param {Number} ty the ty property of the transform
*/ */
/**
* Creates a 2D affine transformation matrix.
*
* @name Matrix#initialize
* @param {Number[]} values the matrix values to initialize this matrix with
*/
/**
* Creates a 2D affine transformation matrix.
*
* @name Matrix#initialize
* @param {Matrix} matrix the matrix to copy the values from
*/
initialize: function Matrix(arg) { initialize: function Matrix(arg) {
var count = arguments.length, var count = arguments.length,
ok = true; ok = true;
if (count === 6) { if (count === 6) {
this.set.apply(this, arguments); this._set.apply(this, arguments);
} else if (count === 1) { } else if (count === 1) {
if (arg instanceof Matrix) { if (arg instanceof Matrix) {
this.set(arg._a, arg._b, arg._c, arg._d, arg._tx, arg._ty); this._set(arg._a, arg._b, arg._c, arg._d, arg._tx, arg._ty);
} else if (Array.isArray(arg)) { } else if (Array.isArray(arg)) {
this.set.apply(this, arg); this._set.apply(this, arg);
} else { } else {
ok = false; ok = false;
} }
@ -72,20 +91,20 @@ var Matrix = Base.extend(/** @lends Matrix# */{
if (!ok) { if (!ok) {
throw new Error('Unsupported matrix parameters'); throw new Error('Unsupported matrix parameters');
} }
return this;
}, },
/** /**
* Sets this transform to the matrix specified by the 6 values. * Sets the matrix to the passed values. Note that any sequence of
* parameters that is supported by the various {@link Matrix()} constructors
* also work for calls of `set()`.
* *
* @param {Number} a the a property of the transform * @function
* @param {Number} b the b property of the transform
* @param {Number} c the c property of the transform
* @param {Number} d the d property of the transform
* @param {Number} tx the tx property of the transform
* @param {Number} ty the ty property of the transform
* @return {Matrix} this affine transform
*/ */
set: function(a, b, c, d, tx, ty, _dontNotify) { set: '#initialize',
// See Point#_set() for an explanation of #_set():
_set: function(a, b, c, d, tx, ty, _dontNotify) {
this._a = a; this._a = a;
this._b = b; this._b = b;
this._c = c; this._c = c;
@ -176,7 +195,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* Concatenates this transform with a translate transformation. * Concatenates this matrix with a translate transformation.
* *
* @name Matrix#translate * @name Matrix#translate
* @function * @function
@ -184,7 +203,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
* @return {Matrix} this affine transform * @return {Matrix} this affine transform
*/ */
/** /**
* Concatenates this transform with a translate transformation. * Concatenates this matrix with a translate transformation.
* *
* @name Matrix#translate * @name Matrix#translate
* @function * @function
@ -203,7 +222,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* Concatenates this transform with a scaling transformation. * Concatenates this matrix with a scaling transformation.
* *
* @name Matrix#scale * @name Matrix#scale
* @function * @function
@ -212,7 +231,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
* @return {Matrix} this affine transform * @return {Matrix} this affine transform
*/ */
/** /**
* Concatenates this transform with a scaling transformation. * Concatenates this matrix with a scaling transformation.
* *
* @name Matrix#scale * @name Matrix#scale
* @function * @function
@ -237,7 +256,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* Concatenates this transform with a rotation transformation around an * Concatenates this matrix with a rotation transformation around an
* anchor point. * anchor point.
* *
* @name Matrix#rotate * @name Matrix#rotate
@ -247,7 +266,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
* @return {Matrix} this affine transform * @return {Matrix} this affine transform
*/ */
/** /**
* Concatenates this transform with a rotation transformation around an * Concatenates this matrix with a rotation transformation around an
* anchor point. * anchor point.
* *
* @name Matrix#rotate * @name Matrix#rotate
@ -282,7 +301,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* Concatenates this transform with a shear transformation. * Concatenates this matrix with a shear transformation.
* *
* @name Matrix#shear * @name Matrix#shear
* @function * @function
@ -291,7 +310,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
* @return {Matrix} this affine transform * @return {Matrix} this affine transform
*/ */
/** /**
* Concatenates this transform with a shear transformation. * Concatenates this matrix with a shear transformation.
* *
* @name Matrix#shear * @name Matrix#shear
* @function * @function
@ -320,7 +339,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* Concatenates this transform with a skew transformation. * Concatenates this matrix with a skew transformation.
* *
* @name Matrix#skew * @name Matrix#skew
* @function * @function
@ -329,7 +348,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
* @return {Matrix} this affine transform * @return {Matrix} this affine transform
*/ */
/** /**
* Concatenates this transform with a skew transformation. * Concatenates this matrix with a skew transformation.
* *
* @name Matrix#skew * @name Matrix#skew
* @function * @function
@ -473,15 +492,15 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* @deprecated, use use {@link #append(matrix)} instead. * @deprecated use use {@link #append(matrix)} instead.
*/ */
concatenate: '#append', concatenate: '#append',
/** /**
* @deprecated, use use {@link #prepend(matrix)} instead. * @deprecated use use {@link #prepend(matrix)} instead.
*/ */
preConcatenate: '#prepend', preConcatenate: '#prepend',
/** /**
* @deprecated, use use {@link #appended(matrix)} instead. * @deprecated use use {@link #appended(matrix)} instead.
*/ */
chain: '#appended', chain: '#appended',
@ -501,7 +520,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* @return {Boolean} whether this transform is the identity transform * @return {Boolean} whether this matrix is the identity matrix
*/ */
isIdentity: function() { isIdentity: function() {
return this._a === 1 && this._b === 0 && this._c === 0 && this._d === 1 return this._a === 1 && this._b === 0 && this._c === 0 && this._d === 1
@ -509,10 +528,10 @@ var Matrix = Base.extend(/** @lends Matrix# */{
}, },
/** /**
* Returns whether the transform is invertible. A transform is not * Checks whether the matrix is invertible. A matrix is not invertible if
* invertible if the determinant is 0 or any value is non-finite or NaN. * the determinant is 0 or any value is infinite or NaN.
* *
* @return {Boolean} whether the transform is invertible * @return {Boolean} whether the matrix is invertible
*/ */
isInvertible: function() { isInvertible: function() {
var det = this._a * this._d - this._c * this._b; var det = this._a * this._d - this._c * this._b;
@ -566,7 +585,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
y = point.y; y = point.y;
if (!dest) if (!dest)
dest = new Point(); dest = new Point();
return dest.set( return dest._set(
x * this._a + y * this._c + this._tx, x * this._a + y * this._c + this._tx,
x * this._b + y * this._d + this._ty, x * this._b + y * this._d + this._ty,
_dontNotify); _dontNotify);
@ -611,7 +630,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
} }
if (!dest) if (!dest)
dest = new Rectangle(); dest = new Rectangle();
return dest.set(min[0], min[1], max[0] - min[0], max[1] - min[1], return dest._set(min[0], min[1], max[0] - min[0], max[1] - min[1],
_dontNotify); _dontNotify);
}, },
@ -638,7 +657,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
y = point.y - this._ty; y = point.y - this._ty;
if (!dest) if (!dest)
dest = new Point(); dest = new Point();
res = dest.set( res = dest._set(
(x * d - y * c) / det, (x * d - y * c) / det,
(y * a - x * b) / det, (y * a - x * b) / det,
_dontNotify); _dontNotify);
@ -741,7 +760,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
*/ */
/** /**
* The transform values as an array, in the same sequence as they are passed * The matrix values as an array, in the same sequence as they are passed
* to {@link #initialize(a, b, c, d, tx, ty)}. * to {@link #initialize(a, b, c, d, tx, ty)}.
* *
* @bean * @bean

View file

@ -130,40 +130,63 @@ var Point = Base.extend(/** @lends Point# */{
* @name Point#initialize * @name Point#initialize
*/ */
initialize: function Point(arg0, arg1) { initialize: function Point(arg0, arg1) {
var type = typeof arg0; var type = typeof arg0,
reading = this.__read,
read = 0;
if (type === 'number') { if (type === 'number') {
var hasY = typeof arg1 === 'number'; var hasY = typeof arg1 === 'number';
this.x = arg0; this._set(arg0, hasY ? arg1 : arg0);
this.y = hasY ? arg1 : arg0; if (reading)
if (this.__read) read = hasY ? 2 : 1;
this.__read = hasY ? 2 : 1;
} else if (type === 'undefined' || arg0 === null) { } else if (type === 'undefined' || arg0 === null) {
this.x = this.y = 0; this._set(0, 0);
if (this.__read) if (reading)
this.__read = arg0 === null ? 1 : 0; read = arg0 === null ? 1 : 0;
} else { } else {
var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0; var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0;
read = 1;
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
this.x = obj[0]; this._set(+obj[0], +(obj.length > 1 ? obj[1] : obj[0]));
this.y = obj.length > 1 ? obj[1] : obj[0];
} else if ('x' in obj) { } else if ('x' in obj) {
this.x = obj.x; this._set(obj.x || 0, obj.y || 0);
this.y = obj.y;
} else if ('width' in obj) { } else if ('width' in obj) {
this.x = obj.width; this._set(obj.width || 0, obj.height || 0);
this.y = obj.height;
} else if ('angle' in obj) { } else if ('angle' in obj) {
this.x = obj.length; this._set(obj.length || 0, 0);
this.y = 0; this.setAngle(obj.angle || 0);
this.setAngle(obj.angle);
} else { } else {
this.x = this.y = 0; this._set(0, 0);
if (this.__read) read = 0;
this.__read = 0;
} }
if (this.__read)
this.__read = 1;
} }
if (reading)
this.__read = read;
return this;
},
/**
* Sets the point to the passed values. Note that any sequence of parameters
* that is supported by the various {@link Point()} constructors also work
* for calls of `set()`.
*
* @function
*/
set: '#initialize',
/**
* Internal helper function to directly set the underlying properties.
*
* Convention regarding {@link #set()} VS {@link #_set()}:
*
* - {@link #_set()} is for actually setting properties, e.g. on Point,
* Size, so that derived classes can reuse other parts (e.g. SegmentPoint)
* - {@link #set()} is a shortcut to #initialize() on all basic types, to
* offer the same amount of flexibility when setting values.
*/
_set: function(x, y) {
this.x = x;
this.y = y;
return this;
}, },
/** /**
@ -180,12 +203,6 @@ var Point = Base.extend(/** @lends Point# */{
* @type Number * @type Number
*/ */
set: function(x, y) {
this.x = x;
this.y = y;
return this;
},
/** /**
* Checks whether the coordinates of the point are equal to that of the * Checks whether the coordinates of the point are equal to that of the
* supplied point. * supplied point.
@ -257,7 +274,7 @@ var Point = Base.extend(/** @lends Point# */{
// assignment, so LinkedPoint does not report changes twice. // assignment, so LinkedPoint does not report changes twice.
if (this.isZero()) { if (this.isZero()) {
var angle = this._angle || 0; var angle = this._angle || 0;
this.set( this._set(
Math.cos(angle) * length, Math.cos(angle) * length,
Math.sin(angle) * length Math.sin(angle) * length
); );
@ -267,7 +284,7 @@ var Point = Base.extend(/** @lends Point# */{
// x and y are 0 // x and y are 0
if (Numerical.isZero(scale)) if (Numerical.isZero(scale))
this.getAngle(); this.getAngle();
this.set( this._set(
this.x * scale, this.x * scale,
this.y * scale this.y * scale
); );
@ -347,7 +364,7 @@ var Point = Base.extend(/** @lends Point# */{
var length = this.getLength(); var length = this.getLength();
// Use #set() instead of direct assignment of x/y, so LinkedPoint // Use #set() instead of direct assignment of x/y, so LinkedPoint
// does not report changes twice. // does not report changes twice.
this.set( this._set(
Math.cos(angle) * length, Math.cos(angle) * length,
Math.sin(angle) * length Math.sin(angle) * length
); );
@ -997,7 +1014,8 @@ var LinkedPoint = Point.extend({
this._setter = setter; this._setter = setter;
}, },
set: function(x, y, _dontNotify) { // See Point#_set() for an explanation of #_set():
_set: function(x, y, _dontNotify) {
this._x = x; this._x = x;
this._y = y; this._y = y;
if (!_dontNotify) if (!_dontNotify)

View file

@ -77,77 +77,92 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
*/ */
initialize: function Rectangle(arg0, arg1, arg2, arg3) { initialize: function Rectangle(arg0, arg1, arg2, arg3) {
var type = typeof arg0, var type = typeof arg0,
read = 0; read;
if (type === 'number') { if (type === 'number') {
// new Rectangle(x, y, width, height) // new Rectangle(x, y, width, height)
this.x = arg0; this._set(arg0, arg1, arg2, arg3);
this.y = arg1;
this.width = arg2;
this.height = arg3;
read = 4; read = 4;
} else if (type === 'undefined' || arg0 === null) { } else if (type === 'undefined' || arg0 === null) {
// new Rectangle(), new Rectangle(null) // new Rectangle(), new Rectangle(null)
this.x = this.y = this.width = this.height = 0; this._set(0, 0, 0, 0);
read = arg0 === null ? 1 : 0; read = arg0 === null ? 1 : 0;
} else if (arguments.length === 1) { } else if (arguments.length === 1) {
// This can either be an array, or an object literal. // This can either be an array, or an object literal.
if (Array.isArray(arg0)) { if (Array.isArray(arg0)) {
this.x = arg0[0]; this._set.apply(this, arg0);
this.y = arg0[1];
this.width = arg0[2];
this.height = arg0[3];
read = 1; read = 1;
} else if (arg0.x !== undefined || arg0.width !== undefined) { } else if (arg0.x !== undefined || arg0.width !== undefined) {
// Another rectangle or a simple object literal // Another rectangle or a simple object literal
// describing one. Use duck typing, and 0 as defaults. // describing one. Use duck typing, and 0 as defaults.
this.x = arg0.x || 0; this._set(arg0.x || 0, arg0.y || 0,
this.y = arg0.y || 0; arg0.width || 0, arg0.height || 0);
this.width = arg0.width || 0;
this.height = arg0.height || 0;
read = 1; read = 1;
} else if (arg0.from === undefined && arg0.to === undefined) { } else if (arg0.from === undefined && arg0.to === undefined) {
// Use #_set to support whatever property the rectangle can // Use Base.filter() to support whatever property the rectangle
// take, but handle from/to separately below. // can take, but handle from/to separately below.
this.x = this.y = this.width = this.height = 0; this._set(0, 0, 0, 0);
this._set(arg0); Base.filter(this, arg0);
read = 1; read = 1;
} }
} }
if (!read) { if (read === undefined) {
// Read a point argument and look at the next value to see whether // Read a point argument and look at the next value to see whether
// it's a size or a point, then read accordingly. // it's a size or a point, then read accordingly.
// We're supporting both reading from a normal arguments list and // We're supporting both reading from a normal arguments list and
// covering the Rectangle({ from: , to: }) constructor, through // covering the Rectangle({ from: , to: }) constructor, through
// Point.readNamed(). // Point.readNamed().
var point = Point.readNamed(arguments, 'from'), var frm = Point.readNamed(arguments, 'from'),
next = Base.peek(arguments); next = Base.peek(arguments),
this.x = point.x; x = frm.x,
this.y = point.y; y = frm.y,
if (next && next.x !== undefined || Base.hasNamed(arguments, 'to')) { width,
height;
if (next && next.x !== undefined
|| Base.hasNamed(arguments, 'to')) {
// new Rectangle(from, to) // new Rectangle(from, to)
// Read above why we can use readNamed() to cover both cases. // Read above why we can use readNamed() to cover both cases.
var to = Point.readNamed(arguments, 'to'); var to = Point.readNamed(arguments, 'to');
this.width = to.x - point.x; width = to.x - x;
this.height = to.y - point.y; height = to.y - y;
// Check if horizontal or vertical order needs to be reversed. // Check if horizontal or vertical order needs to be reversed.
if (this.width < 0) { if (width < 0) {
this.x = to.x; x = to.x;
this.width = -this.width; width = -width;
} }
if (this.height < 0) { if (height < 0) {
this.y = to.y; y = to.y;
this.height = -this.height; height = -height;
} }
} else { } else {
// new Rectangle(point, size) // new Rectangle(point, size)
var size = Size.read(arguments); var size = Size.read(arguments);
this.width = size.width; width = size.width;
this.height = size.height; height = size.height;
} }
this._set(x, y, width, height);
read = arguments.__index; read = arguments.__index;
} }
if (this.__read) if (this.__read)
this.__read = read; this.__read = read;
return this;
},
/**
* Sets the rectangle to the passed values. Note that any sequence of
* parameters that is supported by the various {@link Rectangle()}
* constructors also work for calls of `set()`.
*
* @function
*/
set: '#initialize',
// See Point#_set() for an explanation of #_set():
_set: function(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
return this;
}, },
/** /**
@ -178,17 +193,6 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
* @type Number * @type Number
*/ */
/**
* @ignore
*/
set: function(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
return this;
},
/** /**
* Returns a copy of the rectangle. * Returns a copy of the rectangle.
*/ */
@ -842,12 +846,13 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
var LinkedRectangle = Rectangle.extend({ var LinkedRectangle = Rectangle.extend({
// Have LinkedRectangle appear as a normal Rectangle in debugging // Have LinkedRectangle appear as a normal Rectangle in debugging
initialize: function Rectangle(x, y, width, height, owner, setter) { initialize: function Rectangle(x, y, width, height, owner, setter) {
this.set(x, y, width, height, true); this._set(x, y, width, height, true);
this._owner = owner; this._owner = owner;
this._setter = setter; this._setter = setter;
}, },
set: function(x, y, width, height, _dontNotify) { // See Point#_set() for an explanation of #_set():
_set: function(x, y, width, height, _dontNotify) {
this._x = x; this._x = x;
this._y = y; this._y = y;
this._width = width; this._width = width;

View file

@ -93,36 +93,51 @@ var Size = Base.extend(/** @lends Size# */{
* console.log(size.height); // 50 * console.log(size.height); // 50
*/ */
initialize: function Size(arg0, arg1) { initialize: function Size(arg0, arg1) {
var type = typeof arg0; var type = typeof arg0,
reading = this.__read,
read = 0;
if (type === 'number') { if (type === 'number') {
var hasHeight = typeof arg1 === 'number'; var hasHeight = typeof arg1 === 'number';
this.width = arg0; this._set(arg0, hasHeight ? arg1 : arg0);
this.height = hasHeight ? arg1 : arg0; if (reading)
if (this.__read) read = hasHeight ? 2 : 1;
this.__read = hasHeight ? 2 : 1;
} else if (type === 'undefined' || arg0 === null) { } else if (type === 'undefined' || arg0 === null) {
this.width = this.height = 0; this._set(0, 0);
if (this.__read) if (reading)
this.__read = arg0 === null ? 1 : 0; read = arg0 === null ? 1 : 0;
} else { } else {
var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0; var obj = type === 'string' ? arg0.split(/[\s,]+/) || [] : arg0;
read = 1;
if (Array.isArray(obj)) { if (Array.isArray(obj)) {
this.width = obj[0]; this._set(+obj[0], +(obj.length > 1 ? obj[1] : obj[0]));
this.height = obj.length > 1 ? obj[1] : obj[0];
} else if ('width' in obj) { } else if ('width' in obj) {
this.width = obj.width; this._set(obj.width || 0, obj.height || 0);
this.height = obj.height;
} else if ('x' in obj) { } else if ('x' in obj) {
this.width = obj.x; this._set(obj.x || 0, obj.y || 0);
this.height = obj.y;
} else { } else {
this.width = this.height = 0; this._set(0, 0);
if (this.__read) read = 0;
this.__read = 0;
} }
if (this.__read)
this.__read = 1;
} }
if (reading)
this.__read = read;
return this;
},
/**
* Sets the size to the passed values. Note that any sequence of parameters
* that is supported by the various {@link Size()} constructors also work
* for calls of `set()`.
*
* @function
*/
set: '#initialize',
// See Point#_set() for an explanation of #_set():
_set: function(width, height) {
this.width = width;
this.height = height;
return this;
}, },
/** /**
@ -139,12 +154,6 @@ var Size = Base.extend(/** @lends Size# */{
* @type Number * @type Number
*/ */
set: function(width, height) {
this.width = width;
this.height = height;
return this;
},
/** /**
* Checks whether the width and height of the size are equal to those of the * Checks whether the width and height of the size are equal to those of the
* supplied size. * supplied size.
@ -551,7 +560,8 @@ var LinkedSize = Size.extend({
this._setter = setter; this._setter = setter;
}, },
set: function(width, height, _dontNotify) { // See Point#_set() for an explanation of #_set():
_set: function(width, height, _dontNotify) {
this._width = width; this._width = width;
this._height = height; this._height = height;
if (!_dontNotify) if (!_dontNotify)

View file

@ -80,11 +80,10 @@ Base.inject(/** @lends Base# */{
/** /**
* #_set() is part of the mechanism for constructors which take one object * #_set() is part of the mechanism for constructors which take one object
* literal describing all the properties to be set on the created instance. * literal describing all the properties to be set on the created instance.
* Through {@link Base.filter()} it supports `_filtered`
* handling as required by the {@link Base.readNamed()} mechanism.
* *
* @param {Object} props an object describing the properties to set * @param {Object} props an object describing the properties to set
* @param {Object} [exclude] a lookup table listing properties to exclude
* @param {Boolean} [dontCheck=false] whether to perform a
* Base.isPlainObject() check on props or not
* @return {Boolean} {@true if the object is a plain object} * @return {Boolean} {@true if the object is a plain object}
*/ */
_set: function(props) { _set: function(props) {
@ -306,8 +305,9 @@ Base.inject(/** @lends Base# */{
/** /**
* Copies all properties from `source` over to `dest`, supporting * Copies all properties from `source` over to `dest`, supporting
* _filtered handling as required by Base.readNamed() mechanism, as well * `_filtered` handling as required by {@link Base.readNamed()}
* as an optional exclude` object that lists properties to exclude. * mechanism, as well as an optional exclude` object that lists
* properties to exclude.
*/ */
filter: function(dest, source, exclude) { filter: function(dest, source, exclude) {
// If source is a filtering object, we need to get the keys from the // If source is a filtering object, we need to get the keys from the
@ -515,7 +515,7 @@ Base.inject(/** @lends Base# */{
} }
// When reusing an object, initialize it through #_set() // When reusing an object, initialize it through #_set()
// instead of the constructor function: // instead of the constructor function:
(useTarget ? obj._set : ctor).apply(obj, args); (useTarget ? obj.set : ctor).apply(obj, args);
// Clear target to only use it once. // Clear target to only use it once.
if (useTarget) if (useTarget)
target = null; target = null;

View file

@ -239,8 +239,8 @@ new function() { // Injection scope for various item event handlers
}, },
/** /**
* Sets those properties of the passed object literal on this item to * Sets the properties of the passed object literal on this item to the
* the values defined in the object literal, if the item has property of the * values defined in the object literal, if the item has property of the
* given name (or a setter defined for it). * given name (or a setter defined for it).
* *
* @param {Object} props * @param {Object} props
@ -400,7 +400,7 @@ new function() { // Injection scope for various item event handlers
}, },
setStyle: function(style) { setStyle: function(style) {
// Don't access _style directly so Path#getStyle() can be overriden for // Don't access _style directly so Path#getStyle() can be overridden for
// CompoundPaths. // CompoundPaths.
this.getStyle().set(style); this.getStyle().set(style);
} }
@ -852,7 +852,7 @@ new function() { // Injection scope for various item event handlers
// Restore to the last revertible matrix stored in _backup, and get // Restore to the last revertible matrix stored in _backup, and get
// the bounds again. That way, we can prevent collapsing to 0-size. // the bounds again. That way, we can prevent collapsing to 0-size.
if (!_matrix.isInvertible()) { if (!_matrix.isInvertible()) {
_matrix.initialize(_matrix._backup _matrix.set(_matrix._backup
|| new Matrix().translate(_matrix.getTranslation())); || new Matrix().translate(_matrix.getTranslation()));
bounds = this.getBounds(); bounds = this.getBounds();
} }
@ -1565,7 +1565,7 @@ new function() { // Injection scope for various item event handlers
} }
// Use Matrix#initialize to easily copy over values. // Use Matrix#initialize to easily copy over values.
if (!excludeMatrix) if (!excludeMatrix)
this._matrix.initialize(source._matrix); this._matrix.set(source._matrix);
// We can't just set _applyMatrix as many item types won't allow it, // We can't just set _applyMatrix as many item types won't allow it,
// e.g. creating a Shape in Path#toShape(). // e.g. creating a Shape in Path#toShape().
// Using the setter instead takes care of it. // Using the setter instead takes care of it.

View file

@ -192,7 +192,7 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
setCurrentStyle: function(style) { setCurrentStyle: function(style) {
// TODO: Style selected items with the style: // TODO: Style selected items with the style:
this._currentStyle.initialize(style); this._currentStyle.set(style);
}, },
/** /**

View file

@ -90,8 +90,7 @@ var Shape = Item.extend(/** @lends Shape# */{
height = size.height; height = size.height;
if (type === 'rectangle') { if (type === 'rectangle') {
// Shrink radius accordingly // Shrink radius accordingly
var radius = Size.min(this._radius, size.divide(2)); this._radius.set(Size.min(this._radius, size.divide(2)));
this._radius.set(radius.width, radius.height);
} else if (type === 'circle') { } else if (type === 'circle') {
// Use average of width and height as new size, then calculate // Use average of width and height as new size, then calculate
// radius as a number from that: // radius as a number from that:
@ -99,9 +98,9 @@ var Shape = Item.extend(/** @lends Shape# */{
this._radius = width / 2; this._radius = width / 2;
} else if (type === 'ellipse') { } else if (type === 'ellipse') {
// The radius is a size. // The radius is a size.
this._radius.set(width / 2, height / 2); this._radius._set(width / 2, height / 2);
} }
this._size.set(width, height); this._size._set(width, height);
this._changed(/*#=*/Change.GEOMETRY); this._changed(/*#=*/Change.GEOMETRY);
} }
}, },
@ -127,7 +126,7 @@ var Shape = Item.extend(/** @lends Shape# */{
return; return;
var size = radius * 2; var size = radius * 2;
this._radius = radius; this._radius = radius;
this._size.set(size, size); this._size._set(size, size);
} else { } else {
radius = Size.read(arguments); radius = Size.read(arguments);
if (!this._radius) { if (!this._radius) {
@ -136,13 +135,13 @@ var Shape = Item.extend(/** @lends Shape# */{
} else { } else {
if (this._radius.equals(radius)) if (this._radius.equals(radius))
return; return;
this._radius.set(radius.width, radius.height); this._radius.set(radius);
if (type === 'rectangle') { if (type === 'rectangle') {
// Grow size accordingly // Grow size accordingly
var size = Size.max(this._size, radius.multiply(2)); var size = Size.max(this._size, radius.multiply(2));
this._size.set(size.width, size.height); this._size.set(size);
} else if (type === 'ellipse') { } else if (type === 'ellipse') {
this._size.set(radius.width * 2, radius.height * 2); this._size._set(radius.width * 2, radius.height * 2);
} }
} }
} }

View file

@ -67,7 +67,7 @@ module.exports = function(paper) {
}, },
/** /**
* @deprecated, use use {@link #createCanvas(width, height)} instead. * @deprecated use use {@link #createCanvas(width, height)} instead.
*/ */
Canvas: '#createCanvas' Canvas: '#createCanvas'
}); });

View file

@ -166,7 +166,7 @@ var Curve = Base.extend(/** @lends Curve# */{
handleOut = segment2._handleOut; handleOut = segment2._handleOut;
removed = segment2.remove(); removed = segment2.remove();
if (removed) if (removed)
this._segment1._handleOut.set(handleOut.x, handleOut.y); this._segment1._handleOut.set(handleOut);
} }
return removed; return removed;
}, },
@ -182,8 +182,7 @@ var Curve = Base.extend(/** @lends Curve# */{
}, },
setPoint1: function(/* point */) { setPoint1: function(/* point */) {
var point = Point.read(arguments); this._segment1._point.set(Point.read(arguments));
this._segment1._point.set(point.x, point.y);
}, },
/** /**
@ -197,8 +196,7 @@ var Curve = Base.extend(/** @lends Curve# */{
}, },
setPoint2: function(/* point */) { setPoint2: function(/* point */) {
var point = Point.read(arguments); this._segment2._point.set(Point.read(arguments));
this._segment2._point.set(point.x, point.y);
}, },
/** /**
@ -212,8 +210,7 @@ var Curve = Base.extend(/** @lends Curve# */{
}, },
setHandle1: function(/* point */) { setHandle1: function(/* point */) {
var point = Point.read(arguments); this._segment1._handleOut.set(Point.read(arguments));
this._segment1._handleOut.set(point.x, point.y);
}, },
/** /**
@ -227,8 +224,7 @@ var Curve = Base.extend(/** @lends Curve# */{
}, },
setHandle2: function(/* point */) { setHandle2: function(/* point */) {
var point = Point.read(arguments); this._segment2._handleIn.set(Point.read(arguments));
this._segment2._handleIn.set(point.x, point.y);
}, },
/** /**
@ -487,8 +483,8 @@ var Curve = Base.extend(/** @lends Curve# */{
// Adjust the handles on the existing segments. The new segment // Adjust the handles on the existing segments. The new segment
// will be inserted between the existing segment1 and segment2: // will be inserted between the existing segment1 and segment2:
// Convert absolute -> relative // Convert absolute -> relative
segment1._handleOut.set(left[2] - left[0], left[3] - left[1]); segment1._handleOut._set(left[2] - left[0], left[3] - left[1]);
segment2._handleIn.set(right[4] - right[6],right[5] - right[7]); segment2._handleIn._set(right[4] - right[6],right[5] - right[7]);
} }
// Create the new segment: // Create the new segment:
var x = left[6], y = left[7], var x = left[6], y = left[7],
@ -543,7 +539,7 @@ var Curve = Base.extend(/** @lends Curve# */{
// TODO: Remove in 1.0.0? (deprecated January 2016): // TODO: Remove in 1.0.0? (deprecated January 2016):
/** /**
* @deprecated, use use {@link #divideAt(offset)} or * @deprecated use use {@link #divideAt(offset)} or
* {@link #divideAtTime(time)} instead. * {@link #divideAtTime(time)} instead.
*/ */
divide: function(offset, isTime) { divide: function(offset, isTime) {
@ -553,7 +549,7 @@ var Curve = Base.extend(/** @lends Curve# */{
// TODO: Remove in 1.0.0? (deprecated January 2016): // TODO: Remove in 1.0.0? (deprecated January 2016):
/** /**
* @deprecated, use use {@link #splitAt(offset)} or * @deprecated use use {@link #splitAt(offset)} or
* {@link #splitAtTime(time)} instead. * {@link #splitAtTime(time)} instead.
*/ */
split: function(offset, isTime) { split: function(offset, isTime) {
@ -576,8 +572,8 @@ var Curve = Base.extend(/** @lends Curve# */{
* turning the curve into a straight line. * turning the curve into a straight line.
*/ */
clearHandles: function() { clearHandles: function() {
this._segment1._handleOut.set(0, 0); this._segment1._handleOut._set(0, 0);
this._segment2._handleIn.set(0, 0); this._segment2._handleIn._set(0, 0);
}, },
statics: /** @lends Curve */{ statics: /** @lends Curve */{
@ -1068,7 +1064,7 @@ statics: /** @lends Curve */{
// TODO: Remove in 1.0.0? (deprecated January 2016): // TODO: Remove in 1.0.0? (deprecated January 2016):
/** /**
* @deprecated, use use {@link #getTimeOf(point)} instead. * @deprecated use use {@link #getTimeOf(point)} instead.
*/ */
getParameterAt: '#getTimeAt', getParameterAt: '#getTimeAt',
@ -1121,7 +1117,7 @@ statics: /** @lends Curve */{
// TODO: Remove in 1.0.0? (deprecated January 2016): // TODO: Remove in 1.0.0? (deprecated January 2016):
/** /**
* @deprecated, use use {@link #getTimeOf(point)} instead. * @deprecated use use {@link #getTimeOf(point)} instead.
*/ */
getParameterOf: '#getTimeOf', getParameterOf: '#getTimeOf',

View file

@ -1086,7 +1086,7 @@ var Path = PathItem.extend(/** @lends Path# */{
}, },
/** /**
* @deprecated, use use {@link #splitAt(offset)} instead. * @deprecated use use {@link #splitAt(offset)} instead.
*/ */
split: function(index, time) { split: function(index, time) {
var curve, var curve,

View file

@ -799,8 +799,8 @@ PathItem.inject(new function() {
next = seg.getNext(); next = seg.getNext();
if (seg._path && hasOverlap(prev) && hasOverlap(next)) { if (seg._path && hasOverlap(prev) && hasOverlap(next)) {
seg.remove(); seg.remove();
prev._handleOut.set(0, 0); prev._handleOut._set(0, 0);
next._handleIn.set(0, 0); next._handleIn._set(0, 0);
var curve = prev.getCurve(); var curve = prev.getCurve();
if (curve.isStraight() && curve.getLength() === 0) if (curve.isStraight() && curve.getLength() === 0)
prev.remove(); prev.remove();

View file

@ -198,10 +198,7 @@ var Segment = Base.extend(/** @lends Segment# */{
}, },
setPoint: function(/* point */) { setPoint: function(/* point */) {
var point = Point.read(arguments); this._point.set(Point.read(arguments));
// Do not replace the internal object but update it instead, so
// references to it are kept alive.
this._point.set(point.x, point.y);
}, },
/** /**
@ -216,9 +213,7 @@ var Segment = Base.extend(/** @lends Segment# */{
}, },
setHandleIn: function(/* point */) { setHandleIn: function(/* point */) {
var point = Point.read(arguments); this._handleIn.set(Point.read(arguments));
// See #setPoint:
this._handleIn.set(point.x, point.y);
}, },
/** /**
@ -233,9 +228,7 @@ var Segment = Base.extend(/** @lends Segment# */{
}, },
setHandleOut: function(/* point */) { setHandleOut: function(/* point */) {
var point = Point.read(arguments); this._handleOut.set(Point.read(arguments));
// See #setPoint:
this._handleOut.set(point.x, point.y);
}, },
/** /**
@ -256,8 +249,8 @@ var Segment = Base.extend(/** @lends Segment# */{
* turning the segment into a corner. * turning the segment into a corner.
*/ */
clearHandles: function() { clearHandles: function() {
this._handleIn.set(0, 0); this._handleIn._set(0, 0);
this._handleOut.set(0, 0); this._handleOut._set(0, 0);
}, },
getSelection: function() { getSelection: function() {
@ -527,10 +520,9 @@ var Segment = Base.extend(/** @lends Segment# */{
reverse: function() { reverse: function() {
var handleIn = this._handleIn, var handleIn = this._handleIn,
handleOut = this._handleOut, handleOut = this._handleOut,
inX = handleIn._x, tmp = handleIn.clone();
inY = handleIn._y; handleIn.set(handleOut);
handleIn.set(handleOut._x, handleOut._y); handleOut.set(tmp);
handleOut.set(inX, inY);
}, },
/** /**
@ -603,13 +595,13 @@ var Segment = Base.extend(/** @lends Segment# */{
handleIn2 = to._handleIn, handleIn2 = to._handleIn,
handleOut2 = to._handleOut, handleOut2 = to._handleOut,
handleOut1 = from._handleOut; handleOut1 = from._handleOut;
this._point.set( this._point._set(
u * point1._x + v * point2._x, u * point1._x + v * point2._x,
u * point1._y + v * point2._y, true); u * point1._y + v * point2._y, true);
this._handleIn.set( this._handleIn._set(
u * handleIn1._x + v * handleIn2._x, u * handleIn1._x + v * handleIn2._x,
u * handleIn1._y + v * handleIn2._y, true); u * handleIn1._y + v * handleIn2._y, true);
this._handleOut.set( this._handleOut._set(
u * handleOut1._x + v * handleOut2._x, u * handleOut1._x + v * handleOut2._x,
u * handleOut1._y + v * handleOut2._y, true); u * handleOut1._y + v * handleOut2._y, true);
this._changed(); this._changed();

View file

@ -46,7 +46,8 @@ var SegmentPoint = Point.extend({
this.setSelected(true); this.setSelected(true);
}, },
set: function(x, y) { // See Point#_set() for an explanation of #_set():
_set: function(x, y) {
this._x = x; this._x = x;
this._y = y; this._y = y;
this._owner._changed(this); this._owner._changed(this);

View file

@ -625,10 +625,17 @@ var Color = Base.extend(new function() {
this._alpha = alpha; this._alpha = alpha;
if (reading) if (reading)
this.__read = read; this.__read = read;
return this;
}, },
// Have #_set point to #initialize, as used by Base.importJSON() /**
_set: '#initialize', * Sets the color to the passed values. Note that any sequence of
* parameters that is supported by the various {@link Color()}
* constructors also work for calls of `set()`.
*
* @function
*/
set: '#initialize',
_serialize: function(options, dictionary) { _serialize: function(options, dictionary) {
var components = this.getComponents(); var components = this.getComponents();

View file

@ -68,10 +68,15 @@ var Gradient = Base.extend(/** @lends Gradient# */{
initialize: function Gradient(stops, radial) { initialize: function Gradient(stops, radial) {
// Use UID here since Gradients are exported through dictionary.add(). // Use UID here since Gradients are exported through dictionary.add().
this._id = UID.get(); this._id = UID.get();
if (stops && this._set(stops)) if (stops && this._set(stops)) {
// Erase arguments since we used the passed object instead.
stops = radial = null; stops = radial = null;
if (!this._stops) }
// As these values might already have been set in the _set() call above,
// only initialize them if that hasn't happened yet.
if (this._stops == null) {
this.setStops(stops || ['white', 'black']); this.setStops(stops || ['white', 'black']);
}
if (this._radial == null) { if (this._radial == null) {
// Support old string type argument and new radial boolean. // Support old string type argument and new radial boolean.
this.setRadial(typeof radial === 'string' && radial === 'radial' this.setRadial(typeof radial === 'string' && radial === 'radial'

View file

@ -126,14 +126,15 @@ var Style = Base.extend(new function() {
_class: 'Style', _class: 'Style',
beans: true, beans: true,
initialize: function Style(style, owner, project) { initialize: function Style(style, _owner, _project) {
// We keep values in a separate object that we can iterate over. // We keep values in a separate object that we can iterate over.
this._values = {}; this._values = {};
this._owner = owner; this._owner = _owner;
this._project = owner && owner._project || project || paper.project; this._project = _owner && _owner._project || _project
|| paper.project;
// Use different defaults based on the owner // Use different defaults based on the owner
this._defaults = !owner || owner instanceof Group ? groupDefaults this._defaults = !_owner || _owner instanceof Group ? groupDefaults
: owner instanceof TextItem ? textDefaults : _owner instanceof TextItem ? textDefaults
: itemDefaults; : itemDefaults;
if (style) if (style)
this.set(style); this.set(style);
@ -263,6 +264,7 @@ var Style = Base.extend(new function() {
return fields; return fields;
}, /** @lends Style# */{ }, /** @lends Style# */{
set: function(style) { set: function(style) {
this._values = {}; // Reset already set styles.
// If the passed style object is also a Style, clone its clonable // If the passed style object is also a Style, clone its clonable
// fields rather than simply copying them. // fields rather than simply copying them.
var isStyle = style instanceof Style, var isStyle = style instanceof Style,

View file

@ -389,7 +389,7 @@ var View = Base.extend(Emitter, /** @lends View# */{
if (delta.isZero()) if (delta.isZero())
return; return;
this._setElementSize(width, height); this._setElementSize(width, height);
this._viewSize.set(width, height); this._viewSize._set(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,

View file

@ -46,6 +46,8 @@ test('new Point("10, 20")', function() {
equals(new Point('10, 20'), new Point(10, 20)); equals(new Point('10, 20'), new Point(10, 20));
equals(new Point('10,20'), new Point(10, 20)); equals(new Point('10,20'), new Point(10, 20));
equals(new Point('10 20'), new Point(10, 20)); equals(new Point('10 20'), new Point(10, 20));
// Make sure it's integer values from the string:
equals(new Point('10 20').add(10), new Point(20, 30));
}); });
test('normalize(length)', function() { test('normalize(length)', function() {

View file

@ -41,4 +41,6 @@ test('new Size("10, 20")', function() {
equals(new Size('10, 20'), new Size(10, 20)); equals(new Size('10, 20'), new Size(10, 20));
equals(new Size('10,20'), new Size(10, 20)); equals(new Size('10,20'), new Size(10, 20));
equals(new Size('10 20'), new Size(10, 20)); equals(new Size('10 20'), new Size(10, 20));
// Make sure it's integer values from the string:
equals(new Size('10 20').add(10), new Size(20, 30));
}); });