Implement cached getInternalRoughBounds as well.

This commit is contained in:
Jürg Lehni 2013-12-09 19:33:34 +01:00
parent 7278ee4374
commit b7943239eb
2 changed files with 28 additions and 21 deletions

View file

@ -801,21 +801,29 @@ var Item = Base.extend(Callback, /** @lends Item# */{
delete this._position; delete this._position;
} }
}, Base.each(['getBounds', 'getStrokeBounds', 'getHandleBounds', }, Base.each(['getBounds', 'getStrokeBounds', 'getHandleBounds',
'getRoughBounds', 'getInternalBounds'], 'getRoughBounds', 'getInternalBounds', 'getInternalRoughBounds'],
function(key) { function(key) {
// Produce getters for bounds properties. These handle caching, matrices // Produce getters for bounds properties. These handle caching, matrices
// and redirect the call to the private _getBounds, which can be // and redirect the call to the private _getBounds, which can be
// overridden by subclasses, see below. // overridden by subclasses, see below.
var internal = key === 'getInternalBounds'; // Treat internalBounds and internalRoughBounds untransformed, as
// required by the code that uses these methods internally, but make
// sure they can be cached like all the others as well.
// Pass on the getter that these version actually use, untransformed,
// as internalGetter.
// NOTE: These need to be versions of other methods, as otherwise the
// cache gets messed up.
var match = key.match(/^getInternal(.*)$/),
internalGetter = match ? 'get' + match[1] : null;
this[key] = function(/* matrix */) { this[key] = function(/* matrix */) {
var getter = this._boundsGetter, var getter = this._boundsGetter,
// Allow subclasses to override _boundsGetter if they use // Allow subclasses to override _boundsGetter if they use
// the same calculations for multiple type of bounds. // the same calculations for multiple type of bounds.
// The default is key: // The default is key:
bounds = this._getCachedBounds(!internal bounds = this._getCachedBounds(!internalGetter
&& (typeof getter === 'string' && (typeof getter === 'string'
? getter : getter && getter[key]) ? getter : getter && getter[key])
|| key, arguments[0], null, internal); || key, arguments[0], null, internalGetter);
// If we're returning 'bounds', create a LinkedRectangle that uses // If we're returning 'bounds', create a LinkedRectangle that uses
// the setBounds() setter to update the Item whenever the bounds are // the setBounds() setter to update the Item whenever the bounds are
// changed: // changed:
@ -885,12 +893,13 @@ var Item = Base.extend(Callback, /** @lends Item# */{
* Private method that deals with the calling of _getBounds, recursive * Private method that deals with the calling of _getBounds, recursive
* matrix concatenation and handles all the complicated caching mechanisms. * matrix concatenation and handles all the complicated caching mechanisms.
*/ */
_getCachedBounds: function(getter, matrix, cacheItem, internal) { _getCachedBounds: function(getter, matrix, cacheItem, internalGetter) {
// See if we can cache these bounds. We only cache the bounds // See if we can cache these bounds. We only cache the bounds
// transformed with the internally stored _matrix, (the default if no // transformed with the internally stored _matrix, (the default if no
// matrix is passed). // matrix is passed).
matrix = matrix && matrix.orNullIfIdentity(); matrix = matrix && matrix.orNullIfIdentity();
var _matrix = internal ? null : this._matrix.orNullIfIdentity(), // Do not transform by the internal matrix if there is a internalGetter.
var _matrix = internalGetter ? null : this._matrix.orNullIfIdentity(),
cache = (!matrix || matrix.equals(_matrix)) && getter; cache = (!matrix || matrix.equals(_matrix)) && getter;
// Set up a boundsCache structure that keeps track of items that keep // Set up a boundsCache structure that keeps track of items that keep
// cached bounds that depend on this item. We store this in our parent, // cached bounds that depend on this item. We store this in our parent,
@ -907,8 +916,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
// Set-up the parent's boundsCache structure if it does not // Set-up the parent's boundsCache structure if it does not
// exist yet and add the cacheItem to it. // exist yet and add the cacheItem to it.
var id = cacheItem._id, var id = cacheItem._id,
ref = cacheParent._boundsCache ref = cacheParent._boundsCache = cacheParent._boundsCache || {
= cacheParent._boundsCache || {
// Use both a hashtable for ids and an array for the list, // Use both a hashtable for ids and an array for the list,
// so we can keep track of items that were added already // so we can keep track of items that were added already
ids: {}, ids: {},
@ -931,8 +939,11 @@ var Item = Base.extend(Callback, /** @lends Item# */{
: matrix; : matrix;
// If we're caching bounds on this item, pass it on as cacheItem, so the // If we're caching bounds on this item, pass it on as cacheItem, so the
// children can setup the _boundsCache structures for it. // children can setup the _boundsCache structures for it.
var bounds = this._getBounds(getter === 'getInternalBounds' // getInternalBounds is getBounds untransformed. Do not replace earlier,
? 'getBounds' : getter, matrix, cache ? this : cacheItem); // so we can cache both separately, since they're not in the same
// transformation space!
var bounds = this._getBounds(internalGetter || getter, matrix,
cache ? this : cacheItem);
// If we can cache the result, update the _bounds cache structure // If we can cache the result, update the _bounds cache structure
// before returning // before returning
if (cache) { if (cache) {
@ -940,7 +951,7 @@ var Item = Base.extend(Callback, /** @lends Item# */{
this._bounds = {}; this._bounds = {};
var cached = this._bounds[cache] = bounds.clone(); var cached = this._bounds[cache] = bounds.clone();
// Mark as internal, so Item#transform() won't transform it! // Mark as internal, so Item#transform() won't transform it!
cached._internal = internal; cached._internal = !!internalGetter;
} }
return bounds; return bounds;
}, },

View file

@ -1713,11 +1713,7 @@ var Path = PathItem.extend(/** @lends Path# */{
// If the path is not closed, we should not bail out in case it has a // If the path is not closed, we should not bail out in case it has a
// fill color! // fill color!
if (!closed && !this.hasFill() if (!closed && !this.hasFill()
// We need to call the internal _getBounds, to get non- || !this.getInternalRoughBounds()._containsPoint(point))
// transformed bounds.
// TODO: Implement caching for internal rough bounds and switch
// hit-testing code to using this too.
|| !this._getBounds('getRoughBounds')._containsPoint(point))
return 0; return 0;
// Use the crossing number algorithm, by counting the crossings of the // Use the crossing number algorithm, by counting the crossings of the
// beam in right y-direction with the shape, and see if it's an odd // beam in right y-direction with the shape, and see if it's an odd