Correctly handle paths with only one segment in hit-testing code.

Closes #430.
This commit is contained in:
Jürg Lehni 2014-04-04 12:08:20 +02:00
parent dfacc16788
commit 09d0f5f389
4 changed files with 16 additions and 10 deletions

View file

@ -1690,7 +1690,8 @@ var Item = Base.extend(Callback, /** @lends Item# */{
hitTest: function(point, options) {
point = Point.read(arguments);
options = HitResult.getOptions(Base.read(arguments));
if (this._locked || !this._visible || this._guide && !options.guides)
if (this._locked || !this._visible || this._guide && !options.guides
|| this.isEmpty())
return null;
// Check if the point is withing roughBounds + tolerance, but only if

View file

@ -151,7 +151,7 @@ var Shape = Item.extend(/** @lends Shape# */{
},
isEmpty: function() {
// A shape can never be "empty" in the sense that it does not hold a
// A shape can never be "empty" in the sense that it always holds a
// definition. This is required for Group#bounds to work correctly when
// containing a Shape.
return false;

View file

@ -1747,6 +1747,7 @@ var Path = PathItem.extend(/** @lends Path# */{
var that = this,
style = this.getStyle(),
segments = this._segments,
numSegments = segments.length,
closed = this._closed,
// transformed tolerance padding, see Item#hitTest. We will add
// stroke padding on top if stroke is defined.
@ -1817,7 +1818,7 @@ var Path = PathItem.extend(/** @lends Path# */{
// to run the hit-test on it.
area = new Path({ internal: true, closed: true });
if (closed || segment._index > 0
&& segment._index < segments.length - 1) {
&& segment._index < numSegments - 1) {
// It's a join. See that it's not a round one (one of
// the handles has to be zero too for this!)
if (join !== 'round' && (segment._handleIn.isZero()
@ -1848,22 +1849,25 @@ var Path = PathItem.extend(/** @lends Path# */{
// before stroke or fill.
if (options.ends && !options.segments && !closed) {
if (res = checkSegmentPoints(segments[0], true)
|| checkSegmentPoints(segments[segments.length - 1], true))
|| checkSegmentPoints(segments[numSegments - 1], true))
return res;
} else if (options.segments || options.handles) {
for (var i = 0, l = segments.length; i < l; i++)
for (var i = 0; i < numSegments; i++)
if (res = checkSegmentPoints(segments[i]))
return res;
}
// If we're querying for stroke, perform that before fill
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
// check if there is only one segment.
if (loc) {
// Now see if we're on a segment, and if so, check for its
// stroke join / cap first. If not, do a normal radius check
// for round strokes.
var parameter = loc.getParameter();
if (parameter === 0 || parameter === 1) {
if (parameter === 0 || parameter === 1 && numSegments > 1) {
if (!checkSegmentStroke(loc.getSegment()))
loc = null;
} else if (!isCloseEnough(loc.getPoint(), strokePadding)) {
@ -1872,8 +1876,8 @@ var Path = PathItem.extend(/** @lends Path# */{
}
// If we have miter joins, we may not be done yet, since they can be
// longer than the radius. Check for each segment within reach now.
if (!loc && join === 'miter') {
for (var i = 0, l = segments.length; i < l; i++) {
if (!loc && join === 'miter' && numSegments > 1) {
for (var i = 0; i < numSegments; i++) {
var segment = segments[i];
if (point.getDistance(segment._point) <= miterLimit
&& checkSegmentStroke(segment)) {

View file

@ -387,8 +387,9 @@ var Segment = Base.extend(/** @lends Segment# */{
var path = this._path,
index = this._index;
if (path) {
// The last segment of an open path belongs to the last curve
if (!path._closed && index == path._segments.length - 1)
// The last segment of an open path belongs to the last curve.
if (index > 0 && !path._closed
&& index === path._segments.length - 1)
index--;
return path.getCurves()[index] || null;
}