Correctly clone all attributes in Shape#toPath() and Path#toShape()

Also write documentation for both methods.
Closes #622.
This commit is contained in:
Jürg Lehni 2015-06-16 14:30:40 +02:00
parent ba12eec7f5
commit 2cf6cd7a14
4 changed files with 62 additions and 34 deletions

View file

@ -1486,36 +1486,50 @@ var Item = Base.extend(Emitter, /** @lends Item# */{
return this._clone(new this.constructor(Item.NO_INSERT), insert); return this._clone(new this.constructor(Item.NO_INSERT), insert);
}, },
_clone: function(copy, insert) { /**
* Clones the item within the same project and places the copy above the
* item.
*
* @param {Boolean} [insert=true] specifies whether the copy should be
* inserted into the DOM. When set to {@code true}, it is inserted above the
* original.
* @return {Item} the newly cloned item
*/
_clone: function(copy, insert, includeMatrix) {
var keys = ['_locked', '_visible', '_blendMode', '_opacity',
'_clipMask', '_guide'],
children = this._children;
// Copy over style // Copy over style
copy.setStyle(this._style); copy.setStyle(this._style);
// If this item has children, clone and append each of them: // Clone all children and add them to the copy. tell #addChild we're
if (this._children) { // cloning, as needed by CompoundPath#insertChild().
// Clone all children and add them to the copy. tell #addChild we're for (var i = 0, l = children && children.length; i < l; i++) {
// cloning, as needed by CompoundPath#insertChild(). copy.addChild(children[i].clone(false), true);
for (var i = 0, l = this._children.length; i < l; i++)
copy.addChild(this._children[i].clone(false), true);
} }
// Insert is true by default.
if (insert || insert === undefined)
copy.insertAbove(this);
// Only copy over these fields if they are actually defined in 'this', // Only copy over these fields if they are actually defined in 'this',
// meaning the default value has been overwritten (default is on // meaning the default value has been overwritten (default is on
// prototype). // prototype).
var keys = ['_locked', '_visible', '_blendMode', '_opacity',
'_clipMask', '_guide', '_applyMatrix'];
for (var i = 0, l = keys.length; i < l; i++) { for (var i = 0, l = keys.length; i < l; i++) {
var key = keys[i]; var key = keys[i];
if (this.hasOwnProperty(key)) if (this.hasOwnProperty(key))
copy[key] = this[key]; copy[key] = this[key];
} }
// Use Matrix#initialize to easily copy over values. // Use Matrix#initialize to easily copy over values.
copy._matrix.initialize(this._matrix); if (includeMatrix !== false)
// Copy over _data as well. copy._matrix.initialize(this._matrix);
copy._data = this._data ? Base.clone(this._data) : null; // In case of Path#toShape(), we can't just set _applyMatrix as
// Shape won't allow it. Using the setter instead takes care of it.
// NOTE: This will also bake in the matrix that we just initialized,
// in case #applyMatrix is true.
copy.setApplyMatrix(this._applyMatrix);
// Copy over the selection state, use setSelected so the item // Copy over the selection state, use setSelected so the item
// is also added to Project#selectedItems if it is selected. // is also added to Project#selectedItems if it is selected.
copy.setSelected(this._selected); copy.setSelected(this._selected);
// Copy over _data as well.
copy._data = this._data ? Base.clone(this._data) : null;
// Insert is true by default.
if (insert || insert === undefined)
copy.insertAbove(this);
// Clone the name too, but make sure we're not overriding the original // Clone the name too, but make sure we're not overriding the original
// in the same parent, by passing true for the unique parameter. // in the same parent, by passing true for the unique parameter.
if (this._name) if (this._name)

View file

@ -157,19 +157,29 @@ var Shape = Item.extend(/** @lends Shape# */{
return false; return false;
}, },
// DOCS: #toPath([insert=true]) /**
* Creates a new path item with same geometry as this shape item, and
* inherits all settings from it, similar to {@link Item#clone()}.
*
* @param {Boolean} [insert=true] specifies whether the new path should be
* inserted into the DOM. When set to {@code true}, it is inserted above the
* shape item.
* @return {Shape} the newly created path item with the same geometry as
* this shape item.
* @see Path#toShape(insert)
*/
toPath: function(insert) { toPath: function(insert) {
var path = new Path[Base.capitalize(this._type)]({ var path = this._clone(new Path[Base.capitalize(this._type)]({
center: new Point(), center: new Point(),
size: this._size, size: this._size,
radius: this._radius, radius: this._radius,
insert: false insert: false
}); }), insert);
path.setStyle(this._style); // The created path will inherit #applyMatrix from this Shape, hence it
path.transform(this._matrix); // will always be false.
// Insert is true by default. // Respect the setting of paper.settings.applyMatrix for new paths:
if (insert || insert === undefined) if (paper.settings.applyMatrix)
path.insertAbove(this); path.setApplyMatrix(true);
return path; return path;
}, },

View file

@ -1356,9 +1356,17 @@ var Path = PathItem.extend(/** @lends Path# */{
return this; return this;
}, },
/**
// DOCS: toShape * Attempts to create a new shape item with same geometry as this path item,
* and inherits all settings from it, similar to {@link Item#clone()}.
*
* @param {Boolean} [insert=true] specifies whether the new shape should be
* inserted into the DOM. When set to {@code true}, it is inserted above the
* path item.
* @return {Shape} the newly created shape item with the same geometry as
* this path item if it can be matched, {@code null} otherwise.
* @see Shape#toPath(insert)
*/
toShape: function(insert) { toShape: function(insert) {
if (!this._closed) if (!this._closed)
return null; return null;
@ -1419,18 +1427,14 @@ var Path = PathItem.extend(/** @lends Path# */{
if (type) { if (type) {
var center = this.getPosition(true), var center = this.getPosition(true),
shape = new type({ shape = this._clone(new type({
center: center, center: center,
size: size, size: size,
radius: radius, radius: radius,
insert: false insert: false
}); }), insert, false);
// Determine and apply the shape's angle of rotation. // Determine and apply the shape's angle of rotation.
shape.rotate(topCenter.subtract(center).getAngle() + 90); shape.rotate(topCenter.subtract(center).getAngle() + 90);
shape.setStyle(this._style);
// Insert is true by default.
if (insert || insert === undefined)
shape.insertAbove(this);
return shape; return shape;
} }
return null; return null;

View file

@ -50,9 +50,9 @@ var TextItem = Item.extend(/** @lends TextItem# */{
return this._content === item._content; return this._content === item._content;
}, },
_clone: function _clone(copy, insert) { _clone: function _clone(copy, insert, includeMatrix) {
copy.setContent(this._content); copy.setContent(this._content);
return _clone.base.call(this, copy, insert); return _clone.base.call(this, copy, insert, includeMatrix);
}, },
/** /**