HTML5 Canvases aren't nerve-wracking when used correctly, let's build a particle system

Programming May 07, 2020

Over the last couple of years, HTML5 canvas has  grown substantially, criminally so. People made quite crappy animations and drawings, and there is quite a bit of bad tutorials there as well. Canvas doesn't have to be slow, clunky and difficult.

Canvas is intuitive, awesome and powerful and definitely not slow

HTML5 canvas is awesome. You basically have an API that let's you draw stuff at your heart's will. You can draw and animate pretty much anything you want. but it is a low level API. It doesn't draw an animation, for example. it can draw a circle, but it can't draw the shape of "U".

Setting up the canvas

To set up the canvas, we just need a <canvas> tag with mandatory width and height attributes. To draw stuff on it, we need a canvas rendering 2D context object containing APIs that let's you draw stuff on the canvas.

For this demonstration we use a Particle class that basically draws a circle, and we use the button to add new objects to a sceneGraph. Nothing moves yet, but this is a good starting point.

Adding Motion to the canvas

Adding motion to these particles yields quite a lot of dynamic as you can see in the following pen. To achieve this, we need something that moves these particles. I did not want objects moving in a straight line, bouncing off of the canvas boundaries – this is overdone and doesn't add anything of value to you.

I instead chose circular orbits. I have a class called Orbit which basically initializes with the center of the orbit, the duration of a revolution and initial position (the angle).

Yes, these does take some math, I did my polar and Cartesian co-ordinates pretty well so its kinda natural to me.

Each particle has it's own instance of orbit, and before updating the particle we update the orbit, which calculates the new angle based off the elapsed time, and this calculates the new angle and we get the x,y coordinates. We simply plug those values to the particle and we get these smooth animation.

Finally, instead of using setInterval or setTimeout for updating the animation, we use requestAnimationFrame, this runs just before the screen repaint in the event loop and we get a smooth playback instead of a jittery garbage.

On a i5-9300H laptop CPU I can add anywhere around 15000 - 20000 particles before I start noticing performance drops. Which is enough.

We can hit millions of particles using WebGL/GPU.js but that's  for later.

Sohan Basak

Hi, I am Sohan. A software engineer by profession, I am really passionate about algorithms, AI/ML, Maths and Physics. Play the guitar as a hobby, the maths behind music is fascinating.