mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-03 19:45:44 -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.
|
* matrix that results in no transformation.
|
||||||
*/
|
*/
|
||||||
reset: function(_dontNotify) {
|
reset: function(_dontNotify) {
|
||||||
|
@ -148,6 +148,20 @@ var Matrix = Base.extend(/** @lends Matrix# */{
|
||||||
return this;
|
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.
|
* 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) {
|
setMatrix: function(matrix) {
|
||||||
// Use Matrix#initialize to easily copy over values.
|
// Use Matrix#initialize to easily copy over values.
|
||||||
this._matrix.initialize(matrix);
|
this._matrix.initialize(matrix);
|
||||||
if (this._transformContent)
|
if (this._transformContent) {
|
||||||
this.applyMatrix(true);
|
// Directly apply the internal matrix. This will also call
|
||||||
this._changed(/*#=*/ Change.GEOMETRY);
|
// _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) {
|
setTransformContent: function(transform) {
|
||||||
|
// Tell #transform() to apply the internal matrix if _transformContent
|
||||||
|
// can be set to true.
|
||||||
if (this._transformContent = this._canTransformContent && !!transform)
|
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',
|
// 'children', 'fill-gradients', 'fill-patterns', 'stroke-patterns',
|
||||||
// 'lines'. Default: ['objects', 'children']
|
// 'lines'. Default: ['objects', 'children']
|
||||||
transform: function(matrix, _applyMatrix) {
|
transform: function(matrix, _applyMatrix) {
|
||||||
// Bail out immediatelly if there is nothing to do
|
// If no matrix is provided, or the matrix is the identity, we might
|
||||||
if (matrix.isIdentity())
|
// 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;
|
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
|
// 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,
|
var bounds = this._bounds,
|
||||||
position = this._position;
|
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
|
// We always need to call _changed since we're caching bounds on all
|
||||||
// items, including Group.
|
// 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
|
||||||
// fully recalculate each time.
|
// fully recalculate each time.
|
||||||
var decomp = bounds && matrix.decompose();
|
var decomp = bounds && matrix && matrix.decompose();
|
||||||
if (decomp && !decomp.shearing && decomp.rotation % 90 === 0) {
|
if (decomp && !decomp.shearing && decomp.rotation % 90 === 0) {
|
||||||
// Transform the old bound by looping through all the cached bounds
|
// Transform the old bound by looping through all the cached bounds
|
||||||
// in _bounds and transform each.
|
// in _bounds and transform each.
|
||||||
for (var key in bounds) {
|
for (var key in bounds) {
|
||||||
var rect = bounds[key];
|
var rect = bounds[key];
|
||||||
// If these are internal bounds, only transform them if this
|
// If these are internal bounds, only transform them if this
|
||||||
// item transforming its content.
|
// item applied its matrix.
|
||||||
if (this._transformContent || !rect._internal)
|
if (applyMatrix || !rect._internal)
|
||||||
matrix._transformBounds(rect, rect);
|
matrix._transformBounds(rect, rect);
|
||||||
}
|
}
|
||||||
// If we have cached bounds, update _position again as its
|
// If we have cached bounds, update _position again as its
|
||||||
|
@ -2798,7 +2833,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
if (rect)
|
if (rect)
|
||||||
this._position = rect.getCenter(true);
|
this._position = rect.getCenter(true);
|
||||||
this._bounds = bounds;
|
this._bounds = bounds;
|
||||||
} else if (position) {
|
} else if (matrix && position) {
|
||||||
// Transform position as well.
|
// Transform position as well.
|
||||||
this._position = matrix._transformPoint(position, position);
|
this._position = matrix._transformPoint(position, position);
|
||||||
}
|
}
|
||||||
|
@ -2806,47 +2841,15 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
|
|
||||||
_applyMatrix: function(matrix, applyMatrix) {
|
_applyMatrix: function(matrix) {
|
||||||
var children = this._children;
|
var children = this._children;
|
||||||
if (children) {
|
if (children) {
|
||||||
for (var i = 0, l = children.length; i < l; i++)
|
for (var i = 0, l = children.length; i < l; i++)
|
||||||
children[i].transform(matrix, applyMatrix);
|
children[i].transform(matrix, true);
|
||||||
return 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
|
* Converts the specified point from global project coordinates to local
|
||||||
* coordinates in relation to the the item's own coordinate space.
|
* 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.
|
* NOTE: Does NOT handle self-intersecting CompoundPaths.
|
||||||
*/
|
*/
|
||||||
function reorientPath(path) {
|
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) {
|
if (path instanceof CompoundPath) {
|
||||||
var children = path.removeChildren(),
|
var children = path.removeChildren(),
|
||||||
length = children.length,
|
length = children.length,
|
||||||
|
@ -82,9 +85,8 @@ PathItem.inject(new function() {
|
||||||
// We call reduce() on both cloned paths to simplify compound paths and
|
// We call reduce() on both cloned paths to simplify compound paths and
|
||||||
// remove empty curves. We also apply matrices to both paths in case
|
// remove empty curves. We also apply matrices to both paths in case
|
||||||
// they were transformed.
|
// they were transformed.
|
||||||
var _path1 = reorientPath(path1.clone(false).reduce().applyMatrix());
|
var _path1 = reorientPath(path1);
|
||||||
_path2 = path2 && path1 !== path2
|
_path2 = path2 && path1 !== path2 && reorientPath(path2);
|
||||||
&& reorientPath(path2.clone(false).reduce().applyMatrix());
|
|
||||||
// Do operator specific calculations before we begin
|
// Do operator specific calculations before we begin
|
||||||
// Make both paths at clockwise orientation, except when subtract = true
|
// Make both paths at clockwise orientation, except when subtract = true
|
||||||
// We need both paths at opposite orientation for subtraction.
|
// We need both paths at opposite orientation for subtraction.
|
||||||
|
|
Loading…
Reference in a new issue