JS study notes (fourteen) animation and Canvas graphics

JS study notes (fourteen) animation and Canvas graphics

1. Use requestAnimationFrame

1.1 Early timing animation

In the early days, setInterval() was basically used to control the execution of animation

(function() {
    
    
  function updateAnimations() {
    
    
    doAnimation1();
    doAnimation2();
    // 其他任务
  }
  setInterval(updateAnimations,100);
})();

       updateAnimations() periodically runs the registered animation tasks and reflects changes for each task.

       Neither setInterval() nor setTimeout() can guarantee time precision. The style as the second parameter can only guarantee that the code will be added to the browser's task queue, but it cannot be guaranteed that adding it to the queue will run immediately

       

1.2 requestAnimationFrame

       It is used to notify the JS code that animation is about to be performed, and receives a parameter, which is a function to be called before redrawing the screen. This function is where the DOM styles are modified to reflect what's changed on the next repaint . To implement an animation loop, multiple requestAnimationFrame() calls can be chained. The function passed to requestAnimationFrame() can also be a parameter, which is an instance of DOMHighResTimeStamp, indicating the next redraw time.

       Because requestAnimationFrame() will only call the passed function once, it needs to be called again manually every time the UI is updated.

       

1.3 cancelAnimationFrame

       requestAnimationFrame() also returns a request ID, the redrawing task can be canceled by cancelAnimationFrame()

       

1.4 throttling through requestAnimationFrame

       Browsers that support requestAnimationFrame() will actually expose a callback queue as hooks. A hook is a point before the browser performs the next repaint. This callback queue is a modifiable list of functions that should be called before redrawing.

​ Limit the callback to execute no more than 50 milliseconds:

let enable = true;
function expensiveOperation() {
    
    
  console.log("invoked at",Date.now);
}

window.addEventListener("scroll",() => {
    
    
  if(enable) {
    
    
    enable = false;
    window.requestAnimationFrame(expensiveOperation);
    window.setTimeout(() => enable = true, 50);
  }
});

       The timer is used to limit the actual operation execution interval, and requestAnimationFrame controls which rendering cycle of the browser to execute

       

1.5 Easing animation

       Easing animation is to change the speed of element movement, and the common one is to let the speed stop slowly

Ideas:

  1. Let the distance the box moves gradually decrease each time, and the speed will slowly fall
  2. Core algorithm: (target value-current position)/10 as the step size of each moving distance
  3. Stop condition: make the current box position equal to the target position and stop
function animate(obj, target) {
    
    
  //先清除以前的定时器,只保留当前的一个定时器执行
  clearInterval(obj.timer);
  obj.timer = setInterval(function () {
    
    
    // 步长值写到定时器里面
    var step = (target - obj.offsetLeft) / 10;
    if (obj.offsetLeft >= target) {
    
    
      //停止
      clearInterval(obj.timer);
    }
    obj.style.left = obj.offsetLeft + step + 'px';
  }, 30);
}

       

1.5.1 Easing animation principle

step advanced one:

//把步长改成整数,不要出现小数
var step = Math.ceil((target - obj.offsetLeft) / 10);

If you don't modify it, you may not be able to reach the target position because of the decimal problem.

       

step advanced two:

Satisfied forward and backward

function animate(obj, target) {
    
    
  //先清除以前的定时器,只保留当前的一个定时器执行
  clearInterval(obj.timer);
  obj.timer = setInterval(function () {
    
    
    //把步长改成整数,不要出现小数
    // var step = Math.ceil((target - obj.offsetLeft) / 10);
    var step = (target - obj.offsetLeft) / 10;
    step = step > 0 ? Math.ceil(step) : Math.floor(step);
    if (obj.offsetLeft >= target) {
    
    
      //停止
      clearInterval(obj.timer);
    }
    obj.style.left = obj.offsetLeft + step + 'px';
  }, 30);
}

       

1.5.2 Add callback function to easing animation

btn800.addEventListenr('click',function() {
    
    
    animate(span,800,function() {
    
    });//函数作为回调函数
})

function animate(obj, target) {
    
    
  //先清除以前的定时器,只保留当前的一个定时器执行
  clearInterval(obj.timer);
  obj.timer = setInterval(function () {
    
    
    //把步长改成整数,不要出现小数
    // var step = Math.ceil((target - obj.offsetLeft) / 10);
    var step = (target - obj.offsetLeft) / 10;
    step = step > 0 ? Math.ceil(step) : Math.floor(step);
    if (obj.offsetLeft >= target) {
    
    
      //停止
      clearInterval(obj.timer);
      // 回调函数写到定时器结束里面
      if(callback) {
    
    
          //调用函数
          callback();
      }
    }
    obj.style.left = obj.offsetLeft + step + 'px';
  }, 30);
}

       

2. Basic Canvas Functions

Drawing <canvas>elements must set at least the width and height attributes

<canvas id="drawing" width="200" height="200">hhh</canvas>

Note: width and height have no units

       

2.1 getContext()

       To draw graphics on the canvas, you must first obtain the drawing context . Use getContext() to get a reference to the drawing context. For plane graphics, you need to pass in the parameter "2d" to this method, indicating the 2d context object to be obtained

let drawing = document.getElementById("drawing");

// 确保浏览器支持canvas
if (drawing.getContext) {
    
    
  let context = drawing.getContext('2d');
  //...
}

       

2.2 toDataURL()

       This method can be used to export the image on the canvas element, receiving one parameter: the MIME type of the image to be generated

       

3. 2D painting context

       The coordinate origin (0, 0) of the 2D context is at the upper left corner of <canvas>the element .

3.1 Fill and stroke

  • Fill: fillStyle attribute
  • Stroke: strokeStyle property

       These two properties can be strings, progressive objects or pattern objects, and the default value is "#000000".

let drawing = document.getElementById("drawing");

// 确保浏览器支持canvas
if (drawing.getContext) {
    
    
  let context = drawing.getContext('2d');
  context.strokeStyle = "red";
  context.fillStyle = "#0000ff";
}

       

3.2 Draw a rectangle

The methods are:

  • fillRect() : used to draw and fill a rectangle on the canvas with the specified color , the filled color is specified using the fillStyle property
  • strokeRect() : draws the outline of a rectangle by specifying a color using the strokeStyle property
  • clearRect() : Can erase a certain area in the canvas. Used to make an area in the drawing context transparent

       Both receive 4 parameters: rectangle x coordinate, rectangle y coordinate, rectangle width and rectangle height. The unit is pixel

       

3.3 Drawing paths

3.3.1 Steps

  1. First call the beginPath() method to indicate that you want to start drawing a new path
  2. Then call the following method to draw the path:
    • arc(x, y, radius, startAngle, endAngle, counterclockwise) : Draw an arc with the coordinates (x, y) as the center and radius as the radius, the start angle is startAngle, and the end angle is endAngle. counterclockwise indicates whether to calculate the start angle and end angle counterclockwise
    • arcTo(x1, y1, x2, y2, radius) : Draw an arc from the previous point to (x2, y2) via (x1, y1) with a given radius radius
    • bezierCurveTo(c1x, c1y, c2x, c2y, x, y) : With (c1x, c1y) and (c2x, c2y) as control points, draw an arc from the previous point to (x, y) (cubic Bezier curve)
    • lineTo(x,y) : Draw a line from the previous point to (x,y)
    • moveTo(x, y) : do not draw the line, only move the drawing cursor to (x, y)
    • quadraticCurveTo(cx, cy, x, y) : With (x, y) as the control point, draw an arc from the previous point to (x, y) (quadratic Bezier curve)
    • rect(x, y, width, height) : Draw a rectangle at the coordinate point (x, y) with a given width and height. The difference from fillRect() and strokeRect() is that it creates a path instead of independent graphics
  3. The last step calls stroke() to draw the path

       

3.3.2 isPointInPath()

​ Receives x-axis and y-axis coordinates as parameters. This method is used to determine whether the specified point is on the path , and can be called at any time before closing the path

       

3.4 Drawing text

3.4.1 Basic method of drawing text

       Method: fillText() and strokeText() , both receive 4 parameters: string to be drawn, x coordinate, y coordinate and optional maximum pixel width, the 4 attributes are as follows:

  • font
  • textAlign: Specify the alignment of the text: the values ​​are: "start", "end", "left", "right" and "center", "left", "right" are not recommended
  • textBaseLine: Specifies the baseline of the text, which can change the vertical alignment of the text. The values ​​are: "top", "hanging", "middle", "alphabetic", "ideographic" and "bottom"
  • The maximum width of the text (optional)

       

3.4.2 measureText()

       Receives one parameter, the text to be drawn, and returns a TextMetrics object. The returned object has only one property width, and the measureText() method uses the current values ​​of font, textAlign and textBaseline properties to calculate and draw the size of the specified text

Example: Assuming that the text "Hello world!" is placed in a rectangle with a 140-pixel frame, it can be calculated from a font size of 100 pixels, and it will decrease until the text size is appropriate:

let fontSize = 100;
context.font = fontSize + 'px Arial';
while(context.measureText('Hello world!').width > 140) {
    
    
  fontSize--;
  context.font = fontSize + 'px Arial';
}
context.fillText('Hello world!',10,10);
context.fillText('Font size is' + fontSize + 'px',10,50);

       

3.5 Transformation

The transformation matrix used to change the drawing context:

  • rotate(angle) : Rotate the image by angle radians around the origin
  • scale(scaleX, scaleY) : Scales the image by multiplying scaleX on the x-axis and scaleY on the y-axis. The default value is 1.0
  • translate(x,y) : move the origin (0, 0) to (x, y)
  • transform(m1_1, m1_2, m2_1, m2_2, dx, dy) : directly modify the matrix by matrix multiplication as follows
  • setTransform(m1_1, m1_2, m2_1, m2_2, dx, dy) : Reset the matrix to the default value, and then call transform() with the passed parameters

       

save() and restore()

  • save(): All the settings at the current moment are temporarily stored on the stack, only the settings and transformations applied to the painting context are saved, and the content of the painting context is not saved
  • restore(): Remove and restore previously saved settings from the temporary stack

       

3.6 Drawing images

       To draw an existing image onto the canvas, use drawImage() .

(1) Receive 3 parameters

       Pass in an HTML <img>element, the x and y coordinates of the drawing target, and the result: draw the image to the specified position

let image = document.images[0];
context.drawImage(image,10,10);

       

(2) Receive 5 parameters

       The size of the drawn image can be changed

       Pass in an HTML <img>element, the x and y coordinates of the draw target, the target width and target height. The scaling here only affects the drawn image, not the context's transformation matrix:

context.drawImage(image,50,102030);

Image scaled to 20 pixels wide by 30 pixels high

       

(3) Receive 9 parameters

       Image to draw, source image x coordinate, source image y coordinate, source image width, source image height, target area x coordinate, target area y coordinate, target area width, and target area height

context.drawImage(image,0,10,50,50,0,100,40,60);

       Starting at (0,10), 50 pixels wide and 50 pixels high. When drawn on the canvas, it will start from (0, 100) and become 40 pixels wide and 60 pixels high

       

3.7 Shadows

Attributes:

  • shadowColor
  • shadowOffsetX
  • shadowOffsetY
  • shadowBlur : Pixels representing the amount of blur for the shadow. Default is 0

       

3.8 Gradients

3.8.1 Linear Gradients

step:

  1. Use createLinearGradient() to receive 4 parameters: start point x coordinate, start point y coordinate, end point x coordinate, end point y coordinate. After calling, this method will create a new CanvasGradient object with the specified size and return the instance .
  2. Use **addColorStop()** to assign a color stop to the gradient. Receive two parameters: color scale position (the value in the range of 0~1 indicates, 0 is the first color, 1 is the last color) and CSS string.
let gradient = context.createLinearGradient(30,30,70,70);
gradient.addColorStop(0,'white');
gradient.addColorStop(1,'black');

       

3.8.2 Radial gradient

​ Use **createRadialGradient()** to create and receive 6 parameters: coordinates and radii corresponding to the centers of the two circles

       

3.9 Pattern

       Patterns are used to fill and stroke repeating images of shapes. To create a new pattern, call createPattern() and pass in two parameters: (1) an <img>element and (2) a string representing how the image should be repeated . The value of the second parameter is the same as the background-repeat property of CSS

       

3.10 Image data

       Use getImageData() to get raw image data. Receive 4 parameters: the coordinates of the upper left corner of the first pixel in the data to be obtained and the pixel width and height to be obtained. The returned object is an instance of ImageData, each object contains 3 properties: width, height and data. The data attribute is an array containing the raw pixel information of the image. Each pixel is represented by 4 values ​​in the data array, representing red, green, blue and transparency values ​​respectively

       

3.11 Synthesis

Everything drawn by the 2D context has two properties applied to it: globalAlpha and globalCompositionOperation.

  • globalAlpha : a value ranging from 0 to 1 (including 0 and 1), used to specify the transparency of all drawn content, the default is 0
  • globalCompositionOperation : Indicates how newly drawn shapes blend with shapes already in the context. Is a string, the value is:

       

4. WebGL

The 3D context of the canvas, WebGL is the Web version of OpenGL ES 2.0

4.1 WebGL context

Before using the context, you should check whether the return value exists:

let drawing = document.getElementById("drawing");
// 确保浏览器支持canvas
if (drawing.getContext) {
    
    
  let gl = drawing.getContext("webgl");
  if(gl) {
    
    
    //使用webgl
  }
}

4.2 WebGL basics

       Some options can be specified when getContext() gets the WebGL context. The options are passed in through a parameter object, where options are one or more properties of the parameter object

  • alpha : Boolean, indicating whether to create a transparent channel buffer for the context , the default is true
  • depth : Boolean, indicating whether to use a 16-bit deep buffer , the default is true
  • stencil : Boolean, indicating whether to use 8-bit stencil buffer , default is false
  • antialias : Boolean, indicating whether to use the default mechanism to perform anti-aliasing operations , the default is true
  • premultipliedAlpha : Boolean, indicating whether the drawing buffer premultiplies the transparency value , the default is true
  • preserverDrawingBuffer : Boolean, indicating whether to preserve the drawing buffer after drawing is completed , the default is false
let drawing = document.getElementById("drawing");
// 确保浏览器支持canvas
if (drawing.getContext) {
    
    
    try{
    
    
        let gl = drawing.getContext("webgl",{
    
    alpha:false});
    } catch(ex){
    
    

    }
    if(gl) {
    
    
        //使用webgl
    }
}

       

1. Constants

       In OpenGL, the constant starts with GL, and in WebGL, you need to access it in another way, such as: GL_COLOR_BUFFER_BIT In WebGL, you need to access g.COLOR_BUFFER_BIT

       

2. Method Naming

  • Methods that receive different types and different numbers of parameters will be reflected by the suffix of the method name
  • The number representing the number of parameters comes first, and the string representing the data type ('f' represents a floating-point number, and 'i' represents an integer) follows , such as: gl.uniform4f() indicates that 4 floating-point value parameters are required
  • The method of receiving an array is represented by the letter **'v'**, such as: gl.uniform3iv() means to receive an array parameter containing 3 values

       

3. Prepare to draw

       Before a WebGL context is ready to be used, it is usually necessary to specify a solid color clear <canvas>. To do this, you need to call clearColor() and pass in 4 parameters, which represent red, green, blue and transparent values ​​respectively. The parameter ranges are all (0~1 range) , indicating the intensity of each component in the final color

gl.clearColor(0,0,0,1);
gl.clear(gl.COLOR_BUFFER_BIT);

       

4. Viewport and coordinates

       To change the viewport, call viewport() and pass in the viewport's x, y coordinates, width and height relative to <canvas>the element transaction. If the coordinates outside the viewport are used for drawing, the drawing result will be clipped by the viewport. The
<canvas>
lower left corner represented by the starting        point (0, 0) of the x and y coordinates of the viewport
, the upward and right growth can be done by point (width-1 , height-1) Definition:

 
Example: Define the viewport as <canvas>the upper left quarter area:

gl.viewport(0,drawing.height/2,drawing.width/2,drawing.height/2);

       

5. Buffer

       In JS, vertex information is stored in qualitative arrays. To use this information, they must first be converted to WebGL buffers. To create a buffer, call gl.createBuffer() and use **gl.bindBuffer()** to bind the buffer to the WebGL context. After binding, you can fill the buffer with data, such as:

let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,buffer);
gl.bufferData(gl.ARRAY_BUFFER,new Float32Array([0,0.5,1]),gl.STATIC_DRAW);

The last parameter of the gl.bufferData() method indicates how to use the buffer

  • gl.STATIC_DRAW: The data is loaded once and can be used in multiple draws (generally use this)
  • gl.STREAM_DRAW: Data is loaded once and can only be used in several draws
  • gl.DYNAMIC_DRAW: Data can be modified repeatedly and used in multiple drawing

When the buffer is not in use, call gl.deleteBuffer() to release the memory it occupies

       

6. Errors

       Errors are usually not thrown in WebGL. You must call gl.getError()** after calling the method that may fail. This method returns a constant indicating the type of error that occurred:

       

7. Shaders

       There are two shaders in WebGL: vertex shader and fragment (or pixel) shader , WebGL is implemented using GLSL language

  • Vertex shader: used to convert 3D vertices into 2D points that can be rendered
  • Fragment shader: Used to calculate the correct color to draw a pixel.

7.1 Writing shaders

       Every shader has a **main()** method that is executed repeatedly during drawing. There are two ways to pass parameters to shaders: attribute and uniform. attribute: used to pass vertices into the vertex shader, uniform: used to pass constant values ​​into any shader. . Attributes and uniforms are defined outside the main() function. After the value type keyword comes the data type, then the variable name

attribute vec2 aVertexPosition;
void main() {
    gl_Position = vec4(aVertexPosition,0.0,1.0);
}

       An attribute called aVertexPosition is defined. The attribute is an array containing two items (data type vec2), representing the x and y coordinates

       

4.3 WebGL1 and WebGL2

WebGL1 is almost compatible with WebGL12. In WebGL12, many functions have become default functions. The following features have become standard features of WebGL12:

Guess you like

Origin blog.csdn.net/weixin_45950819/article/details/120763824