two.js: Breaks on Web worker because it uses window instead of self

Hi Jono, Your library looks promising and I’m eager to use it for rendering to canvas and mostly to WebGL. However, I render my canvas in a web worker using OffscreenCanvas, and it seems that this library breaks down in that environment because it makes too many assumptions. I’ve been trying for a while to get this to work.

One of the main issues is that window is assumed to be defined, as you assign either “window” or “global” to root. If you’d use “self” instead of, or as alternative to, “window”, it would work fine in a web worker.

The library also tries to access the document in other places. For example, in line 4922 and 7961, it says: canvas = (root.document ? root.document.createElement('canvas') : { getContext: _.identity });

Why don’t you use the domElement here? Creating the canvas element fails in the worker, and then it ends up with the identity context, so that later, the library does calls like .clearRect() on the string ‘2d’, which fails. I am also confused why the 2d rendering context is used to clear the canvas when the rendering is explicitly set to WebGL? It seems some kind of combination between 2d and WebGL context is used. Could you help me understand what’s going on there, and what I could do to make it work without creating new elements in the library?

Thanks for your help! Micha

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 21 (10 by maintainers)

Most upvoted comments

Okay, latest dev branch should have the fix and working. By the way, that is pretty crazy you can send an offscreen canvas to a WebWorker and then the image just updates… o_O

Thanks for helping out! Curious to see what you make. Please don’t hesitate to share when you’re done.

Would supplying a reference to your canvas when constructing a new instance of Two.js suffice? An API around the lines of:

var two = new Two({
  type: Two.Types.webgl,
  domElement: canvasToBeRendered,
  offscreenElement: referenceCanvasForTextureTransfer
});

Where canvasToBeRendered and referenceCanvasForTextureTransfer are both OffscreenCanvas elements?

Yeah, I think you more than did your job 😃 But odd that I haven’t encountered this before.

Oh that’s odd! I just don’t have texImage2D on WebGLRenderingContext for some reason. I’m using Chrome 69 on Ubuntu.

That’s up on dev for you. 👍 Hope it works out!

Awesome thanks. Try giving one of the built files in the latest commit on dev a try. Hopefully that fix works for your. You should get a warning about Two.Text measurements, but it shouldn’t be blocking. If it still doesn’t work then it’s going to take some time to figure this out…

Thanks for the message! You’re looking to use OffscreenCanvas API as in this blog post?

https://developers.google.com/web/updates/2018/08/offscreen-canvas

There are a few issues that make that not possible with Two.js at the moment because the library relies on a few DOM calls:

  1. Measuring text width
  2. Loading bitmap imagery into the context
  3. No reference to self as you mention

I’ve written spoofs compatible with Node, but yet to try with a WebWorker. I think clearing up those should yield working results. A quick way to test this is to build the app without the SVG Renderer, Sprite, ImageSequence, Texture, and Text classes.

To answer your question about why the WebGL Renderer has a canvas internally: this is because all the 2D shapes are drawn in Canvas2D and then uploaded to WebGL as a texture. There are only quads drawn in WebGL.

I’ll make a note to address the window, global, self issue. Do you know an example library that handled it well? Maybe I can reference them for a good paradigm to enable this.