Bouncing Shapes Background With Canvas

maurerkrisztian

Krisztián Maurer

Posted on July 27, 2022

Bouncing Shapes Background With Canvas

The goal of this project is to make a cool background with randomized shapes and to be customizable.

Demo: https://canvas-shapes-background.netlify.app/

Code: https://github.com/MaurerKrisztian/CanvasShapesBackground

Simple example usage:

Maurer Krisztián
https://codepen.io/maurerkrisztian/pen/rNdGerb

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type='text/javascript' src="https://canvas-shapes-background.netlify.app/bundle.js"></script>
</head>
<body>
<canvas id="myCanvas"></canvas>
<script>
    createShapeCanvas("myCanvas", {
        modelNumbers: 11,
        colors: ['blue', 'red', 'green', 'yellow'],
        backgroundColor: 'black', //'none',
        enabledModels: ['Triangle', 'Circle', 'Rect'],
        minSpeed: 11,
        maxSpeed: 11,
        lineWidth: 3,
        sizeMultiplier: 2,
        startPosition: 'random' //  'middle' | 'random',
        isFullScreen: true,
    })
</script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

I added a configurator with the demo: https://canvas-shapes-background.netlify.app/

  • Easily test different configs and copy the configured settings.

Maurer Krisztián

"createShapeCanvas" has 2 arg

  • canvas id
  • config

config

  • startPosition: 'middle' | 'random' initial model position
  • enabledModels: thies shapes will be generated randomly
  • modelNumbers: generate this amount of models from "enabledModels" array
  • colors: pisck random color from this array for shapes
  • backgroundColor: canvas background color, can be "none"
  • minSpeed: shape min speed
  • maxSpeed: shape max speed
  • lineWidth: shape border line width
  • sizeMultiplier: multiply the generated size with this
  • isFullScreen: fullscreen or element size

How I made it?

I used HTML Canvas.

I wanted to be easily extendable, so abstracted some thing:

Animator:

  • it is responsible for setup every frame and call the modell update()

Model:

  • has 2 main responsibility:
  • draw() - draw the shape,
  • update()
    • howto behave based on the current x,y position and
    • xd, dy aka where to want to move and how fast. If you confused how dx, dy it works it basicly a vector. it has a direction (this will be the model direction) and a length (this will be the model speed). vector

Example model:

export class CircleModel implements IModel {
    static MODEL_NAME = 'Circle'

    color: string;

    constructor(private x: number, private y: number, private dx: number, private dy: number, private radius: number, private lineWidth: number = Setup.CONFIG.lineWidth) {
        this.color = Utils.pickRandomFromArray<string>(Setup.CONFIG.colors)
    }

    draw(context: CanvasRenderingContext2D) {
        context.lineWidth = this.lineWidth;
        context.beginPath();
        context.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
        context.strokeStyle = this.color;
        context.stroke();
        context.lineWidth = DEFAULT_LINE_WIDTH;
    }


    update(context: CanvasRenderingContext2D) {
        if (this.x > Context.canvasWidth - this.radius || this.x < 0 + this.radius) {
            this.dx = -this.dx;
        }
        if (this.y > Context.canvasHeight - this.radius || this.y < 0 + this.radius) {
            this.dy = -this.dy;
        }

        this.x = this.x + this.dx;
        this.y = this.y + this.dy;

        this.draw(context);
    }
}
Enter fullscreen mode Exit fullscreen mode

I wanted to baunce of from the side of the canvas so

Good to know where is the canvas side.

Coordinate system:
Maurer Krisztián Coordinate system

So x(0) the left min position and x(canvasWidth) the right side posion, similarly with y.

        if (this.x > Context.canvasWidth - this.radius || this.x < 0 + this.radius) {
            this.dx = -this.dx;
        }
Enter fullscreen mode Exit fullscreen mode

If the current position (center of the circle) greather than canvas width - radius than change the x direction

Similarly with y.

At the end we need to set the new position:

this.x = this.x + this.dx;
this.y = this.y + this.dy;
Enter fullscreen mode Exit fullscreen mode

I made 3 model: Cirle, Rect, Triangle.

But you can add easily your model:

  • create a model
  • add to ModelFactory
    private static createRandomModel() {
        const speed = Utils.generateRandom(Setup.CONFIG.minSpeed, Setup.CONFIG.maxSpeed)
        const randoModelName = Utils.pickRandomFromArray(Setup.CONFIG.enabledModels)
        switch (randoModelName) {
            case CircleModel.MODEL_NAME:
                return this.createRandomCircle(speed)
                break;
            case TriangleModel.MODEL_NAME:
                return this.createRandomTriangle(speed)
                break;
            case RectModel.MODEL_NAME:
                return this.createRandomRect(speed)
                break;
            default:
                throw new Error(`Model not found with name: ${randoModelName}`)
        }
    }
Enter fullscreen mode Exit fullscreen mode

Howto create importable script?

I just added the init function to the window so you can import the bundle script and call this function.

window.createShapeCanvas = createShapeCanvas
Enter fullscreen mode Exit fullscreen mode

Future plans:

  • add more models
  • add more config options
  • create a react component and publish to npm
💖 💪 🙅 🚩
maurerkrisztian
Krisztián Maurer

Posted on July 27, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Bouncing Shapes Background With Canvas