Implement Style#windingRule and use it in Path#contains().

This commit is contained in:
Jürg Lehni 2013-10-18 14:54:13 +02:00
parent 4f27be8f12
commit 5d0fd8f970
5 changed files with 27 additions and 22 deletions

View file

@ -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}
*

View file

@ -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();
}

View file

@ -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();
}

View file

@ -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

View file

@ -78,6 +78,7 @@ var Style = Base.extend(new function() {
miterLimit: 10,
dashOffset: 0,
dashArray: [],
windingRule: 'nonzero',
// Shadows
shadowColor: undefined,
shadowBlur: 0,