I'm trying to use the experimental Canvas feature - offscreenCanvas.
index.html
<html>
<body>
<canvas id="myCanvas" width="400" height="400"></canvas>
</body>
<script>
const canvas = document.querySelector('#myCanvas');
const offscreenCanvas = canvas.transferControlToOffscreen();
const worker = new Worker('./worker.js');
worker.postMessage({offscreenCanvas}, [offscreenCanvas]);
</script>
</html>
worker.js
onmessage = e => {
const ctx = e.data.offscreenCanvas.getContext('2d');
ctx.fillRect(0 , 0, 100 , 100);
ctx.commit();
}
Everything is working fine here, I draw simple rectangle on the canvas. Now - how to pass additional information with postMessage? For example - is it possible to send object with rectangle coordinates?
Like
const obj = {
x: 0,
y: 0,
}
I tried to use transferable objects by creating new Int8Array:
const bufferObj = new Int8Array([obj.x, obj.y]);
To be honest I don't know how to send it to worker and read it from the event object. I was thinking about
worker.postMessage(offscreenCanvas, bufferObj, [offscreenCanvas, bufferObj]);
But this throw an error Value at index 1 does not have a transferable type. Any idea how to solve this?
First, if you don't need to transfer the ownership of the object, but just send it to the worker, you can do that:
const obj = {
x: 0,
y: 0,
}
worker.postMessage({offscreenCanvas, obj}, [offscreenCanvas]);
And then just access from the worker to e.data.obj
without issues. For simple object I would say it's not a major issue, since postMessage
use Structured clone algorithm
However, if you need optimization, and you pass a large amount of data – as an offscreen canvas – you want to transfer the object on the other side instead.
In such case, your error was using a Typed Array
that does not implement a Transferable
interface. You have, instead, to pass the ArrayBuffer
. For example:
const buff = new Uint8Array([obj.x, obj.y]).buffer;
worker.postMessage({offscreenCanvas, buff}, [offscreenCanvas, buff]);
That should works.