pixi-essentials: Can't get pointer events to work

Whatever I try, I can’t get pointer events to work when adding an SVGScene to the stage. Whatever else I add to the stage works interactively fine and also the stage itself fires events just fine, but for some reason not the SVG Scene. Interactive of the scene is set to true tho (also tried buttonMode just to be sure)

I tried several event types, like pointerup, tap and click. Also tried both .on() and .addListener() on both the SVGScene object (which is extended from DisplayObject) as well as the svgScene.root just to be sure.

Also created a complete fresh project with only pixi in it, just a stage and only the SVGScene added to it. But nothing seems to work.

According to the docs the events should be supported, so I don’t get this.

Is there anything we should know, other than settings interactive to true, to make interactivity with pointers work?

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Comments: 23 (13 by maintainers)

Most upvoted comments

Screen Shot 2022-03-06 at 11 39 58 AM

Hmm I updated the pen with the prototype modification. The prototype isn’t supposed to have the worldTransform - it is the instantiated object / SVGScene that has it.

Make sure you’re not using arrow functions as they hard set the this.

I’ll add containsPoint later tonight.

So the child problem is kind of why I didn’t want to add a “default” way of implementing interactivity. Although @pixi-essentials/svg does provide a scene graph, it’s a “disconnected” internal scene. The scene graph is an “implementation detail”. Usually, if you are rendering an arbitrary SVG file — this won’t be an issue (pun intended). That does means the this.root is not a child of SVGScene, and it’s protected from the outside.

The reason behind this is to give you performance optimization out of the box:

  • The scene is automatically culled on each render.
  • The transform matrices are not recalculated if they didn’t change at the root.

Back to adding interactivity, there are a couple of ways to go about this:

  1. Since the “root” node is disconnected from the SVGScene, you could treat the SVGScene as a factory:
import { SVGScene } from '@pixi-essentials/svg';

const stage;
const scene = new SVGScene(svgsvgElement);

stage.addChild(scene['root']);

You loose the performance optimizations described earlier, but they might not matter if you need hit testing inside the scene already.

  1. Create an interaction bridge.

You can use PixiJS’ TreeSearch to do hit testing for you on the “root” of inside all SVGScene events.

// TODO: Convert to factory format and reuse code for other events

const scene = new SVGScene(el);
const treeSearch = new TreeSearch();

scene.on('pointerdown', (e) => {
  // Note: Use a different event object
  treeSearch.hitTest(..., (nextEvent) => {
    nextEvent.target?.emit('pointerdown', nextEvent);
  });
);
});

The new EventSystem has better support for this. Here, you’d have to check if the target object changed between pointerdown and pointerup before emitting a click event.

With this method, you could use a faster hit testing algorithm if you know parts of the scene you don’t want to search through or if you want to use something like a spatial hash cause the SVG tree is huge.

ignore the trackedPointers tho

If that ↑ doesn’t work, I’ll add interactivity 😃

Hey, I see the problem with extending. You can add in the method too instead since it’s not defined:

SVGScene.prototype.containsPoint = function(point) { ... }

Hi @ShukantPal , Thanks for diving into it. I am very surprised this isn’t already build in. That’s a huge setback. Without being able to use the SVGScene with interactivity that enormously limits the things we can actually use the SVGScene for in real life applications. That’s unfortunate.

I am now trying to extend the SVGScene class tho hoping to add this and try to implement your example. But I’m already bumping into all kinds of walls making this possible.

Starting at the beginning: the from() function to load the svg and return the scene-class needs to be overriden already, because the original class don’t return the new overriden class, but a SVGScene object instead, so immediately after loading everything we added to our own extended class will never be available like this.

So I tried to override that from() method too (which doesn’t feel right, as we are already creating all kinds of unnecesary duplicate code, making everything larger), just to find out that you’re using all kinds of things from outside the class that’s not available in our project and is not exported. Things like _SVG_DOCUMENT_CACHE and the _load() function. This makes it hard to say the least to actually override the class that shouldn’t even needed to be changed.

Let’s say I do manage to get that from() method extended (where it looks like I pretty much have to copy a lot of code making the output larger and having duplicate code that wille never get updated by an update on the module), than we’re not there yet. And then the real fun only starts: adding all the things to have the interactivity working on the scene, its children, and everything recursively. And all that with several pointer event types and it should also work when used within other containers which can zoom in and out etc. Like the pixi-viewport we’re using in this project.

I keep trying, because we’re already working long time on a project which uses this and I would’ve never thought interactivity not working. But I could use all the help with this. It would help if the original class would at least have everything available for the extended class and the SVGScene object would never be returned hardcoded. If it’s even possible to avoid that, I’m not sure (perhaps something like a ‘self’ should be possible?).

Let me know if you have any questions or suggestions on this!

Thanks. To be really honest my best and only suggestion would really be: please add interactivity! We can’t live without really!

Hi @Friksel , I can try to look at this this weekend.