mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-06 04:42:15 -05:00
Implement a first version of Item#hitTest(), so far working only for Path items. Work in progress.
This commit is contained in:
parent
de87c1f97a
commit
69a7d0bfd4
7 changed files with 154 additions and 7 deletions
77
src/item/HitResult.js
Normal file
77
src/item/HitResult.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Paper.js
|
||||
*
|
||||
* This file is part of Paper.js, a JavaScript Vector Graphics Library,
|
||||
* based on Scriptographer.org and designed to be largely API compatible.
|
||||
* http://paperjs.org/
|
||||
* http://scriptographer.org/
|
||||
*
|
||||
* Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
|
||||
* http://lehni.org/ & http://jonathanpuckey.com/
|
||||
*
|
||||
* Distributed under the MIT license. See LICENSE file for details.
|
||||
*
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name HitResult
|
||||
*
|
||||
* @class
|
||||
*
|
||||
* @extends CurveLocation
|
||||
*/
|
||||
HitResult = CurveLocation.extend(/** @lends HitResult# */{
|
||||
initialize: function(type, item) {
|
||||
this._type = type;
|
||||
if (item instanceof CurveLocation) {
|
||||
// If a CurveLocation is passed, we can simply copy over values
|
||||
// since HitResult is also an instance of CurveLocation.
|
||||
this._item = item._curve._path;
|
||||
Base.each(item, function(value, key) {
|
||||
this[key] = value;
|
||||
}, this);
|
||||
} else {
|
||||
this._item = item;
|
||||
}
|
||||
},
|
||||
|
||||
statics: {
|
||||
/**
|
||||
* Merges default options into options hash for #hitTest() calls, and
|
||||
* marks as merged, to prevent repeated merging in nested calls.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
getOptions: function(options) {
|
||||
// TODO: Consier moving to HitResult / HitEvent?
|
||||
return options && options._merged ? options : Base.merge({
|
||||
// Hit the fill of items
|
||||
fill: true,
|
||||
// Hit the curves of path items, taking into account the stroke
|
||||
// width.
|
||||
stroke: true,
|
||||
// Hit the part of segments that curves pass through
|
||||
// (Segment#point)
|
||||
// TODO: Shall we call this points?
|
||||
segments: true,
|
||||
// Only first or last segment hits on path (mutually exclusive
|
||||
// with segments: true)
|
||||
// TODO: Shall we calls this: endPoints?
|
||||
ends: false,
|
||||
// Hit the parts of segments that define the curvature
|
||||
handles: true,
|
||||
// Hit items that are marked as guides
|
||||
guides: false,
|
||||
// Only hit selected objects
|
||||
selected: false,
|
||||
// Type of item, for instanceof check: PathItem, TexItem, etc
|
||||
type: Item,
|
||||
// Tolerance
|
||||
tolerance: 2,
|
||||
// Mark as merged, so next time Base.merge isn't called
|
||||
_merged: true
|
||||
}, options);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -668,6 +668,27 @@ var Item = this.Item = Base.extend(/** @lends Item# */{
|
|||
return raster;
|
||||
},
|
||||
|
||||
hitTest: function(point, options, matrix) {
|
||||
options = HitResult.getOptions(options);
|
||||
// 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
|
||||
return this._children || !(options.guides && !this._guide
|
||||
|| options.selected && !this._selected)
|
||||
? this._hitTest(point, options, matrix) : null;
|
||||
},
|
||||
|
||||
_hitTest: function(point, options, matrix) {
|
||||
if (this._children) {
|
||||
for (var i = 0, l = this._children.length; i < l; i++) {
|
||||
var res = this._children[i].hitTest(point, options, matrix);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* {@grouptitle Hierarchy Operations}
|
||||
* Adds the specified item as a child of this item at the end of the
|
||||
|
@ -1583,10 +1604,10 @@ var Item = this.Item = Base.extend(/** @lends Item# */{
|
|||
},
|
||||
|
||||
/*
|
||||
_transform: function(matrix, flags) {
|
||||
// The code that performs the actual transformation of content,
|
||||
// if defined. Item itself does not define this.
|
||||
},
|
||||
_transform: function(matrix, flags) {
|
||||
// The code that performs the actual transformation of content,
|
||||
// if defined. Item itself does not define this.
|
||||
},
|
||||
*/
|
||||
|
||||
toString: function() {
|
||||
|
|
|
@ -45,12 +45,14 @@ var sources = [
|
|||
'src/item/PlacedItem.js',
|
||||
'src/item/Raster.js',
|
||||
'src/item/PlacedSymbol.js',
|
||||
// TODO: Move to item?
|
||||
'src/path/CurveLocation.js',
|
||||
'src/item/HitResult.js',
|
||||
|
||||
'src/path/Segment.js',
|
||||
'src/path/SegmentPoint.js',
|
||||
'src/path/SelectionState.js',
|
||||
'src/path/Curve.js',
|
||||
'src/path/CurveLocation.js',
|
||||
'src/path/PathItem.js',
|
||||
'src/path/Path.js',
|
||||
'src/path/CompoundPath.js',
|
||||
|
|
|
@ -75,12 +75,13 @@ var paper = new function() {
|
|||
//#include "item/PlacedItem.js"
|
||||
//#include "item/Raster.js"
|
||||
//#include "item/PlacedSymbol.js"
|
||||
//#include "path/CurveLocation.js"
|
||||
//#include "item/HitResult.js"
|
||||
|
||||
//#include "path/Segment.js"
|
||||
//#include "path/SegmentPoint.js"
|
||||
//#include "path/SelectionState.js"
|
||||
//#include "path/Curve.js"
|
||||
//#include "path/CurveLocation.js"
|
||||
//#include "path/PathItem.js"
|
||||
//#include "path/Path.js"
|
||||
//#include "path/CompoundPath.js"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* All rights reserved.
|
||||
*/
|
||||
|
||||
// TODO: Consider simply naming Location?
|
||||
/**
|
||||
* @name CurveLocation
|
||||
*
|
||||
|
@ -87,7 +88,8 @@ CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
* @bean
|
||||
*/
|
||||
getItem: function() {
|
||||
return this._curve && this._curve._path;
|
||||
// Support _item for HitResult
|
||||
return this._item || this._curve && this._curve._path;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -193,6 +195,12 @@ CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
toString: function() {
|
||||
var parts = [],
|
||||
point = this.getPoint();
|
||||
// Support for HitResult that inherits from CurveLocation
|
||||
if (this._type)
|
||||
parts.push('type: ' + this._type);
|
||||
if (this._item)
|
||||
parts.push('item: ' + this._item);
|
||||
// Normal CurveLocation properties:
|
||||
if (point)
|
||||
parts.push('point: ' + point);
|
||||
var index = this.getIndex();
|
||||
|
@ -201,6 +209,8 @@ CurveLocation = Base.extend(/** @lends CurveLocation# */{
|
|||
var parameter = this.getParameter();
|
||||
if (parameter != null)
|
||||
parts.push('parameter: ' + Base.formatNumber(parameter));
|
||||
if (this._distance != null)
|
||||
parts.push('distance: ' + Base.formatNumber(this._distance));
|
||||
return '{ ' + parts.join(', ') + ' }';
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1193,6 +1193,32 @@ var Path = this.Path = PathItem.extend(/** @lends Path# */{
|
|||
for (var i = 0, l = curves.length; i < l; i++)
|
||||
crossings += curves[i].getCrossings(point, matrix);
|
||||
return (crossings & 1) == 1;
|
||||
},
|
||||
|
||||
_hitTest: function(point, options, matrix) {
|
||||
// TODO:
|
||||
// segments: true,
|
||||
// ends: false,
|
||||
// handles: true,
|
||||
var radius = (options.stroke ? this.getStrokeWidth() / 2 : 0)
|
||||
+ (options.tolerance || 0),
|
||||
loc;
|
||||
// If we're querying for stroke, perform that before fill
|
||||
if (options.stroke && radius > 0)
|
||||
loc = this.getNearestLocation(point, matrix);
|
||||
// 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 (!(loc && loc._distance <= radius) && options.fill
|
||||
&& this.getFillColor() && this.contains(point, matrix))
|
||||
return new HitResult('fill', this);
|
||||
// Now query stroke if we haven't already
|
||||
if (!loc && radius > 0)
|
||||
loc = this.getNearestLocation(point, matrix);
|
||||
if (loc._distance <= radius)
|
||||
return options.stroke
|
||||
? new HitResult('stroke', loc)
|
||||
: new HitResult('fill', this);
|
||||
}
|
||||
|
||||
// TODO: intersects(item)
|
||||
|
|
|
@ -181,6 +181,16 @@ var Project = this.Project = Base.extend(/** @lends Project# */{
|
|||
this._selectedItems[i].setSelected(false);
|
||||
},
|
||||
|
||||
hitTest: function(point, options) {
|
||||
options = HitResult.getOptions(options);
|
||||
for (var i = 0, l = this.layers.length; i < l; i++) {
|
||||
var res = this.layers[i].hitTest(point, options);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* {@grouptitle Project Hierarchy}
|
||||
*
|
||||
|
|
Loading…
Reference in a new issue