Page 1 of 3 OffscreenCanvas is relatively new but it can make your graphics smooth without blocking the UI thread. In this extract from a chapter in my new book on JavaScript Graphics we look at how it works.
Now available as a paperback or ebook from Amazon.
JavaScript Bitmap Graphics With Canvas
Contents
- JavaScript Graphics
- Getting Started With Canvas
- Drawing Paths
Extract: Basic Paths Extract: SVG Paths Extract: Bezier Curves
- Stroke and Fill
Extract: Stroke Properties Extract: Fill and Holes Extract: Gradient & Pattern Fills
- Transformations
Extract: Transformations Extract: Custom Coordinates Extract Graphics State
- Text
Extract: Text, Typography & SVG Extract: Unicode
- Clipping, Compositing and Effects
Extract: Clipping & Basic Compositing
- Generating Bitmaps
Extract: Introduction To Bitmaps Extract : Animation
- WebWorkers & OffscreenCanvas
Extract: Web Workers Extract: OffscreenCanvas
- Bit Manipulation In JavaScript
Extract: Bit Manipulation
- Typed Arrays
Extract: Typed Arrays
- Files, blobs, URLs & Fetch
Extract: Blobs & Files Extract: Read/Writing Local Files Extract: Fetch API **NEW!
- Image Processing
Extract: ImageData Extract:The Filter API
- 3D WebGL
Extract: WebGL 3D
- 2D WebGL
Extract: WebGL Convolutions
<ASIN:B07XJQDS4Z>
<ASIN:1871962579>
<ASIN:1871962560>
Even if you can make your animation run fast enough, you still have the problem of the pauses that occur whenever the UI thread has to deal with something else. There are situations when your animation can freeze for a considerable time. The solution is to move the animation from the UI thread to a different thread.
Until recently there was no way that a JavaScript programmer could take advantage of the OS to schedule threads or multiple cores to implement true parallelism, but now we have web workers which implement background processing on a non-UI thread. The only problem is that a web worker cannot access the DOM and the canvas object is part of the DOM. To make it possible to implement graphics processing off the UI thread, the OffscreenCanvas object was introduced. It is still reasonably new and at the time of writing Chrome is the only browser to fully support it. While supported in Firefox, it is disabled by default and you need to set a flag to enable it, and even then it only supports the WebGL graphics context.
It is worth making clear that while OffscreenCanvas has been introduced as something to make animation smoother, almost any intensive graphics operation is better implemented as a web worker. Indeed any intensive operation of any kind is best implemented in this way.
Before we look at how to use OffscreenCanvas we need to find out the basics of using a web worker. This is explained in detail in the chapter but here is a summary:
-
Communication between the UI and worker thread is via events fired by one thread and received by the other.
-
Each thread only processes events when not occupied with running code.
-
This means that events may not be dealt with promptly.
-
Data can be transferred between threads using the event object that is made available to the event handler.
-
Data is not shared – a copy is made for the receiving thread.
-
The UI thread is generally set up to respond to events promptly, but the worker thread isn’t.
-
A graphics-oriented worker thread is the exception to the rule as it generally gives up its thread with each call to requestAnimationFrame.
Sections in book but not in this extract:
- Basic Web Worker
- The Trouble With Threads
- Basic Communication Methods
- UI Thread to Worker Thread
- Worker Thread to UI Thread
- Transferable Objects
OffscreenCanvas
An OffscreenCanvas is a canvas object that isn’t part of the screen display. It is simply an area of memory that you can draw into using all of the familiar methods. The fact that it isn’t part of the display, and isn’t part of the DOM, means that it can be used from the UI thread and from a worker thread. When used from the UI thread it behaves a lot like a canvas object that you haven’t added to the DOM, but it also has some additional methods.
You create an OffscreenCanvas object using:
var offCanvas=new OffscreenCanvas(width,height);
Notice that as this is not part of the DOM it doesn’t have a style width and height like a canvas object. It does have width and height properties, however. It also has a getContext method that you can use to draw on it and a pair of new methods:
-
convertToBlob() converts the image to a binary blob using the format of any of the supported graphics file types – jpg, png. For lossy compression you can also specify a quality parameter.
-
transferToImageBitmap() returns an ImageBitmap object based on the current contents of the OffscreenCanvas.
OffscreenCanvas in the UI Thread
As already mentioned, you can use an OffscreenCanvas wherever you would otherwise use a canvas object not added to the DOM and, as long as you are only targeting browsers that support OffscreenCanvas, it is sensible to use it instead. However, at the time of writing only Chrome supports it in the 2d context.
For example, the bitmap for the ball in the example at the end of the previous chapter can be created using, in the main program;
var ctx2 = new OffscreenCanvas(40, 40).getContext("2d");
var path = new Path2D();
var r = 20;
path.arc(20, 20, r, 0, 2 * Math.PI);
ctx2.fill(path);
And to make this visible you simply use, in render:
ctx.drawImage(ctx2.canvas, this.pos.x - r, this.pos.y – r);
which is exactly how you would do it with a standard canvas object.
You can see the complete modified program at www.iopress.info.
Alternatively you could create an ImageBitmap and use it in place of the canvas:
var ballImage=ctx2.canvas.transferToImageBitmap();
You would then render the ball using:
ctx.drawImage(ballImage, this.pos.x - r, this.pos.y – r);
which is in principle faster.
|