Switch to new simpler convention for control of beans creation in straps.js

This commit is contained in:
Jürg Lehni 2014-04-02 20:53:18 +02:00
parent 4d52867b4a
commit fa9786b344
12 changed files with 352 additions and 352 deletions

View file

@ -1,5 +1,5 @@
{ {
"browser" : true, "browser": true,
"evil": true, "evil": true,
"wsh": true, "wsh": true,
"trailing": false, "trailing": false,

View file

@ -13,7 +13,7 @@
"test" "test"
], ],
"devDependencies": { "devDependencies": {
"straps": "~1.4.3", "straps": "~1.5.0",
"acorn": "git://github.com/paperjs/acorn#0.3.2", "acorn": "git://github.com/paperjs/acorn#0.3.2",
"esprima": "~1.0.3", "esprima": "~1.0.3",
"stats.js": "r11" "stats.js": "r11"

View file

@ -716,17 +716,15 @@ var Matrix = Base.extend(/** @lends Matrix# */{
applyToContext: function(ctx) { applyToContext: function(ctx) {
ctx.transform(this._a, this._c, this._b, this._d, this._tx, this._ty); ctx.transform(this._a, this._c, this._b, this._d, this._tx, this._ty);
} }
}, new function() { }, Base.each(['a', 'c', 'b', 'd', 'tx', 'ty'], function(name) {
// Create getters and setters for all internal attributes. // Create getters and setters for all internal attributes.
return Base.each(['a', 'c', 'b', 'd', 'tx', 'ty'], function(name) { var part = Base.capitalize(name),
var part = Base.capitalize(name), prop = '_' + name;
prop = '_' + name; this['get' + part] = function() {
this['get' + part] = function() { return this[prop];
return this[prop]; };
}; this['set' + part] = function(value) {
this['set' + part] = function(value) { this[prop] = value;
this[prop] = value; this._changed();
this._changed(); };
}; }, {}));
}, {});
});

View file

@ -1,3 +1,4 @@
/* /*
* Paper.js - The Swiss Army Knife of Vector Graphics Scripting. * Paper.js - The Swiss Army Knife of Vector Graphics Scripting.
* http://paperjs.org/ * http://paperjs.org/
@ -238,6 +239,246 @@ var Point = Base.extend(/** @lends Point# */{
return [f.number(this.x), f.number(this.y)]; return [f.number(this.x), f.number(this.y)];
}, },
/**
* The length of the vector that is represented by this point's coordinates.
* Each point can be interpreted as a vector that points from the origin
* ({@code x = 0}, {@code y = 0}) to the point's location.
* Setting the length changes the location but keeps the vector's angle.
*
* @type Number
* @bean
*/
getLength: function() {
return Math.sqrt(this.x * this.x + this.y * this.y);
},
setLength: function(length) {
// Whenever chaining both x & y, use #set() instead of direct
// assignment, so LinkedPoint does not report changes twice.
if (this.isZero()) {
var angle = this._angle || 0;
this.set(
Math.cos(angle) * length,
Math.sin(angle) * length
);
} else {
var scale = length / this.getLength();
// Force calculation of angle now, so it will be preserved even when
// x and y are 0
if (Numerical.isZero(scale))
this.getAngle();
this.set(
this.x * scale,
this.y * scale
);
}
},
/**
* Returns the smaller angle between two vectors. The angle is unsigned, no
* information about rotational direction is given.
*
* @name Point#getAngle
* @function
* @param {Point} point
* @return {Number} the angle in degrees
*/
/**
* The vector's angle in degrees, measured from the x-axis to the vector.
*
* @name Point#getAngle
* @bean
* @type Number
*/
getAngle: function(/* point */) {
return this.getAngleInRadians.apply(this, arguments) * 180 / Math.PI;
},
setAngle: function(angle) {
this.setAngleInRadians.call(this, angle * Math.PI / 180);
},
getAngleInDegrees: '#getAngle',
setAngleInDegrees: '#setAngle',
/**
* Returns the smaller angle between two vectors in radians. The angle is
* unsigned, no information about rotational direction is given.
*
* @name Point#getAngleInRadians
* @function
* @param {Point} point
* @return {Number} the angle in radians
*/
/**
* The vector's angle in radians, measured from the x-axis to the vector.
*
* @name Point#getAngleInRadians
* @bean
* @type Number
*/
getAngleInRadians: function(/* point */) {
if (!arguments.length) {
return this.isZero()
// Return the preserved angle in case the vector has no
// length, and update the internal _angle in case the
// vector has a length. See #setAngle() for more
// explanations.
? this._angle || 0
: this._angle = Math.atan2(this.y, this.x);
} else {
var point = Point.read(arguments),
div = this.getLength() * point.getLength();
if (Numerical.isZero(div)) {
return NaN;
} else {
return Math.acos(this.dot(point) / div);
}
}
},
setAngleInRadians: function(angle) {
// We store a reference to _angle internally so we still preserve it
// when the vector's length is set to zero, and then anything else.
// Note that we cannot rely on it if x and y are something else than 0,
// since updating x / y does not automatically change _angle!
this._angle = angle;
if (!this.isZero()) {
var length = this.getLength();
// Use #set() instead of direct assignment of x/y, so LinkedPoint
// does not report changes twice.
this.set(
Math.cos(angle) * length,
Math.sin(angle) * length
);
}
},
/**
* The quadrant of the {@link #angle} of the point.
*
* Angles between 0 and 90 degrees are in quadrant {@code 1}. Angles between
* 90 and 180 degrees are in quadrant {@code 2}, angles between 180 and 270
* degrees are in quadrant {@code 3} and angles between 270 and 360 degrees
* are in quadrant {@code 4}.
*
* @type Number
* @bean
*
* @example
* var point = new Point({
* angle: 10,
* length: 20
* });
* console.log(point.quadrant); // 1
*
* point.angle = 100;
* console.log(point.quadrant); // 2
*
* point.angle = 190;
* console.log(point.quadrant); // 3
*
* point.angle = 280;
* console.log(point.quadrant); // 4
*/
getQuadrant: function() {
return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3;
}
}, /** @lends Point# */{
// Explicitly deactivate the creation of beans, as we have functions here
// that look like bean getters but actually read arguments.
// See #getDirectedAngle(), #getDistance()
beans: false,
/**
* Returns the angle between two vectors. The angle is directional and
* signed, giving information about the rotational direction.
*
* Read more about angle units and orientation in the description of the
* {@link #angle} property.
*
* @param {Point} point
* @return {Number} the angle between the two vectors
*/
getDirectedAngle: function(/* point */) {
var point = Point.read(arguments);
return Math.atan2(this.cross(point), this.dot(point)) * 180 / Math.PI;
},
/**
* Returns the distance between the point and another point.
*
* @param {Point} point
* @param {Boolean} [squared=false] Controls whether the distance should
* remain squared, or its square root should be calculated.
* @return {Number}
*/
getDistance: function(/* point, squared */) {
var point = Point.read(arguments),
x = point.x - this.x,
y = point.y - this.y,
d = x * x + y * y,
squared = Base.read(arguments);
return squared ? d : Math.sqrt(d);
},
/**
* Normalize modifies the {@link #length} of the vector to {@code 1} without
* changing its angle and returns it as a new point. The optional
* {@code length} parameter defines the length to normalize to.
* The object itself is not modified!
*
* @param {Number} [length=1] The length of the normalized vector
* @return {Point} the normalized vector of the vector that is represented
* by this point's coordinates
*/
normalize: function(length) {
if (length === undefined)
length = 1;
var current = this.getLength(),
scale = current !== 0 ? length / current : 0,
point = new Point(this.x * scale, this.y * scale);
// Preserve angle.
if (scale >= 0)
point._angle = this._angle;
return point;
},
/**
* Rotates the point by the given angle around an optional center point.
* The object itself is not modified.
*
* Read more about angle units and orientation in the description of the
* {@link #angle} property.
*
* @param {Number} angle the rotation angle
* @param {Point} center the center point of the rotation
* @returns {Point} the rotated point
*/
rotate: function(angle, center) {
if (angle === 0)
return this.clone();
angle = angle * Math.PI / 180;
var point = center ? this.subtract(center) : this,
s = Math.sin(angle),
c = Math.cos(angle);
point = new Point(
point.x * c - point.y * s,
point.x * s + point.y * c
);
return center ? point.add(center) : point;
},
/**
* Transforms the point by the matrix as a new point. The object itself is
* not modified!
*
* @param {Matrix} matrix
* @return {Point} the transformed point
*/
transform: function(matrix) {
return matrix ? matrix._transformPoint(this) : this;
},
/** /**
* Returns the addition of the supplied value to both coordinates of * Returns the addition of the supplied value to both coordinates of
* the point as a new point. * the point as a new point.
@ -429,255 +670,6 @@ var Point = Base.extend(/** @lends Point# */{
return new Point(-this.x, -this.y); return new Point(-this.x, -this.y);
}, },
/**
* Transforms the point by the matrix as a new point. The object itself
* is not modified!
*
* @param {Matrix} matrix
* @return {Point} the transformed point
*/
transform: function(matrix) {
return matrix ? matrix._transformPoint(this) : this;
},
/**
* {@grouptitle Distance & Length}
*
* Returns the distance between the point and another point.
*
* @param {Point} point
* @param {Boolean} [squared=false] Controls whether the distance should
* remain squared, or its square root should be calculated.
* @return {Number}
*/
getDistance: function(point, squared) {
// NOTE: Although we're reading from the argument list, we need the
// above arguments to prevent beans from being created (Straps.js issue)
// And for browser optimization we shouldn't re-assign an object to it,
// but we need to prevent the minifier from removing it again, so:
var _point = Point.read(arguments),
x = _point.x - this.x,
y = _point.y - this.y,
d = x * x + y * y;
// Reassigning boolean values to arguments is apparently OK.
squared = Base.read(arguments);
return squared ? d : Math.sqrt(d);
},
/**
* The length of the vector that is represented by this point's coordinates.
* Each point can be interpreted as a vector that points from the origin
* ({@code x = 0}, {@code y = 0}) to the point's location.
* Setting the length changes the location but keeps the vector's angle.
*
* @type Number
* @bean
*/
getLength: function() {
return Math.sqrt(this.x * this.x + this.y * this.y);
},
setLength: function(length) {
// Whenever chaining both x & y, use #set() instead of direct
// assignment, so LinkedPoint does not report changes twice.
if (this.isZero()) {
var angle = this._angle || 0;
this.set(
Math.cos(angle) * length,
Math.sin(angle) * length
);
} else {
var scale = length / this.getLength();
// Force calculation of angle now, so it will be preserved even when
// x and y are 0
if (Numerical.isZero(scale))
this.getAngle();
this.set(
this.x * scale,
this.y * scale
);
}
},
/**
* Normalize modifies the {@link #length} of the vector to {@code 1} without
* changing its angle and returns it as a new point. The optional
* {@code length} parameter defines the length to normalize to.
* The object itself is not modified!
*
* @param {Number} [length=1] The length of the normalized vector
* @return {Point} the normalized vector of the vector that is represented
* by this point's coordinates
*/
normalize: function(length) {
if (length === undefined)
length = 1;
var current = this.getLength(),
scale = current !== 0 ? length / current : 0,
point = new Point(this.x * scale, this.y * scale);
// Preserve angle.
if (scale >= 0)
point._angle = this._angle;
return point;
},
/**
* {@grouptitle Angle & Rotation}
* Returns the smaller angle between two vectors. The angle is unsigned, no
* information about rotational direction is given.
*
* @name Point#getAngle
* @function
* @param {Point} point
* @return {Number} the angle in degrees
*/
/**
* The vector's angle in degrees, measured from the x-axis to the vector.
*
* @name Point#getAngle
* @bean
* @type Number
*/
getAngle: function(/* point */) {
return this.getAngleInRadians.apply(this, arguments) * 180 / Math.PI;
},
setAngle: function(angle) {
this.setAngleInRadians.call(this, angle * Math.PI / 180);
},
getAngleInDegrees: '#getAngle',
setAngleInDegrees: '#setAngle',
/**
* Returns the smaller angle between two vectors in radians. The angle is
* unsigned, no information about rotational direction is given.
*
* @name Point#getAngleInRadians
* @function
* @param {Point} point
* @return {Number} the angle in radians
*/
/**
* The vector's angle in radians, measured from the x-axis to the vector.
*
* @name Point#getAngleInRadians
* @bean
* @type Number
*/
getAngleInRadians: function(/* point */) {
if (!arguments.length) {
return this.isZero()
// Return the preseved angle in case the vector has no
// length, and update the internal _angle in case the
// vector has a length. See #setAngle() for more
// explanations.
? this._angle || 0
: this._angle = Math.atan2(this.y, this.x);
} else {
var point = Point.read(arguments),
div = this.getLength() * point.getLength();
if (Numerical.isZero(div)) {
return NaN;
} else {
return Math.acos(this.dot(point) / div);
}
}
},
setAngleInRadians: function(angle) {
// We store a reference to _angle internally so we still preserve it
// when the vector's length is set to zero, and then anything else.
// Note that we cannot rely on it if x and y are something else than 0,
// since updating x / y does not automatically change _angle!
this._angle = angle;
if (!this.isZero()) {
var length = this.getLength();
// Use #set() instead of direct assignment of x/y, so LinkedPoint
// does not report changes twice.
this.set(
Math.cos(angle) * length,
Math.sin(angle) * length
);
}
},
/**
* The quadrant of the {@link #angle} of the point.
*
* Angles between 0 and 90 degrees are in quadrant {@code 1}. Angles between
* 90 and 180 degrees are in quadrant {@code 2}, angles between 180 and 270
* degrees are in quadrant {@code 3} and angles between 270 and 360 degrees
* are in quadrant {@code 4}.
*
* @type Number
* @bean
*
* @example
* var point = new Point({
* angle: 10,
* length: 20
* });
* console.log(point.quadrant); // 1
*
* point.angle = 100;
* console.log(point.quadrant); // 2
*
* point.angle = 190;
* console.log(point.quadrant); // 3
*
* point.angle = 280;
* console.log(point.quadrant); // 4
*/
getQuadrant: function() {
return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3;
},
/**
* Returns the angle between two vectors. The angle is directional and
* signed, giving information about the rotational direction.
*
* Read more about angle units and orientation in the description of the
* {@link #angle} property.
*
* @param {Point} point
* @return {Number} the angle between the two vectors
*/
getDirectedAngle: function(point) {
// NOTE: Although we're reading from the argument list, we need the
// above arguments to prevent beans from being created (Straps.js issue)
// And for browser optimization we shouldn't re-asign an object to it,
// but we need to prevent the minifier from removing it again, so:
var _point = point;
_point = Point.read(arguments);
return Math.atan2(this.cross(_point), this.dot(_point)) * 180 / Math.PI;
},
/**
* Rotates the point by the given angle around an optional center point.
* The object itself is not modified.
*
* Read more about angle units and orientation in the description of the
* {@link #angle} property.
*
* @param {Number} angle the rotation angle
* @param {Point} center the center point of the rotation
* @returns {Point} the rotated point
*/
rotate: function(angle, center) {
if (angle === 0)
return this.clone();
angle = angle * Math.PI / 180;
var point = center ? this.subtract(center) : this,
s = Math.sin(angle),
c = Math.cos(angle);
point = new Point(
point.x * c - point.y * s,
point.x * s + point.y * c
);
return center ? point.add(center) : point;
},
/** /**
* {@grouptitle Tests} * {@grouptitle Tests}
* *

View file

@ -21,6 +21,9 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
_class: 'Rectangle', _class: 'Rectangle',
// Tell Base.read that the Rectangle constructor supports reading with index // Tell Base.read that the Rectangle constructor supports reading with index
_readIndex: true, _readIndex: true,
// Enforce creation of beans, as bean getters have hidden parameters.
// See #getPoint() below.
beans: true,
/** /**
* Creates a Rectangle object. * Creates a Rectangle object.
@ -821,7 +824,11 @@ var Rectangle = Base.extend(/** @lends Rectangle# */{
this[setX](point.x); this[setX](point.x);
this[setY](point.y); this[setY](point.y);
}; };
}, {}); }, {
// Enforce creation of beans, as bean getters have hidden parameters
// See _dontLink argument above.
beans: true
});
}); });
/** /**

View file

@ -476,6 +476,10 @@ var Item = Base.extend(Callback, /** @lends Item# */{
} }
}; };
}, {}), /** @lends Item# */{ }, {}), /** @lends Item# */{
// Enforce creation of beans, as bean getters have hidden parameters.
// See #getPosition() below.
beans: true,
// Note: These properties have their getter / setters produced in the // Note: These properties have their getter / setters produced in the
// injection scope above. // injection scope above.
@ -873,14 +877,12 @@ var Item = Base.extend(Callback, /** @lends Item# */{
bounds.height, this, 'setBounds') bounds.height, this, 'setBounds')
: bounds; : bounds;
}; };
// As the function defines a _matrix parameter and has no setter,
// Straps.js doesn't produce a bean for it. Explicitely define an
// accesor now too:
this[key] = {
get: this[getter]
};
}, },
/** @lends Item# */{ /** @lends Item# */{
// Enforce creation of beans, as bean getters have hidden parameters.
// See _matrix parameter above.
beans: true,
/** /**
* Protected method used in all the bounds getters. It loops through all the * Protected method used in all the bounds getters. It loops through all the
* children, gets their bounds and finds the bounds around all of them. * children, gets their bounds and finds the bounds around all of them.
@ -1062,6 +1064,10 @@ var Item = Base.extend(Callback, /** @lends Item# */{
* @ignore * @ignore
*/ */
}), /** @lends Item# */{ }), /** @lends Item# */{
// Enforce creation of beans, as bean getters have hidden parameters.
// See #getGlobalMatrix() below.
beans: true,
_decompose: function() { _decompose: function() {
return this._decomposed = this._matrix.decompose(); return this._decomposed = this._matrix.decompose();
}, },
@ -1146,7 +1152,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
* @type Matrix * @type Matrix
* @bean * @bean
*/ */
getGlobalMatrix: function() { getGlobalMatrix: function(_internal) {
var matrix = this._globalMatrix, var matrix = this._globalMatrix,
updateVersion = this._project._updateVersion, updateVersion = this._project._updateVersion,
viewMatrix = this.getView()._matrix; viewMatrix = this.getView()._matrix;
@ -1164,9 +1170,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
: viewMatrix); : viewMatrix);
matrix._updateVersion = updateVersion; matrix._updateVersion = updateVersion;
} }
// TODO: Fix Straps.js so we can pass this on as _internal argument and return _internal ? matrix : viewMatrix.inverted().concatenate(matrix);
// still have a bean created.
return arguments[0] ? matrix : viewMatrix.inverted().concatenate(matrix);
}, },
/** /**
@ -1194,7 +1198,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
*/ */
getTransformContent: '#getApplyMatrix', getTransformContent: '#getApplyMatrix',
setTransformContent: '#setApplyMatrix', setTransformContent: '#setApplyMatrix',
}, /** @lends Item# */{
/** /**
* {@grouptitle Project Hierarchy} * {@grouptitle Project Hierarchy}
* The project that this item belongs to. * The project that this item belongs to.

View file

@ -219,16 +219,20 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
for (var i = 0, l = children.length; i < l; i++) for (var i = 0, l = children.length; i < l; i++)
area += children[i].getArea(); area += children[i].getArea();
return area; return area;
}, }
}, /** @lends CompoundPath# */{
// Enforce bean creation for getPathData(), as it has hidden parameters.
beans: true,
getPathData: function(precision) { getPathData: function(_precision) {
// NOTE: #setPathData() is defined in PathItem.
var children = this._children, var children = this._children,
paths = []; paths = [];
for (var i = 0, l = children.length; i < l; i++) for (var i = 0, l = children.length; i < l; i++)
paths.push(children[i].getPathData(precision)); paths.push(children[i].getPathData(_precision));
return paths.join(' '); return paths.join(' ');
}, }
}, /** @lends CompoundPath# */{
_getChildHitTestOptions: function(options) { _getChildHitTestOptions: function(options) {
// If we're not specifically asked to returns paths through // If we're not specifically asked to returns paths through
// options.type == 'path' do not test children for fill, since a // options.type == 'path' do not test children for fill, since a

View file

@ -28,6 +28,10 @@
*/ */
var CurveLocation = Base.extend(/** @lends CurveLocation# */{ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
_class: 'CurveLocation', _class: 'CurveLocation',
// Enforce creation of beans, as bean getters have hidden parameters.
// See #getSegment() below.
beans: true,
// DOCS: CurveLocation class description: add these back when the mentioned // DOCS: CurveLocation class description: add these back when the mentioned
// functioned have been added: {@link Path#split(location)} // functioned have been added: {@link Path#split(location)}
/** /**
@ -82,13 +86,6 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
return this._segment; return this._segment;
}, },
setSegment: function(segment) {
// NOTE: We only include this setter so the above getter can declare
// the _preferFirst parameter without having to hide it.
// See Straps.js beans conventions.
this._segment = segment;
},
/** /**
* The curve by which the location is defined. * The curve by which the location is defined.
* *
@ -109,11 +106,6 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
return this._curve; return this._curve;
}, },
setCurve: function(curve) {
// See #setSegment()
this._curve = curve;
},
/** /**
* The curve location on the intersecting curve, if this location is the * The curve location on the intersecting curve, if this location is the
* result of a call to {@link PathItem#getIntersections(path)} / * result of a call to {@link PathItem#getIntersections(path)} /
@ -199,11 +191,6 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
return this._parameter; return this._parameter;
}, },
setParameter: function(parameter) {
// See #setSegment()
this._parameter = parameter;
},
/** /**
* The point which is defined by the {@link #curve} and * The point which is defined by the {@link #curve} and
* {@link #parameter}. * {@link #parameter}.
@ -219,11 +206,6 @@ var CurveLocation = Base.extend(/** @lends CurveLocation# */{
return this._point; return this._point;
}, },
setPoint: function(point) {
// See #setSegment()
this._point = point;
},
/** /**
* The tangential vector to the {@link #curve} at the given location. * The tangential vector to the {@link #curve} at the given location.
* *

View file

@ -254,51 +254,6 @@ var Path = PathItem.extend(/** @lends Path# */{
return curves[curves.length - 1]; return curves[curves.length - 1];
}, },
/**
* The segments contained within the path, described as SVG style path data.
*
* @type String
* @bean
*/
getPathData: function(precision) {
var segments = this._segments,
f = Formatter.instance,
parts = [];
// TODO: Add support for H/V and/or relative commands, where appropriate
// and resulting in shorter strings
function addCurve(seg1, seg2, skipLine) {
var point1 = seg1._point,
point2 = seg2._point,
handle1 = seg1._handleOut,
handle2 = seg2._handleIn;
if (handle1.isZero() && handle2.isZero()) {
if (!skipLine) {
// L = absolute lineto: moving to a point with drawing
parts.push('L' + f.point(point2, precision));
}
} else {
// c = relative curveto: handle1, handle2 + end - start,
// end - start
var end = point2.subtract(point1);
parts.push('c' + f.point(handle1, precision)
+ ' ' + f.point(end.add(handle2), precision)
+ ' ' + f.point(end, precision));
}
}
if (segments.length === 0)
return '';
parts.push('M' + f.point(segments[0]._point));
for (var i = 0, l = segments.length - 1; i < l; i++)
addCurve(segments[i], segments[i + 1], false);
if (this._closed) {
addCurve(segments[segments.length - 1], segments[0], true);
parts.push('z');
}
return parts.join('');
},
/** /**
* Specifies whether the path is closed. If it is closed, Paper.js connects * Specifies whether the path is closed. If it is closed, Paper.js connects
* the first and last segments. * the first and last segments.
@ -336,7 +291,51 @@ var Path = PathItem.extend(/** @lends Path# */{
// up-to-date and don't need notification. // up-to-date and don't need notification.
this._changed(/*#=*/ Change.SEGMENTS); this._changed(/*#=*/ Change.SEGMENTS);
} }
}, }
}, /** @lends Path# */{
// Enforce bean creation for getPathData(), as it has hidden parameters.
beans: true,
getPathData: function(_precision) {
// NOTE: #setPathData() is defined in PathItem.
var segments = this._segments,
f = Formatter.instance,
parts = [];
// TODO: Add support for H/V and/or relative commands, where appropriate
// and resulting in shorter strings
function addCurve(seg1, seg2, skipLine) {
var point1 = seg1._point,
point2 = seg2._point,
handle1 = seg1._handleOut,
handle2 = seg2._handleIn;
if (handle1.isZero() && handle2.isZero()) {
if (!skipLine) {
// L = absolute lineto: moving to a point with drawing
parts.push('L' + f.point(point2, _precision));
}
} else {
// c = relative curveto: handle1, handle2 + end - start,
// end - start
var end = point2.subtract(point1);
parts.push('c' + f.point(handle1, _precision)
+ ' ' + f.point(end.add(handle2), _precision)
+ ' ' + f.point(end, _precision));
}
}
if (segments.length === 0)
return '';
parts.push('M' + f.point(segments[0]._point));
for (var i = 0, l = segments.length - 1; i < l; i++)
addCurve(segments[i], segments[i + 1], false);
if (this._closed) {
addCurve(segments[segments.length - 1], segments[0], true);
parts.push('z');
}
return parts.join('');
}
}, /** @lends Path# */{
// TODO: Consider adding getSubPath(a, b), returning a part of the current // TODO: Consider adding getSubPath(a, b), returning a part of the current
// path, with the added benefit that b can be < a, and closed looping is // path, with the added benefit that b can be < a, and closed looping is
@ -2439,7 +2438,7 @@ var Path = PathItem.extend(/** @lends Path# */{
z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)), z = 4 / 3 * Math.sin(half) / (1 + Math.cos(half)),
segments = []; segments = [];
for (var i = 0; i <= count; i++) { for (var i = 0; i <= count; i++) {
// Explicitely use to point for last segment, since depending // Explicitly use to point for last segment, since depending
// on values the calculation adds imprecision: // on values the calculation adds imprecision:
var pt = to, var pt = to,
out = null; out = null;

View file

@ -181,7 +181,16 @@ var PathItem = Item.extend(/** @lends PathItem# */{
return locations; return locations;
}, },
/**
* The path's geometry, formatted as SVG style path data.
*
* @name PathItem#getPathData
* @type String
* @bean
*/
setPathData: function(data) { setPathData: function(data) {
// NOTE: #getPathData() is defined in CompoundPath / Path
// This is a very compact SVG Path Data parser that works both for Path // This is a very compact SVG Path Data parser that works both for Path
// and CompoundPath. // and CompoundPath.

View file

@ -24,6 +24,7 @@
*/ */
var Segment = Base.extend(/** @lends Segment# */{ var Segment = Base.extend(/** @lends Segment# */{
_class: 'Segment', _class: 'Segment',
beans: true,
/** /**
* Creates a new Segment object. * Creates a new Segment object.
@ -146,7 +147,8 @@ var Segment = Base.extend(/** @lends Segment# */{
_serialize: function(options) { _serialize: function(options) {
// If the Segment is linear, only serialize point, otherwise handles too // If the Segment is linear, only serialize point, otherwise handles too
return Base.serialize(this.isLinear() ? this._point return Base.serialize(this.isLinear() ? this._point
: [this._point, this._handleIn, this._handleOut], options, true); : [this._point, this._handleIn, this._handleOut],
options, true);
}, },
_changed: function(point) { _changed: function(point) {

View file

@ -116,7 +116,10 @@ var Style = Base.extend(new function() {
// Override default fillColor for text items // Override default fillColor for text items
_textDefaults: new Base(defaults, { _textDefaults: new Base(defaults, {
fillColor: new Color() // black fillColor: new Color() // black
}) }),
// Enforce creation of beans, as bean getters have hidden parameters
// See _dontMerge argument below.
beans: true
}; };
Base.each(defaults, function(value, key) { Base.each(defaults, function(value, key) {