diff --git a/src/item/HitResult.js b/src/item/HitResult.js index c9069e39..c2fadde5 100644 --- a/src/item/HitResult.js +++ b/src/item/HitResult.js @@ -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, diff --git a/src/item/Item.js b/src/item/Item.js index 118b3b8d..f43a991b 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -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}. * options.type: 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. * options.fill: {@code Boolean} – hit test the fill of items. * options.stroke: {@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 diff --git a/src/item/PlacedSymbol.js b/src/item/PlacedSymbol.js index bc66aea2..24ec45d6 100644 --- a/src/item/PlacedSymbol.js +++ b/src/item/PlacedSymbol.js @@ -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) { diff --git a/src/path/CompoundPath.js b/src/path/CompoundPath.js index 5dca4722..3b648f0d 100644 --- a/src/path/CompoundPath.js +++ b/src/path/CompoundPath.js @@ -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) { diff --git a/src/project/Project.js b/src/project/Project.js index e5e6f979..c9011c99 100644 --- a/src/project/Project.js +++ b/src/project/Project.js @@ -263,7 +263,8 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{ * in points, can also be controlled through * {@link Project#options}{@code .hitTolerance}. * options.type: 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. * options.fill: {@code Boolean} – hit test the fill of items. * options.stroke: {@code Boolean} – hit test the curves of path * items, taking into account stroke width.