diff --git a/src/item/Item.js b/src/item/Item.js index a3b8bd34..86fda596 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -548,17 +548,18 @@ var Item = this.Item = Base.extend(Callback, /** @lends Item# */{ this._matrix.initialize(matrix); this._changed(/*#=*/ Change.GEOMETRY); } -}, Base.each(['bounds', 'strokeBounds', 'handleBounds', 'roughBounds'], +}, Base.each(['getBounds', 'getStrokeBounds', 'getHandleBounds', 'getRoughBounds'], 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 type = this._boundsType, + this[name] = function(/* matrix */) { + var getter = this._boundsGetter, bounds = this._getCachedBounds( - // 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, + // Allow subclasses to override _boundsGetter if they use the + // same calculations for multiple type of bounds. + // The default is name: + typeof getter == 'string' ? getter : getter && getter[name] || name, // Pass on the optional matrix arguments[0]); // If we're returning 'bounds', create a LinkedRectangle that uses the @@ -572,11 +573,11 @@ function(name) { * Private method that deals with the calling of _getBounds, recursive * matrix concatenation and handles all the complicated caching mechanisms. */ - _getCachedBounds: function(type, matrix, cacheItem) { + _getCachedBounds: function(getter, matrix, cacheItem) { // See if we can cache these bounds. We only cache the bounds // transformed with the internally stored _matrix, (the default if no // matrix is passed). - var cache = (!matrix || matrix.equals(this._matrix)) && type; + var cache = (!matrix || matrix.equals(this._matrix)) && getter; // 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, // for multiple reasons: @@ -614,7 +615,7 @@ function(name) { : identity ? matrix : matrix.clone().concatenate(this._matrix); // If we're caching bounds on this item, pass it on as cacheItem, so the // children can setup the _boundsCache structures for it. - var bounds = this._getBounds(type, matrix, cache ? this : cacheItem); + var bounds = this._getBounds(getter, matrix, cache ? this : cacheItem); // If we can cache the result, update the _bounds cache structure // before returning if (cache) { @@ -654,7 +655,7 @@ function(name) { * Subclasses override it to define calculations for the various required * bounding types. */ - _getBounds: function(type, matrix, cacheItem) { + _getBounds: function(getter, matrix, cacheItem) { // Note: We cannot cache these results here, since we do not get // _changed() notifications here for changing geometry in children. // But cacheName is used in sub-classes such as PlacedItem. @@ -670,7 +671,7 @@ function(name) { for (var i = 0, l = children.length; i < l; i++) { var child = children[i]; if (child._visible && !child.isEmpty()) { - var rect = child._getCachedBounds(type, matrix, cacheItem); + var rect = child._getCachedBounds(getter, matrix, cacheItem); x1 = Math.min(rect.x, x1); y1 = Math.min(rect.y, y1); x2 = Math.max(rect.x + rect.width, x2); @@ -1871,11 +1872,11 @@ function(name) { var rect = bounds[key]; matrix._transformBounds(rect, rect); } - // If we have cached 'bounds', update _position again as its - // center. We need to take into account _boundsType here too, in - // case another type is assigned to it, e.g. 'strokeBounds'. - var type = this._boundsType, - rect = bounds[type && type.bounds || 'bounds']; + // If we have cached bounds, update _position again as its + // center. We need to take into account _boundsGetter here too, in + // case another getter is assigned to it, e.g. 'getStrokeBounds'. + var getter = this._boundsGetter, + rect = bounds[getter && getter.getBounds || getter || 'getBounds']; if (rect) this._position = rect.getCenter(true); this._bounds = bounds; diff --git a/src/item/PlacedItem.js b/src/item/PlacedItem.js index aa3755be..77d2273e 100644 --- a/src/item/PlacedItem.js +++ b/src/item/PlacedItem.js @@ -25,7 +25,7 @@ */ var PlacedItem = this.PlacedItem = Item.extend(/** @lends PlacedItem# */{ // PlacedItem uses strokeBounds for bounds - _boundsType: { bounds: 'strokeBounds' }, + _boundsGetter: { getBounds: 'getStrokeBounds' }, _hitTest: function(point, options, matrix) { var hitResult = this._symbol._definition._hitTest(point, options, matrix); diff --git a/src/item/PlacedSymbol.js b/src/item/PlacedSymbol.js index afd31c41..bc617689 100644 --- a/src/item/PlacedSymbol.js +++ b/src/item/PlacedSymbol.js @@ -94,11 +94,11 @@ var PlacedSymbol = this.PlacedSymbol = PlacedItem.extend(/** @lends PlacedSymbol return this._clone(new PlacedSymbol(this.symbol, this._matrix.clone())); }, - _getBounds: function(type, matrix) { + _getBounds: function(getter, matrix) { // Redirect the call to the symbol definition to calculate the bounds // TODO: Implement bounds caching through passing on of cacheItem, so // that Symbol#_changed() notification become unnecessary! - return this.symbol._definition._getCachedBounds(type, matrix); + return this.symbol._definition._getCachedBounds(getter, matrix); }, draw: function(ctx, param) { diff --git a/src/item/Raster.js b/src/item/Raster.js index d9777917..1f8b7398 100644 --- a/src/item/Raster.js +++ b/src/item/Raster.js @@ -25,7 +25,7 @@ var Raster = this.Raster = PlacedItem.extend(/** @lends Raster# */{ _type: 'raster', // Raster doesn't make the distinction between the different bounds, // so use the same name for all of them - _boundsType: 'bounds', + _boundsGetter: 'getBounds', // TODO: Implement url / type, width, height. // TODO: Have PlacedSymbol & Raster inherit from a shared class? @@ -404,7 +404,7 @@ var Raster = this.Raster = PlacedItem.extend(/** @lends Raster# */{ this.getContext(true).putImageData(data, point.x, point.y); }, - _getBounds: function(type, matrix) { + _getBounds: function(getter, matrix) { var rect = new Rectangle(this._size).setCenter(0, 0); return matrix ? matrix._transformBounds(rect) : rect; }, diff --git a/src/path/Path.js b/src/path/Path.js index 892e4211..43a28ff3 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1860,12 +1860,15 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ }, new function() { // A dedicated scope for the tricky bounds calculations /** * Returns the bounding rectangle of the item excluding stroke width. + * All bounds functions below have the same first four parameters: + * segments, closed, style, matrix, so they can be called from + * Path#_getBounds() and also be used in Curve. But not all of them use all + * these parameters, and some define additional ones after. */ - function getBounds(matrix, strokePadding) { + function getBounds(segments, closed, style, matrix, strokePadding) { // Code ported and further optimised from: // http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html - var segments = this._segments, - first = segments[0]; + var first = segments[0]; // If there are no segments, return "empty" rectangle, just like groups, // since #bounds is assumed to never return null. if (!first) @@ -1937,10 +1940,9 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ } for (var i = 1, l = segments.length; i < l; i++) processSegment(segments[i]); - if (this._closed) + if (closed) processSegment(first); - return Rectangle.create(min[0], min[1], - max[0] - min[0], max[1] - min[1]); + return Rectangle.create(min[0], min[1], max[0] - min[0], max[1] - min[1]); } /** @@ -1989,22 +1991,18 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ /** * Returns the bounding rectangle of the item including stroke width. */ - function getStrokeBounds(matrix) { - // See #draw() for an explanation of why we can access _style - // properties directly here: - var style = this._style; + function getStrokeBounds(segments, closed, style, matrix) { // TODO: Find a way to reuse 'bounds' cache instead? if (!style._strokeColor || !style._strokeWidth) - return getBounds.call(this, matrix); + return getBounds(segments, closed, style, matrix); var radius = style._strokeWidth / 2, padding = getPenPadding(radius, matrix), - bounds = getBounds.call(this, matrix, padding), + bounds = getBounds(segments, closed, style, matrix, padding), join = style._strokeJoin, cap = style._strokeCap, // miter is relative to stroke width. Divide it by 2 since we're // measuring half the distance below - miter = style._miterLimit * style._strokeWidth / 2, - segments = this._segments; + miter = style._miterLimit * style._strokeWidth / 2; // Create a rectangle of padding size, used for union with bounds // further down var joinBounds = new Rectangle(new Size(padding).multiply(2)); @@ -2074,9 +2072,9 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ } } - for (var i = 1, l = segments.length - (this._closed ? 0 : 1); i < l; i++) + for (var i = 1, l = segments.length - (closed ? 0 : 1); i < l; i++) addJoin(segments[i], join); - if (this._closed) { + if (closed) { addJoin(segments[0], join); } else { addCap(segments[0], cap, 0); @@ -2088,7 +2086,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ /** * Returns the bounding rectangle of the item including handles. */ - function getHandleBounds(matrix, strokePadding, joinPadding) { + function getHandleBounds(segments, closed, style, matrix, strokePadding, joinPadding) { var coords = new Array(6), x1 = Infinity, x2 = -x1, @@ -2096,8 +2094,8 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ y2 = x2; strokePadding = strokePadding / 2 || 0; joinPadding = joinPadding / 2 || 0; - for (var i = 0, l = this._segments.length; i < l; i++) { - var segment = this._segments[i]; + for (var i = 0, l = segments.length; i < l; i++) { + var segment = segments[i]; segment._transformCoordinates(matrix, coords, false); for (var j = 0; j < 6; j += 2) { // Use different padding for points or handles @@ -2121,28 +2119,29 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{ * Returns the rough bounding rectangle of the item that is shure to include * all of the drawing, including stroke width. */ - function getRoughBounds(matrix) { + function getRoughBounds(segments, closed, style, matrix) { // Delegate to handleBounds, but pass on radius values for stroke and // joins. Hanlde miter joins specially, by passing the largets radius // possible. - var style = this._style, - strokeWidth = style._strokeColor ? style._strokeWidth : 0; - return getHandleBounds.call(this, matrix, strokeWidth, + var strokeWidth = style._strokeColor ? style._strokeWidth : 0; + return getHandleBounds(segments, closed, style, matrix, strokeWidth, style._strokeJoin == 'miter' ? strokeWidth * style._miterLimit : strokeWidth); } - var get = { - bounds: getBounds, - strokeBounds: getStrokeBounds, - handleBounds: getHandleBounds, - roughBounds: getRoughBounds - }; - return { - _getBounds: function(type, matrix) { - return get[type].call(this, matrix); + statics: { + getBounds: getBounds, + getStrokeBounds: getStrokeBounds, + getHandleBounds: getHandleBounds, + getRoughBounds: getRoughBounds + }, + + _getBounds: function(getter, matrix) { + // See #draw() for an explanation of why we can access _style + // properties directly here: + return Path[getter](this._segments, this._closed, this._style, matrix); } }; }); diff --git a/src/text/PointText.js b/src/text/PointText.js index 04cda026..7bec834d 100644 --- a/src/text/PointText.js +++ b/src/text/PointText.js @@ -96,7 +96,7 @@ var PointText = this.PointText = TextItem.extend(/** @lends PointText# */{ var context = null; return { - _getBounds: function(type, matrix) { + _getBounds: function(getter, matrix) { // Create an in-memory canvas on which to do the measuring if (!context) context = CanvasProvider.getCanvas( diff --git a/src/text/TextItem.js b/src/text/TextItem.js index 1d6b2a70..56c31356 100644 --- a/src/text/TextItem.js +++ b/src/text/TextItem.js @@ -28,7 +28,7 @@ var TextItem = this.TextItem = Item.extend(/** @lends TextItem# */{ // TextItem doesn't make the distinction between the different bounds, // so use the same name for all of them - _boundsType: 'bounds', + _boundsGetter: 'getBounds', initialize: function(pointOrMatrix) { // Note that internally #characterStyle is the same as #style, but