mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-05 20:32:00 -05:00
Refactor getBounds code so that functionality can be exposed as static methods on Path.
This commit is contained in:
parent
021009abbc
commit
0d2ed108e2
7 changed files with 55 additions and 55 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
},
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue