mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-03-13 16:33:28 -04:00
Implement Style#windingRule and use it in Path#contains().
This commit is contained in:
parent
4f27be8f12
commit
5d0fd8f970
5 changed files with 27 additions and 22 deletions
|
@ -2185,12 +2185,22 @@ var Item = Base.extend(Callback, /** @lends Item# */{
|
|||
* miterLimit imposes a limit on the ratio of the miter length to the
|
||||
* {@link Item#strokeWidth}.
|
||||
*
|
||||
* @default 10
|
||||
* @property
|
||||
* @name Item#miterLimit
|
||||
* @default 10
|
||||
* @type Number
|
||||
*/
|
||||
|
||||
/**
|
||||
* The winding-rule with which the shape gets filled. Please note that only
|
||||
* modern browsers support winding-rules other than {@code 'nonzero'}.
|
||||
*
|
||||
* @property
|
||||
* @name Item#windingRule
|
||||
* @default 'nonzero'
|
||||
* @type String('nonzero', 'evenodd')
|
||||
*/
|
||||
|
||||
/**
|
||||
* {@grouptitle Fill Style}
|
||||
*
|
||||
|
|
|
@ -192,7 +192,7 @@ var Shape = Item.extend(/** @lends Shape# */{
|
|||
if (!clip && (fillColor || strokeColor)) {
|
||||
this._setStyles(ctx);
|
||||
if (fillColor)
|
||||
ctx.fill();
|
||||
ctx.fill(style.getWindingRule());
|
||||
if (strokeColor)
|
||||
ctx.stroke();
|
||||
}
|
||||
|
|
|
@ -203,31 +203,28 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
|||
ctx.beginPath();
|
||||
for (var i = 0, l = children.length; i < l; i++)
|
||||
children[i]._draw(ctx, param);
|
||||
var res = ctx.isPointInPath(point.x, point.y);
|
||||
var res = ctx.isPointInPath(point.x, point.y, this.getWindingRule());
|
||||
CanvasProvider.release(ctx);
|
||||
return res && children;
|
||||
/*#*/ } // options.nativeContains
|
||||
|
||||
// Compound paths are a little complex: In order to determine whether a
|
||||
// point is inside a path or not due to the even-odd rule, we need to
|
||||
// point is inside a path or not due to the winding rule, we need to
|
||||
// check all the children and count how many intersect. If it's an odd
|
||||
// number, the point is inside the path. Once we know it's inside the
|
||||
// path, _hitTest also needs access to the first intersecting element,
|
||||
// for the HitResult, so we collect and return a list here.
|
||||
// for the HitResult, so we return it here.
|
||||
var total = 0,
|
||||
children = [];
|
||||
first = null,
|
||||
evenOdd = this.getWindingRule() === 'evenodd';
|
||||
for (var i = 0, l = this._children.length; i < l; i++) {
|
||||
var child = this._children[i],
|
||||
winding = child._getWinding(point);
|
||||
total += winding;
|
||||
/*
|
||||
if (winding & 1)
|
||||
children.push(child);
|
||||
*/
|
||||
if (winding)
|
||||
children.push(child);
|
||||
if (!first && (evenOdd ? winding & 1 : winding))
|
||||
first = child;
|
||||
}
|
||||
return total && children; // <- non-zero // even-odd: (total & 1) && children;
|
||||
return (evenOdd ? total & 1 : total) && first;
|
||||
},
|
||||
|
||||
_hitTest: function _hitTest(point, options) {
|
||||
|
@ -235,7 +232,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
|||
Base.merge(options, { fill: false }));
|
||||
if (!res && options.fill && this.hasFill()) {
|
||||
res = this._contains(point);
|
||||
res = res ? new HitResult('fill', res[0]) : null;
|
||||
res = res ? new HitResult('fill', res) : null;
|
||||
}
|
||||
return res;
|
||||
},
|
||||
|
@ -253,7 +250,7 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
|||
if (!param.clip) {
|
||||
this._setStyles(ctx);
|
||||
if (style.getFillColor())
|
||||
ctx.fill();
|
||||
ctx.fill(style.getWindingRule());
|
||||
if (style.getStrokeColor())
|
||||
ctx.stroke();
|
||||
}
|
||||
|
|
|
@ -1732,15 +1732,12 @@ var Path = PathItem.extend(/** @lends Path# */{
|
|||
// To compare with native canvas approach:
|
||||
var ctx = CanvasProvider.getContext(1, 1);
|
||||
this._draw(ctx, Base.merge({ clip: true }));
|
||||
var res = ctx.isPointInPath(point.x, point.y);
|
||||
var res = ctx.isPointInPath(point.x, point.y, this.getWindingRule());
|
||||
CanvasProvider.release(ctx);
|
||||
return res;
|
||||
/*#*/ } // options.nativeContains
|
||||
|
||||
// even-odd:
|
||||
// return !!(this._getWinding(point) & 1);
|
||||
// non-zero:
|
||||
return !!this._getWinding(point);
|
||||
var winding = this._getWinding(point);
|
||||
return !!(this.getWindingRule() == 'evenodd' ? winding & 1 : winding);
|
||||
},
|
||||
|
||||
_hitTest: function(point, options) {
|
||||
|
@ -2034,7 +2031,7 @@ var Path = PathItem.extend(/** @lends Path# */{
|
|||
// or stroke, there is no need to continue.
|
||||
this._setStyles(ctx);
|
||||
if (fillColor)
|
||||
ctx.fill();
|
||||
ctx.fill(style.getWindingRule());
|
||||
if (strokeColor) {
|
||||
if (dashLength) {
|
||||
// We cannot use the path created by drawSegments above
|
||||
|
|
|
@ -78,6 +78,7 @@ var Style = Base.extend(new function() {
|
|||
miterLimit: 10,
|
||||
dashOffset: 0,
|
||||
dashArray: [],
|
||||
windingRule: 'nonzero',
|
||||
// Shadows
|
||||
shadowColor: undefined,
|
||||
shadowBlur: 0,
|
||||
|
|
Loading…
Reference in a new issue