npm.nicfv.com
    Preparing search index...

    Animation

    In this example, we learn how to animate a bouncing ball on the canvas. We need to use the canvas loop(dt) callback function which can compute the new state and render each frame.

    Our Ball and Ground classes both implement Drawable by implementing the draw(ctx) function which is used to render the objects onto the canvas.

    For our Ball class, we also want to create a custom step(dt) function to compute the motion of the ball at each interval. Note that dt is in milliseconds, so if we want to convert that into seconds, we need to divide by 1,000.

    $$\text{s} = \frac{\text{ms}}{1000}$$

    We have also provided a keydown(key) event listener, that when space is pressed, the ball is dropped again, resetting the animation.

    Follow these steps to create a new webpack project and install the graphico dependency to run this example.

    # Create and open project folder
    mkdir Animation_demo
    cd Animation_demo
    # Initialize project and install dependencies
    npm init -y
    npm pkg set type="module"
    npm i graphico@1.1.0 webpack-cli
    # Create source files
    touch index.html
    mkdir src
    touch src/index.js
    # Open new files
    open index.html
    open src/index.js

    Copy and paste the following source code blocks into the newly created files.

    <html>

    <head>
    <script type="text/javascript" src="dist/main.js" defer></script>
    </head>

    <body>
    <p>Press <kbd>space</kbd> to restart animation.</p>
    </body>

    </html>
    import { Canvas } from 'graphico';

    const px_per_m = 100; // Pixels per meter
    const G = 9.81; // Gravitation constant [m/s^2]

    class Ball {
    #color;
    #x;
    #r;
    #y;
    #vy;
    #groundY;
    constructor(color = '', radius = 0, x = 0, dropHeight = 0, groundY = 0) {
    this.#color = color;
    this.#x = x;
    this.#r = radius;
    this.#y = groundY - dropHeight;
    this.#vy = 0;
    this.#groundY = groundY;
    }
    reset(dropHeight = 0) {
    this.#y = this.#groundY - dropHeight;
    this.#vy = 0;
    }
    step(dt) {
    const dt_s = dt / 1000; // convert ms to s
    this.#vy += px_per_m * G * dt_s; // [px/m] * [m/s^2] * [s] = [px/s]
    this.#y += this.#vy * dt_s; // [px/s] * [s] = [px]
    // Check if the ball should bounce off the ground
    if (this.#y + this.#r >= this.#groundY) {
    this.#y = this.#groundY - this.#r; // make sure ball doesn't go through the ground
    this.#vy *= -0.9; // some "energy" is lost
    }
    }
    draw(ctx) {
    ctx.fillStyle = this.#color;
    ctx.beginPath();
    ctx.arc(this.#x, this.#y, this.#r, 0, 2 * Math.PI);
    ctx.fill();
    }
    }

    class Ground {
    #y;
    constructor(y = 0) {
    this.#y = y;
    }
    draw(ctx) {
    ctx.fillStyle = 'sandybrown';
    ctx.fillRect(0, this.#y, canvas.width, canvas.height);
    }
    }

    // Create the animation objects
    const ball = new Ball('red', 10, 100, 100, 150);
    const ground = new Ground(150);

    // Create the canvas
    const canvas = new Canvas({
    border: 'black',
    borderBlur: 'gray',
    background: 'skyblue',
    width: 200,
    height: 200,
    loop(dt) {
    ball.step(dt); // Compute the motion for the ball
    canvas.clear(); // Clear the canvas before rendering any objects
    canvas.draw(ground); // Draw the ground (calls the ground.draw() function)
    canvas.draw(ball); // Draw the ball
    },
    keydown(key) {
    // Press space to drop the ball
    if (key === ' ') {
    ball.reset(100);
    }
    },
    });

    In the base project directory Animation_demo/, run the following command. If changes are made in the source files, the demo will automatically be recompiled. Press CTRL+C to stop running.

    npx webpack --mode development --watch
    

    Open the index.html file in any web browser of your choice! You should see a page similar to the one below.