Basic principles of animation

Animation refers to a work that is played continuously by many frames of still pictures at a certain speed (such as 16 pictures per second), and the naked eye mistakenly thinks the picture is active due to the illusion of visual residual image. In order to get the active picture, there will be subtle changes between each picture. The most common way to make pictures is to draw them on paper or celluloid.

Once the graphics based on HTML5 canvas are drawn, it is still there. If we need to move it, we have to redraw all the figures (including the previous ones). That is to say, to achieve animation effect is to draw an image on the canvas, empty the canvas, then draw the image, and then empty... That is, to repeat the operation before the animation is finished playing!


Basic steps of animation

We can draw a frame through the following steps:

  1. Empty canvas
  • Unless the next thing you're going to draw is full of canvas (for example, a background image), you need to clear everything. The easiest way is to use the clearrect method.
  1. Save canvas status
  • If you want to change some settings that will change the canvas state (style, deformation, etc.), and you want to be in the original state at each frame, you need to save it first.
  1. Draw animated shapes
  • This step is to redraw the animation frame.
  1. Restore canvas status
  • If you have saved the state of canvas, you can restore it first and then redraw the next frame.

Manipulating animation

In order to implement animation, we need some methods that can perform redrawing regularly. There are two ways to do this. First, you can use the 'setinterval' and 'setTimeout' methods to control redrawing at a set point in time.

Available timing execution methods:

//When the interval is set, the function will be executed regularly.
setInterval(function, delay)

//Execute the function after the set time
setTimeout(function, delay)

// tell the browser to execute the animation and request the browser to call the specified function to update the animation before the next repainting.
requestAnimationFrame(callback)

About 'requestanimationframe', this is an API specially designed for high-performance frame animation. Different browsers have different implementations, and we can also unify this method by extension.

if (!window.requestAnimationFrame) {
      window.requestAnimationFrame = (window.webkitRequestAnimationFrame ||
                                      window.mozRequestAnimationFrame ||
                                      window.msRequestAnimationFrame ||
                                      window.oRequestAnimationFrame ||
                                      function (callback) {
                                        return window.setTimeout(callback, 1000 / 60 );
                                      });
    }

 if (!window.cancelAnimationFrame) {
      window.cancelAnimationFrame = (window.cancelRequestAnimationFrame ||
                                     window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame ||
                                     window.mozCancelAnimationFrame || window.mozCancelRequestAnimationFrame ||
                                     window.msCancelAnimationFrame || window.msCancelRequestAnimationFrame ||
                                     window.oCancelAnimationFrame || window.oCancelRequestAnimationFrame ||
                                     window.clearTimeout);
    }

Animation: moving a small ball

Through the understanding of the above knowledge, we can try to realize a small ball moving down.


1. Preparation

<html>
<body>
    <canvas id="myCanvas" width="200" height="200" style="border: 1px solid">
        Your browser does not support canvas, please upgrade your browser
    </canvas>
</body>
</html>

<script>
    //Prepare canvas
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");
    
    //To draw a small ball, the parameter vy refers to the offset on the y-axis. The larger the value of the y-axis is, the lower the position of the small ball is
    function drawBall(vy) {
        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = "red";
        ctx.arc(100, 55 + vy, 15, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
    }
    
    //Initialize, draw a static ball
    drawBall(0)
</script>


2. Redraw the ball with timer

    //Define offset
    var i = 0; 
    //Define to move the ball down 100 pixels
    var distance = 100; 
    //Turn on a timer
    var timer = setInterval(function(){
        //Increase the offset value every time you redraw
        i++; 
        //Draw a small ball at each increment offset
        drawBall(i); 
        if(i > distance){
            //If the ball has completed the task of moving 100 pixels, destroy the timer
            clearInterval(timer);
        }
    })

It can be seen from the above figure that every offset of the small ball in the downward moving track is drawn. Obviously, such a picture is not what we want. We only need to display a small ball, so we only need to clear the previous drawing before each drawing of the small ball. The final code is as follows:

<html>
<body>
    <canvas id="myCanvas" width="200" height="200" style="border: 1px solid">
        Your browser does not support canvas, please upgrade your browser
    </canvas>
</body>
</html>
<script>
    //Prepare canvas
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");
    
    //To draw a small ball, the parameter vy refers to the offset on the y-axis. The larger the value of the y-axis is, the lower the position of the small ball is
    function drawBall(vy) {
        ctx.save();
        ctx.beginPath();
        ctx.fillStyle = "red";
        ctx.arc(100, 55 + vy, 15, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
    }
    
    //Initialize, draw a static ball
    drawBall(0)

    //Define offset
    var i = 0; 
    //Define to move the ball down 100 pixels
    var distance = 100; 
    //Turn on a timer
    var timer = setInterval(function(){
        //Increase the offset value every time you redraw
        i++; 
        //Empty canvas
        ctx.clearRect(0,0,200,200); 
        //Draw a small ball at each increment offset
        drawBall(i);
        if(i > distance){
            //If the ball has completed the task of moving 100 pixels, destroy the timer
            clearInterval(timer);
        }
    })
</script>


Animation: to achieve a bouncing ball

In the above example, we have been able to move the ball. If we want to achieve the rebound effect after falling to the ground, how to achieve it?

My thoughts:

  1. At the initial stage of preparation, we need to draw a line as the ground, a regular circle as the ball, and an ellipse as the extrusion effect of the ball when it contacts the ground.
  2. Move the ball to the ground and display the oval ball. After the whole extrusion process, the round ball will be displayed when it rebounds.

The attempt code is as follows:

<html>

<body>
    <canvas id="myCanvas" width="200" height="200" style="border: 1px solid">
        Your browser does not support canvas, please upgrade your browser
    </canvas>
</body>

</html>
<script>
    //Prepare canvas
    var canvas = document.getElementById("myCanvas");
    var ctx = canvas.getContext("2d");
    //Set the default fill color, which is the ball color
    ctx.fillStyle = "red";

    //The moving distance of the ball, y value of the ground - y value of the ball's starting position - radius of the ball
    var distance = 160 - 55 - 15
    //The amount of deformation caused by extrusion of a small elliptical ball
    var degree = 5

    //Draw the ground
    function drawGround() {
        ctx.save();
        ctx.beginPath();
        ctx.moveTo(0, 160);
        ctx.lineTo(200, 160);
        ctx.stroke();
        ctx.restore();
    }

    //Draw a little round ball
    function drawBall(vy) {
        ctx.save();
        ctx.beginPath();
        //Move down as offset increases
        ctx.arc(100, 55 + vy, 15, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
    }

    //Draw an oval ball
    function drawBall2(v) {
        ctx.save();
        ctx.beginPath();
        //In the process of deformation, because the height of ellipse becomes smaller and smaller, the coordinate value of Y-axis of ellipse will be increased, showing the effect that the small ball is close to the ground
        ctx.ellipse(100, 145 + v, 15 + v, 15 - v, 0, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
    }

    //Clear the screen and restore the scene
    function clear() {
        ctx.clearRect(0, 0, 200, 200)
        drawGround()
    }

    //Initialize scene
    drawGround();
    drawBall(0);
    //Offset control parameters
    var i = 0 
    //Extrusion control parameters
    var i2 = 0 
    //Rebound or not
    var isBack = false

    setInterval(function () {
        if (i > -1 && i <= distance) {
            //When the ball is moving in the air
            //If the current state is rebound, decrease the value of y-axis; if it is decline, increase the value of y-axis
            if (isBack) {
                i--;
            } else {
                i++;
            }
            //Draw a ball moving in the air
            clear();
            drawBall(i);
        } else if (i == -1 && isBack == true) {
            //When the rebound ball returns to the starting position, the state is set to descend and the offset control parameter is reset
            //Equivalent to restarting animation
            isBack = false
            i = 0
        }
        else {
            //When the ball has completed the movement of the specified distance, indicating that it has contacted the ground, the operation of the oval ball is started
            if (i2 > -1 && i2 <= degree) {
                //The ball is in the process of extrusion
                //Operate the extrusion degree control parameter to show the process of flattening the ball and then returning to its original state
                if (isBack) {
                    i2--;
                } else {
                    i2++;
                }
                //Drawing a small ball during squashing
                clear();
                drawBall2(i2);
            } else if (i2 == -1 && isBack == true) {
                //When the ball returns to its original state after extrusion, the offset control parameter will be set to achieve the upward effect of the ball in the rebound process
                //Because it's rebound, so I always decreases and the ball goes up
                i = distance
            }
            else {
                //When the small ball completes the extrusion process, i.e. the increasing of I2 is larger than the maximum extrusion amount degree, it will enter the rebound state
                isBack = true
                //Operate the extrusion degree control parameter to make the ball enter the rebound calculation process 
                i2 = degree
            }
        }
    }, 20)

</script>
Your browser does not support canvas, please upgrade your browser

Of course, the animation can be upgraded to control the falling speed of the ball through the acceleration of gravity. Some more humanized effects can be achieved one by one through various mathematical algorithms, which requires continuous learning and research in the years to come.