当前位置:网站首页>How to optimize the performance of canvas?
How to optimize the performance of canvas?
2022-07-18 13:43:00 【yc_ one thousand two hundred and twenty-four】
What is? CANVAS?
First of all canvas, Front end students may be familiar with , Take a very simple example , Screenshots of commonly used web pages 、H5 game 、 Front end dynamic effect 、 Visual chart ..., There are canvas Application scenarios of ,
The official definition :
canvas yes HTML5 A new label provided , ie9 Just started to support ,canvas Is a canvas with a rectangular area , It can be used JS Control each pixel to paint on it .canvas Label use JavaScript Drawing images on Web pages , It does not have drawing function .canvas There are multiple draw paths 、 rectangular 、 circular 、 Characters and methods to add images .
It's easy to see , Actually canvas The addition of this label , It gives us more ability to create amazing front-end effects . But you know he also has performance problems ?? This article will briefly talk about canvas Performance optimization .
What factors will affect canvas Performance of
canvas Several ways to optimize
We all know that animations are rendered on browsers Every second up to 60 frame , That is to say 1 We'll finish it in seconds 60 Secondary image rendering , That is, the drawing time of each frame of image is actually (1000/ 60). If the animation time in each frame is less than 16.7 ms Hot, there will be Caton 、 Frame loss . and canvas It is actually an instruction drawing system , He completes the drawing operation through drawing instructions .
influence canvas Two key factors :
The first rendering has a large number of graphics , That is, drawing instructions are called more times ,
The second rendered figure is large , It takes a long time to render a drawing
Optimize canvas
Reduce the call of drawing instructions
How to understand this sentence , Suppose you want to draw right in the scene n deformation , This is a For common requirements, you may write the following lines of code without paying attention :
function drawAnyShape(points) {
for(let i=0; i<points.length; i++) {
const p1 = points[i]
const p2 = i=== points.length - 1 ? points[0] : points[i+1]
ctx.fillStyle = 'black'
ctx.beginPath();
ctx.moveTo(...p1)
ctx.lineTo(...p2)
ctx.closePath();
ctx.stroke()
}
}
points The corresponding point of generating polygon , The code is as follows :
function generatePolygon(x,y,r, edges = 3) {
const points = []
const detla = 2* Math.PI / edges;
for(let i= 0;i<edges;i++) {
const theta = i * detla;
points.push([x+ r * Math.sin(theta), y + r * Math.cos(theta)])
}
return points
}
Look at this fps Low like this , Many people say at this time , You draw a lot of graphics , Then I just need to quietly change the code , You can make fps Return to normal
Rewrite the method of regular polygon :
function drawAnyShape2(points) {
ctx.beginPath();
ctx.moveTo(...points[0]);
ctx.fillStyle = 'black'
for(let i=1; i<points.length; i++) {
ctx.lineTo(...points[i])
}
ctx.closePath();
ctx.stroke()
}
Looked at the fps Has successfully risen to 30fps, Why is that , In the first paragraph, we do the drawing operation in the loop , Cycle time , stoke() once , This is clearly unreasonable , The second one directly put stoke() , Put it out of the loop , In fact, it was called once , So we can conclude that reducing drawing instructions can improve canvas Performance of
Layered rendering
Why layered rendering is needed , In the game , Suppose the character keeps moving , However, the background may add a lot of fancy elements , But every time I update , The scene itself is unchanged , Only the characters keep moving , If each frame is redrawn again, it will cause a waste of performance , At this time canvas And that's what happened Let's look at the next picture first, and you may understand .
I passed 3 individual canvas Fold together , By setting each canvas Of z-index Reached 3 The illusion that two canvases are still on the same layer , So I'm here requestAnimation in , Only need to Just redraw the moving graphics , The rest is still standing still .
Pseudo code
<canvas id="backgroundCanvas" />
<canvas id="peopleActionCanvas" />
const peopleActionCanvas = document.getElementById('peopleActionCanvas');
const backgroundCanvas = document.getElementById('backgroundCanvas');
function draw(){
drawPeopleAction(peopleActionCanvas);
if (needDrawBackground) {
drawBackground(backgroundCanvas);
}
requestAnimationFrame(draw);
}
A background layer, a motion layer , In the abstract , When should we do layering , If the canvas is purely static, there is no need to do layering , If there are static and dynamic , You can put the logic layer at the top , Then the display layer Put it at the bottom to realize the so-called Layered rendering , But it's best to keep 3-5 individual .
Local rendering
Local rendering is actually calling canvas Of clip Method . Official documents MDN The use of this method
**CanvasRenderingContext2D**.clip() yes Canvas 2D API The method of setting the currently created path as the current cutting path
How to use canvas Draw a picture 1/4 round .
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'red'
ctx.arc(100, 100, 75, 0, Math.PI*2, false);
//ctx.clip();
ctx.fillRect(0, 0, 100,100);
When filling here of no avail clip The picture should be a rectangle .
At this time I put clip Note to solve , The rectangle becomes a semicircle . therefore clip This api combination fillRect fill Is to fill any graphics path .
canvas In the picture 1000 Circles , If you change only one color , The others 999 It's all the same This waste is definitely a performance problem , If you are doing animation effects, you can imagine , The frame loss is very serious . Here we can use the above api
The correct way is to do local refresh :
Determine the bounding box of the changed element ( Whether there is an intersection )
Draw the path then clip
Finally, redraw the changed figure
clip() Determine the clipping region of the drawing , Graphics outside the area cannot be drawn , View details CanvasRenderingContext2D.clip() clearRect(x, y, width, height) Erases the color inside the specified rectangle , see CanvasRenderingContext2D.clearRect()
Bounding box
Use a box to surround the figure , In fact, in geometry, we call it bounding box Or is it boundingBox. It can be used to quickly detect whether two figures intersect , But it's still not accurate enough . It's better to use graphic algorithm to solve . Or collision detection in the game , All have this concept . What is discussed here is 2d Of boudingbox, It's a little bit easier .
The dotted box is actually boundingBox, In fact, according to the size of the graph , Calculate a rectangular border . We know the theory , Mapping to the code hierarchy , How can we express it ? Here we take you to the native implementation bound2d class , In fact, each of them 2d graphics , Can be realized . because 2d Graphics are made up of points , So just get the discrete point set of each graph , Then for these points , To get a 2d Spatial boundBox.
Off screen CANVAS and WEBWORKER
Let's start with What is off screen canvas???
OffscreenCanvas Provides an off screen rendering of canvas object . It's in the window environment and web worker The environment is effective .
Off screen rendering canvas object , Is this really useful when we actually write animation ???
Imagine the following scenario : If you find yourself repeating some of the same painting operations on each animation frame , Please consider diverting it to the canvas outside the screen . then , You can render off screen images to the main canvas as often as you need , It is not necessary to repeat the step of generating the image first . Because the browser is single threaded ,canvas The calculation and rendering are actually in the same thread . This will lead to ( Sometimes it takes time ) The calculation operation of will result in App Carton , Reduce the user experience .
Fortunately, , OffscreenCanvas Off screen Canvas It can solve this problem very well !
up to now ,canvas All the drawing functions are similar to <canvas> Tags are bound together , It means canvas API and DOM It's coupled . and OffscreenCanvas, Just like its name , By way of Canvas Move out of the screen to decouple DOM and canvas API.
Because of this decoupling ,OffscreenCanvas Rendering and DOM Completely separated , And more than ordinary canvas Speed increased a little , And that's just because of both (Canvas and DOM) There is no synchronization between . But more importantly , After separating the two ,canvas Will be available in Web Worker Use in , Even in Web Worker There is no DOM. This gives canvas Offers more possibilities .
This is off the screen canvas Why and why webworker The reason for this match .
How to create off screen CANVAS?
Create off screen canvas There are two ways :
One is through OffscreenCanvas The constructor of is created directly . For example, the following example code :
// Off screen canvas
const offscreen = new OffscreenCanvas(200, 200);
The second is to use canvas Of transferControlToOffscreen Function to get a OffscreenCanvas object , Draw the OffscreenCanvas object , It will also draw canvas object . For example, the following code :
const canvas = document.getElementById('canvas');
const offscreen = canvas.transferControlToOffscreen();
I wrote the following little demo Verify whether it is reliable
const canvas = document.getElementById('canvas');
// Off screen canvas
const offscreen1 = new OffscreenCanvas(200, 200);
const offscreen2 = canvas.transferControlToOffscreen();
console.error(offscreen1,offscreen2, '222')
Off screen canvas How to communicate with the main thread canvas Communication ?
At this time, another api transferToImageBitmap
adopt transferToImageBitmap The function can be derived from OffscreenCanvas Object to create a ImageBitmap object . This object can be used for other canvas The draw .
For example, a common use is , Put a more time-consuming drawing in web worker Under the OffscreenCanvas On the object , After drawing , Create a ImageBitmap object , And pass the object to the page side , Draw... At the end of the page ImageBitmap object .
Write a little demo Under test :
Before optimization
We draw 10000 * 10000 A rectangle to see the response and time of the page , The code is as follows :
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
function draw() {
for(let i = 0;i < 10000;i ++){
for(let j = 0;j < 1000;j ++){
ctx.fillRect(i*3,j*3,2,2);
}
}
}
draw()
ctx.arc(100,75,50,0,2*Math.PI);
ctx.stroke()
It's obvious , Before rendering the graphics , The browser is unresponsive , We can't do approval . Such a user experience must be very poor .
After optimization
We use off screen canvas + webworker To optimize , The code is as follows :
Let's take a look first worker Code for :
let offscreen,ctx;
// Monitor the information sent by the main process
onmessage = function (e) {
if(e.data.msg == 'init'){
init();
draw();
}
}
function init() {
offscreen = new OffscreenCanvas(512, 512);
ctx = offscreen.getContext("2d");
}
// Drawing graphics
function draw() {
ctx.clearRect(0,0,offscreen.width,offscreen.height);
for(var i = 0;i < 10000;i ++){
for(var j = 0;j < 1000;j ++){
ctx.fillRect(i*3,j*3,2,2);
}
}
const imageBitmap = offscreen.transferToImageBitmap();
// To the main thread
postMessage({imageBitmap:imageBitmap},[imageBitmap]);
}
Look at the code of the main thread :
const worker = new Worker('./worker.js')
worker.postMessage({msg:'init'});
worker.onmessage = function (e) {
// Here we receive work From the screen canvas Bitmap
ctx.drawImage(e.data.imageBitmap,0,0);
}
ctx.arc(100,75,50,0,2*Math.PI);
ctx.stroke()
Compare two obvious changes , Drawing multiple rectangles is a very time-consuming operation, which will affect the rendering of other graphics , Off screen can be used canvas + webworker To solve this loss of response .
summary
The number and size of graphics drawn will affect canvas Performance of
Too many graphics , But only refresh part You can use partial rendering
The logical layer is separated from the background layer You can use layered rendering
Some long-time logic affects the main thread , You can use off screen rendering and webworker To solve the problem 边栏推荐
- Common protocols of tcp/ip
- DSP core class library Net version degradation
- 解决Filter中获取body内容报错,getReader() has already been called for this request
- [TinyML]NetAug:Network Augmentation for Tiny Deep Learning
- Dpr-34, AC220V double position relay
- Guess the size of the number ii[what problem does dynamic planning solve?]
- Opencvsharp (C openCV) pointer method reads and modifies image pixel values (with source code)
- Dynamic cool 404 page source code
- 6、 JMeter timer
- 【luogu AT2230】Water Distribution(状压DP)(最小生成树)
猜你喜欢

Hcip first day study -- Review HCIA (static)

Software testing zero basic testing - Basic Concepts

Excel, how to choose the right chart?

Dual position relay dls-5/1

Status of the process

递归求解二叉树的遍历(常考基础例题)

Exploratory software testing
![[TinyML]NetAug:Network Augmentation for Tiny Deep Learning](/img/b4/e4d6d2394b6e1ad7bcfdc9ae984913.png)
[TinyML]NetAug:Network Augmentation for Tiny Deep Learning

Research progress of transfer learning in medical image classification

Sword finger offer 50 The first character that appears only once
随机推荐
7.15 Résumé du concours de simulation
Hcip the next day
Practice Guide for peanut shell inner net penetration
Task-Customized Self-Supervised Pre-training with Scalable Dynamic Routing
312312dd
[step on the pit] resurrect Pico go
Status of the process
Automatically download when node requests a page
Research progress of transfer learning in medical image classification
03_ Case setup [resttemplate calls microservices]
OpenCV:05滤波器
Qimage image format summary
Low power test scheme of jishili multimeter
单细胞论文记录(part15)--Integrated analysis of multimodal single-cell data
MulterError: Unexpected field
Dls-42/4-4 dc110v double position relay
DzzOffice_ Flowplayer player changes
Expert routine of BW conversion based on AMDP
Analysis of JSON operation examples in golang
基本的unix域协议编程