Efecto Navideño para blogs usando HTML5

Luego de implementar el citado evento en mi propio blog, he recibido muchas preguntas de cómo lo logré.

image

He aquí la respuesta:

Este trabajo es basado en un algoritmo de Javascript para HTML5 creado por David Flanagan que se basa en generar un elemento canvas por cada copito de nieve bajando en el blog. Entonces cada copo de nieve se agrega al DOM y es animado usando posicionamiento a través de CSS. Sin embargo se puede mejor usar un solo canvas y animar los copos dentro de este tal como lo sugiere Giorgo Sardo, con el fin de ahorrar memoria. Esto sin embargo puede producir que se bloquee la interacción normal con la página… es así que lo mejor es poner el canvas en un background de menor prioridad (atrás del contenido) tal como lo pueden ver en mi blog.

Este es el JavaScript requerido:

 (function () {

    // Start Animation only if browser support <canvas>
    if (document.createElement('canvas').getContext) {
        if (document.readyState === 'complete')
            Snow();
        else
            window.addEventListener('DOMContentLoaded', Snow,
         false);
    }

    var deg = Math.PI / 180;         //Degrees to radians
    var sqrt3_2 = Math.sqrt(3) / 2; //Height of an eq triangle
    var flakes = [];               // Things that are dropping
    var scrollspeed = 64;   // How often we animate things
    var snowspeed = 500;   // How often we add a new snowflake
    var maxflakes = 20;//Max number of flakes to be added
    var rand = function (n) { return Math.floor(n * 
        Math.random()); }

    var canvas, sky;
    var snowingTimer;
    var invalidateMeasure = false;

    function Snow() {
        canvas = document.createElement('canvas');
        canvas.style.position = 'fixed';
        canvas.style.top = '0px';
        canvas.style.left = '0px';
        canvas.style.zIndex = '0';
        document.body.insertBefore(canvas, 
            document.body.firstChild);
        sky = canvas.getContext('2d');

        ResetCanvas();

        snowingTimer = setInterval(createSnowflake,snowspeed);
        setInterval(moveSnowflakes, scrollspeed);

        window.addEventListener('resize', ResetCanvas, false);
    }

    function ResetCanvas() {
        invalidateMeasure = true;
        canvas.width = document.body.offsetWidth;
        canvas.height = window.innerHeight;
        sky.strokeStyle = '#0066CC';
        sky.fillStyle = 'white';
    }

    function drawFlake(x, y, size, order) {
        sky.save();
        sky.translate(x, y);
        snowflake(order, 0, Math.floor(sqrt3_2 * y), size);
        sky.fill();
        sky.stroke();
        sky.restore();
    }

    function snowflake(n, x, y, len) {
        sky.save();           // Save current transformation
        sky.beginPath();
        sky.translate(x, y);   
        // Translate to starting point
        sky.moveTo(0, 0);      // Begin a new subpath there
        leg(n);       // Draw the first leg of the fractal
        sky.rotate(-120 * deg); 
         // Rotate 120 degrees anticlockwise
        leg(n);             // Draw the second leg
        sky.rotate(-120 * deg); // Rotate again.
        leg(n);             // Draw the final leg
        sky.closePath();      // Close the subpath
        sky.restore();        
        // Restore original transformation

        // Draw a single leg of a level-n Koch snowflake.
        // Leaves the current point at the end of
        // the leg it has drawn and translates the coordinate
        // system so the current point is (0,0). 
        // This means you
        // can easily call rotate() after drawing a leg.
        function leg(n) {
            sky.save();           // Save current transform
            if (n == 0) {           // Non-recursive case:
                sky.lineTo(len, 0);//   Just a horizontal line
            }
            else { // Recursive case:           _  _
                //     draw 4 sub-legs like:  \/
                sky.scale(1 / 3, 1 / 3);  
                 // Sub-legs are 1/3rd size
                leg(n - 1);           
              // Draw the first sub-leg
                sky.rotate(60 * deg);  
              // Turn 60 degrees clockwise
                leg(n - 1);          
               // Draw the second sub-leg
                sky.rotate(-120 * deg); 
              // Rotate 120 degrees back
                leg(n - 1);           // Third sub-leg
                sky.rotate(60 * deg);  
                  // Back to original heading
                leg(n - 1);           // Final sub-leg
            }
            sky.restore();            // Restore the transform
            sky.translate(len, 0);// Translate to end of leg
        }
    }

    function createSnowflake() {
        var order = 2;
        var size = 10 + rand(90);
        var t = (document.body.offsetWidth - 964) / 2;
        var x = (rand(2) == 0) ? rand(t) : t + 964 + rand(t);
        // Make it fit with my blog
        var y = window.pageYOffset;

        flakes.push({ x: x, y: y, vx: 
         0, vy: 3 + rand(3), size: size, order: order });

        if (flakes.length > maxflakes) 
           clearInterval(snowingTimer);
    }

    function moveSnowflakes() {
        sky.clearRect(0, 0, canvas.width, canvas.height);

        var maxy = canvas.height;

        for (var i = 0; i < flakes.length; i++) {
            var flake = flakes[i];

            flake.y += flake.vy;
            flake.x += flake.vx;

            if (flake.y > maxy) flake.y = 0;
            if (invalidateMeasure) {
                var t = (canvas.width - 964) / 2;
                flake.x = (rand(2) == 0) ? 
                   rand(t) : t + 964 + rand(t);
            }

            drawFlake(flake.x,flake.y,flake.size,flake.order);

            // Sometimes change the sideways velocity
            if (rand(4) == 1) flake.vx += (rand(11) - 5) / 10;
            if (flake.vx > 2) flake.vx = 2;
            if (flake.vx < -2) flake.vx = -2;
        }
        if (invalidateMeasure) invalidateMeasure = false;
    }


}());
 Felices fiestas! 

snowflake, snow effect, JavaScript, html5, css, canvas, animation, christmas, blog