diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js index bfaca9b..8083be8 100644 --- a/src/core/textures/Texture.js +++ b/src/core/textures/Texture.js @@ -612,6 +612,7 @@ */ Texture.EMPTY = new Texture(new BaseTexture()); removeAllHandlers(Texture.EMPTY); +removeAllHandlers(Texture.EMPTY.baseTexture); /** * A white texture of 10x10 size, used for graphics and other things @@ -622,3 +623,4 @@ */ Texture.WHITE = createWhiteTexture(); removeAllHandlers(Texture.WHITE); +removeAllHandlers(Texture.WHITE.baseTexture); diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js index bfaca9b..8083be8 100644 --- a/src/core/textures/Texture.js +++ b/src/core/textures/Texture.js @@ -612,6 +612,7 @@ */ Texture.EMPTY = new Texture(new BaseTexture()); removeAllHandlers(Texture.EMPTY); +removeAllHandlers(Texture.EMPTY.baseTexture); /** * A white texture of 10x10 size, used for graphics and other things @@ -622,3 +623,4 @@ */ Texture.WHITE = createWhiteTexture(); removeAllHandlers(Texture.WHITE); +removeAllHandlers(Texture.WHITE.baseTexture); diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 459fb30..a0956a4 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -13,12 +13,6 @@ const MOUSE_POINTER_ID = 'MOUSE'; -// private constants for use in processInteractive - tracks whether we hit anything at all, or an -// actual interactive child, so that we can keep that state going back up the display tree -const HIT_NONE = 0; -const HIT_ANY = 1; -const HIT_INTERACTIVE = 2; - /** * The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive * if its interactive parameter is set to true @@ -767,7 +761,7 @@ * interactionEvent, displayObject and hit will be passed to the function * @param {boolean} [hitTest] - this indicates if the objects inside should be hit test against the point * @param {boolean} [interactive] - Whether the displayObject is interactive - * @return {number} returns 1 or 2 if the displayObject hit the point, 0 if not + * @return {boolean} returns true if the displayObject hit the point */ processInteractive(interactionEvent, displayObject, func, hitTest, interactive) { @@ -793,7 +787,7 @@ interactive = displayObject.interactive || interactive; - let hit = HIT_NONE; + let hit = false; let interactiveParent = interactive; // if the displayobject has a hitArea, then it does not need to hitTest children. @@ -842,14 +836,13 @@ // This means we no longer need to hit test anything else. We still need to run // through all objects, but we don't need to perform any hit tests. - if (childHit === HIT_INTERACTIVE) + if (childHit) { - hitTest = false; - hit = HIT_INTERACTIVE; - } - else if (hit === HIT_NONE) - { - hit = HIT_ANY; + if (interactionEvent.target) + { + hitTest = false; + } + hit = true; } } } @@ -862,21 +855,21 @@ // We also don't need to worry about hit testing if once of the displayObjects children // has already been hit - but only if it was interactive, otherwise we need to keep // looking for an interactive child, just in case we hit one - if (hitTest && hit !== HIT_INTERACTIVE) + if (hitTest && !interactionEvent.target) { if (displayObject.hitArea) { displayObject.worldTransform.applyInverse(point, this._tempPoint); if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y)) { - hit = displayObject.interactive ? HIT_INTERACTIVE : HIT_ANY; + hit = true; } } else if (displayObject.containsPoint) { if (displayObject.containsPoint(point)) { - hit = displayObject.interactive ? HIT_INTERACTIVE : HIT_ANY; + hit = true; } } } diff --git a/src/core/textures/Texture.js b/src/core/textures/Texture.js index bfaca9b..8083be8 100644 --- a/src/core/textures/Texture.js +++ b/src/core/textures/Texture.js @@ -612,6 +612,7 @@ */ Texture.EMPTY = new Texture(new BaseTexture()); removeAllHandlers(Texture.EMPTY); +removeAllHandlers(Texture.EMPTY.baseTexture); /** * A white texture of 10x10 size, used for graphics and other things @@ -622,3 +623,4 @@ */ Texture.WHITE = createWhiteTexture(); removeAllHandlers(Texture.WHITE); +removeAllHandlers(Texture.WHITE.baseTexture); diff --git a/src/interaction/InteractionManager.js b/src/interaction/InteractionManager.js index 459fb30..a0956a4 100644 --- a/src/interaction/InteractionManager.js +++ b/src/interaction/InteractionManager.js @@ -13,12 +13,6 @@ const MOUSE_POINTER_ID = 'MOUSE'; -// private constants for use in processInteractive - tracks whether we hit anything at all, or an -// actual interactive child, so that we can keep that state going back up the display tree -const HIT_NONE = 0; -const HIT_ANY = 1; -const HIT_INTERACTIVE = 2; - /** * The interaction manager deals with mouse, touch and pointer events. Any DisplayObject can be interactive * if its interactive parameter is set to true @@ -767,7 +761,7 @@ * interactionEvent, displayObject and hit will be passed to the function * @param {boolean} [hitTest] - this indicates if the objects inside should be hit test against the point * @param {boolean} [interactive] - Whether the displayObject is interactive - * @return {number} returns 1 or 2 if the displayObject hit the point, 0 if not + * @return {boolean} returns true if the displayObject hit the point */ processInteractive(interactionEvent, displayObject, func, hitTest, interactive) { @@ -793,7 +787,7 @@ interactive = displayObject.interactive || interactive; - let hit = HIT_NONE; + let hit = false; let interactiveParent = interactive; // if the displayobject has a hitArea, then it does not need to hitTest children. @@ -842,14 +836,13 @@ // This means we no longer need to hit test anything else. We still need to run // through all objects, but we don't need to perform any hit tests. - if (childHit === HIT_INTERACTIVE) + if (childHit) { - hitTest = false; - hit = HIT_INTERACTIVE; - } - else if (hit === HIT_NONE) - { - hit = HIT_ANY; + if (interactionEvent.target) + { + hitTest = false; + } + hit = true; } } } @@ -862,21 +855,21 @@ // We also don't need to worry about hit testing if once of the displayObjects children // has already been hit - but only if it was interactive, otherwise we need to keep // looking for an interactive child, just in case we hit one - if (hitTest && hit !== HIT_INTERACTIVE) + if (hitTest && !interactionEvent.target) { if (displayObject.hitArea) { displayObject.worldTransform.applyInverse(point, this._tempPoint); if (displayObject.hitArea.contains(this._tempPoint.x, this._tempPoint.y)) { - hit = displayObject.interactive ? HIT_INTERACTIVE : HIT_ANY; + hit = true; } } else if (displayObject.containsPoint) { if (displayObject.containsPoint(point)) { - hit = displayObject.interactive ? HIT_INTERACTIVE : HIT_ANY; + hit = true; } } } diff --git a/test/interaction/InteractionManager.js b/test/interaction/InteractionManager.js index d4467fe..c87fa5c 100644 --- a/test/interaction/InteractionManager.js +++ b/test/interaction/InteractionManager.js @@ -882,6 +882,42 @@ }); }); }); + + it('Semi-complicated nesting with overlap, should not call behind callback', function () + { + const stage = new PIXI.Container(); + const frontParent = new PIXI.Container(); + const frontChild = new PIXI.Graphics(); + const behindParent = new PIXI.Container(); + const subParent = new PIXI.Container(); + const behindChild = new PIXI.Graphics(); + const behindCallback = sinon.spy(function behindSpy() { /* no op*/ }); + const frontCallback = sinon.spy(function frontSpy() { /* no op*/ }); + + behindChild.beginFill(0xFF); + behindChild.drawRect(0, 0, 50, 50); + subParent.on('click', behindCallback); + + frontChild.beginFill(0x00FF); + frontChild.drawRect(0, 0, 50, 50); + frontParent.on('click', frontCallback); + const pointer = this.pointer = new MockPointer(stage); + + behindParent.x = 25; + subParent.interactive = true; + frontParent.interactive = true; + + behindParent.addChild(subParent); + subParent.addChild(behindChild); + stage.addChild(behindParent); + frontParent.addChild(frontChild); + stage.addChild(frontParent); + + pointer.click(40, 10); + + expect(behindCallback).to.not.have.been.called; + expect(frontCallback).to.have.been.calledOnce; + }); }); describe('cursor changes', function ()