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

 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

No comments: