Angular | Web Staff | chart.js
How to use OffscreenCanvas to draw charts from within a web worker
In our previous articleIn this article, we talked about web workers in Angular. We presented some of the benefits and drawbacks of using one. We even got a chance to see them in action in a demo application.
In this article, we will continue the study of web workers. we will use
OffscreenCanvas API for creating charts with Web Workers. In the process, we’ll highlight some of their limitations and how we can work around them.
let’s get started!
Disclaimer: As of today, Offscreen Canvas API Not supported by all browsers yet,
we will use chart.js To render our charts. So, we need to install the relevant package by running the following command in terminal:
npm install chart.js
We add a new page to our demo application. This page creates a chart based on the selected number entered through the range input element.
Respectively, we have class file. Whenever the user changes the value,
modelChange method is called. this method passes
updateDataLength method of
DataService (line 13).
We don’t have a real backend, so
DataService Simulates data generation and fetching from the API. every time
updateDataLength When called, the service generates new data.
data$ Worth watching for this service. we do it in
ngAfterViewInit Lifecycle Hook Method. We will use the generated data to do something.
As we will see, that involves using some
chartCanvas, a reference to a DOM element. We query the view using the element
ViewChild Decorator. but the view questions are set before
ngAfterViewInit So called, so the place of subscription.
On line 15, we check whether web workers are supported. If they are not, we create the chart from the main thread.
Let’s see how it looks in action.
The application “freezes” (for example, the user cannot navigate) while the chart is loading. Can web workers help with this?
Let’s review the application again, this time using Web Workers.
Web worker did the job. But now there is another problem. Note that no labels appear when hovering over the chart!
One of the main limitations of web workers is that they do not have access to the DOM. Additionally, they have limited access to methods and properties.
According to him official documentWhen using chart.js in web worker:
,[…] Chart.js plugins that use the DOM (including any mouse interaction) probably won’t work.
The good news is that we can work around these limits… but we all have to do the work.
Whoa, what’s the bad news?
The bad news is that all DOM related events will no longer work. Even resizing won’t work. So we have to work for every event we are interested in.
But first things first!
How can we create chart from within web worker itself?
Instead of giving the canvas to the web worker, we are Transferring the rendering control of the canvas, We create canvas once and then use it
OffscreenCanvas Transferable to any rendering from within the web worker.
- On lines 16-21, we are handling the rendering on the canvas. First, we initialize the web worker (line 17) and draw to the canvas for the first time (line 18). Then, we perform a subsequent redraw (line 20).
- On lines 34-40, the first draw occurs. We create the offscreen canvas (line 34) and pass it to the web worker. We also pass the offscreen canvas as a transferable (line 40).
- On lines 44-46, we manually create a canvas, add it to the DOM, and return it
- on line 50, we use
postMessageTo send new data and do a redraw.
What about the implementation of worker?
So far, the implementation of the Web Worker looks like the following:
importScripts to import charts.js, If we try to import it with normal syntax we will get compile errors. This is because of the limitations of the DOM that we talked about earlier. We also This was explained in detail in our previous article.,
Simply put, we send custom-made events to the Web Worker and inside the Web Worker declare a function to handle each event.
we send a
firstDraw In the beginning to initialize the canvas and draw the chart. then, we send
redraw event to destroy the previous chart and draw a new one on the offscreen canvas.
Rendering the chart from within the web worker had several side effects.
One of them was that the chart was no longer responsive. If we resize the browser’s window, the chart doesn’t resize with it, which can be problematic.
We can proxy the resize event and manually resize the chart.
- On line 16, we register the resize event.
- On line 23, we add an event listener
windowThing. Whenever our browser is resized, we proxy the event to a web worker to resize the chart accordingly.
Accordingly, our web worker should be able to handle the resize event. we make a
resize function and add it to the handler.
Another side effect we noticed earlier was that mouse interaction stopped working. No label was displayed when hovering over the chart.
OK, you know the drill!
We can proxy mouse events and handle them as we see fit. we modify
ChartComponent and, more specifically, its
createCanvas way. We add event listeners to the canvas
On the worker side, we add the corresponding handler functions. Here’s the code:
On lines 3-16, we handle
We identify the closest bar on the x-axis with respect to the current location of the mouse. In our case, we have two datasets. We Access each dataset’s metadata from within the chart (line 7 and 8).
Then we check if the mouse touched any of the bars nearby and programmatically display (or hide) the label (lines 9-14).
mouseenter we enable
mousemove Event handling while on
mouseleave We disable it and close any open labels. Enable/Disable is necessary to ensure that no label will remain displayed.
Disclaimer: This is just our custom implementation that will work for the vertical bar chart in this demo. Our focus is on teaching you the method, not the implementation. Hope you get the picture!
We won’t go into the details of implementation-specific helper functions, such as
You can find the complete source code This GitHub repository,
In this article it is studied how to render charts with web workers in Angular.
It is possible to render charts in the background but this has many side effects. This is due to limited access of web workers to the DOM.
We demonstrated how to work around these side effects by proxying events to a web worker. But then all the work has to be done to handle these events with your own custom implementation.
Thank you for reading. Stay tuned for more.