We interrupt an article on Canvas animation and performance optimization to lay a foundation for us to better enter the world of WebGL.
The content of this article may be a little difficult to understand, I hope you have any questions. Let’s get down to business without further ado.
1. Actual animation
First introduce the animation content we want to achieve: the source of the meteor in the night sky.
Today I will share with you how to write canvas animation and how to optimize.
1.1 Setup Page
Canvas page composition is very simple. As follows:
<! DOCTYPEhtml>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Canvas animation and performance optimization</title>
<! -- Introduce page styles -->
<link rel="stylesheet" href="./style/index.css">
</head>
<body>
<canvas id="shooting-star">Your browser does not support the Canvas tag, please upgrade or choose another browser</canvas>
</body>
</html>
<! -- Introducing page functionality -->
<script src="./js/index.js"></script>
Copy the code
Create an HTML file and import CSS and JS files.
There is a problem here, as we shared earlier, that the width and height of the canvas tag must be set in HTML. But to fit our screen, we use JS to set the width and height of the canvas.
1.2 Concrete Implementation
1. First create a meteor class. And add a startup method
class ShootingStar{
// constructor
constructor() {}
// Start method
start(){}}// Instantiate an object and start it
new ShootingStar().start();
Copy the code
2. Get tocanvas
Object and drawing context, and setcanvas
The width and height of
Note: The width and height are set here because the canvas will appear blurred.
// constructor
constructor() {
// Get the canvas object
this.ctx = document.getElementById('id name');
// Get the drawing context
this.c = this.ctx.getContext('2d');
// Get the width of the current page
this.maxW = document.body.offsetWidth;
this.maxH = document.body.offsetHeight;
// Define an array of stars in the night sky, which will be used later in the development
this.skyList = [];
}
// Initialize the width and height of the canvas
initCanvasSize() {
this.ctx.width = this.maxW;
this.ctx.height = this.maxH;
}
// Call the initialization function in the start method
start() {
this.initCanvasSize();
}
Copy the code
3. Paint the background
Here we did not introduce the picture, is to simulate the effect of a starry sky, slightly simple.
// Draw the background
drawBackground() {
// Number of stars in the night sky
const maxCount = 500;
// Create a solid black background
this.c.fillRect(0.0.this.ctx.width, this.ctx.height);
// Create random coordinates. Random within the current page
for (let i = 0; i < maxCount; i++) {
const r = ~~(Math.random() * 3);
const x = ~~(Math.random() * this.maxW);
const y = ~~(Math.random() * this.maxH);
// Push the random coordinates into the array
this.skyList.push({
x,y,r
})
}
}
Copy the code
4. Enable meteor mode
// Initialize the background and start drawing the meteor again
initBackground() {
this.c.beginPath();
this.c.fillStyle = 'rgba (0,0,0,0.2)';
// Empty the current canvas
this.c.rect(0.0.this.maxW, this.maxH);
this.c.fill();
// Redraw the background
this.drawStarList();
// Start drawing the meteor again
this.startShootingStar();
}
// Draw a meteor
drawStar(x, y) {
this.drawStarList()
this.c.beginPath();
this.c.fillStyle = 'white';
this.c.arc(x,y,2.0.Math.PI * 2);
this.c.fill();
}
// Add a trailing effect
drawCover() {
this.c.beginPath();
this.c.fillStyle = 'rgba (0,0,0,0.06)';
this.c.rect(0.0.this.ctx.width,this.ctx.height);
this.c.fill();
}
// Enable meteor mode
startShootingStar() {
// Set the speed of x and y
let x = ~~(Math.random() * this.maxW);
let y = 4;
// Set the color of the meteor.
this.c.fillStyle = 'darkorange';
// Get the maximum distance a meteor can fall. It disappears at this distance
const clearY = Math.random() * this.maxH;
// Draw the function.
const draw = () = > {
x -= 1;
y += 4;
// If the current slide distance is greater than the maximum distance, initialize the current background.
if (y >= clearY) {
this.initBackground();
return;
}
// Draw a meteor, passing in the current x and y coordinates
this.drawStar(x, y);
// This function is used to make the meteor have a trailing effect.
this.drawCover();
// Use this function to animate
requestAnimationFrame(draw);
}
draw()
}
Copy the code
Here animation combat part of the content is shared, interested students can view the source code, you can also try to achieve the following.
2. Performance optimization
2.1 Use calculations instead of frequent rendering
Instead of frequent canvas rendering, calculations are often used during rendering. The principle is similar to DOM backflow. Because canvas is also part of DOM, too many operations will affect performance. Of course, if you use an algorithm that is particularly expensive to implement, it’s a different story.
2.2 use requestAnimationFrame
In many cases, we are used to using setInterval and setTimeout to animate pages. There are also many friends who find this implementation will lose frames. There are two reasons:
SetInterval and setTimeout
Depending on the browser’s asynchronous loop, the animation execution time we set may not be the actual animation execution time, perhaps at this timeJs engine
Other code is being executed, so you lose frames.- Refresh frequency depends on screen resolution and screen size. The screen refresh rate may vary from device to device.
For both of these, we used requestAnimationFrame to optimize the animation implementation. It has two distinct advantages over the former
- It is up to the system to decide when the callback is executed, and the browser optimizes the method invocation during execution.
- Redraw by frame, pass
requestAnimationFrame
The interval between page redrawing or rewinding caused by callbacks is the same as the interval between display refresh. sorequestAnimationFrame
Don’t need to likesetTimeout
Instead, the browser picks up and uses the display refresh frequency from the system
2.3 Off-screen rendering
Off-screen rendering can be understood as creating an alternate canvas but not displaying it on the page, performing pre-rendering operations. This operation uses the drawImage method, whose first argument can take either a picture object or a Canvas object.
Concrete implementation:
Process the content to be manipulated on the off-screen canvas first, and then use the drawImage method to put it into the display layer.
2.4 Layered Canvas
It is also a way of using multiple canvas to separate render static content and content requiring frequent calculation. The more complex the scene, the more suitable to use this method. The concrete implementation is as follows
Schematic diagram:
This way we can break down our requirements into modules. Break out the content that needs to be drawn frequently to reduce the performance cost.
The performance optimization approach is mainly a number of daily attention points and split methods, not a panacea.
In the animation implementation of canvas, algorithm also occupies a large part. For example, particle operation in Canvas often involves tens of thousands of pixels. Improper use of algorithm may cause great problems.
Well, that’s all for today’s sharing, an impromptu piece of content. Next we will share webGL content, if you are interested in it, don’t miss it. Bye~