DEV Community

Cover image for Bouncing Shapes Background With Canvas
Krisztián Maurer
Krisztián Maurer

Posted on • Edited on

7 2

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

Sentry blog image

How I fixed 20 seconds of lag for every user in just 20 minutes.

Our AI agent was running 10-20 seconds slower than it should, impacting both our own developers and our early adopters. See how I used Sentry Profiling to fix it in record time.

Read more

Top comments (1)

Collapse
 
maurerkrisztian profile image
Krisztián Maurer

What do you think? should I make it a react component?

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more