Intro
One of the things I love the most about the HTML5 canvas are particle systems. For this post I prepared a small but good looking example. One of the colleagues from work even thought that I used some kind of graphical framework to do this and couldn't believe it's just plain old javascript.
The Particle definition
var Particle = function (ind) {
// remember the index inside array
// faster performance on collisions
this.ind = ind;
// initial position
this.x = randomMax(canvas.width);
this.y = randomMax(canvas.height);
// random direction vectors
this.dy = -5 + randomMax(10);
this.dx = -5 + randomMax(10);
// radius (small flash in the beginning)
this.r = randomMax(radiusmax);
// give it a random color from the set
this.color = colorSet[Math.floor(Math.random() * colorSet.length)];
};
Particle draw method
// reduce the size of the particle down to the minimal size
// using log function - looks nicer and more organic
this.r = this.r > miParticleSize ?
flashfactor * (Math.log(this.r) / Math.LN10)
: miParticleSize;
// adjust particle position
this.y += this.dy;
this.x += this.dx;
// check for collision with other particles
// only on same color
for (var i = this.ind + 1; i < particleSystem.particles.length; i++) {
if (distance(this, particleSystem.particles[i]) < criticalDistance
&& this.color === particleSystem.particles[i].color) {
this.r = radiusmax;
particleSystem.particles[i].r = radiusmax;
}
}
// if the particle is outside of the canvas
// or moving vectors are both 0
if (this.x < 0 || this.x > canvas.width
|| this.y < 0 || this.y > canvas.height
|| (this.dy === 0 && this.dx === 0)) {
// initialize the particle again
this.x = randomMax(canvas.width);
this.y = randomMax(canvas.height);
this.dy = -5 + randomMax(10);
this.dx = -5 + randomMax(10);
}
ctx.beginPath();
// this is the part that makes people thing it's a framework
// simple radial gradient
fillStyle = ctx.createRadialGradient(this.x, this.y, this.r * 0.001,
this.x, this.y, this.r
);
fillStyle.addColorStop(0, this.color);
fillStyle.addColorStop(1, particleBackground);
// particle drawing code
ctx.fillStyle = fillStyle;
ctx.beginPath();
ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
ctx.fill();
Other than helper function and standard shims that's all there is to it.
Firefox issues
I couldn't find why firefox deals so bad with a larger number of particles, essentially everything freezes past 100 particles on firefox. Initialy I thought it's my draw method, but turned out that there's not much to be improved there.
Even when I removed the draw code and let the firefox "draw" the objects with an empty method the performace was still very poor (around 5-6 fps). If you perhaps figured it out or know about some issues please let me know!
And here's my example on:Codepen
When I saw it the first time I knew it's going to take a couple of tricks to get the timings right
and since I wasn't completely satisfied with the way I solved the number Pi visualization I decided
that I had to implement a state machine.
This example is more about timings and matching colors and shapes while the math is pretty straight forward and relatively simple.
I've spent most of the evening analyzing the movement, drawing triangles, calculating the angles,
making canvas experiments. At one point I came to a conclusion that the moving dot is nothing more
than a representation of a tan function and felt a bit stupid because it should have been obvious!