2013-09-28

Canvas plasma particles

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 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

No comments: