This time I mainly write two themes:
- Some performance tuning considerations for Canvas rendering
- The idea of canvas rendering glow effect
I recently updated mapbox-plugins with some features and examples, but I haven’t added any in a long time. Mainly to experiment with various artistic effects, our goal is to do some front-end art with the code to make the data come alive. (Some people argue that this kind of thing is too flashy. I’m just talking about decorating websites, blogs, animating tracks in visualization libraries, and extending to other application scenarios. Is there no value in creating a reasonable visual experience? !).
Canvas performance optimized by several points
1. Reduce context switches!
That’s number one. We all know that context switching is one of the most brain-taxing tasks at work. Switching from one task to another complex task can take ten minutes to review the code you’ve written before. Canvas rendering mechanism is also similar, because the configuration of renderingContext will mostly involve the vertex rendering style and chip rasterization style in the final rendering of GPU (this should be similar to WebGL). Changing styles can have significant performance overhead, especially for the following:
ctx.shadowBlur
(Blur type rendering is a particular performance drain)ctx.globalAlpha
Frequent switchingctx.strokeStyle
.ctx.fillStyle
Frequent assignments (involving parsing of color strings! Expensive!)ctx.save
和ctx.rotate
Circular combination of equal coordinate axis translation and rotation
For example, when I was making this audio visualization library, I used a lot of changes to the global transparency. The color and transparency of each dot might be different, and there might be a particle glow effect of squares in the background. 30fps is not ideal. The reason is that globalAlpha switches too many frames in a single render. And for rendering convenience, there are many shifts and rotations of the following coordinate axes in a frame. Such rendering overhead causes a large load on both CPU and GPU.
// This is done for each block particle element, which is not desirable
ctx.save();
ctx.translate(dot.x, dot.y);
ctx.rotate(dot.rotate);
ctx.rect(0.0, dot.size, dot.size);
ctx.restore();
ctx.fill();
Copy the code
As you can see in the performance figure, the ctX.Globalalpha switch alone took close to 10 milliseconds, resulting in less than 20fps on lower-end computers. Multiple toggling of globalAlpha should be avoided; at most, one or two frame calls should be sufficient
The solution is to convert the pressure of rendering to CPU calculations, such as the repeated translational rotation of just the coordinate axis, these are for the convenience of rendering (in fact, it is lazy o(╥﹏╥) O do not want to calculate a few trigg functions), but rendering is just time-consuming. It is best to get the direct render parameters by calculating them beforehand, and call the simplest rect, ARC, etc commands to render.
2. Careful shadowBlur
ShadowBlur is a performance killer. Although this configuration allows us to have a blur around our graphics elements, we should be careful with CSS styles or renderingContext that have a blur effect. In the fuzzy algorithm, the blur of one pixel requires the participation of multiple surrounding pixels, such as writing a Gaussian blur function, which has additional performance overhead.
The solution, in the absence of shadowBlur scenes, will effectively improve the frame rate of animation. The glow effect should be implemented in other ways, which will be discussed later.
3. Avoid unnecessary rendering
This last point is actually very important to look beyond the technical point of view to see which elements are completely unnecessary to render, such as tens of thousands of circles. No one can see it, and you can’t see it clearly. Rendering too many graphic elements in a screen is sometimes a false requirement, and should be nerfed.
Another technical solution is to carry out pixel interpolation for this series of data in advance in the calculation process, that is, to map to the coordinate system of canvas and map to pixels.
For example, if we have millions of data points and we put them on the screen, it doesn’t mean we have to draw millions of points. Instead, we calculate which points will fall in this pixel, and what color will that pixel take on. We actually end up rendering with a few million pixels on the screen so that we can render with less pressure, and this idea is also useful in Echarts big data rendering, and it’s often used in fluid field rendering. For example: github.com/cambecc/air here in the source code reflects the idea of pixel interpolation
Luminous effect idea
This is easy, save it for tomorrow, it’s too late to finish it. In addition, I also want to record this topic:
- The application of spatial index library in element selection and collision detection
Finally, vudio, an audio visual library enhanced before fork, has some bottlenecks and is being worked out. I hope this article can give you some inspiration.
reference
Canvas Best Practices (Performance)
Small program Canvas optimization actual combat
CSS animation and performance acceleration