jonobr1 / two.js

A renderer agnostic two-dimensional drawing api for the web.
https://two.js.org
MIT License
8.31k stars 455 forks source link

Is there a way to access `Two.group.renderer.elem`? #616

Closed hughplay closed 2 years ago

hughplay commented 2 years ago

Describe your question

I try to access Two.Group.renderer.elem as Olivier described in https://github.com/jonobr1/two.js/issues/209. However, it failed. Accessing elem through the returned Proxy object seems not feasible. I wonder if there is another way to do this?

Your code (either pasted here, or a link to a hosted example)

Olivier's code (need to replace two.js in resource to make it work ) works in jsfiddle but failed under my environment.

My testing code:

this.ball = this.two.interpret(svg);
this.ball.center();
console.log(this.ball.renderer)
console.log(this.ball.renderer.elem)

Screenshots

What I see in my console:

image

You can see that this.ball.renderer contains elem, but directly accessing it will get undefined.

I know it must be something related to Proxy but have no idea how to resolve this problem.

Environment (please select one):


If applicable:

Desktop (please complete the following information):

Additional context

I use Vue 3 and import two.js like:

import Two from "two.js";
jonobr1 commented 2 years ago

Using console.log can be tricky when dealing with JavaScript functions that are called frequently. In the case of Two.js the update loop is called multiple times a second through the requestAnimationFrame API. If you have instantiated your scene like this:

var two = new Two({ autostart: true });

Then it's likely that the at the point in the code you're describing the SVG element has yet to be created. However, when you pop open the console.log that is displaying the information at the time you clicked the carat, likely many frames have passed between the point in your code and when you clicked.

What you need to do when creating and directly accessing Two.js elements is to force the update loop yourself. This will generate the SVG element in the scene for you. Modifying your snippet, it should work with something like this:

this.ball = this.two.interpret(svg);
this.ball.center();
this.two.update();
console.log(this.ball.renderer)
console.log(this.ball.renderer.elem) // Should exist now

Alternatively, the id of the Two.js object is passed on to its SVG counterpart. While it wouldn't solve your current issue of retrieving an element that has yet to be created, this way does give you another way to access elements:

var elem = two.renderer.domElement.querySelector(`#${this.ball.id}`);

Hope this helps!

hughplay commented 2 years ago

Ok, I got it. After manually update, it works! Thanks! : )

jonobr1 commented 2 years ago

Glad to hear. Happy coding!