Small knowledge, big challenge! This article is participating in the creation activity of essential knowledge for programmers. This article also participates in the “Diggin Star Project” to win the creation gift package and challenge the creation incentive money

preface

Hello, everyone, I am Fly brother, this is the third output article this month, each month four original this is my own requirements, will not live up to everyone on the front of the public number graphics like. Now, let’s move on to today’s topic: Canvas Performance optimization. After reading this article, you can learn the following:

  1. What factors affect canvas performance
  2. How to Optimize Canvas

What are the factors that affect Canvas

We all know that browsers render animations up to 60 frames per second, which means that we do 60 images per second, and that’s (1000/60) per frame. If the animation time of each frame is less than 16.7ms, the lag and frame loss will occur. In fact, Canvas is an instruction drawing system. It completes the drawing operation by drawing instructions. So it’s easy to think of two key factors:

  1. Number of graphs drawn
  2. The size of the graph to draw

It’s easy to understand, if you draw a graph in milliseconds what if you draw 10,000 graphs? It will definitely take a long time, if other operations, UI interactions, render other graphics… This results in longer rendering times. All images drawn by canvas are composed of small pixels. The pixels needed to draw a circle with radius 5 and a circle with radius 1000 must be different. So I’m going to show you a picture to make it very clear what the composition of a drawing is.

The picture

The larger the number of graphics you have, the more pixels you need, so the pixel shader has to be executed constantly.

I wrote two small demo to verify our conjecture, the paper comes zhongjue shallow, must know this to practice wow!

Number of graphs drawn

Mainly draw 100 and draw 10000 balls for comparison

Let’s look at the code first:

const canvas = document.getElementById('canvas') const ctx = canvas.getContext('2d') const WIDTH = canvas.width const HEIGHT = canvas.height function randomColor() { return ( 'rgb( ' + ((Math.random() * 255) >> 0) + ',' + ((Math.random() * 255) >> 0) + ',' + ((Math.random() * 255) >> 0) + ' )' ) } function drawCirle(radius = 10) { const x = Math.random() *  WIDTH const y = Math.random() * HEIGHT ctx.fillStyle = randomColor() ctx.beginPath() ctx.arc(x, y, radius, 0, Math.PI * 2) ctx.fill() } function draw(count = 1) { for (let i = 0; i < count; i++) { drawCirle() } } function update() { ctx.clearRect(0, 0, WIDTH, HEIGHT) draw() requestAnimationFrame(update) } requestAnimationFrame(update)Copy the code

Drawing 100

The FPS of drawing 100 balls is still stable at 30fps:

100

Drawing 10000

100

– FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS FPS Therefore, it verifies our conjecture that the performance of canvas is related to the number of graphs drawn

Command + Shift + p to search 🔍 render FPS will be found naturally.

The size of the graph to draw

Let’s check if the size of the drawing affects the FPS. I’m going to change the number of balls to 1000 and the radius to 10.

So the number of balls is 1000, and the radius is 10.

Let’s take a look at the GIF:

Oct-24-2021 20-23-40

We see that the frame rate is stable at about 30fps, and with the same number of balls, I change the radius of the ball to 200, and we look at the frame rate, and then you see that the frame rate drops a little bit. As shown in figure:

Oct-24-2021 20-24-16

In conclusion, there are two factors affecting canvas:

  1. The number of graphics first rendered
  2. The second is the size of the rendered graphics

In fact, let me analyze in depth, the number of graphics rendered in the first one is more, that is, the number of drawing instructions called is more,

The second rendering is larger because it takes longer to render a drawing

Now I’m going to start optimizing the canvas

Reduce the invocation of drawing commands

Suppose you wanted to draw a positive n distortion in a scene, which is a very common requirement and you might have inadvertently written down the following lines of code:

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() } }Copy the code

Points correspond to the points that generate polygons. 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 }Copy the code

Mainly according to a circle center, according to the number of edges generated corresponding points.

At first glance this code looks fine, generating a regular polygon. At this point I have drawn 1000 regular polygons on the page:

Before optimization

When I saw how low the FPS was, a lot of people said, “You draw a lot of graphics, I can just quietly change the code and get the FPS back to normal.

I rewrote the regular polygon method:

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() }Copy the code

Let’s take a look at the FPS at this point:

The optimized

In the first paragraph, we do drawing operation in the loop and repeat once to stoke(), which is obviously unreasonable. In the second paragraph, we directly put stoke() outside the loop, which is actually called once. Therefore, we can conclude that reducing drawing instructions can improve the performance of canvas

The last

Follow my public account “front-end graphics” for more fun and interesting graphics knowledge. “If you also love technology, like” graphics, data visualization, games “📚 and are fascinated by it, welcome to add my personal wechat (wZF582344150), will invite you to join my” visual communication learning group for programming for joy ~ “🦄. “I’m Fly”, currently working in the interactive game group of an e-commerce company. In this era of crazy and rapid iteration of Internet technology, I am glad to grow stronger with you! 😉