mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-08 05:42:07 -05:00
More documentation edits and function reordering.
This commit is contained in:
parent
fb36a275ac
commit
6b611add37
4 changed files with 522 additions and 363 deletions
|
@ -98,6 +98,14 @@ var Point = this.Point = Base.extend({
|
||||||
return Point.create(this.x, this.y);
|
return Point.create(this.x, this.y);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string} A string representation of the point.
|
||||||
|
*/
|
||||||
|
toString: function() {
|
||||||
|
var format = Base.formatNumber;
|
||||||
|
return '{ x: ' + format(this.x) + ', y: ' + format(this.y) + ' }';
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
@ -279,11 +287,20 @@ var Point = this.Point = Base.extend({
|
||||||
return Point.create(-this.x, -this.y);
|
return Point.create(-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) {
|
transform: function(matrix) {
|
||||||
return matrix._transformPoint(this);
|
return matrix._transformPoint(this);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Distance & Length}
|
||||||
|
*
|
||||||
* Returns the distance between the point and another point.
|
* Returns the distance between the point and another point.
|
||||||
*
|
*
|
||||||
* @param {Point} point
|
* @param {Point} point
|
||||||
|
@ -348,15 +365,8 @@ var Point = this.Point = Base.extend({
|
||||||
return point;
|
return point;
|
||||||
},
|
},
|
||||||
|
|
||||||
// DOCS: Point#getQuadrant
|
|
||||||
/**
|
|
||||||
* @return {number}
|
|
||||||
*/
|
|
||||||
getQuadrant: function() {
|
|
||||||
return this.x >= 0 ? this.y >= 0 ? 1 : 4 : this.y >= 0 ? 2 : 3;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Angle & Rotation}
|
||||||
* Returns the smaller angle between two vectors. The angle is unsigned, no
|
* Returns the smaller angle between two vectors. The angle is unsigned, no
|
||||||
* information about rotational direction is given.
|
* information about rotational direction is given.
|
||||||
*
|
*
|
||||||
|
@ -432,6 +442,14 @@ var Point = this.Point = Base.extend({
|
||||||
return this.getAngle(arguments[0]);
|
return this.getAngle(arguments[0]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// DOCS: Point#getQuadrant
|
||||||
|
/**
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
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
|
* Returns the angle between two vectors. The angle is directional and
|
||||||
* signed, giving information about the rotational direction.
|
* signed, giving information about the rotational direction.
|
||||||
|
@ -490,6 +508,8 @@ var Point = this.Point = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Tests}
|
||||||
|
*
|
||||||
* Checks whether the point is inside the boundaries of the rectangle.
|
* Checks whether the point is inside the boundaries of the rectangle.
|
||||||
*
|
*
|
||||||
* @param {Rectangle} rect the rectangle to check against
|
* @param {Rectangle} rect the rectangle to check against
|
||||||
|
@ -555,6 +575,7 @@ var Point = this.Point = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Vectorial Math Functions}
|
||||||
* Returns the dot product of the point and another point.
|
* Returns the dot product of the point and another point.
|
||||||
*
|
*
|
||||||
* @param {Point} point
|
* @param {Point} point
|
||||||
|
@ -597,12 +618,14 @@ var Point = this.Point = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return {string} A string representation of the point.
|
* This property is only present if the point is an anchor or control point
|
||||||
|
* of a {@link Segment} or a {@link Curve}. In this case, it returns
|
||||||
|
* true if it is selected, false otherwise
|
||||||
|
*
|
||||||
|
* @name Point#selected
|
||||||
|
* @property
|
||||||
|
* @return {boolean} true if the point is selected, false otherwise
|
||||||
*/
|
*/
|
||||||
toString: function() {
|
|
||||||
var format = Base.formatNumber;
|
|
||||||
return '{ x: ' + format(this.x) + ', y: ' + format(this.y) + ' }';
|
|
||||||
},
|
|
||||||
|
|
||||||
statics: {
|
statics: {
|
||||||
/** @lends Point */
|
/** @lends Point */
|
||||||
|
|
|
@ -48,7 +48,7 @@ var Gradient = this.Gradient = Base.extend({
|
||||||
/**
|
/**
|
||||||
* The gradient stops on the gradient ramp.
|
* The gradient stops on the gradient ramp.
|
||||||
*
|
*
|
||||||
* @type {array}
|
* @type GradientStop[]
|
||||||
* @bean
|
* @bean
|
||||||
*/
|
*/
|
||||||
getStops: function() {
|
getStops: function() {
|
||||||
|
|
831
src/item/Item.js
831
src/item/Item.js
|
@ -36,42 +36,6 @@ var Item = this.Item = Base.extend({
|
||||||
this.setStyle(this._project.getCurrentStyle());
|
this.setStyle(this._project.getCurrentStyle());
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* Clones the item within the same project and places the copy above the
|
|
||||||
* item.
|
|
||||||
*
|
|
||||||
* @return the newly cloned item
|
|
||||||
*/
|
|
||||||
clone: function() {
|
|
||||||
return this._clone(new this.constructor());
|
|
||||||
},
|
|
||||||
|
|
||||||
_clone: function(copy) {
|
|
||||||
// Copy over style
|
|
||||||
copy.setStyle(this._style);
|
|
||||||
// If this item has children, clone and append each of them:
|
|
||||||
if (this._children) {
|
|
||||||
for (var i = 0, l = this._children.length; i < l; i++)
|
|
||||||
copy.appendTop(this._children[i].clone());
|
|
||||||
}
|
|
||||||
// Only copy over these fields if they are actually defined in 'this'
|
|
||||||
// TODO: Consider moving this to Base once it's useful in more than one
|
|
||||||
// place
|
|
||||||
var keys = ['locked', 'visible', 'opacity', 'blendMode', '_clipMask'];
|
|
||||||
for (var i = 0, l = keys.length; i < l; i++) {
|
|
||||||
var key = keys[i];
|
|
||||||
if (this.hasOwnProperty(key))
|
|
||||||
copy[key] = this[key];
|
|
||||||
}
|
|
||||||
// Move the clone above the original, at the same position.
|
|
||||||
copy.moveAbove(this);
|
|
||||||
// Only set name once the copy is moved, to avoid setting and unsettting
|
|
||||||
// name related structures.
|
|
||||||
if (this._name)
|
|
||||||
copy.setName(this._name);
|
|
||||||
return copy;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private notifier that is called whenever a change occurs in this item or
|
* Private notifier that is called whenever a change occurs in this item or
|
||||||
* its sub-elements, such as Segments, Curves, PathStyles, etc.
|
* its sub-elements, such as Segments, Curves, PathStyles, etc.
|
||||||
|
@ -97,7 +61,13 @@ var Item = this.Item = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of the item.
|
* The name of the item. If the item has a name, it can be accessed by name
|
||||||
|
* through its parent's children list.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* var path = new Path();
|
||||||
|
* path.name = 'example';
|
||||||
|
* project.activeLayer.children['example'].remove();
|
||||||
*
|
*
|
||||||
* @type string
|
* @type string
|
||||||
* @bean
|
* @bean
|
||||||
|
@ -123,7 +93,334 @@ var Item = this.Item = Base.extend({
|
||||||
delete children[name];
|
delete children[name];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The item's position within the project. This is the
|
||||||
|
* {@link Rectangle#center} of the {@link #bounds} rectangle.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Create a circle at position { x: 10, y: 10 }
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
* circle.fillColor = 'red';
|
||||||
|
*
|
||||||
|
* // Move the circle to { x: 20, y: 20 }
|
||||||
|
* circle.position = new Point(20, 20);
|
||||||
|
*
|
||||||
|
* // Move the circle 10 points to the right and 10 points down
|
||||||
|
* circle.position += new Point(10, 10);
|
||||||
|
* console.log(circle.position); // { x: 30, y: 30 }
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Create a circle at position { x: 10, y: 10 }
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
* circle.fillColor = 'red';
|
||||||
|
*
|
||||||
|
* // Move the circle 10 points to the right
|
||||||
|
* circle.position.x += 10;
|
||||||
|
* console.log(circle.position); // { x: 20, y: 10 }
|
||||||
|
*
|
||||||
|
* @type Point
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getPosition: function() {
|
||||||
|
// Cache position value
|
||||||
|
if (!this._position) {
|
||||||
|
// Center is a LinkedPoint as well, so we can use _x and _y
|
||||||
|
var center = this.getBounds().getCenter();
|
||||||
|
this._position = LinkedPoint.create(this, 'setPosition',
|
||||||
|
center._x, center._y);
|
||||||
|
}
|
||||||
|
return this._position;
|
||||||
|
},
|
||||||
|
|
||||||
|
setPosition: function(point) {
|
||||||
|
point = Point.read(arguments);
|
||||||
|
if (point)
|
||||||
|
this.translate(point.subtract(this.getPosition()));
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path style of the item.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
* circle.style = {
|
||||||
|
* fillColor: new RGBColor(1, 0, 0),
|
||||||
|
* strokeColor: new RGBColor(0, 1, 0),
|
||||||
|
* strokeWidth: 5
|
||||||
|
* };
|
||||||
|
*
|
||||||
|
* @type PathStyle
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getStyle: function() {
|
||||||
|
return this._style;
|
||||||
|
},
|
||||||
|
|
||||||
|
setStyle: function(style) {
|
||||||
|
this._style.initialize(style);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether an item is selected and will also return {@code true} if
|
||||||
|
* the item is partially selected (groups with some selected items/partially
|
||||||
|
* selected paths).
|
||||||
|
*
|
||||||
|
* Paper.js draws the visual outlines of selected items on top of your
|
||||||
|
* project. This can be useful for debugging, as it allows you to see the
|
||||||
|
* construction of paths, position of path curves, individual segment points
|
||||||
|
* and bounding boxes of symbol and raster items.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* console.log(project.selectedItems.length); // 0
|
||||||
|
* var path = new Path.Circle(new Size(50, 50), 25);
|
||||||
|
* path.selected = true; // Select the path
|
||||||
|
* console.log(project.selectedItems.length) // 1
|
||||||
|
*
|
||||||
|
* @type boolean true if the item is selected, false otherwise
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
isSelected: function() {
|
||||||
|
if (this._children) {
|
||||||
|
for (var i = 0, l = this._children.length; i < l; i++) {
|
||||||
|
if (this._children[i].isSelected()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return !!this._selected;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
setSelected: function(selected) {
|
||||||
|
if (this._children) {
|
||||||
|
for (var i = 0, l = this._children.length; i < l; i++) {
|
||||||
|
this._children[i].setSelected(selected);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((selected = !!selected) != this._selected) {
|
||||||
|
// TODO: when an item is removed or moved to another
|
||||||
|
// project, it needs to be removed from _selectedItems
|
||||||
|
this._selected = selected;
|
||||||
|
this._project._selectItem(this, selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: isFullySelected / setFullySelected
|
||||||
|
// TODO: Change to getter / setters for these below that notify of changes
|
||||||
|
// through _changed()
|
||||||
|
|
||||||
|
// TODO: Item#isLocked is currently ignored in the documentation, as
|
||||||
|
// locking an item currently has no effect
|
||||||
|
/**
|
||||||
|
* Specifies whether the item is locked.
|
||||||
|
*
|
||||||
|
* @type boolean
|
||||||
|
* @default false
|
||||||
|
* @ignore
|
||||||
|
*/
|
||||||
|
locked: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the item is visible. When set to {@code false}, the
|
||||||
|
* item won't be drawn.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* var path = new Path.Circle(new Point(50, 50), 20);
|
||||||
|
* path.fillColor = 'red';
|
||||||
|
* console.log(path.visible) // true
|
||||||
|
* path.visible = false; // Hides the path
|
||||||
|
*
|
||||||
|
* @type boolean true if the item is visible, false otherwise
|
||||||
|
* @default true
|
||||||
|
*/
|
||||||
|
visible: true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies whether the item defines a clip mask. This can only be set on
|
||||||
|
* paths, compound paths, and text frame objects, and only if the item is
|
||||||
|
* already contained within a clipping group.
|
||||||
|
*
|
||||||
|
* @type boolean
|
||||||
|
* @default false
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
isClipMask: function() {
|
||||||
|
return this._clipMask;
|
||||||
|
},
|
||||||
|
|
||||||
|
setClipMask: function(clipMask) {
|
||||||
|
this._clipMask = clipMask;
|
||||||
|
if (this._clipMask) {
|
||||||
|
this.setFillColor(null);
|
||||||
|
this.setStrokeColor(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The blend mode of the item.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* var circle = new Path.Circle(new Point(50, 50), 10);
|
||||||
|
* circle.fillColor = 'red';
|
||||||
|
*
|
||||||
|
* // Change the blend mode of the path item:
|
||||||
|
* circle.blendMode = 'multiply';
|
||||||
|
*
|
||||||
|
* @type String('normal','screen','multiply','difference','src-in','add','overlay','hard-light','dodge','burn','darken','lighten','exclusion')
|
||||||
|
* @default 'normal'
|
||||||
|
*/
|
||||||
|
blendMode: 'normal',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The opacity of the item as a value between 0 and 1.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Create a circle at position { x: 50, y: 50 }
|
||||||
|
* var circle = new Path.Circle(new Point(50, 50), 20);
|
||||||
|
* circle.fillColor = 'red';
|
||||||
|
*
|
||||||
|
* // Change the opacity of the circle to 50%:
|
||||||
|
* circle.opacity = 0.5;
|
||||||
|
*
|
||||||
|
* @type number
|
||||||
|
* @default 1
|
||||||
|
*/
|
||||||
|
opacity: 1,
|
||||||
|
|
||||||
|
// TODO: get/setIsolated (print specific feature)
|
||||||
|
// TODO: get/setKnockout (print specific feature)
|
||||||
|
// TODO get/setAlphaIsShape
|
||||||
|
// TODO: get/setData
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@grouptitle Project Hierarchy}
|
||||||
|
* The project that this item belongs to.
|
||||||
|
*
|
||||||
|
* @type Project
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getProject: function() {
|
||||||
|
return this._project;
|
||||||
|
},
|
||||||
|
|
||||||
|
_setProject: function(project) {
|
||||||
|
if (this._project != project) {
|
||||||
|
this._project = project;
|
||||||
|
if (this._children) {
|
||||||
|
for (var i = 0, l = this._children.length; i < l; i++) {
|
||||||
|
this._children[i]._setProject(project);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: #getLayer()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The item that this item is contained within.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* var path = new Path();
|
||||||
|
* // New items are placed in the active layer:
|
||||||
|
* console.log(path.parent == project.activeLayer); // true
|
||||||
|
*
|
||||||
|
* var group = new Group();
|
||||||
|
* group.appendTop(path);
|
||||||
|
* // Now the parent of the path has become the group:
|
||||||
|
* console.log(path.parent == group); // true
|
||||||
|
*
|
||||||
|
* @type Item
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getParent: function() {
|
||||||
|
return this._parent;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The children items contained within this item. Items that define a
|
||||||
|
* {@link #name} can also be accessed by name.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* var path = new Path();
|
||||||
|
* var group = new Group();
|
||||||
|
* group.appendTop(path);
|
||||||
|
*
|
||||||
|
* // The path has been placed in the children list of the group:
|
||||||
|
* console.log(group.children[0] == path);
|
||||||
|
*
|
||||||
|
* path.name = 'example';
|
||||||
|
* // Now the path can also be accessed by name:
|
||||||
|
* console.log(group.children['example'] == path); // true
|
||||||
|
*
|
||||||
|
* @type Item[]
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getChildren: function() {
|
||||||
|
return this._children;
|
||||||
|
},
|
||||||
|
|
||||||
|
setChildren: function(items) {
|
||||||
|
this.removeChildren();
|
||||||
|
for (var i = 0, l = items && items.length; i < l; i++)
|
||||||
|
this.appendTop(items[i]);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first item contained within this item. This is a shortcut for
|
||||||
|
* accessing {@code item.children[0]}.
|
||||||
|
*
|
||||||
|
* @type Item
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getFirstChild: function() {
|
||||||
|
return this._children && this._children[0] || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last item contained within this item.This is a shortcut for
|
||||||
|
* accessing {@code item.children[item.children.length - 1]}.
|
||||||
|
*
|
||||||
|
* @type Item
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getLastChild: function() {
|
||||||
|
return this._children && this._children[this._children.length - 1]
|
||||||
|
|| null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The next item on the same level as this item.
|
||||||
|
*
|
||||||
|
* @type Item
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getNextSibling: function() {
|
||||||
|
return this._parent && this._parent._children[this._index + 1] || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The previous item on the same level as this item.
|
||||||
|
*
|
||||||
|
* @type Item
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getPreviousSibling: function() {
|
||||||
|
return this._parent && this._parent._children[this._index - 1] || null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The index of this item within the list of its parent's children.
|
||||||
|
*
|
||||||
|
* @type number
|
||||||
|
* @bean
|
||||||
|
*/
|
||||||
|
getIndex: function() {
|
||||||
|
return this._index;
|
||||||
|
},
|
||||||
|
|
||||||
_removeFromNamed: function() {
|
_removeFromNamed: function() {
|
||||||
var children = this._parent._children,
|
var children = this._parent._children,
|
||||||
namedChildren = this._parent._namedChildren,
|
namedChildren = this._parent._namedChildren,
|
||||||
|
@ -157,7 +454,10 @@ var Item = this.Item = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the item from the project.
|
* Removes the item from the project. If the item has children, they are also
|
||||||
|
* removed.
|
||||||
|
*
|
||||||
|
* @return {boolean} true if the item was removed, false otherwise
|
||||||
*/
|
*/
|
||||||
remove: function() {
|
remove: function() {
|
||||||
if (this.isSelected())
|
if (this.isSelected())
|
||||||
|
@ -165,6 +465,20 @@ var Item = this.Item = Base.extend({
|
||||||
return this._removeFromParent();
|
return this._removeFromParent();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all of the item's children (if any).
|
||||||
|
*
|
||||||
|
* @return {boolean} true if removing was successful, false otherwise
|
||||||
|
*/
|
||||||
|
removeChildren: function() {
|
||||||
|
var removed = false;
|
||||||
|
if (this._children) {
|
||||||
|
for (var i = this._children.length - 1; i >= 0; i--)
|
||||||
|
removed = this._children[i].remove() || removed;
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When passed a project, copies the item to the project,
|
* When passed a project, copies the item to the project,
|
||||||
* or duplicates it within the same project. When passed an item,
|
* or duplicates it within the same project. When passed an item,
|
||||||
|
@ -185,174 +499,39 @@ var Item = this.Item = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies whether an item is selected and will also return true if
|
* Clones the item within the same project and places the copy above the
|
||||||
* the item is partially selected (groups with
|
* item.
|
||||||
* some selected items/partially selected paths).
|
|
||||||
*
|
*
|
||||||
* @example
|
* @return {Item} the newly cloned item
|
||||||
* console.log(project.selectedItems.length); // 0
|
*/
|
||||||
* var path = new Path.Circle(new Size(50, 50), 25);
|
clone: function() {
|
||||||
* path.selected = true; // Select the path
|
return this._clone(new this.constructor());
|
||||||
* console.log(project.selectedItems.length) // 1
|
},
|
||||||
*
|
|
||||||
* @type boolean
|
_clone: function(copy) {
|
||||||
* @bean
|
// Copy over style
|
||||||
*/
|
copy.setStyle(this._style);
|
||||||
isSelected: function() {
|
// If this item has children, clone and append each of them:
|
||||||
if (this._children) {
|
if (this._children) {
|
||||||
for (var i = 0, l = this._children.length; i < l; i++) {
|
for (var i = 0, l = this._children.length; i < l; i++)
|
||||||
if (this._children[i].isSelected()) {
|
copy.appendTop(this._children[i].clone());
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return !!this._selected;
|
|
||||||
}
|
}
|
||||||
return false;
|
// Only copy over these fields if they are actually defined in 'this'
|
||||||
},
|
// TODO: Consider moving this to Base once it's useful in more than one
|
||||||
|
// place
|
||||||
setSelected: function(selected) {
|
var keys = ['locked', 'visible', 'opacity', 'blendMode', '_clipMask'];
|
||||||
if (this._children) {
|
for (var i = 0, l = keys.length; i < l; i++) {
|
||||||
for (var i = 0, l = this._children.length; i < l; i++) {
|
var key = keys[i];
|
||||||
this._children[i].setSelected(selected);
|
if (this.hasOwnProperty(key))
|
||||||
}
|
copy[key] = this[key];
|
||||||
} else {
|
|
||||||
if ((selected = !!selected) != this._selected) {
|
|
||||||
// TODO: when an item is removed or moved to another
|
|
||||||
// project, it needs to be removed from _selectedItems
|
|
||||||
this._selected = selected;
|
|
||||||
this._project._selectItem(this, selected);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
// Move the clone above the original, at the same position.
|
||||||
|
copy.moveAbove(this);
|
||||||
/**
|
// Only set name once the copy is moved, to avoid setting and unsettting
|
||||||
* The project that this item belongs to.
|
// name related structures.
|
||||||
*
|
if (this._name)
|
||||||
* @type Project
|
copy.setName(this._name);
|
||||||
* @bean
|
return copy;
|
||||||
*/
|
|
||||||
getProject: function() {
|
|
||||||
return this._project;
|
|
||||||
},
|
|
||||||
|
|
||||||
_setProject: function(project) {
|
|
||||||
if (this._project != project) {
|
|
||||||
this._project = project;
|
|
||||||
if (this._children) {
|
|
||||||
for (var i = 0, l = this._children.length; i < l; i++) {
|
|
||||||
this._children[i]._setProject(project);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: isFullySelected / setFullySelected
|
|
||||||
// TODO: Change to getter / setters for these below that notify of changes
|
|
||||||
// through _changed()
|
|
||||||
/**
|
|
||||||
* Specifies whether the item is locked.
|
|
||||||
*
|
|
||||||
* @type boolean
|
|
||||||
* @default false
|
|
||||||
*/
|
|
||||||
locked: false,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies whether the item is visible.
|
|
||||||
*
|
|
||||||
* @type boolean
|
|
||||||
* @default true
|
|
||||||
*/
|
|
||||||
visible: true,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The opacity of the item as a value between 0 and 1.
|
|
||||||
*
|
|
||||||
* @type number
|
|
||||||
* @default 1
|
|
||||||
*/
|
|
||||||
opacity: 1,
|
|
||||||
|
|
||||||
// DOCS: list the different blend modes that are possible.
|
|
||||||
/**
|
|
||||||
* The blend mode of the item.
|
|
||||||
* @type string
|
|
||||||
* @default 'normal'
|
|
||||||
*/
|
|
||||||
blendMode: 'normal',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Specifies whether the item defines a clip mask. This can only be set on
|
|
||||||
* paths, compound paths, and text frame objects, and only if the item is
|
|
||||||
* already contained within a clipping group.
|
|
||||||
*
|
|
||||||
* @type boolean
|
|
||||||
* @default false
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
isClipMask: function() {
|
|
||||||
return this._clipMask;
|
|
||||||
},
|
|
||||||
|
|
||||||
setClipMask: function(clipMask) {
|
|
||||||
this._clipMask = clipMask;
|
|
||||||
if (this._clipMask) {
|
|
||||||
this.setFillColor(null);
|
|
||||||
this.setStrokeColor(null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: get/setIsolated (print specific feature)
|
|
||||||
// TODO: get/setKnockout (print specific feature)
|
|
||||||
// TODO get/setAlphaIsShape
|
|
||||||
// TODO: get/setData
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The item that this item is contained within.
|
|
||||||
*
|
|
||||||
* @type Item
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
getParent: function() {
|
|
||||||
return this._parent;
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: #getLayer()
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of this item within the list of its parent's children.
|
|
||||||
*
|
|
||||||
* @type number
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
getIndex: function() {
|
|
||||||
return this._index;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The children items contained within this item.
|
|
||||||
*
|
|
||||||
* @type array
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
getChildren: function() {
|
|
||||||
return this._children;
|
|
||||||
},
|
|
||||||
|
|
||||||
setChildren: function(items) {
|
|
||||||
this.removeChildren();
|
|
||||||
for (var i = 0, l = items && items.length; i < l; i++)
|
|
||||||
this.appendTop(items[i]);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the item contains any children items.
|
|
||||||
*
|
|
||||||
* @return {boolean} true if it has one or more children, false otherwise.
|
|
||||||
*/
|
|
||||||
hasChildren: function() {
|
|
||||||
return this._children && this._children.length > 0;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -370,63 +549,48 @@ var Item = this.Item = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes all of the item's children, if it has any
|
* Rasterizes the item into a newly created Raster object. The item itself
|
||||||
|
* is not removed after rasterization.
|
||||||
|
*
|
||||||
|
* @param {number} [resolution=72] the resolution of the raster in dpi
|
||||||
|
* @return {Raster} the newly created raster item
|
||||||
*/
|
*/
|
||||||
removeChildren: function() {
|
rasterize: function(resolution) {
|
||||||
var removed = false;
|
// TODO: why would we want to pass a size to rasterize? Seems to produce
|
||||||
if (this._children) {
|
// weird results on Scriptographer. Also we can't use antialiasing, since
|
||||||
for (var i = this._children.length - 1; i >= 0; i--)
|
// Canvas doesn't support it yet. Project colorMode is also out of the
|
||||||
removed = this._children[i].remove() || removed;
|
// question for now.
|
||||||
}
|
var bounds = this.getStrokeBounds(),
|
||||||
return removed;
|
scale = (resolution || 72) / 72,
|
||||||
|
canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)),
|
||||||
|
ctx = canvas.getContext('2d'),
|
||||||
|
matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y);
|
||||||
|
matrix.applyToContext(ctx);
|
||||||
|
this.draw(ctx, {});
|
||||||
|
var raster = new Raster(canvas);
|
||||||
|
raster.setPosition(this.getPosition());
|
||||||
|
raster.scale(1 / scale);
|
||||||
|
return raster;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The first item contained within this item.
|
* {@grouptitle Tests}
|
||||||
|
* Checks if the item contains any children items.
|
||||||
*
|
*
|
||||||
* @type Item
|
* @return {boolean} true if it has one or more children, false otherwise.
|
||||||
* @bean
|
|
||||||
*/
|
*/
|
||||||
getFirstChild: function() {
|
hasChildren: function() {
|
||||||
return this._children && this._children[0] || null;
|
return this._children && this._children.length > 0;
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The last item contained within this item.
|
|
||||||
*
|
|
||||||
* @type Item
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
getLastChild: function() {
|
|
||||||
return this._children && this._children[this._children.length - 1]
|
|
||||||
|| null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The next item on the same level as this item.
|
|
||||||
*
|
|
||||||
* @type Item
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
getNextSibling: function() {
|
|
||||||
return this._parent && this._parent._children[this._index + 1] || null;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The previous item on the same level as this item.
|
|
||||||
*
|
|
||||||
* @type Item
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
getPreviousSibling: function() {
|
|
||||||
return this._parent && this._parent._children[this._index - 1] || null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// TODO: Item#isEditable is currently ignored in the documentation, as
|
||||||
|
// locking an item currently has no effect
|
||||||
/**
|
/**
|
||||||
* Checks whether the item is editable.
|
* Checks whether the item is editable.
|
||||||
*
|
*
|
||||||
* @return {boolean} true when neither the item, nor its parents are
|
* @return {boolean} true when neither the item, nor its parents are
|
||||||
* locked or hidden, false otherwise.
|
* locked or hidden, false otherwise.
|
||||||
|
* @ignore
|
||||||
*/
|
*/
|
||||||
isEditable: function() {
|
isEditable: function() {
|
||||||
var parent = this;
|
var parent = this;
|
||||||
|
@ -466,6 +630,7 @@ var Item = this.Item = Base.extend({
|
||||||
// TODO: isBelow
|
// TODO: isBelow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Hierarchy Tests}
|
||||||
* Checks whether the specified item is the parent of the item.
|
* Checks whether the specified item is the parent of the item.
|
||||||
*
|
*
|
||||||
* @param {Item} item The item to check against
|
* @param {Item} item The item to check against
|
||||||
|
@ -616,100 +781,10 @@ var Item = this.Item = Base.extend({
|
||||||
*/
|
*/
|
||||||
// TODO: getControlBounds
|
// TODO: getControlBounds
|
||||||
|
|
||||||
/**
|
|
||||||
* Rasterizes the item into a newly created Raster object. The item itself
|
|
||||||
* is not removed after rasterization.
|
|
||||||
*
|
|
||||||
* @param {number} [resolution=72] the resolution of the raster in dpi
|
|
||||||
* @return {Raster} the newly created raster item
|
|
||||||
*/
|
|
||||||
rasterize: function(resolution) {
|
|
||||||
// TODO: why would we want to pass a size to rasterize? Seems to produce
|
|
||||||
// weird results on Scriptographer. Also we can't use antialiasing, since
|
|
||||||
// Canvas doesn't support it yet. Project colorMode is also out of the
|
|
||||||
// question for now.
|
|
||||||
var bounds = this.getStrokeBounds(),
|
|
||||||
scale = (resolution || 72) / 72,
|
|
||||||
canvas = CanvasProvider.getCanvas(bounds.getSize().multiply(scale)),
|
|
||||||
ctx = canvas.getContext('2d'),
|
|
||||||
matrix = new Matrix().scale(scale).translate(-bounds.x, -bounds.y);
|
|
||||||
matrix.applyToContext(ctx);
|
|
||||||
this.draw(ctx, {});
|
|
||||||
var raster = new Raster(canvas);
|
|
||||||
raster.setPosition(this.getPosition());
|
|
||||||
raster.scale(1 / scale);
|
|
||||||
return raster;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The item's position within the project. This is the
|
|
||||||
* {@link Rectangle#center} of the {@link Item#bounds} rectangle.
|
|
||||||
*
|
|
||||||
* @type Point
|
|
||||||
* @bean
|
|
||||||
*/
|
|
||||||
getPosition: function() {
|
|
||||||
// Cache position value
|
|
||||||
if (!this._position) {
|
|
||||||
// Center is a LinkedPoint as well, so we can use _x and _y
|
|
||||||
var center = this.getBounds().getCenter();
|
|
||||||
this._position = LinkedPoint.create(this, 'setPosition',
|
|
||||||
center._x, center._y);
|
|
||||||
}
|
|
||||||
return this._position;
|
|
||||||
},
|
|
||||||
|
|
||||||
setPosition: function(point) {
|
|
||||||
point = Point.read(arguments);
|
|
||||||
if (point)
|
|
||||||
this.translate(point.subtract(this.getPosition()));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param flags: Array of any of the following: 'objects', 'children',
|
|
||||||
* 'fill-gradients', 'fill-patterns', 'stroke-patterns', 'lines'.
|
|
||||||
* Default: ['objects', 'children']
|
|
||||||
*
|
|
||||||
* @ignore
|
|
||||||
*/
|
|
||||||
transform: function(matrix, flags) {
|
|
||||||
// TODO: Handle flags, add TransformFlag class and convert to bit mask
|
|
||||||
// for quicker checking
|
|
||||||
// TODO: Call transform on chidren only if 'children' flag is provided
|
|
||||||
if (this._transform)
|
|
||||||
this._transform(matrix, flags);
|
|
||||||
// Transform position as well. Do not modify _position directly,
|
|
||||||
// since it's a LinkedPoint and would cause recursion!
|
|
||||||
if (this._position)
|
|
||||||
matrix._transformPoint(this._position, this._position, true);
|
|
||||||
if (this._children) {
|
|
||||||
for (var i = 0, l = this._children.length; i < l; i++) {
|
|
||||||
var child = this._children[i];
|
|
||||||
child.transform(matrix, flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// PORT: Return 'this' in all chainable commands
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
|
||||||
_transform: function(matrix, flags) {
|
|
||||||
// The code that performs the actual transformation of content,
|
|
||||||
// if defined. Item itself does not define this.
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Translates (moves) the item by the given offset point.
|
|
||||||
*
|
|
||||||
* @param {Point} delta the offset to translate the item by
|
|
||||||
*/
|
|
||||||
translate: function(delta) {
|
|
||||||
var mx = new Matrix();
|
|
||||||
return this.transform(mx.translate.apply(mx, arguments));
|
|
||||||
},
|
|
||||||
|
|
||||||
// DOCS: document the different arguments that this function can receive.
|
// DOCS: document the different arguments that this function can receive.
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Transform Functions}
|
||||||
|
*
|
||||||
* Scales the item by the given value from its center point, or optionally
|
* Scales the item by the given value from its center point, or optionally
|
||||||
* by a supplied point.
|
* by a supplied point.
|
||||||
*
|
*
|
||||||
|
@ -730,9 +805,36 @@ var Item = this.Item = Base.extend({
|
||||||
* // Scale the path 200% from its bottom left corner
|
* // Scale the path 200% from its bottom left corner
|
||||||
* circle.scale(2, circle.bounds.bottomLeft);
|
* circle.scale(2, circle.bounds.bottomLeft);
|
||||||
*
|
*
|
||||||
|
* @name Item#scale^1
|
||||||
|
* @function
|
||||||
* @param {number} scale the scale factor
|
* @param {number} scale the scale factor
|
||||||
* @param {Point} [center=the center point of the item]
|
* @param {Point} [center=the center point of the item]
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* Scales the item by the given values from its center point, or optionally
|
||||||
|
* by a supplied point.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Create a circle at position { x: 10, y: 10 }
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
* console.log(circle.bounds.width); // 20
|
||||||
|
*
|
||||||
|
* // Scale the path horizontally by 200%
|
||||||
|
* circle.scale(1, 2);
|
||||||
|
*
|
||||||
|
* console.log(circle.bounds.width); // 40
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Create a circle at position { x: 10, y: 10 }
|
||||||
|
* var circle = new Path.Circle(new Point(10, 10), 10);
|
||||||
|
*
|
||||||
|
* // Scale the path 200% horizontally from its bottom left corner
|
||||||
|
* circle.scale(1, 2, circle.bounds.bottomLeft);
|
||||||
|
*
|
||||||
|
* @param {number} sx the horizontal scale factor
|
||||||
|
* @param {number} sy the vertical scale factor
|
||||||
|
* @param {Point} [center=the center point of the item]
|
||||||
|
*/
|
||||||
scale: function(sx, sy /* | scale */, center) {
|
scale: function(sx, sy /* | scale */, center) {
|
||||||
// See Matrix#scale for explanation of this:
|
// See Matrix#scale for explanation of this:
|
||||||
if (arguments.length < 2 || typeof sy === 'object') {
|
if (arguments.length < 2 || typeof sy === 'object') {
|
||||||
|
@ -743,6 +845,16 @@ var Item = this.Item = Base.extend({
|
||||||
center || this.getPosition()));
|
center || this.getPosition()));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translates (moves) the item by the given offset point.
|
||||||
|
*
|
||||||
|
* @param {Point} delta the offset to translate the item by
|
||||||
|
*/
|
||||||
|
translate: function(delta) {
|
||||||
|
var mx = new Matrix();
|
||||||
|
return this.transform(mx.translate.apply(mx, arguments));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates the item by a given angle around the given point.
|
* Rotates the item by a given angle around the given point.
|
||||||
*
|
*
|
||||||
|
@ -779,18 +891,39 @@ var Item = this.Item = Base.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The path style of the item.
|
* Transform the item.
|
||||||
*
|
*
|
||||||
* @type PathStyle
|
* @param {Matrix} matrix
|
||||||
* @bean
|
* @param {array} flags Array of any of the following: 'objects', 'children',
|
||||||
|
* 'fill-gradients', 'fill-patterns', 'stroke-patterns', 'lines'.
|
||||||
|
* Default: ['objects', 'children']
|
||||||
*/
|
*/
|
||||||
getStyle: function() {
|
transform: function(matrix, flags) {
|
||||||
return this._style;
|
// TODO: Handle flags, add TransformFlag class and convert to bit mask
|
||||||
|
// for quicker checking
|
||||||
|
// TODO: Call transform on chidren only if 'children' flag is provided
|
||||||
|
if (this._transform)
|
||||||
|
this._transform(matrix, flags);
|
||||||
|
// Transform position as well. Do not modify _position directly,
|
||||||
|
// since it's a LinkedPoint and would cause recursion!
|
||||||
|
if (this._position)
|
||||||
|
matrix._transformPoint(this._position, this._position, true);
|
||||||
|
if (this._children) {
|
||||||
|
for (var i = 0, l = this._children.length; i < l; i++) {
|
||||||
|
var child = this._children[i];
|
||||||
|
child.transform(matrix, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// PORT: Return 'this' in all chainable commands
|
||||||
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
setStyle: function(style) {
|
/*
|
||||||
this._style.initialize(style);
|
_transform: function(matrix, flags) {
|
||||||
},
|
// The code that performs the actual transformation of content,
|
||||||
|
// if defined. Item itself does not define this.
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
// TODO: toString
|
// TODO: toString
|
||||||
|
|
||||||
|
@ -926,6 +1059,7 @@ var Item = this.Item = Base.extend({
|
||||||
/** @lends Item# */
|
/** @lends Item# */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Hierarchy Operations}
|
||||||
* Inserts the specified item as a child of the item by appending it to
|
* Inserts the specified item as a child of the item by appending it to
|
||||||
* the list of children and moving it above all other children. You can
|
* the list of children and moving it above all other children. You can
|
||||||
* use this function for groups, compound paths and layers.
|
* use this function for groups, compound paths and layers.
|
||||||
|
@ -967,6 +1101,7 @@ var Item = this.Item = Base.extend({
|
||||||
//DOCS: document removeOn(param)
|
//DOCS: document removeOn(param)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* {@grouptitle Remove On Event}
|
||||||
* Removes the item when the next {@link Tool#onMouseMove} event is fired.
|
* Removes the item when the next {@link Tool#onMouseMove} event is fired.
|
||||||
*
|
*
|
||||||
* @name Item#removeOnMove
|
* @name Item#removeOnMove
|
||||||
|
|
|
@ -34,7 +34,7 @@ var Path = this.Path = PathItem.extend({
|
||||||
* path.moveTo(30, 30);
|
* path.moveTo(30, 30);
|
||||||
* path.lineTo(100, 100);
|
* path.lineTo(100, 100);
|
||||||
*
|
*
|
||||||
* @param {array} [segments] An optional array of segments (or points to be
|
* @param {Segment[]} [segments] An optional array of segments (or points to be
|
||||||
* converted to segments) that will be added to the path.
|
* converted to segments) that will be added to the path.
|
||||||
*
|
*
|
||||||
* @class The Path item represents a path in a Paper.js project.
|
* @class The Path item represents a path in a Paper.js project.
|
||||||
|
@ -271,6 +271,7 @@ var Path = this.Path = PathItem.extend({
|
||||||
* @param {Segment|Point} segment the segment or point to be added.
|
* @param {Segment|Point} segment the segment or point to be added.
|
||||||
* @return {Segment} the added segment. This is not necessarily the same
|
* @return {Segment} the added segment. This is not necessarily the same
|
||||||
* object, e.g. if the segment to be added already belongs to another path.
|
* object, e.g. if the segment to be added already belongs to another path.
|
||||||
|
* @operator none
|
||||||
*/
|
*/
|
||||||
add: function(segment1 /*, segment2, ... */) {
|
add: function(segment1 /*, segment2, ... */) {
|
||||||
return arguments.length > 1 && typeof segment1 !== 'number'
|
return arguments.length > 1 && typeof segment1 !== 'number'
|
||||||
|
|
Loading…
Reference in a new issue