preface

This article mainly summarizes some personal experience in learning canvas, hoping to provide some ideas for those who want to learn canvas or are learning canvas. The article proceeds mainly in chronological order.

The holes you step in

1. Set the canvas width and height with properties

In accordance with our usual development habits, we usually use CSS to set the width and height of canvas. Here is a circle arc(100, 70, 50, 0, math.pi * 2) drawn under 300px width and 200px height using CSS. The result is an oval shape.

The reason is that canvas is first drawn with the property width and height (default is 300*150 when not set), and then enlarged to the style width and height set by CSS after drawing, so it is equivalent to drawing the graph is scaled. There are problems with distortion and wrong proportions.
or js canvas. Width =600; canvas.height=300; Don’t write width and height in units, whatever you write in HTML will end up in px units, whereas in JS you write width and height in non-PX units will end up in 0 units.

2. Call the beginPath method to clear the drawn path

Once a path is created, it is almost never cleared until the beginPath method is called.

1. A drawn path is not cleared by a stroke call

ctx.lineWidth =20; Ctx.strokestyle = "rgba(0,255,0,0.5)" ctx.moveto (50, 70) ctx.lineto (350, 70); ctx.stroke(); ctx.lineWidth = 2; ctx.strokeStyle = "black" ctx.moveTo(50, 100) ctx.lineTo(350, 100); ctx.stroke();Copy the code

Wanting to draw two horizontal lines, the above code was written naturally in the beginning. The actual effect is shown below



You can see that on the second stroke, the black line is drawn in both places. Because the path of the stroke is not cleared after the stroke is called. In other words, paths are not disposable. So calling stroke again draws all the paths that were previously generated. This is easy to overlook, because most of the time the drawing style doesn’t change, and it’s not easy to see the effect of repeated drawing.

2. ClearRect cannot clear a path

ClearRect is a common way to clear an area of the canvas, but it does not clear the path. If you call the stroke method after clearRect, the previous path will still be drawn.

3. Canvas. width = canvas.width clears the path

Canvas. Width = canvas. Width is a technique to empty the canvas. In practice, it is found that this method is equivalent to resetting the entire canvas, not only the drawn content on the canvas is cleared, but also the path is cleared. And all properties set on the drawing context are reset to default values. The column method is intended to show that there must be another way to clear the path, but it’s not the usual way.

3. Abnormal line drawn when lineWidth is odd

Problem 1.

When the line width is odd, especially 1px, the line color and width are not normal

2. The analysis

The fundamental reason is that the minimum drawing unit of canvas is 1px and the drawing method of canvas is determined. When canvas draws a line, it takes the given path as the center, like extending on both sides, each extending half of the line width. As shown in the figure below



When drawing a line from (3,1) to (3,5) with lineWidth of 1px, start with x coordinate 3 as the center and draw 0.5px on each side, namely the dark blue part of the picture. The minimum drawing unit of canvas is 1 px, and the current drawing is 2.5-3.5 area, so 2-2.5 area must also be drawn. As a result, 2-3 pixel area will be evenly allocated with the given color value, and the color will be pale visually. Same thing with region 3-4. So the final width changed from 1 px to 2 px.

Why is it so obvious when the line width is 1 px? The second reason is that when you draw a 1px line, the color value of the entire line fades, while when you draw a 3px or wider line, only the half pixel at the edge expands and fades, and the middle line remains the color you set.

3. Solutions

According to the above analysis, the solution is to shift by 0.5 pixels when drawing such a line, as shown below. That is, (3.5,1) to (3.5,5). What is actually drawn is a vertical line at 3-4 pixels. There is an easy way to translate 0.5 pixels without worrying about the exact coordinates.

Summary of key functions

This part mainly summarizes the important APIS in Canvas, which are often used or helpful to solve problems.

I. Deformation in Canvas

Morphing is a very useful feature in Canvas. There are three types: Translate, rotate and scale. It is important to understand that deformation in canvas does not change the content that has been drawn. It’s a transformation of the canvas coordinate system. MDN has a very good sentence, here to share:

Once an image in a canvas is drawn, it stays that way until it is cleared and redrawn or overwritten directly over the original area.

1. Coordinate system in Canvas

The default coordinate system in Canvas: the origin is in the upper left corner of canvas, the horizontal x axis is positive to the right, and the vertical Y axis is positive to the downward. Draws a rectangle in the default coordinate system,20,100,100 CTX. FillRect (20)The rendering effect is shown below

A Translate transform is performed.CTX. Translate (120120).. That is, shift the coordinate system 120 pixels to the right and down. If you don’t draw the graph, the canvas looks the same. Because just changing the position of the coordinate system has no effect on the graph already drawn on the canvas. Translate executes the code to draw the rectangle again,20,100,100 CTX. FillRect (20)The canvas now looks like the image below

Although the parameters of the two rectangles are exactly the same, the starting coordinates of the rectangles (20,20) are not in the same position in the canvas for the two draws. Because the coordinate system has changed.

2. Deformation is generally used with save and restore

Save saves all the states of Cavans, which can be roughly divided into: deformation, style attributes, and clipping paths. Record separately after the clipping path. It can be understood that calling save once is equivalent to pushing the current state of canvas into an array, while calling restore is pop out the last state of the array for you to use. Follow the last in first out rule. When you use multiple variants, a single call to restore restores directly, rather than setting the original value one by one. It’s very convenient to use.

3. A variety of deformation with the use

Rotate and Scale are often used in conjunction with Translate. Like this watch animation.

The three Pointers in this animation are dynamic, meaning they need to be redrawn all the time. Their idea: according to the current moment, calculate the deviation Angle of the time minute second pointer to the 12 o ‘clock direction, that is, the vertical upward direction. The rotate transform is then used to rotate the coordinate system by the corresponding deviation Angle. At this time, you only need to draw from the center of the clock to 12 o ‘clock, and the correct offset Angle will be displayed on the canvas. So in this process, with rotate you have to translate the coordinate system to the center of the clock, otherwise it will rotate from the top left corner of the canvas. Obviously not.

Clip method isPointInPath method

1. Clip the path

When the clip method is called, the drawing on the canvas takes effect only for the clipped area. It should be noted that the clip clipping is the last path drawn in the drawing environment. The default is to crop the entire canvas. Here’s an example of how to draw the circular grid below:



Drawing this figure without using the Clip method may require complex calculations.

Using clip, it becomes very simple: First draw a circular path call Clip, and then you can draw the grid freely. You can draw the grid directly for the entire canvas. Finally, only the clipped area, namely the circular area, will be drawn.

In another clip application scenario, clearRect is usually used to clear a canvas area, but clearRect can only clear a rectangular area. What if you want to clear non-rectangular areas? Below is a simple drawing tool that makes a circular eraser

The clip method is used to clear the circular eraser path, and then the Clip method is used to clear the circular eraser using clearRect. As long as the clearRect rectangle is large enough to cover the circular eraser, the contents of the eraser are cleared.

2. IsPointInPath method

IsPointInPath (x,y) determines whether the incoming point is in the drawing path and is the last drawing path. This method is used more often in interactions. The following is also a usage scenario

The figure shows two ways to draw a quadratic Bezier curve. One way is to drag the ball, the control point, and draw the Bezier curve accordingly. If you don’t click on the ball, then you go to another place to draw the Bezier curve. Here you need to determine if the mouse is mouseDown inside the ball. In this case, the isPointInPath method is used, noting that the ball path must be the last path drawn before calling the method.

Such regular shapes as circles may be computed by themselves without using the above two methods. For example, if the mouse is pressed in the ball, it can also be judged by whether the distance between the mouse position and the center of the ball is greater than the radius of the ball. But if you have complex shapes, irregular shapes, a lot of times it’s very difficult to calculate.

Iii. Composite graphics globalCompositeOperation

The globalCompositeOperation property sets the compositing method for painted and newly painted graphics. The default is obviously the new graph overwriting the old graph, with the new graph having a higher level and the default source-over. You can definitely put the new drawing under the old one. The globalCompositeOperation has a value of destination-over.The use scene is the selected effect in this example, adding a shadow to the box. Setting the shadow requires a rectangle of the same size to be drawn, so normally the newly drawn rectangle will overwrite the original one, so set globalCompositeOperation to destination-over so that the contents of the new rectangle will be overwritten under the original one, Only the shadows I needed showed up.

GlobalCompositeOperation also has some common values that can be used to compose new shapes, such as the moon compositing from globalCompositeOperation source-out. Source-out means that the out part of the new graph is drawn without overlap.The default value source-out

The globalCompositeOperation has many values that will not be listed. This attribute feels useful, but so far I don’t know enough about its usage scenarios. So if there is an encounter in the later study will be added.

performance

Finally, I would like to give my personal opinion on canvas performance. If you don’t redraw frequently, you don’t need to worry too much about performance in most cases. Drawing once is not a problem with modern browsers. The thing to watch out for is frequent redrawing.

The most important thing when repainting frequently is to repaint only what must be repainted. For example, in the previous animation of the clock, everything is still except for three hands, and it is enough to draw the static thing once. At this time, multi-layer canvas can be used, that is, the static part is placed under one canvas, and the dynamic part is superimposed on the top with another canvas. For example, in the eraser example mentioned in the clip above, the background of this drawing tool is a base canvas, because the background never needs to be changed. So you don’t have to worry about removing the background when you erase it.

conclusion

This paper is a summary of the first stage of learning canvas. Welcome to point out any errors or inaccuracies in the article. Finally, the article draws the source code of the example here, interested partners can have a look: github.com/Yuchaocheng…