pixijs icon indicating copy to clipboard operation
pixijs copied to clipboard

@pixi/events Masked container with nested child containers doesn't bubble events.

Open jramstedt opened this issue 4 years ago • 11 comments

Expected Behavior

Grandchild's event listeners should work as they do with non masked grandparent.

Current Behavior

Grandchild's event listeners are not triggered if it's grandparent is masked.

Steps to Reproduce

See running example.

Create following hierarchy:

Container with mask and interactive -> Container without any event listeners or mask -- -> Displayobject with eventlistnener

Test with mask enabled: Does not work. Comment out adding mask: Does work.

Environment

  • pixi.js version: 6.1.3
  • Browser & Version: Chrome 94
  • OS & Version: Windows 10
  • Running Example: https://www.pixiplayground.com/#/edit/t5WBOFp3-SBRfYvedOxe1

jramstedt avatar Oct 25 '21 13:10 jramstedt

I agree this seems like a bug. Thanks for the example and simple explanation @jramstedt

bigtimebuddy avatar Oct 25 '21 14:10 bigtimebuddy

Seems to be working fine if you comment out these lines: delete PIXI.Renderer.__plugins.interaction; renderer.addSystem(PIXI.EventSystem, 'events');

Running example https://www.pixiplayground.com/#/edit/rJ34d_evdxC1k-6lZwEpB

kjarrio avatar Oct 31 '21 05:10 kjarrio

Seems to be working fine if you comment out these lines: delete PIXI.Renderer.__plugins.interaction; renderer.addSystem(PIXI.EventSystem, 'events');

Yes, This is a @pixi/events problem.

jramstedt avatar Nov 01 '21 08:11 jramstedt

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Mar 02 '22 13:03 stale[bot]

Any news?

jramstedt avatar Mar 06 '22 10:03 jramstedt

It's not a bug, explanation

I've done some investigating and this is not a bug. In your code, you have the following scene graph structure:

Stage
 |
Container
 |
Container, Mask
|          |
Button     (no children)

This means the mask is like any other DisplayObject and it'll capture events passing it's hit-test if one of it's ancestors is interactive. Indeed, the mask you've added is a 75px square that's transparent and it is rendered above the red button. That's why the hitTestRecursive method returns a 0-length array on the mask (it passes hit testing but since it's not interactive, it isn't included in the propagation path of the ensuing pointerdown event):

Screen Shot 2022-04-09 at 10 07 07 PM

What you can do about it!

1 − (suboptimal) Reorder your scene graph

You can reorder the children of the grandparent container, such that the mask comes before the button. This will cause the hit-testing algorithm to prioritize the button over the mask.

However, the mask will continue to capture events that happen outside the button but inside the mask.

2 − (optimal) Set visible to false on the mask

You can instead set the visible flag on the mask to false. The hit-testing algorithm will ignore these invisible objects.

I've updated the playground you've attached to this issue to demonstrate the fix.

Screen Shot 2022-04-09 at 10 17 39 PM

https://www.pixiplayground.com/#/edit/t5WBOFp3-SBRfYvedOxe1

ShukantPal avatar Apr 10 '22 02:04 ShukantPal

@bigtimebuddy I'm open to putting in any documentation changes needed to make this more obvious.

ShukantPal avatar Apr 10 '22 02:04 ShukantPal

@ShukantPal very good and clear explanation! 👍

domis86 avatar Apr 10 '22 07:04 domis86

Thanks for the explanation. However, I would assume this to work the same way as before, otherwise migrating to new events can be laborious and error prone.

jramstedt avatar Apr 19 '22 08:04 jramstedt

Wouldn't the "fix" just be to also check "isMask" when checking for visible in hit testing?

jramstedt avatar Apr 19 '22 08:04 jramstedt

Oh yes, but you’d have to wait for a release

ShukantPal avatar Apr 19 '22 13:04 ShukantPal

@ShukantPal I tested this with 7.1.2

Masks are not masking if visible = false.

This is still a problem. Childs of masked containers doesn't work. They don't change pointer or get events.

jramstedt avatar Feb 03 '23 17:02 jramstedt

I found a workaround. Adding empty rectangle to mask's hitArea circumvents this problem.

this.mask.hitArea = Rectangle.EMPTY

Note: If you want to listen events in "empty" areas the masked displayobject needs hitArea to be set. This is because the mask's area aren't added to event bounds.

jramstedt avatar Feb 03 '23 17:02 jramstedt

Hey @jramstedt

This should be fixed in 7.2.0. We now ignore masks when doing hit testing

Zyie avatar Mar 17 '23 15:03 Zyie