Post

Intro to Canvas with Particles

This is what we’ll be making!

If you can’t see anything then your device doesn’t support canvas. You can still follow along, but it’ll be more fun if you can see your work.

Canvas is a super fun way to create animations on the browser! It’s also very easy to get started.

To make it even easier to start, use CodePen to write your code. I’ll be sharing CodePen examples along the way.

Finally I’m writing this to get you started with canvas very quickly. There are many ways to optimise the code below, but I’ve used this technique to make an entire snake game, so it’ll suffice.

HTML

Add the following html to the page.

<canvas id="myCanvas" width="500px" height="300px"></canvas>

JavaScript

That HTML sure was hard.

Let’s get something drawn on the canvas:

var canvas = document.getElementById("myCanvas");

var ctx = canvas.getContext('2d');

ctx.fillStyle = "purple";
ctx.fillRect(10, 40, 10, 25);

You’ve successfully drawn on the canvas.

See the Pen GWJMYO by Andrew Jakubowicz (@Spyr1014) on CodePen.

Let’s see what we did.

On the first line we get a reference to the canvas in the html. Before using a canvas, we must choose how to use it. In this case we’ll choose to use the canvas with a '2d' context. There are other contexts as well, but the '2d' context is perfect for 2d renderings.

Once we get a context, we can use that context’s methods to draw on the canvas. Here we pick a color, and then draw a rectangle with that color.

The canvas is like instructing a painter. If we tell a painter to dip their brush in pink paint, it shouldn’t be surprising when everything is drawn is pink.

See the Pen bqdoPQ by Andrew Jakubowicz (@Spyr1014) on CodePen.

Furthering this analogy, for an animation the painter must draw the new position of the object every frame.

To create new frames we use a function called requestAnimationFrame().

requestAnimationFrame() takes a function that it will call on the next frame. To create an animation, we’ll create our own function called update() and then we’ll call it over and over again every frame. The update() function we write will update the square.

Let’s create a square that falls down the screen and resets back to it’s starting position when it hits the ground.

var canvas = document.getElementById("myCanvas"),
    ctx = canvas.getContext('2d');

ctx.fillStyle = "pink";

var squarePosition = 0;
var maxFallDistance = 50;

function update(){
  // Uncomment below and see what happens.
  // ctx.clearRect(0, 0, 500, 300);
  
  requestAnimationFrame(update);
  ctx.fillRect(20, squarePosition, 10, 10);
  
  // Now we will move the position.
  squarePosition = squarePosition + 0.1;
  
  // Move squarePosition back to initial
  // position when fallHeight reached
  if (squarePosition > maxFallDistance) {
    squarePosition = 0
  }
}

update();

See the Pen OpVOJo by Andrew Jakubowicz (@Spyr1014) on CodePen.

Notice that it’s not a falling square, but an elongating line! On the first line of the update function I’ve commented out ctx.clearRect(0, 0, 500, 300);. What do you notice when you uncomment this?

Before uncommenting this line, the painter paints the square some distance lower on the canvas. This painter never paints over the canvas clearing it of past squares. With the command ctx.clearRect(0, 0, 500, 300);, the painter starts off each frame by painting over the entire canvas. Try changing the clearRect to fillRect and change the fillStyle. This is how you add a background. By default the canvas is transparent, and using clearRect paints the canvas transparently. This is fantastic if you want to overlay your canvas on top of other html elements on the page.

Now that we can move a single square, we can add more squares. An easy method I use is to allow each particle to maintain it’s own state, and store any particles in an array.

Then we can forEach over each element in the array calling update() on each of them, followed by a draw() function.

Finally we want to destroy particles eventually! Because we store our particles in an array, we can filter over the array using the isAlive() method. Filter will filter out anything that isn’t alive.

Below is a full example with a very simple particle, followed by a demo:

var canvas = document.getElementById("myCanvas"),
    ctx = canvas.getContext('2d');

ctx.fillStyle = "pink";

// Constructor for a single particle
function Particle(x, y, heightOfCanvas){
    this.x = x;
    this.y = y;
    this.speed = 1;
    this.heightOfCanvas = heightOfCanvas;

    this.update = function(){
        this.y += this.speed;
    }
    this.draw = function(){
        ctx.fillRect(this.x, this.y, 10, 10);
    }
    this.isAlive = function(){
        return this.y < this.heightOfCanvas;
    }
}

var particlesList = [];

function update(){
  ctx.clearRect(0, 0, 500, 200);    // Clear frame.
  
  // Get next frame ready
  requestAnimationFrame(update);

  // Fill array
  if (particlesList.length < 10) {
      particlesList.push(new Particle(Math.random() * 500, 0, 300));
  }
  
  // Move the particles
  particlesList.forEach(p => p.update());

  // Cull any "dead" particles
  particlesList = particlesList.filter(p => p.isAlive());

  // Draw the living particles
  particlesList.forEach(p => p.draw())

}

update();

See the Pen RpWNZz by Andrew Jakubowicz (@Spyr1014) on CodePen.

You have the power

There are many qualities that you can change! Feel free to invent new particles that die in different ways. Maybe when a particle dies it adds a bunch more particles to the array? Maybe the particle stores an opacity and fades out?

If you find a problem or have any questions/concerns, please tweet me!