mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Internalize Item#applyMatrix() code in #transform() and add short-cut method to it in Matrix#apply()
This commit is contained in:
parent
6fdb9f60bd
commit
fb1420eee0
3 changed files with 74 additions and 55 deletions
|
@ -137,7 +137,7 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
},
|
||||
|
||||
/**
|
||||
* "Resets" the matrix by setting its values to the ones of the identity
|
||||
* Resets the matrix by setting its values to the ones of the identity
|
||||
* matrix that results in no transformation.
|
||||
*/
|
||||
reset: function(_dontNotify) {
|
||||
|
@ -148,6 +148,20 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
|||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Applies the matrix to the item that it belongs to, if possible.
|
||||
* @return {Boolean} {@true if the matrix was applied}
|
||||
*/
|
||||
apply: function() {
|
||||
var owner = this._owner;
|
||||
if (owner) {
|
||||
owner.transform(null, true);
|
||||
// If the matrix was successfully applied, it will be reset now.
|
||||
return this.isIdentity();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Concatenates this transform with a translate transformation.
|
||||
*
|
||||
|
|
105
src/item/Item.js
105
src/item/Item.js
|
@ -1134,9 +1134,13 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
setMatrix: function(matrix) {
|
||||
// Use Matrix#initialize to easily copy over values.
|
||||
this._matrix.initialize(matrix);
|
||||
if (this._transformContent)
|
||||
this.applyMatrix(true);
|
||||
this._changed(/*#=*/ Change.GEOMETRY);
|
||||
if (this._transformContent) {
|
||||
// Directly apply the internal matrix. This will also call
|
||||
// _changed() for us.
|
||||
this.transform(null, true);
|
||||
} else {
|
||||
this._changed(/*#=*/ Change.GEOMETRY);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1174,8 +1178,10 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
},
|
||||
|
||||
setTransformContent: function(transform) {
|
||||
// Tell #transform() to apply the internal matrix if _transformContent
|
||||
// can be set to true.
|
||||
if (this._transformContent = this._canTransformContent && !!transform)
|
||||
this.applyMatrix();
|
||||
this.transform(null, true);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2760,34 +2766,63 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
||||
// 'lines'. Default: ['objects', 'children']
|
||||
transform: function(matrix, _applyMatrix) {
|
||||
// Bail out immediatelly if there is nothing to do
|
||||
if (matrix.isIdentity())
|
||||
// If no matrix is provided, or the matrix is the identity, we might
|
||||
// still have some work to do in case _transformContent is true
|
||||
if (matrix && matrix.isIdentity())
|
||||
matrix = null;
|
||||
var _matrix = this._matrix,
|
||||
applyMatrix = (_applyMatrix || this._transformContent)
|
||||
// Don't apply _matrix if the result of concatenating with
|
||||
// matrix would be identity.
|
||||
&& (!_matrix.isIdentity() || matrix);
|
||||
// Bail out if there is nothing to do.
|
||||
if (!matrix && !applyMatrix)
|
||||
return this;
|
||||
// Simply preconcatenate the internal matrix with the passed one:
|
||||
if (matrix)
|
||||
_matrix.preConcatenate(matrix);
|
||||
// Call #_applyMatrix() now, if we need to directly apply the internal
|
||||
// _matrix transformations to the item's content.
|
||||
// Application is not possible on Raster, PointText, PlacedSymbol, since
|
||||
// the matrix is where the actual transformation state is stored.
|
||||
if (applyMatrix = applyMatrix && this._applyMatrix(_matrix)) {
|
||||
// When the _matrix could be applied, we also need to transform
|
||||
// color styles (only gradients so far) and pivot point:
|
||||
var pivot = this._pivot,
|
||||
style = this._style,
|
||||
// pass true for _dontMerge so we don't recursively transform
|
||||
// styles on groups' children.
|
||||
fillColor = style.getFillColor(true),
|
||||
strokeColor = style.getStrokeColor(true);
|
||||
if (pivot)
|
||||
pivot.transform(_matrix);
|
||||
if (fillColor)
|
||||
fillColor.transform(_matrix);
|
||||
if (strokeColor)
|
||||
strokeColor.transform(_matrix);
|
||||
// Reset the internal matrix to the identity transformation if it
|
||||
// was possible to apply it.
|
||||
_matrix.reset(true);
|
||||
}
|
||||
// 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, so preserve them.
|
||||
var bounds = this._bounds,
|
||||
position = this._position;
|
||||
// Simply preconcatenate the internal matrix with the passed one:
|
||||
this._matrix.preConcatenate(matrix);
|
||||
// Call applyMatrix if we need to directly apply the accumulated
|
||||
// transformations to the item's content.
|
||||
if (this._transformContent || _applyMatrix)
|
||||
this.applyMatrix(true);
|
||||
// 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
|
||||
// fully recalculate each time.
|
||||
var decomp = bounds && matrix.decompose();
|
||||
var decomp = bounds && matrix && matrix.decompose();
|
||||
if (decomp && !decomp.shearing && decomp.rotation % 90 === 0) {
|
||||
// Transform the old bound by looping through all the cached bounds
|
||||
// in _bounds and transform each.
|
||||
for (var key in bounds) {
|
||||
var rect = bounds[key];
|
||||
// If these are internal bounds, only transform them if this
|
||||
// item transforming its content.
|
||||
if (this._transformContent || !rect._internal)
|
||||
// item applied its matrix.
|
||||
if (applyMatrix || !rect._internal)
|
||||
matrix._transformBounds(rect, rect);
|
||||
}
|
||||
// If we have cached bounds, update _position again as its
|
||||
|
@ -2798,7 +2833,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
if (rect)
|
||||
this._position = rect.getCenter(true);
|
||||
this._bounds = bounds;
|
||||
} else if (position) {
|
||||
} else if (matrix && position) {
|
||||
// Transform position as well.
|
||||
this._position = matrix._transformPoint(position, position);
|
||||
}
|
||||
|
@ -2806,47 +2841,15 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
return this;
|
||||
},
|
||||
|
||||
_applyMatrix: function(matrix, applyMatrix) {
|
||||
_applyMatrix: function(matrix) {
|
||||
var children = this._children;
|
||||
if (children) {
|
||||
for (var i = 0, l = children.length; i < l; i++)
|
||||
children[i].transform(matrix, applyMatrix);
|
||||
children[i].transform(matrix, true);
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
applyMatrix: function(_dontNotify) {
|
||||
// Call #_applyMatrix() with the internal _matrix and pass true for
|
||||
// applyMatrix. Application is not possible on Raster, PointText,
|
||||
// PlacedSymbol, since the matrix is where the actual location /
|
||||
// transformation state is stored.
|
||||
// Pass on the transformation to the content, and apply it there too,
|
||||
// by passing true for the 2nd hidden parameter.
|
||||
var matrix = this._matrix;
|
||||
if (this._applyMatrix(matrix, true)) {
|
||||
// When the matrix could be applied, we also need to transform
|
||||
// color styles (only gradients so far) and pivot point:
|
||||
var pivot = this._pivot,
|
||||
style = this._style,
|
||||
// pass true for _dontMerge so we don't recursively transform
|
||||
// styles on groups' children.
|
||||
fillColor = style.getFillColor(true),
|
||||
strokeColor = style.getStrokeColor(true);
|
||||
if (pivot)
|
||||
pivot.transform(matrix);
|
||||
if (fillColor)
|
||||
fillColor.transform(matrix);
|
||||
if (strokeColor)
|
||||
strokeColor.transform(matrix);
|
||||
// Reset the internal matrix to the identity transformation if it
|
||||
// was possible to apply it.
|
||||
matrix.reset(true);
|
||||
if (!_dontNotify)
|
||||
this._changed(/*#=*/ Change.GEOMETRY);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Converts the specified point from global project coordinates to local
|
||||
* coordinates in relation to the the item's own coordinate space.
|
||||
|
|
|
@ -43,6 +43,9 @@ PathItem.inject(new function() {
|
|||
* NOTE: Does NOT handle self-intersecting CompoundPaths.
|
||||
*/
|
||||
function reorientPath(path) {
|
||||
// Create a cloned version of the path firsts that we can modify freely,
|
||||
// with its matrix applied to its geometry.
|
||||
path = path.clone(false).reduce().transform(null, true);
|
||||
if (path instanceof CompoundPath) {
|
||||
var children = path.removeChildren(),
|
||||
length = children.length,
|
||||
|
@ -82,9 +85,8 @@ PathItem.inject(new function() {
|
|||
// We call reduce() on both cloned paths to simplify compound paths and
|
||||
// remove empty curves. We also apply matrices to both paths in case
|
||||
// they were transformed.
|
||||
var _path1 = reorientPath(path1.clone(false).reduce().applyMatrix());
|
||||
_path2 = path2 && path1 !== path2
|
||||
&& reorientPath(path2.clone(false).reduce().applyMatrix());
|
||||
var _path1 = reorientPath(path1);
|
||||
_path2 = path2 && path1 !== path2 && reorientPath(path2);
|
||||
// Do operator specific calculations before we begin
|
||||
// Make both paths at clockwise orientation, except when subtract = true
|
||||
// We need both paths at opposite orientation for subtraction.
|
||||
|
|
Loading…
Reference in a new issue