Implement hit-test options: segments, handles and ends.

This commit is contained in:
Jürg Lehni 2011-07-08 23:26:21 +02:00
parent 9db96ae898
commit c033a5a7bc
2 changed files with 38 additions and 12 deletions

View file

@ -22,11 +22,16 @@
* @extends CurveLocation
*/
HitResult = Base.extend(/** @lends HitResult# */{
initialize: function(type, item, location) {
initialize: function(type, item, values) {
this.type = type;
this.item = item;
if (location)
this.location = location;
if (values) {
// Copy over passed values, depending on use case.
// DOCS: HitResult#location, #segment, #point
Base.each(values, function(value, key) {
this[key] = value;
}, this);
}
},
statics: {
@ -55,7 +60,7 @@ HitResult = Base.extend(/** @lends HitResult# */{
// its segments (Segment#point)
segments: true,
// Hit the parts of segments that define the curvature
handles: true,
handles: false,
// Only first or last segment hits on path (mutually exclusive
// with segments: true)
ends: false,

View file

@ -1196,13 +1196,34 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
},
_hitTest: function(point, options, matrix) {
// TODO:
// segments: true,
// ends: false,
// handles: true,
var radius = (options.stroke ? this.getStrokeWidth() / 2 : 0)
+ (options.tolerance || 0),
loc;
var tolerance = options.tolerance || 0,
radius = (options.stroke ? this.getStrokeWidth() / 2 : 0) + tolerance,
loc,
res;
// If we're asked to query for segments, ends or handles, do all that
// before stroke or fill.
var coords = [],
that = this;
function checkSegment(segment, ends) {
segment._transformCoordinates(matrix, coords);
for (var j = ends || options.segments ? 0 : 2,
m = !ends && options.handles ? 6 : 2; j < m; j += 2) {
if (point.getDistance(coords[j], coords[j + 1]) < tolerance)
return new HitResult(j == 0 ? 'segment'
: 'handle-' + (j == 2 ? 'in' : 'out'),
that, { segment: segment });
}
}
if (options.ends && !options.segments && !this._closed) {
if (res = checkSegment(this.getFirstSegment(), true)
|| checkSegment(this.getLastSegment(), true))
return res;
} else if (options.segments || options.handles) {
for (var i = 0, l = this._segments.length; i < l; i++) {
if (res = checkSegment(this._segments[i]))
return res;
}
}
// If we're querying for stroke, perform that before fill
if (options.stroke && radius > 0)
loc = this.getNearestLocation(point, matrix);
@ -1217,7 +1238,7 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
loc = this.getNearestLocation(point, matrix);
if (loc && loc._distance <= radius)
return options.stroke
? new HitResult('stroke', this, loc)
? new HitResult('stroke', this, { location: location })
: new HitResult('fill', this);
}