Creating particles with JavaScript and Canvas

- Andrés Cruz

En español
Creating particles with JavaScript and Canvas

Example

In this post we will see how to create a particle system using JavaScript and Canvas.

Creating the particle system (JavaScript)

As always, I first present the complete code of the particle experiment which we will analyze in the next section:

    var c = document.getElementById("canvas-club");
    var ctx = c.getContext("2d");
    var w = c.width = window.innerWidth;
    var h = c.height = window.innerHeight;
    var particles = [];
    var maxParticles = 100;
    var size = 5;
    var r = size / 2;
    var clearColor = "rgba(0, 0, 0, .1)";

    function random(min, max) {
        return (Math.random() * (max - min)) + min;
    }

    function P() {
    }

    P.prototype = {
        init: function () {
            this.x = random(0, (w - size));
            this.y = h + random(0, 20);
            this.vx = 0;
            this.vy = random(-1, -2);
        },
        draw: function () {
            var hue = (h - this.y) * .6;

            ctx.fillStyle = "hsla(" + hue + ", 100%, 50%, .8)";
            ctx.strokeStyle = "hsla(" + hue + ", 100%, 50%, " + this.alpha + ")";
            ctx.lineWidth = r / 2;

            ctx.beginPath();
            ctx.arc(this.x + r, this.y + r, r, 0, 2 * Math.PI, false);
            ctx.fill();

            this.update();
        },
        update: function () {

            this.x += this.vx;
            this.y += this.vy;
            this.vx *= 1.15;
            if (this.y < h * .8 && Math.random() > .5) {
                this.vx = random(-1, 1);
                this.vy -= .05;
            }

            if (this.y + 50 < 0) {
                this.init();
            }
        }
    }

    function setup() {

        for (var i = 0; i < maxParticles; i++) {
            (function (x) {
                setTimeout(function () {
                    var p = new P();
                    p.init();
                    particles.push(p);
                }, x * 100)

            })(i);
        }
    }
    function anim() {

        for (var i in particles) {
            var p = particles[i];
            p.draw();
        }

        ctx.fillStyle = clearColor;
        ctx.fillRect(0, 0, w, h);

        window.requestAnimationFrame(anim);
    }

    setup();
    anim();

Analyzing the above JavaScript code...

First I would like to start with some considerations:

  • Each particle is painted independently of the others on the Canvas as you can see in the draw method.
  • The color of the particles varies according to the distance traveled.
  • The tail of the particles is achieved by re-painting a transparent dark background over the entire Canvas each time the particles are painted.

Now let's take a closer look at the simple JavaScript code.

Global Variables

In the first section all global variables are declared; among them are those that allow access to the Canvas and its context, in addition to the dimensions of the Canvas:

    var c = document.getElementById("canvas-club");
    var ctx = c.getContext("2d");
    var w = c.width = window.innerWidth;
    var h = c.height = window.innerHeight;

The particles will have different sizes, colors and speeds that are calculated randomly (Ramdom), these mentioned characteristics are registered through a set of variables; the particles will be stored in an array where a particle corresponds to a position in the array:

    var p = new P();
    p.init();
    particles.push(p);

The "base class" of particles

We use the prototype property to create a kind of "base class" for our particles and access their properties:

function P() {}

    P.prototype = {
        init: function () {
            this.x = random(0, (w - size));
            this.y = h + random(0, 20);
            this.vx = 0;
            this.vy = random(-1, -2);
        },
        draw: function () {
            var hue = (h - this.y) * .6;

            ctx.fillStyle = "hsla(" + hue + ", 100%, 50%, .8)";
            ctx.strokeStyle = "hsla(" + hue + ", 100%, 50%, " + this.alpha + ")";
            ctx.lineWidth = r / 2;

            ctx.beginPath();
            ctx.arc(this.x + r, this.y + r, r, 0, 2 * Math.PI, false);
            ctx.fill();

            this.update();
        },
        update: function () {

            this.x += this.vx;
            this.y += this.vy;
            this.vx *= 1.15;
            if (this.y < h * .8 && Math.random() > .5) {
                this.vx = random(-1, 1);
                this.vy -= .05;
            }

            if (this.y + 50 < 0) {
                this.init();
            }
        }
    }

More information about the prototype property in: MDN: Object.prototype.

As its name suggests, the draw function paints the little circles that are our particles.

The update function alters the behavior of the particles, changing by random values (or initializing the position once they are not visible within the Canvas) their position and speed.

Creating the structure for all particles

The setTimeout function adds particles little by little based on a varying time interval:

    function setup() {

        for (var i = 0; i < maxParticles; i++) {
            (function (x) {
                setTimeout(function () {
                    var p = new P();
                    p.init();
                    particles.push(p);
                }, x * 100)

            })(i);
        }
    }

The particles are created, painted and animated little by little; this results in the particles being displayed progressively and not all clumped together at once.

Painting the particles (animating)

In this section we paint one particle at a time and use the window.requestAnimationFrame method that was already covered in a previous installment called: EL SECRETO DE LAS ANIMACIONES EN JAVASCRIPT (REQUESTANIMATIONFRAME()); remembering a bit the use of the Window.requestAnimationFrame() function, it allows you to animate figures drawn on a Canvas element:

 

    function anim() {
        ctx.fillStyle = clearColor;
        ctx.fillRect(0, 0, w, h);

        for (var i in particles) {
            var p = particles[i];
            p.draw();
        }
        window.requestAnimationFrame(anim);
    }

The lines of code:

ctx.fillStyle = clearColor;
ctx.fillRect(0, 0, w, h);

They paint a transparent black rectangle in order to show a tail to the moving circles; the lighter the background color, the longer this tail will be left behind by the particles:

Cola Partícula

If this transparent black background were not painted, our experiment would be as follows:

Partícula sin fondo negro transparente

The rest of the JavaScript code is easy to interpret; again I leave the link of the original experiment: CodePen: Livelines.

Andrés Cruz

Develop with Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz In Udemy

I agree to receive announcements of interest about this Blog.