Canvas technology sharing

Introduction to canvas

Before learning a new technology, understanding the historical development and causes of this technology will help us understand this technology more deeply.

Historically, canvas was first proposed by Apple Inc. to create a control panel component in Mac OS X webkit. Before canvas was called HTML draft and standard, we used some alternative methods to draw, such as being criticized. Flash, and very powerful SVG (Scalable Vector Graphics, scalable vector markup), and VML (Vector Markup Language, vector markup) that can only be used in IE (IE 5.0 and above). Even some front-ends can use div + css to complete the drawing.

In general, when there is no canvas, drawing graphics in the browser is more complicated, and after the appearance of the canvas, drawing 2D graphics is relatively easy.

NOTE: Use div to draw some simple graphics, such as rectangle, circle, triangle, trapezoid, but it is not so complicated.

But canvas also has disadvantages. Because it is a canvas with the nature of the relevant resolution of digital pictures of cloth , it is doomed in different resolutions, when the content of the drawing canvas display will be different. In addition, the content canvas drawing does not belong to any DOM element , the element browser viewer can not find that they can not detect a mouse click on a canvas in which content, it is clear that these two aspects, are not as good as SVG canvas of.

For example: if you use CSS to set the size of the canvas element, it may cause the drawn graphics to become distorted, such as rectangular to square, circular to ellipse, etc. This is because the canvas size and the element size are different It will automatically adapt to the size of the element. If the two are proportional, the canvas will be scaled proportionally without distortion.

In this way, canvas has such obvious shortcomings, is it better to use SVG directly?

No, have you heard a word? There is no perfect solution, only suitable.

SVG is based on XML, then it means that the elements in SVG can be regarded as DOM elements , and DOM operation can be enabled. At the same time, each drawn image in SVG is regarded as an object. If the properties of SVG objects change, the browser will Reproduce graphics automatically.

The above are the advantages of SVG, but through this advantage, we can also find some problems:

  1. Usually, applications that overuse DOM will become very slow, so complex SVG will cause slow rendering. But for applications like maps, SVG is the first choice.
  2. Browser rearrangement occurs when the browser window changes, element size position changes, font changes, and so on.
  3. Even if DOM operations can be enabled, the cost of DOM operations is still relatively expensive (DOM and JS are implemented separately).

Back to the topic.

2D graphics canvas is drawn through JavaScript, and <canvas>the label itself is not drawing any power, it is just a container. When drawing, the canvas is rendered pixel by pixel. Once the graphics are drawn, the element is no longer concerned by the browser (the script is finished, and the drawn graphics are not part of the DOM).

It is worth noting that the HTML standard ( whatwg standard ) clearly states: Authors should not use the canvaselement in a document when a more suitable element is available. Therefore, do not abuse the element.

canvas is now almost all browsers support, but previous versions of IE 9.0 does not support canvaselements

Basic use of canvas

Canvas is an HTML element, so to use canvas, you first need to:

<canvas id="canvas" width="600" height="300">

In the first line of HTML code, you can see two attributes: widthand height, it indicates the width and height of the canvas. As mentioned above, do n’t use CSS to specify the size, because when the proportion of CSS and the size of the canvas is inconsistent Unable to scale proportionally, resulting in distorted graphics. When the canvas size is not set, the canvas will be initialized to a 300px * 150px canvas by default.

"The current browser does not support canvas" is the content of the element, but it is only used as a fallback content (ie, fallback content ). This content will be displayed only when the browser does not support canvas.

The canvas element itself has no drawing ability, but only serves as a container, so it needs to be drawn through a script such as JavaScript:

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');

The above HTML + JS code is necessary to use canvas, no matter what content to draw, these few lines of code are indispensable.

getContext()It is a method provided by the canvas element to get the drawing context (or the rendering context). It has only one parameter: the context format. Passing in here 2dmeans getting 2D image drawing environment. Since it getContextis a method provided by the canvas element, we can getContextcheck the support of the browser by detecting the existence of the method.

The type of context variable is CanvasRenderingContext2D.

The rendering context is not easy to understand, it can be understood as a brush for drawing.

How to determine the drawing position on the canvas? Is the coordinates.

In canvas, the upper left corner of the canvas is the origin, the horizontal axis is the x-axis for width, and the vertical axis is the y-axis for height [^ 1]. The position of the origin can be moved. We will not consider the movement of the origin for the time being.

In w3c school , the drawing API provided by canvas is roughly divided into the following types [^ 2]:

  1. Color, style, shadow
  2. Line style
  3. rectangle
  4. path
  5. Convert
  6. text
  7. Image rendering
  8. Pixel operation
  9. synthesis
  10. other

Canvas combination example

In the above example, it contains rectangles, circles, lines, text, and "text". In detail, it will involve many APIs, which will make this article very long, and it is not necessary. It is worth one. Mentioned is the Bezier curve, which is the mathematical curve of the two-dimensional graphics application. The general vector graphics software uses it to accurately draw the curve. The Bezier curve is a very important parameter curve in computer graphics [^ 3].

First order bezier curve

Quadratic bezier curve

Cubic bezier curve

The above pictures are first order Bezier curve, second order Bezier curve and third order Bezier curve in order. From the figure, it can be clearly seen that the one-time Bezier curve is actually a straight line. Of course, there are higher-order curves, but canvas only provides quadratic and cubic Bezier curves.

Take the API of the quadratic Bezier curve as an example:

quadraticCurveTo(cp1x, cp1y, x, y);

(cp1x, cp1y) represents the control point coordinates, (x, y) represents the end point coordinates. There is still a starting point coordinate missing, assuming it is (x0, y0), who is this (x0, y0)?

Is calling quadraticCurveToa function, context in which the coordinates (drawing context). for example:

var cxt = canvas.getContext('2d'); // 认为canvas已经获取到
cxt.moveTo(120, 90);
cxt.quadraticCurveTo(130, 80, 130, 70);
cxt.quadraticCurveTo(115, 70, 115, 50);
cxt.quadraticCurveTo(115, 30, 155, 30);
cxt.quadraticCurveTo(195, 30, 195, 50);
cxt.quadraticCurveTo(195, 70, 155, 70);
cxt.quadraticCurveTo(135, 90, 120, 90);

The result of running this code is a dialog box (represented in the first picture). As you can see, before calling the quadratic Bezier curve, we set the starting point, that is, move the brush to the coordinates (120, 90 ), In subsequent calls, the end point of the previous Bezier curve is used as the starting point of this curve.

At this time, some people may ask: Can I moveTonot draw if I remove this call? If the subsequent lineTofunction is called , it really can't be drawn. But don't forget, there is another Bezier curve, this is a straight line, he is a straight line with (cp1x, cp1y) as the starting point and (x, y) as the ending point. So, moveToafter removing it, it will only affect the drawing of the first curve. But if you delete the last line of code stroke(), you wo n’t see anything on the browser when the program ends.

From this, we should think about another question: Why is a stroke()function necessary?

In fact, canvas is a state-based drawing. According to this, the APIs provided by canvas can be divided into two types: state setting and specific drawing.

stroke(), fill()Etc. The function is to draw the content to the canvas canvas container.

arc(), lineTo(), rect()And other functions is provided a function of the state of the brush.

In that fantasy type movie or TV series, you can often see a Taoist void symbol. After drawing, push it forward and it will be printed on the corresponding symbol or person.

Taoist void symbol, this process is like the process of setting the brush state of canvas.

Push forward, this is the specific drawing, we don't know how to draw, anyway, this symbol is drawn. (Mentioned before, canvas is a pixel by pixel rendering of)

"Text" drawing, please note that this text is quoted, ordinary text, we only need to call the drawing fillText(), and the text here refers to the dot matrix font , in programs such as single-chip or LCD, by lighting A series of dots display text or patterns. The lighting process is more complicated. It can be simply understood that the pixel on the LCD is lit when the pixel is set to 1, and it is not lit when it is 0 (the actual may be the opposite). Then the "text" drawing in canvas is the same. By establishing a font library corresponding to the text, when a certain text needs to be drawn, find the corresponding text dot matrix in the font library, and then mark the dot matrix as 1. The position is lit (filled).

In actual operation, it may not be so simple to light up. You may want to make cooler content, fill it with a circle, fill it with a rectangle, or even say that you want to create a dynamic explosion effect. To some other calculations.

Rectangle fill

The picture above is an example filled with rectangles, the numbers correspond to 8x8 dot matrix.

Advanced animation of canvas

Let ’s think about a problem first. Suppose now that we have learned how to draw a circle. Now we need to make an animation related to physics: flat throw motion.

How to achieve it now?

When you may see this problem, some people are suddenly confused: I learned a function to draw a circle, and you let me simulate such a difficult animation. You clearly want to murder Zheng!

Some people may think that the flat-throw motion, learned in high school physics, is basically just a problem of a small ball. In a two-dimensional plane, this small ball can be regarded as a circle. Just a circle?

After this, we continue to think down, assuming that the ball in the horizontal throw motion has an initial velocity v0 in the horizontal direction, except gravity, it is not affected by other external forces, that is, there is a gravity acceleration g (for simplicity of calculation, we It can be simply set as g = 10m/s^2), and there is no initial velocity vh (or called vh = 0;) in the vertical direction , as shown below:

Flat throw

From the picture, we can see some very interesting phenomena, such as: the horizontal direction of the ball is exactly the same as the horizontal axis of the canvas, and the vertical direction is also consistent with the vertical axis.

Then the physical formula corresponding to the flat throw motion:

// 竖直方向无初速度,水平方向没有外力
x = v0 * t; // 水平方向位移
h = 1/2 * g * t * t; // 竖直方向位移

// 竖直方向有初速度
h = vh * t - 1/2 * g * t * t; // 竖直方向位移

It is found that the coordinates (x, h) and canvas (x, y) are the same, and we are not doing physics problems, that is, the parameters v0, t, g, vh are known, our only What needs to be done is to calculate the (x, h) at any time, that is, the coordinates (x, y) of the ball on the canvas.

At the end of the analysis, we can now get the position coordinates of the ball at any time, then we can also draw the ball at any time on the canvas.

According to the above analysis, some people may say: You are wrong, you should be special. The ball is not necessarily thrown from the left, it can also be thrown from the right, or upward.

Indeed, the above analysis just took out one of the more special states to study, limited to space (and the topic of this article is canvas rather than physics), and did not generalize to more general conclusions, but in fact, these analyses are enough, whether it is displacement Or speed, he is a vector, with a direction, then we may wish to stipulate: take the coordinate axis of the canvas, the direction in which the value increases is the positive direction, then throw it from the right, it can be regarded as the reverse direction, which can be expressed as -v0, and finally through the calculation The formula of displacement can get the correct coordinates (but this time it is more troublesome to calculate the coordinate x, you can not use the above formula directly).

I have analyzed so much and said that we are most concerned about the realization.

In the previous analysis, we know that if we want to find the location coordinates of the ball at any time, the required parameters are: v0, t, g, vh. Where should these parameters be stored? How to design this data structure?

Of course, we can directly set these parameters as global variables, but this is obviously not suitable. Among these parameters, the only suitable setting for global variables is the acceleration of gravity g. And v0, t, vh should be the "properties" of the ball itself, so we should abstract it into a class.

function Ball(r, v0, vh, t) {
    this.r = r;
    this.v0 = v0;
    this.vh = vh;
    this.t = t;
    this.x = 0;
    this.h = 0;

    this.calcX = function() { /* 计算水平位移 */ }
    this.calcH = function() { /* 计算竖直位移 */ }

var ball = { x: 0, h: 0, r: 10, v0: 0, vh: 0, g: 10};
// 重力加速度无论是作为全局变量还是小球属性,均可

// es6之后
class Ball {

Each of the above three methods has its own advantages. Just choose a suitable method.

"You say that I have a big head in physics. Is there any simpler?"

It ’s even simpler. Anyway, it does n’t require 100% reduction of physics scenes:

var ball = { x: 0, y: 0, r: 10, vx: 5, vy: 0, g: 5 };
setInterval(() => {
    ball.vy += ball.g; // 竖直方向速度增加
    ball.y += ball.vy; // 竖直方向位移
    ball.x += ball.vx; // 水平方向位移
    cxt.clearRect(0, 0, 800, 300);
    cxt.fillStyle = 'black';
    cxt.arc(ball.x, ball.y, ball.r, 0, 2*Math.PI);
}, 50);

OK, it's over.

This is a bit more advanced animation. May be learning a few functions, this animation will be more dazzling. For example, after learning rectangular filling and mastering a little bit of rgba knowledge, you can make a "tail" out, that is, the long tail effect. Specifically, just replace the above code cxt.clearRect()with:

cxt.fillStyle = 'rgba(255, 255, 255, 0.2)';
cxt.fillRect(0, 0, 800, 300);

This can make us look like our coding is very powerful.

It's still not satisfying to do this step: the ball falls down vigorously, and the animation will disappear after a while.

It doesn't matter, we can do " collision detection ". It seems to be a taller vocabulary, but in fact there is nothing taller. If based on the analysis in the first part of this section, then we have to consider the momentum loss caused by the collision, which is quite complicated.

But the simplified version is easy to say. The ball hits the upper / lower boundary, the speed in the vertical direction is reversed, and the speed is halved. The left and right borders can be treated similarly.

if (ball.r + ball.x > canvas_width) {
    ball.vx *= -0.5
if (ball.r + ball.y > canvas_height) {
    ball.vy *= -0.5;

NOTE: Collision detection refers to " boundary detection " here. It is obviously meaningless to continue falling when the ball falls to the border, because we cannot see the animation behind. So either stop when it hits the boundary, or start again, or do other processing. In short, no meaningless animation can appear.

Like the greedy snakes you played before, there will be various walls. When the controlled snake touches the wall, the game will fail, or when there is no wall, the snake will come out from the other direction.


Having said so much, you will find that this article not only does not directly list different DEMOs to introduce functions, but also tries to avoid introducing too many APIs in canvas.

Personally, canvas is actually a function library. It is no different from what we usually use forEach, splice, split, map, reduce. They are packaged and used directly. Check the function manual to understand the usage. , More familiar with it a few times.

When I first entered the university, the professional teacher told us that program = algorithm + data structure. Even now, many people are emphasizing this point. If you have the heart, think back to the previous section. When analyzing the flat toss movement, I am essentially considering the algorithm; when designing the ball class, I am considering object-oriented, but more is considering the data The structure problem, after considering these contents, I began to realize the concrete.

Reference materials:

[^ 1]: MDN document
[^ 2]: HTML 5 Canvas Reference Manual

This article was first published on a personal blog . Welcome to ^-^.
Sweep and make a little progress every day ~

Guess you like