Define private getBounds() function that handles matrix concatenation, bounds caching and calling of _getBounds, leading to further simplifications in PlacedItem.

This commit is contained in:
Jürg Lehni 2011-11-26 10:39:51 +01:00
parent 2605fadcfd
commit 1fd9242fd8
4 changed files with 50 additions and 49 deletions

View file

@ -1253,51 +1253,64 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
return false;
}
}, new function() {
/**
* Private method that deals with the calling of _getBounds and handles all
* the complicated caching mechanisms.
*/
// TODO: See if calling getBounds.call(item, type, matrix) and using this
// instead of item speeds things up.
function getBounds(item, type, matrix) {
// If the result of concatinating the passed matrix with our internal
// one is an identity transformation, set it to null for faster
// processing
var identity = item._matrix.isIdentity();
matrix = !matrix || matrix.isIdentity()
? identity ? null : item._matrix
: identity ? matrix : matrix.clone().concatenate(item._matrix);
// See if we can cache these bounds. We only cache non-transformed
// bounds on items without children, as we do not receive hierarchy
// change notifiers from children, and walking up the parents and
// merging cache bounds is not expensive.
var cache = !item._children && !matrix && type;
if (cache && item._bounds && item._bounds[cache])
return item._bounds[cache];
var bounds = item._getBounds(type, matrix);
// If we're returning 'bounds', create a LinkedRectangle that uses
// the setBounds() setter to update the Item whenever the bounds are
// changed:
if (name == 'bounds')
bounds = LinkedRectangle.create(item, 'setBounds',
bounds.x, bounds.y, bounds.width, bounds.height);
// If we can cache the result, update the _bounds cache structure
// before returning
if (cache) {
if (!item._bounds)
item._bounds = {};
item._bounds[cache] = bounds;
}
return bounds;
}
return Base.each(['bounds', 'strokeBounds', 'handleBounds', 'roughBounds'],
function(name) {
// Produce getters for bounds properties. These handle caching, matrices
// and redirect the call to the private _getBounds, which can be
// overridden by subclasses, see below.
this['get' + Base.capitalize(name)] = function(/* matrix */) {
var matrix = arguments[0];
// If the matrix is an identity transformation, set it to null for
// faster processing
if (matrix && matrix.isIdentity())
matrix = null;
// Allow subclasses to override _boundsType if they use the same
// calculations for multiple types. The default is name:
var type = this._boundsType;
if (typeof type != 'string')
type = type && type[name] || name;
// See if we can cache these bounds. We only cache non-transformed
// bounds on items without children, as we do not receive hierarchy
// change notifiers from children, and walking up the parents and
// merging cache bounds is not expensive.
var cache = !this._children && !matrix && type;
if (cache && this._bounds && this._bounds[cache])
return this._bounds[cache];
var bounds = this._getBounds(type, matrix);
// If we're returning 'bounds', create a LinkedRectangle that uses
// the setBounds() setter to update the Item whenever the bounds are
// changed:
if (name == 'bounds')
bounds = LinkedRectangle.create(this, 'setBounds',
bounds.x, bounds.y, bounds.width, bounds.height);
// If we can cache the result, update the _bounds cache structure
// before returning
if (cache) {
if (!this._bounds)
this._bounds = {};
this._bounds[cache] = bounds;
}
return bounds;
return getBounds(this,
// Allow subclasses to override _boundsType if they use the
// same calculations for multiple types.
// The default is name:
typeof type == 'string' ? type : type && type[name] || name,
arguments[0]);
};
}, {
// Note: The documentation for the bounds properties is defined in the
// next injection object.
/**
* Internal method used in all the bounds getters. It loops through all
* Protected method used in all the bounds getters. It loops through all
* the children, gets their bounds and finds the bounds around all of
* them. Subclasses override it to define calculations for the various
* required bounding types.
@ -1311,10 +1324,6 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
// Scriptographer behaves weirdly then too.
if (!children || children.length == 0)
return new Rectangle();
// Concate the nate the passed matrix with the inner one, or start
// with one.
matrix = matrix ? matrix.clone().concatenate(this._matrix)
: this._matrix;
var x1 = Infinity,
x2 = -x1,
y1 = x1,
@ -1322,7 +1331,7 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{
for (var i = 0, l = children.length; i < l; i++) {
var child = children[i];
if (child._visible) {
var rect = child._getBounds(type, matrix);
var rect = getBounds(child, type, matrix);
x1 = Math.min(rect.x, x1);
y1 = Math.min(rect.y, y1);
x2 = Math.max(rect.x + rect.width, x2);

View file

@ -48,13 +48,5 @@ var PlacedItem = this.PlacedItem = Item.extend(/** @lends PlacedItem# */{
setMatrix: function(matrix) {
this._matrix = matrix.clone();
this._changed(Change.GEOMETRY);
},
_getBounds: function(type, matrix) {
// Concatenate the passed matrix with the internal one
matrix = matrix ? matrix.clone().concatenate(this._matrix)
: this._matrix;
// Call _calculateBounds, which needs to be defined in the subclasses:
return this._calculateBounds(type, matrix);
}
});

View file

@ -94,7 +94,7 @@ var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend(/** @lends PlacedSymbol
return this._clone(new PlacedSymbol(this.symbol, this._matrix.clone()));
},
_calculateBounds: function(type, matrix) {
_getBounds: function(type, matrix) {
// Redirect the call to the symbol definition to calculate the bounds
return this.symbol._definition._getBounds(type, matrix);
},

View file

@ -382,9 +382,9 @@ var Raster = this.Raster = PlacedItem.extend(/** @lends Raster# */{
this.getContext(true).putImageData(data, point.x, point.y);
},
_calculateBounds: function(type, matrix) {
return matrix._transformBounds(
new Rectangle(this._size).setCenter(0, 0));
_getBounds: function(type, matrix) {
var rect = new Rectangle(this._size).setCenter(0, 0);
return matrix ? matrix._transformBounds(rect) : rect;
},
_hitTest: function(point, options) {