mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-20 22:39:50 -05:00
Improve Item#transform() and implement #applyMatrix() to support nested matrices. Work in progress.
This commit is contained in:
parent
b0b49d027a
commit
9e5eb17264
5 changed files with 71 additions and 51 deletions
|
@ -1665,6 +1665,7 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
* @function
|
* @function
|
||||||
* @param {Number} scale the scale factor
|
* @param {Number} scale the scale factor
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
|
* @param {Boolean} apply
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Scaling an item from its center point:
|
* // Scaling an item from its center point:
|
||||||
|
@ -1697,6 +1698,7 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
* @param {Number} hor the horizontal scale factor
|
* @param {Number} hor the horizontal scale factor
|
||||||
* @param {Number} ver the vertical scale factor
|
* @param {Number} ver the vertical scale factor
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
|
* @param {Boolean} apply
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
* // Scaling an item horizontally by 300%:
|
* // Scaling an item horizontally by 300%:
|
||||||
|
@ -1709,24 +1711,26 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
* // Scale the path horizontally by 300%
|
* // Scale the path horizontally by 300%
|
||||||
* circle.scale(3, 1);
|
* circle.scale(3, 1);
|
||||||
*/
|
*/
|
||||||
scale: function(hor, ver /* | scale */, center) {
|
scale: function(hor, ver /* | scale */, center, apply) {
|
||||||
// See Matrix#scale for explanation of this:
|
// See Matrix#scale for explanation of this:
|
||||||
if (arguments.length < 2 || typeof ver === 'object') {
|
if (arguments.length < 2 || typeof ver === 'object') {
|
||||||
|
apply = center;
|
||||||
center = ver;
|
center = ver;
|
||||||
ver = hor;
|
ver = hor;
|
||||||
}
|
}
|
||||||
return this.transform(new Matrix().scale(hor, ver,
|
return this.transform(new Matrix().scale(hor, ver,
|
||||||
center || this.getPosition()));
|
center || this.getPosition(true)), apply);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates (moves) the item by the given offset point.
|
* Translates (moves) the item by the given offset point.
|
||||||
*
|
*
|
||||||
* @param {Point} delta the offset to translate the item by
|
* @param {Point} delta the offset to translate the item by
|
||||||
|
* @param {Boolean} apply
|
||||||
*/
|
*/
|
||||||
translate: function(delta) {
|
translate: function(delta, apply) {
|
||||||
var mx = new Matrix();
|
var mx = new Matrix();
|
||||||
return this.transform(mx.translate.apply(mx, arguments));
|
return this.transform(mx.translate.apply(mx, arguments), apply);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1736,6 +1740,7 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
*
|
*
|
||||||
* @param {Number} angle the rotation angle
|
* @param {Number} angle the rotation angle
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
|
* @param {Boolean} apply
|
||||||
* @see Matrix#rotate
|
* @see Matrix#rotate
|
||||||
*
|
*
|
||||||
* @example {@paperscript}
|
* @example {@paperscript}
|
||||||
|
@ -1770,9 +1775,9 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
* path.rotate(3, view.center);
|
* path.rotate(3, view.center);
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
rotate: function(angle, center) {
|
rotate: function(angle, center, apply) {
|
||||||
return this.transform(new Matrix().rotate(angle,
|
return this.transform(new Matrix().rotate(angle,
|
||||||
center || this.getPosition()));
|
center || this.getPosition(true)), apply);
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO: Add test for item shearing, as it might be behaving oddly.
|
// TODO: Add test for item shearing, as it might be behaving oddly.
|
||||||
|
@ -1784,6 +1789,7 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
* @function
|
* @function
|
||||||
* @param {Point} point
|
* @param {Point} point
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
|
* @param {Boolean} apply
|
||||||
* @see Matrix#shear
|
* @see Matrix#shear
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
|
@ -1795,41 +1801,48 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
* @param {Number} hor the horizontal shear factor.
|
* @param {Number} hor the horizontal shear factor.
|
||||||
* @param {Number} ver the vertical shear factor.
|
* @param {Number} ver the vertical shear factor.
|
||||||
* @param {Point} [center={@link Item#position}]
|
* @param {Point} [center={@link Item#position}]
|
||||||
|
* @param {Boolean} apply
|
||||||
* @see Matrix#shear
|
* @see Matrix#shear
|
||||||
*/
|
*/
|
||||||
shear: function(hor, ver, center) {
|
shear: function(hor, ver, center, apply) {
|
||||||
// PORT: Add support for center back to Scriptographer too!
|
// PORT: Add support for center and apply back to Scriptographer too!
|
||||||
// See Matrix#scale for explanation of this:
|
// See Matrix#scale for explanation of this:
|
||||||
if (arguments.length < 2 || typeof ver === 'object') {
|
if (arguments.length < 2 || typeof ver === 'object') {
|
||||||
|
apply = center;
|
||||||
center = ver;
|
center = ver;
|
||||||
ver = hor;
|
ver = hor;
|
||||||
}
|
}
|
||||||
return this.transform(new Matrix().shear(hor, ver,
|
return this.transform(new Matrix().shear(hor, ver,
|
||||||
center || this.getPosition()));
|
center || this.getPosition(true)), apply);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform the item.
|
* Transform the item.
|
||||||
*
|
*
|
||||||
* @param {Matrix} matrix
|
* @param {Matrix} matrix the matrix by which the item shall be transformed.
|
||||||
|
* @param {Boolean} apply controls wether the transformation should just be
|
||||||
|
* concatenated to {@link #matrix} ({@code false}) or if it should directly
|
||||||
|
* be applied to item's content and its children.
|
||||||
*/
|
*/
|
||||||
// Remove this for now:
|
// Remove this for now:
|
||||||
// @param {String[]} flags Array of any of the following: 'objects',
|
// @param {String[]} flags Array of any of the following: 'objects',
|
||||||
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
||||||
// 'lines'. Default: ['objects', 'children']
|
// 'lines'. Default: ['objects', 'children']
|
||||||
transform: function(matrix, flags) {
|
transform: function(matrix, apply) {
|
||||||
// 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.
|
|
||||||
// Calling _changed will clear _bounds and _position, but depending
|
// Calling _changed will clear _bounds and _position, but depending
|
||||||
// on matrix we can calculate and set them again.
|
// on matrix we can calculate and set them again.
|
||||||
var bounds = this._bounds,
|
var bounds = this._bounds,
|
||||||
position = this._position,
|
position = this._position,
|
||||||
children = this._children;
|
children = this._children;
|
||||||
|
bounds = position = null;
|
||||||
|
// Simply preconcatenate the internal matrix with the passed one:
|
||||||
|
this._matrix.preConcatenate(matrix);
|
||||||
if (this._transform)
|
if (this._transform)
|
||||||
this._transform(matrix, flags);
|
this._transform(matrix);
|
||||||
// We need to call _changed even if we don't have _transform, since
|
if (apply)
|
||||||
// we're caching bounds on such items too now, e.g. Group
|
this.applyMatrix(false);
|
||||||
|
// We always need to call _changed since we're caching bounds on all
|
||||||
|
// items, including Group.
|
||||||
this._changed(Change.GEOMETRY);
|
this._changed(Change.GEOMETRY);
|
||||||
// Detect matrices that contain only translations and scaling
|
// Detect matrices that contain only translations and scaling
|
||||||
// and transform the cached _bounds and _position without having to
|
// and transform the cached _bounds and _position without having to
|
||||||
|
@ -1855,12 +1868,33 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
// changes, since it's a LinkedPoint and would cause recursion!
|
// changes, since it's a LinkedPoint and would cause recursion!
|
||||||
this._position = matrix._transformPoint(position, position, true);
|
this._position = matrix._transformPoint(position, position, true);
|
||||||
}
|
}
|
||||||
for (var i = 0, l = children && children.length; i < l; i++)
|
|
||||||
children[i].transform(matrix, flags);
|
|
||||||
// PORT: Return 'this' in all chainable commands
|
// PORT: Return 'this' in all chainable commands
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
applyMatrix: function(recursive) {
|
||||||
|
if (this._applyMatrix(this._matrix, recursive)) {
|
||||||
|
// Set _matrix to the identity
|
||||||
|
// TODO: Introduce Matrix#setIdentity() and use it from
|
||||||
|
// #initialize() too?
|
||||||
|
this._matrix.initialize();
|
||||||
|
// TODO: This needs a _changed notification, but the GEOMETRY
|
||||||
|
// actually sdoesnt change! What to do?
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_applyMatrix: function(matrix, recursive) {
|
||||||
|
if (this._children) {
|
||||||
|
for (var i = 0, l = this._children.length; i < l; i++) {
|
||||||
|
var child = this._children[i];
|
||||||
|
child.transform(matrix);
|
||||||
|
if (recursive)
|
||||||
|
child.applyMatrix(true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transform the item so that its {@link #bounds} fit within the specified
|
* Transform the item so that its {@link #bounds} fit within the specified
|
||||||
* rectangle, without changing its aspect ratio.
|
* rectangle, without changing its aspect ratio.
|
||||||
|
@ -1931,13 +1965,6 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
this.setBounds(newBounds);
|
this.setBounds(newBounds);
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
|
||||||
_transform: function(matrix, flags) {
|
|
||||||
// The code that performs the actual transformation of content,
|
|
||||||
// if defined. Item itself does not define this.
|
|
||||||
},
|
|
||||||
*/
|
|
||||||
|
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return (this.constructor._name || 'Item') + (this._name
|
return (this.constructor._name || 'Item') + (this._name
|
||||||
? " '" + this._name + "'"
|
? " '" + this._name + "'"
|
||||||
|
|
|
@ -25,12 +25,5 @@
|
||||||
*/
|
*/
|
||||||
var PlacedItem = this.PlacedItem = Item.extend(/** @lends PlacedItem# */{
|
var PlacedItem = this.PlacedItem = Item.extend(/** @lends PlacedItem# */{
|
||||||
// PlacedItem uses strokeBounds for bounds
|
// PlacedItem uses strokeBounds for bounds
|
||||||
_boundsType: { bounds: 'strokeBounds' },
|
_boundsType: { bounds: 'strokeBounds' }
|
||||||
|
|
||||||
_transform: function(matrix, flags) {
|
|
||||||
// In order to set the right context transformation when drawing the
|
|
||||||
// raster, simply preconcatenate the internal matrix with the provided
|
|
||||||
// one.
|
|
||||||
this._matrix.preConcatenate(matrix);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -64,6 +64,7 @@ var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend(/** @lends PlacedSymbol
|
||||||
initialize: function(symbol, matrixOrOffset) {
|
initialize: function(symbol, matrixOrOffset) {
|
||||||
this.base();
|
this.base();
|
||||||
this.setSymbol(symbol instanceof Symbol ? symbol : new Symbol(symbol));
|
this.setSymbol(symbol instanceof Symbol ? symbol : new Symbol(symbol));
|
||||||
|
// XXX: Define one way of creating matrices and passing them to ctors
|
||||||
this._matrix = matrixOrOffset !== undefined
|
this._matrix = matrixOrOffset !== undefined
|
||||||
? matrixOrOffset instanceof Matrix
|
? matrixOrOffset instanceof Matrix
|
||||||
? matrixOrOffset
|
? matrixOrOffset
|
||||||
|
|
|
@ -206,21 +206,20 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
||||||
// 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
|
||||||
// taken into account.
|
// taken into account.
|
||||||
|
|
||||||
_transform: function(matrix, flags) {
|
_applyMatrix: function(matrix) {
|
||||||
if (matrix && !matrix.isIdentity()) {
|
var coords = new Array(6);
|
||||||
var coords = new Array(6);
|
for (var i = 0, l = this._segments.length; i < l; i++) {
|
||||||
for (var i = 0, l = this._segments.length; i < l; i++) {
|
this._segments[i]._transformCoordinates(matrix, coords, true);
|
||||||
this._segments[i]._transformCoordinates(matrix, coords, true);
|
|
||||||
}
|
|
||||||
// TODO: Can't we access _style._fillColor, as we do in strokeBounds?
|
|
||||||
var fillColor = this.getFillColor(),
|
|
||||||
strokeColor = this.getStrokeColor();
|
|
||||||
// Try calling transform on colors in case they are GradientColors.
|
|
||||||
if (fillColor && fillColor.transform)
|
|
||||||
fillColor.transform(matrix);
|
|
||||||
if (strokeColor && strokeColor.transform)
|
|
||||||
strokeColor.transform(matrix);
|
|
||||||
}
|
}
|
||||||
|
// TODO: Can't we access _style._fillColor, as we do in strokeBounds?
|
||||||
|
var fillColor = this.getFillColor(),
|
||||||
|
strokeColor = this.getStrokeColor();
|
||||||
|
// Try calling transform on colors in case they are GradientColors.
|
||||||
|
if (fillColor && fillColor.transform)
|
||||||
|
fillColor.transform(matrix);
|
||||||
|
if (strokeColor && strokeColor.transform)
|
||||||
|
strokeColor.transform(matrix);
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -38,6 +38,7 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{
|
||||||
initialize: function(point) {
|
initialize: function(point) {
|
||||||
this.base();
|
this.base();
|
||||||
this._point = Point.read(arguments).clone();
|
this._point = Point.read(arguments).clone();
|
||||||
|
// XXX: Define one way of creating matrices and passing them to ctors
|
||||||
this._matrix = new Matrix().translate(this._point);
|
this._matrix = new Matrix().translate(this._point);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -62,9 +63,8 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{
|
||||||
this.translate(Point.read(arguments).subtract(this._point));
|
this.translate(Point.read(arguments).subtract(this._point));
|
||||||
},
|
},
|
||||||
|
|
||||||
_transform: function(matrix, flags) {
|
_transform: function(matrix) {
|
||||||
this._matrix.preConcatenate(matrix);
|
// Transform _point:
|
||||||
// Also transform _point:
|
|
||||||
matrix._transformPoint(this._point, this._point);
|
matrix._transformPoint(this._point, this._point);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue