diff --git a/CHANGELOG.md b/CHANGELOG.md index 61fe3279..c69223e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). +- Support `fillRule` for `Konva.Shape` on hit graph + ### 9.3.13 (2024-07-05) - Fallback for `Konva.Text.measureSize()` when 2d context doesn't return full data diff --git a/src/Container.ts b/src/Container.ts index efd4c2f5..d7bb5494 100644 --- a/src/Container.ts +++ b/src/Container.ts @@ -307,6 +307,7 @@ export abstract class Container< * canvas and redraw every shape inside the container, it should only be used for special situations * because it performs very poorly. Please use the {@link Konva.Stage#getIntersection} method if at all possible * because it performs much better + * nodes with listening set to false will not be detected * @method * @name Konva.Container#getAllIntersections * @param {Object} pos diff --git a/src/Layer.ts b/src/Layer.ts index 9766ec21..4e5ff961 100644 --- a/src/Layer.ts +++ b/src/Layer.ts @@ -309,6 +309,7 @@ export class Layer extends Container { * get visible intersection shape. This is the preferred * method for determining if a point intersects a shape or not * also you may pass optional selector parameter to return ancestor of intersected shape + * nodes with listening set to false will not be detected * @method * @name Konva.Layer#getIntersection * @param {Object} pos diff --git a/src/Node.ts b/src/Node.ts index 281601c7..a26ce37b 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -3155,6 +3155,8 @@ addGetterSetter(Node, 'listening', true, getBooleanValidator()); /** * get/set listening attr. If you need to determine if a node is listening or not * by taking into account its parents, use the isListening() method + * nodes with listening set to false will not be detected in hit graph + * so they will be ignored in container.getIntersection() method * @name Konva.Node#listening * @method * @param {Boolean} listening Can be true, or false. The default is true. diff --git a/src/Shape.ts b/src/Shape.ts index 4d77de82..e34abbfd 100644 --- a/src/Shape.ts +++ b/src/Shape.ts @@ -128,8 +128,13 @@ function _fillFunc(this: Node, context) { function _strokeFunc(context) { context.stroke(); } -function _fillFuncHit(context) { - context.fill(); +function _fillFuncHit(this: Node, context) { + const fillRule = this.attrs.fillRule; + if (fillRule) { + context.fill(fillRule); + } else { + context.fill(); + } } function _strokeFuncHit(context) { context.stroke(); diff --git a/src/Stage.ts b/src/Stage.ts index 4fe8a567..b5ef1695 100644 --- a/src/Stage.ts +++ b/src/Stage.ts @@ -353,6 +353,7 @@ export class Stage extends Container { /** * get visible intersection shape. This is the preferred * method for determining if a point intersects a shape or not + * nodes with listening set to false will not be detected * @method * @name Konva.Stage#getIntersection * @param {Object} pos diff --git a/test/unit/Shape-test.ts b/test/unit/Shape-test.ts index 79d2e2d6..26758dda 100644 --- a/test/unit/Shape-test.ts +++ b/test/unit/Shape-test.ts @@ -2303,4 +2303,36 @@ describe('Shape', function () { assert.equal(callCount, 0); Konva.Util.warn = oldWarn; }); + + it('fill rule on hit graph', function () { + var stage = addStage(); + + var layer = new Konva.Layer(); + stage.add(layer); + + var mask = new Konva.Shape({ + sceneFunc: function (ctx, shape) { + ctx.beginPath(); + ctx.rect(0, 0, 500, 500); + ctx.rect(100, 100, 100, 100); + ctx.closePath(); + ctx.fillShape(shape); + }, + draggable: true, + fill: 'red', + fillRule: 'evenodd', + }); + + layer.add(mask); + layer.draw(); + const trace = layer.getContext().getTrace(); + + assert.equal( + trace, + 'clearRect(0,0,578,200);clearRect(0,0,578,200);save();transform(1,0,0,1,0,0);beginPath();rect(0,0,500,500);rect(100,100,100,100);closePath();fillStyle=red;fill(evenodd);restore();' + ); + + const hitShape = layer.getIntersection({ x: 150, y: 150 }); + assert.equal(hitShape, null); + }); });