DEV Community

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

Posted on • Edited on

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

Top comments (1)

Collapse
 
maurerkrisztian profile image
Krisztián Maurer

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