I. Canvas Application Scenario:

1. Games: Many page H5 games are drawn on canvas.

2. The chart

Ii. How to use Canvas

1. Start by creating a Canvas element in the HTML to tell the browser I’m going to start drawing.

 <canvas id="myCanvas" width="500" height="500"></canvas>
Copy the code

2. Get the Canvas element

var canvas =document.getElementById('myCanvas')
Copy the code

3. Get the canvas context

 var ctx = canvas.getContext('2d');
Copy the code

Because it’s on a plane, it’s 2d instead of 3D.

  • Two objects need to be distinguished here: the element object and the context

  • The element object is the Canvas element, which is our canvas

  • The context object is retrieved by getContext(‘ 2d ‘)

  • Context is a state machine. You can change several states of the context, and almost all render operations, the final effect depends on the state of the context itself. For example, the width of the rectangle drawn by strokeRect depends on the context’s state lineWidth, which was set earlier.

4. Canvas blur

Sometimes the picture drawn by our canvas will be distorted when placed in HTML. In this case, the canvas will be enlarged so that it will not appear blurred when placed in HTML.

From this, we can see that canvas is actually a bitmap, which will have distortion phenomenon.

Three, draw patterns

Draw the shape

1. Line moveTo, lineTo

  • MoveTo is moving a brush to a point

  • LineTo is to go from the point I just moved to to another point.

  • However, canvas drawing requires two more steps: beginPath() // Create a new path, after the generation, the drawing command is pointed to the path to generate the path clothPath() // After the path is closed, the drawing command is pointed to the context again

Key points:

1. Both fill and stroke methods are applied to all current subpaths. Fill generates solid graphics by filling the content area of the path.

When you call fill(), all shapes that are not closed will be closed automatically, so you don’t need to call closePath(). But stroke() is not closed automatically.

2. BeginPath () is required to start another path after completing a path.

  ctx.lineWidth = 10;
  ctx.fillStyle = "yellow";
  ctx.beginPath();
  ctx.moveTo(50.50);
  ctx.lineTo(100.100);
  ctx.closePath();
  ctx.fill(); // Generate solid graphics by filling the content area of the path

  ctx.strokeStyle = 'red';
  ctx.stroke();// Use lines to draw shapes.
Copy the code

2. The rectangular

Rect (x,y,width,height); 2.fillRect(x,y,width,height); 3. StrokeRect (x,y,width,height) 4. ClearRect (x,y,width,height) - Clear the specified rectangle so that the clear part is completely transparent. Since the first method does not color the path, we generally use the latter two methods, the second to draw and fill the rectangle, and the third to draw and strokeCopy the code

3. The arc

Arc (x1, y1, x2, y2, r) arc(x1, y1, x2, y2, r)Copy the code

6. The gradient

createLinearGradient(x1, y1, x2, y2); Linear gradientCopy the code

7. Quadratic Bessel curve and cubic Bessel curve

  • quadraticCurveTo(cp1x, cp1y, x, y)

  • Draw a quadratic Bessel curve, cp1x,cp1y as a control point, x,y as the end point.

  • bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)

  • Draw Bessel curves three times, with cp1x and CP1y as control points 1, cp2x and cp2y as control points 2, and x and y as end points.

A quadratic Bezier curve has a start point (blue), an end point (blue), and a control point (red), while a cubic Bezier curve has two control points.

Ctx.beginpath (); ctx.moveTo(75, 25); CTX. QuadraticCurveTo (25, 25, 25, 62.5); ctx.quadraticCurveTo(25, 100, 50, 100); ctx.quadraticCurveTo(50, 120, 30, 125); ctx.quadraticCurveTo(60, 120, 65, 100); CTX. QuadraticCurveTo (125, 100, 125, 62.5); ctx.quadraticCurveTo(125, 25, 75, 25); ctx.stroke(); // Three times bezier curve draw heart ctx.beginPath(); ctx.moveTo(75, 40); ctx.bezierCurveTo(75, 37, 70, 25, 50, 25); CTX. BezierCurveTo (20, 25, 20, 62.5, 20, 62.5); ctx.bezierCurveTo(20, 80, 40, 102, 75, 120); CTX. BezierCurveTo (110, 102, 130, 80, 130, 62.5); CTX. BezierCurveTo (130, 62.5, 130, 25, 100, 25); ctx.bezierCurveTo(85, 25, 75, 37, 75, 40); ctx.fill();Copy the code

8. Clip the path

  • There are stroke and fill methods for drawing graphics, and the third one, clip, is here

    Converts the path currently being built to the current clipped path.

We use the clip() method to create a new clipping path.

By default, canvas has a crop path as large as itself (i.e., no crop effect)

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  ctx.fillRect(0.0.150.150);
  ctx.translate(75.75);

  // Create a circular clipping path
  ctx.beginPath();
  ctx.arc(0.0.60.0.Math.PI*2.true);
  ctx.clip();

  // draw background
  var lingrad = ctx.createLinearGradient(0, -75.0.75);
  lingrad.addColorStop(0.'# 232256');
  lingrad.addColorStop(1.'# 143778');

  ctx.fillStyle = lingrad;
  ctx.fillRect(-75, -75.150.150);

  // draw stars
  for (var j=1; j<50; j++){ ctx.save(); ctx.fillStyle ='#fff';
    ctx.translate(75-Math.floor(Math.random()*150),
                  75-Math.floor(Math.random()*150));
    drawStar(ctx,Math.floor(Math.random()*4) +2); ctx.restore(); }}function drawStar(ctx,r){
  ctx.save();
  ctx.beginPath()
  ctx.moveTo(r,0);
  for (var i=0; i<9; i++){ ctx.rotate(Math.PI/5);
    if(i%2= =0) {
      ctx.lineTo((r/0.525731) *0.200811.0);
    } else {
      ctx.lineTo(r,0);
    }
  }
  ctx.closePath();
  ctx.fill();
  ctx.restore();
}

Copy the code

Everything that appears in the crop path will not be drawn until it is created. We’ll notice this when we draw a linear gradient. 50 randomly positioned (scaled) stars will be drawn, but only those in the cropped path will be drawn.

Fourth, performance optimization

1, inPre-render on off-screen Canvas Similar shapes or duplicate objects

If you find yourself repeating some of the same drawing operations on each animation frame, consider diverting it to an off-screen canvas. You can then render the off-screen image to the main canvas as often as needed, without having to repeat the steps of generating that image in the first place.

myEntity.offscreenCanvas = document.createElement("canvas");
myEntity.offscreenCanvas.width = myEntity.width;
myEntity.offscreenCanvas.height = myEntuty.heihgt;
myEntity.offscreenContext = myEntity.offscreenCanvas.getContext("2d"); . myEntity.render(myEntity.offscreenContext);Copy the code

2. Avoid sub-pixel rendering of floating point coordinate points and use integers instead

CTX. DrawImage (myimage.png, 0.3, 0.5); Browsers do extra calculations to achieve anti-aliasing. To avoid this, be sure to round the coordinates with math.floor () when you call drawImageCopy the code

3. Do not use it when caching different sizes of images in the off-screen canvasdrawImageTime scale image

4. Use multiple layers of canvas to paint a complex scene

Suppose you have a game with a UI at the top, gameplay actions in the middle, and a static background at the bottom. In this case, you can split the game into three

layers. The UI changes only with user input, the game layer changes with each new frame, and the background usually stays the same.

<div id="stage">
   <canvas id="ui-layer" width="" height=""/>
   <canvas id="game-layer" width="" height=""/>
   <canvas id="backgground-layer" width="" height=""/>
<div/>
<style>
  #stage {
    width: 480px;
    height: 320px;
    position: relative;
    border: 2px solid black
  }
  canvas { position: absolute; }
  #ui-layer { z-index: 3 }
  #game-layer { z-index: 2 }
  #background-layer { z-index: 1 }
</style>
Copy the code

5. Avoid drawing a large image on the canvas every frame. Use CSS to set a large background image behind the canvas element

CSS Transforms use a GPU, which is faster

It is best not to scale the canvas directly, or to have a smaller canvas and scale it up, rather than a larger canvas and scale it down.

7. If your game uses canvas and doesn’t need transparency, turn off transparency to help the browser optimize internally

var ctx = canvas.getContext('2d', { alpha: false });
Copy the code

8, animation, please usewindow.requestAnimationFrame()Rather thanwindow.setInterval()

Browsers can optimize parallel animation sequences, rearrange sequences more sensively, and combine actions within a single rendering cycle for smoother animation. For example, with requestAnimationFrame(), JS animations can be synchronized with CSS animations/transforms or SVG SMIL animations. In addition, if you run an animation in a browser TAB, the browser will pause it when the TAB is not visible, which reduces CPU and memory stress and saves battery life.

9. To avoid blocking caused by a large number of calculations, Worker and task splitting methods can be used to avoid complex algorithms blocking animation

10. Gather the function calls of canvas together, do not frequently schedule beginPath, closePath, stroke and fill, and reduce the calls to canvas API.

for (var i = 0; i < points.length - 1; i++) {
  var p1 = points[i];
  var p2 = points[i+1];
  context.beginPath();
  context.moveTo(p1.x, p1.y);
  context.lineTo(p2.x, p2.y);
  context.stroke();
}
====>
context.beginPath();
for (var i = 0; i < points.length - 1; i++) {
  var p1 = points[i];
  var p2 = points[i+1];
  context.moveTo(p1.x, p1.y);
  context.lineTo(p2.x, p2.y);
}
context.stroke();
Copy the code

Change the CANVAS State machine as little as possible.

  for (var i = 0; i < STRIPES; i++) {
          context.fillStyle = (i % 2 ? COLOR1 : COLOR2);
          context.fillRect(i * GAP, 0, GAP, 480);
      } 
      
   ====> 
  context.fillStyle = COLOR1;
      for (var i = 0; i < STRIPES / 2; i++) {
          context.fillRect((i * 2) * GAP, 0, GAP, 480);
      }
      context.fillStyle = COLOR2;
      for (var i = 0; i < STRIPES / 2; i++) {
          context.fillRect((i * 2 + 1) * GAP, 0, GAP, 480);
      }
Copy the code

12. Partial redraw renders different points in the canvas, rather than the entire new state

Since the drawing method of Canvas is paintbrush, it will be drawn on the Canvas every time the API is called when drawing on Canvas, and once drawn, it will become a part of the Canvas. No object is saved when drawing the graph. Once the graph needs to be updated, the whole Canvas needs to be cleared and the Canvas needs to be redrawn.

  1. Clear the color of the specified area and set the clip.
-Clip () to determine the drawing of cutting area, area outside the drawings can't, for details see CanvasRenderingContext2D. The clip ()-   clearRect(*x*.*y*.*width*.*height*) erase within the specified rectangle color, view CanvasRenderingContext2D. ClearRect ()Copy the code
  1. All shapes that intersect this region are redrawn

13. Avoid shadowBlur as much as possible. The performance overhead of shadow rendering is usually high

14. Avoid text rendering when possible

15. Use large physical libraries with caution

16. Try different ways to clear the canvas (clearRect() vs. fillRect()Vs. resizing canvas)

Performance improves in turn.