Implement option.type filtering in #hitTest() functions.

This commit is contained in:
Jürg Lehni 2013-12-08 16:32:42 +01:00
parent 2896f14e43
commit afe00add32
5 changed files with 44 additions and 50 deletions

View file

@ -108,7 +108,8 @@ var HitResult = Base.extend(/** @lends HitResult# */{
// Use _merged property to not repeatetly merge using new Base in
// recursion.
return options && options._merged ? options : new Base({
// Type of item, for instanceof check: PathItem, TexItem, etc
// Type of item, for instanceof check: 'group', 'layer', 'path',
// 'compound-path', 'shape','raster', 'placed-symbol', ...
type: null,
// Tolerance
tolerance: paper.project.options.hitTolerance || 2,

View file

@ -292,8 +292,8 @@ var Item = Base.extend(Callback, /** @lends Item# */{
/**
* The type of the item as a string.
*
* @type String('group', 'layer', 'path', 'compound-path', 'raster',
* 'placed-symbol', 'point-text')
* @type String('group', 'layer', 'path', 'compound-path', 'shape',
* 'raster', 'placed-symbol', 'point-text')
* @bean
*/
getType: function() {
@ -1532,7 +1532,8 @@ var Item = Base.extend(Callback, /** @lends Item# */{
* in points. Can also be controlled through
* {@link Project#options}{@code .hitTolerance}.
* <b>options.type:</b> Only hit test again a certain item
* type: {@link PathItem}, {@link Raster}, {@link TextItem}, etc.
* type: {String('group', 'layer', 'path', 'compound-path', 'shape',
* 'raster', 'placed-symbol', 'point-text')}, etc.
* <b>options.fill:</b> {@code Boolean} hit test the fill of items.
* <b>options.stroke:</b> {@code Boolean} hit test the curves of path
* items, taking into account stroke width.
@ -1574,9 +1575,13 @@ var Item = Base.extend(Callback, /** @lends Item# */{
// Transform point to local coordinates but use untransformed point
// for bounds check above.
point = this._matrix._inverseTransform(point);
var that = this,
// Filter for type, guides and selected items if that's required.
var checkSelf = !(options.guides && !this._guide
|| options.selected && !this._selected
|| options.type && this._type !== options.type),
that = this,
res;
function checkBounds(type, part) {
var pt = bounds['get' + part]();
// TODO: We need to transform the point back to the coordinate
@ -1586,9 +1591,8 @@ var Item = Base.extend(Callback, /** @lends Item# */{
{ name: Base.hyphenate(part), point: pt });
}
if ((options.center || options.bounds) &&
// Ignore top level layers:
!(this instanceof Layer && !this._parent)) {
// Ignore top level layers by checking for _parent:
if (checkSelf && (options.center || options.bounds) && this._parent) {
// Don't get the transformed bounds, check against transformed
// points instead
var bounds = this._getBounds('getBounds');
@ -1605,30 +1609,29 @@ var Item = Base.extend(Callback, /** @lends Item# */{
}
}
// TODO: Support option.type even for things like CompoundPath where
// children are matched but the parent is returned.
// Filter for guides or selected items if that's required
if ((res || (res = this._children || !(options.guides && !this._guide
|| options.selected && !this._selected)
? this._hitTest(point, options) : null))
&& res.point) {
// Transform the point back to the outer coordinate system.
res.point = that._matrix.transform(res.point);
var children = !res && this._children;
if (children) {
var opts = this._getChildHitTestOptions(options);
// Loop backwards, so items that get drawn last are tested first
for (var i = children.length - 1; i >= 0 && !res; i--)
res = children[i].hitTest(point, opts);
}
if (!res && checkSelf)
res = this._hitTest(point, options);
// Transform the point back to the outer coordinate system.
if (res && res.point)
res.point = that._matrix.transform(res.point);
return res;
},
_getChildHitTestOptions: function(options) {
return options;
},
_hitTest: function(point, options) {
var children = this._children;
if (children) {
// Loop backwards, so items that get drawn last are tested first
for (var i = children.length - 1, res; i >= 0; i--)
if (res = children[i].hitTest(point, options))
return res;
} else if (options.fill && this.hasFill() && this._contains(point)) {
// The default implementation honly handles 'fill' through #_contains()
if (options.fill && this.hasFill() && this._contains(point))
return new HitResult('fill', this);
}
},
// DOCS: Item#matches

View file

@ -121,12 +121,12 @@ var PlacedSymbol = Item.extend(/** @lends PlacedSymbol# */{
},
_hitTest: function(point, options, matrix) {
var result = this._symbol._definition._hitTest(point, options, matrix);
var res = this._symbol._definition._hitTest(point, options, matrix);
// TODO: When the symbol's definition is a path, should hitResult
// contain information like HitResult#curve?
if (result)
result.item = this;
return result;
if (res)
res.item = this;
return res;
},
_draw: function(ctx, param) {

View file

@ -244,24 +244,13 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
return winding;
},
_hitTest : function _hitTest(point, options) {
// Do not test children for fill, since a compound path forms one shape.
// options.compoundChildren allows to specifically do so, see below.
var res = _hitTest.base.call(this, point,
new Base(options, { fill: false }));
if (!res) {
// If asked to query all children seperately, perform the same loop
// as Item#hitTest() now on the compound children.
if (options.compoundChildren) {
var children = this._children;
for (var i = children.length - 1; i >= 0 && !res; i--)
res = children[i]._hitTest(point, options);
} else if (options.fill && this.hasFill()
&& this._contains(point)) {
res = new HitResult('fill', this);
}
}
return res;
_getChildHitTestOptions: function(options) {
// If we're not specifically asked to returns paths through
// options.type == 'path' do not test children for fill, since a
// compound path forms one shape.
return options.type === 'path'
? options
: new Base(options, { fill: false });
},
_draw: function(ctx, param) {

View file

@ -263,7 +263,8 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
* in points, can also be controlled through
* {@link Project#options}{@code .hitTolerance}.
* <b>options.type:</b> Only hit test again a certain item
* type: {@link PathItem}, {@link Raster}, {@link TextItem}, etc.
* type: {String('group', 'layer', 'path', 'compound-path', 'shape',
* 'raster', 'placed-symbol', 'point-text')}, etc.
* <b>options.fill:</b> {@code Boolean} hit test the fill of items.
* <b>options.stroke:</b> {@code Boolean} hit test the curves of path
* items, taking into account stroke width.