Creando partículas con JavaScript y Canvas

- Andrés Cruz

In english

Ver ejemplo

En esta entrada veremos cómo crear un sistema de partículas empleando JavaScript y Canvas.

Creando el sistema de partículas (JavaScript)

Al igual que siempre, primero les presento el código completo del experimento de partículas el cual analizaremos en la siguiente sección:

    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();

Analizando el código JavaScript anterior...

Primero quisiera comenzar con algunas consideraciones:

  • Cada partícula es pintada independientemente de las demás en en Canvas como podrás ver el el método draw.
  • A las partículas se les varía el color según la distancia recorrida.
  • La cola de las partículas se logra re-pintando un fondo oscuro transparente sobre todo el Canvas cada vez que se pinten las partículas.

Ahora si veamos en detalle el sencillo código JavaScript.

Variables Globales

En la primera sección son declaradas todas las variables globales; entre las mismas se encuentran aquellas que permiten acceder al Canvas y su contexto, además de las dimensiones del Canvas:

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

Las partículas tendrán tamaños, colores y velocidades distintas que son calculadas aleatoriamente (Ramdom), estas características mencionadas son registradas a través de un conjunto de variables; las partículas serán almacenadas en un array en donde una partícula corresponde a una posición del array:

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

La "clase base" de las partículas

Empleamos la propiedad prototype para crear una especie de "clase base" para nuestras partículas y acceder a sus propiedades:

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();
            }
        }
    }

Más información sobre la propiedad prototype en: MDN: Object.prototype.

Como su nombre indica, la función draw pinta los pequeños círculos que son nuestras partículas.

La función update altera el comportamiento de las partículas, cambiando por valores aleatorios (o inicializando la posición una vez que no sean visibles dentro del Canvas) la posición y velocidad de las mismas.

Creando la estructura para todas las partículas

Con la función setTimeout se agregan partículas poco a poco en base a un intervalo de tiempo variante:

    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);
        }
    }

Se van creando, pintando y animando las partículas poco a poco; esto da como resultado que las partículas se van mostrando progresivamente y no todas agrupadas de una vez.

Pintando las partículas (animando)

En esta sección pintamos una partícula por vez y empleamos el método window.requestAnimationFrame que ya fue tratado en una entrega anterior llamada: EL SECRETO DE LAS ANIMACIONES EN JAVASCRIPT (REQUESTANIMATIONFRAME()); recordando un poco el uso de la función Window.requestAnimationFrame(), permite animar figuras dibujadas en un elemento Canvas:

 

    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);
    }

Las líneas de código:

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

Pintan un rectángulo negro transparente con el objetivo de mostrar una cola a los círculos moviéndose; mientras más claro el color de fondo, más largo será esta cola dejada por las partículas:

Cola Partícula

Si no fuera pintado este fondo negro transparente nuestro experimento quedaría de la siguiente forma:

Partícula sin fondo negro transparente

El resto del código JavaScript es de facil interpretación; de nuevo les dejo el enlace del experimento original: CodePen: Livelines.

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy