From a931a2530c02b0b586ac0bf4c76074b6184fa2f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrg=20Lehni?= Date: Fri, 11 Apr 2014 14:57:58 +0200 Subject: [PATCH] Implement `options.curves`option for hit-testing curves regardless of stroke settings. --- src/item/HitResult.js | 8 ++++---- src/item/Item.js | 11 ++++++++--- src/path/Path.js | 41 +++++++++++++++++++++++------------------ src/project/Project.js | 6 ++++-- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/src/item/HitResult.js b/src/item/HitResult.js index b651843c..c742e594 100644 --- a/src/item/HitResult.js +++ b/src/item/HitResult.js @@ -39,8 +39,8 @@ var HitResult = Base.extend(/** @lends HitResult# */{ * * @name HitResult#type * @property - * @type String('segment', 'handle-in', 'handle-out', 'stroke', 'fill', - * 'bounds', 'center', 'pixel') + * @type String('segment', 'handle-in', 'handle-out', 'curve', 'stroke', + * 'fill', 'bounds', 'center', 'pixel') */ /** @@ -62,8 +62,8 @@ var HitResult = Base.extend(/** @lends HitResult# */{ */ /** - * If the HitResult has a type of 'stroke', this property gives more - * information about the exact position that was hit on the path. + * If the HitResult has a type of 'curve' or 'stroke', this property gives + * more information about the exact position that was hit on the path. * * @name HitResult#location * @property diff --git a/src/item/Item.js b/src/item/Item.js index c6bcf4c2..8222f9f5 100644 --- a/src/item/Item.js +++ b/src/item/Item.js @@ -296,6 +296,9 @@ var Item = Base.extend(Callback, /** @lends Item# */{ * }); */ set: function(props) { + // Filter out `insert` since that only makes sense at creation time and + // is handled separately in the constructor.Also avoids overriding + // Path#insert(). if (props) this._set(props, { insert: true }); return this; @@ -1658,10 +1661,12 @@ var Item = Base.extend(Callback, /** @lends Item# */{ * {@code Group, Layer, Path, CompoundPath, Shape, Raster, PlacedSymbol, * PointText}, 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. - * options.segment: {@code Boolean} – hit test for + * options.stroke: {@code Boolean} – hit test the stroke of path + * items, taking into account the setting of stroke color and width. + * options.segments: {@code Boolean} – hit test for * {@link Segment#point} of {@link Path} items. + * options.curves: {@code Boolean} – hit test the curves of path + * items, without taking the stroke color or width into account. * options.handles: {@code Boolean} – hit test for the handles * ({@link Segment#handleIn} / {@link Segment#handleOut}) of path segments. * options.ends: {@code Boolean} – only hit test for the first or diff --git a/src/path/Path.js b/src/path/Path.js index 526d12b9..bde74067 100644 --- a/src/path/Path.js +++ b/src/path/Path.js @@ -1756,13 +1756,17 @@ var Path = PathItem.extend(/** @lends Path# */{ strokePadding = tolerancePadding, join, cap, miterLimit, area, loc, res, - hasStroke = options.stroke && style.hasStroke(), - hasFill = options.fill && style.hasFill(), - radius = hasStroke ? style.getStrokeWidth() / 2 - // Set radius to 0 so when we're hit-testing, the tolerance - // is used for fill too, through stroke functionality. - : hasFill ? 0 : null; - if (radius != null) { + hitStroke = options.stroke && style.hasStroke(), + hitFill = options.fill && style.hasFill(), + hitCurves = options.curves, + radius = hitStroke + ? style.getStrokeWidth() / 2 + // Set radius to 0 when we're hit-testing fills with + // tolerance, to handle tolerance through stroke hit-test + // functionality. Also use 0 when hit-testing curves. + : hitFill && options.tolerance > 0 || hitCurves + ? 0 : null; + if (radius !== null) { if (radius > 0) { join = style.getStrokeJoin(); cap = style.getStrokeCap(); @@ -1858,7 +1862,7 @@ var Path = PathItem.extend(/** @lends Path# */{ return res; } // If we're querying for stroke, perform that before fill - if (radius != null) { + if (radius !== null) { loc = this.getNearestLocation(point); // Note that paths need at least two segments to have an actual // stroke. But we still check for segments with the radius fallback @@ -1891,16 +1895,17 @@ var Path = PathItem.extend(/** @lends Path# */{ // Don't process loc yet, as we also need to query for stroke after fill // in some cases. Simply skip fill query if we already have a matching // stroke. If we have a loc and no stroke then it's a result for fill. - return !loc && hasFill && this._contains(point) || loc && !hasStroke - ? new HitResult('fill', this) - : loc - ? new HitResult('stroke', this, { - location: loc, - // It's fine performance wise to call getPoint() again - // since it was already called before. - point: loc.getPoint() - }) - : null; + return !loc && hitFill && this._contains(point) + || loc && !hitStroke && !hitCurves + ? new HitResult('fill', this) + : loc + ? new HitResult(hitStroke ? 'stroke' : 'curve', this, { + location: loc, + // It's fine performance wise to call getPoint() + // again since it was already called before. + point: loc.getPoint() + }) + : null; } // TODO: intersects(item) diff --git a/src/project/Project.js b/src/project/Project.js index 076afbcb..0b1f1077 100644 --- a/src/project/Project.js +++ b/src/project/Project.js @@ -272,10 +272,12 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{ * {@code Group, Layer, Path, CompoundPath, Shape, Raster, PlacedSymbol, * PointText}, 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. + * options.stroke: {@code Boolean} – hit test the stroke of path + * items, taking into account the setting of stroke color and width. * options.segments: {@code Boolean} – hit test for * {@link Segment#point} of {@link Path} items. + * options.curves: {@code Boolean} – hit test the curves of path + * items, without taking the stroke color or width into account. * options.handles: {@code Boolean} – hit test for the handles * ({@link Segment#handleIn} / {@link Segment#handleOut}) of path segments. * options.ends: {@code Boolean} – only hit test for the first or