mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-03 19:45:44 -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
|
||||
* @param {Number} scale the scale factor
|
||||
* @param {Point} [center={@link Item#position}]
|
||||
* @param {Boolean} apply
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // 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} ver the vertical scale factor
|
||||
* @param {Point} [center={@link Item#position}]
|
||||
* @param {Boolean} apply
|
||||
*
|
||||
* @example {@paperscript}
|
||||
* // 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%
|
||||
* circle.scale(3, 1);
|
||||
*/
|
||||
scale: function(hor, ver /* | scale */, center) {
|
||||
scale: function(hor, ver /* | scale */, center, apply) {
|
||||
// See Matrix#scale for explanation of this:
|
||||
if (arguments.length < 2 || typeof ver === 'object') {
|
||||
apply = center;
|
||||
center = ver;
|
||||
ver = hor;
|
||||
}
|
||||
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.
|
||||
*
|
||||
* @param {Point} delta the offset to translate the item by
|
||||
* @param {Boolean} apply
|
||||
*/
|
||||
translate: function(delta) {
|
||||
translate: function(delta, apply) {
|
||||
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 {Point} [center={@link Item#position}]
|
||||
* @param {Boolean} apply
|
||||
* @see Matrix#rotate
|
||||
*
|
||||
* @example {@paperscript}
|
||||
|
@ -1770,9 +1775,9 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
|||
* path.rotate(3, view.center);
|
||||
* }
|
||||
*/
|
||||
rotate: function(angle, center) {
|
||||
rotate: function(angle, center, apply) {
|
||||
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.
|
||||
|
@ -1784,6 +1789,7 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
|||
* @function
|
||||
* @param {Point} point
|
||||
* @param {Point} [center={@link Item#position}]
|
||||
* @param {Boolean} apply
|
||||
* @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} ver the vertical shear factor.
|
||||
* @param {Point} [center={@link Item#position}]
|
||||
* @param {Boolean} apply
|
||||
* @see Matrix#shear
|
||||
*/
|
||||
shear: function(hor, ver, center) {
|
||||
// PORT: Add support for center back to Scriptographer too!
|
||||
shear: function(hor, ver, center, apply) {
|
||||
// PORT: Add support for center and apply back to Scriptographer too!
|
||||
// See Matrix#scale for explanation of this:
|
||||
if (arguments.length < 2 || typeof ver === 'object') {
|
||||
apply = center;
|
||||
center = ver;
|
||||
ver = hor;
|
||||
}
|
||||
return this.transform(new Matrix().shear(hor, ver,
|
||||
center || this.getPosition()));
|
||||
center || this.getPosition(true)), apply);
|
||||
},
|
||||
|
||||
/**
|
||||
* 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:
|
||||
// @param {String[]} flags Array of any of the following: 'objects',
|
||||
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
||||
// 'lines'. Default: ['objects', 'children']
|
||||
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.
|
||||
transform: function(matrix, apply) {
|
||||
// Calling _changed will clear _bounds and _position, but depending
|
||||
// on matrix we can calculate and set them again.
|
||||
var bounds = this._bounds,
|
||||
position = this._position,
|
||||
children = this._children;
|
||||
bounds = position = null;
|
||||
// Simply preconcatenate the internal matrix with the passed one:
|
||||
this._matrix.preConcatenate(matrix);
|
||||
if (this._transform)
|
||||
this._transform(matrix, flags);
|
||||
// We need to call _changed even if we don't have _transform, since
|
||||
// we're caching bounds on such items too now, e.g. Group
|
||||
this._transform(matrix);
|
||||
if (apply)
|
||||
this.applyMatrix(false);
|
||||
// We always need to call _changed since we're caching bounds on all
|
||||
// items, including Group.
|
||||
this._changed(Change.GEOMETRY);
|
||||
// Detect matrices that contain only translations and scaling
|
||||
// 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!
|
||||
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
|
||||
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
|
||||
* rectangle, without changing its aspect ratio.
|
||||
|
@ -1931,13 +1965,6 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
|
|||
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() {
|
||||
return (this.constructor._name || 'Item') + (this._name
|
||||
? " '" + this._name + "'"
|
||||
|
|
|
@ -25,12 +25,5 @@
|
|||
*/
|
||||
var PlacedItem = this.PlacedItem = Item.extend(/** @lends PlacedItem# */{
|
||||
// PlacedItem uses strokeBounds for bounds
|
||||
_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);
|
||||
}
|
||||
_boundsType: { bounds: 'strokeBounds' }
|
||||
});
|
||||
|
|
|
@ -64,6 +64,7 @@ var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend(/** @lends PlacedSymbol
|
|||
initialize: function(symbol, matrixOrOffset) {
|
||||
this.base();
|
||||
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
|
||||
? matrixOrOffset instanceof Matrix
|
||||
? 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
|
||||
// taken into account.
|
||||
|
||||
_transform: function(matrix, flags) {
|
||||
if (matrix && !matrix.isIdentity()) {
|
||||
var coords = new Array(6);
|
||||
for (var i = 0, l = this._segments.length; i < l; i++) {
|
||||
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);
|
||||
_applyMatrix: function(matrix) {
|
||||
var coords = new Array(6);
|
||||
for (var i = 0, l = this._segments.length; i < l; i++) {
|
||||
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);
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,6 +38,7 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{
|
|||
initialize: function(point) {
|
||||
this.base();
|
||||
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);
|
||||
},
|
||||
|
||||
|
@ -62,9 +63,8 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{
|
|||
this.translate(Point.read(arguments).subtract(this._point));
|
||||
},
|
||||
|
||||
_transform: function(matrix, flags) {
|
||||
this._matrix.preConcatenate(matrix);
|
||||
// Also transform _point:
|
||||
_transform: function(matrix) {
|
||||
// Transform _point:
|
||||
matrix._transformPoint(this._point, this._point);
|
||||
},
|
||||
|
||||
|
|
Loading…
Reference in a new issue