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