Friday, December 9, 2016

letItSnow() // javascript

// NOTE: This script does not work in some browsers, due to lack of support for SVG effects/animation.

'use strict';
function letItSnow(options) { // Joel Elliott <3 CC0 
    var SVG_NS = 'http://www.w3.org/2000/svg';

    var getSnowflakeArm = function (x, y, radius) {
        // TODO: this could be enhanced to make much more intersting snowflake shapes, with input parameters and/or randomized values
        // round all numbers to a max of 2 decimal places
        var x0 = Math.round(x * 100) / 100;
        var y0 = Math.round(y * 100) / 100;
        radius = Math.round(radius * 100) / 100;
        var radiusOffset1 = radius / 5;
        var xArm1 = radius / 5;
        var yArm1 = radius / 10;
        var radiusOffset2 = radiusOffset1 * 2;
        var xArm2 = xArm1 * 2;
        var yArm2 = yArm1 * 2;

        var armPoints = [];
        // draw from center to tip
        armPoints.push({ a: 'M', x: x0, y: y0 });
        armPoints.push({ a: 'L', x: x0, y: y0 - radius });

        // draw first spoke -- from tip, to center, to tip
        armPoints.push({ a: 'M', x: x0 + xArm1, y: y0 - radius + yArm1 });
        armPoints.push({ a: 'L', x: x0, y: y0 - radius + radiusOffset1 });
        armPoints.push({ a: 'L', x: x0 - xArm1, y: y0 - radius + yArm1 });

        // draw second spoke
        armPoints.push({ a: 'M', x: x0 + xArm2, y: y0 - radius + yArm2 });
        armPoints.push({ a: 'L', x: x0, y: y0 - radius + radiusOffset2 });
        armPoints.push({ a: 'L', x: x0 - xArm2, y: y0 - radius + yArm2 });

        var d = '';
        for (var j = 0; j < armPoints.length; j++) {
            var p = armPoints[j];
            d += '\n' + p.a + p.x + ',' + p.y;
        }
        return d;
    }

    var getSnowflake = function (x, y, radius, speed, spin, clockwise) {
        var secondsSpin = (11 - spin) / 4; // spin should be from 1 to 10
        var sign = clockwise ? 1 : -1;

        var g = document.createElementNS(SVG_NS, 'g');

        // the bigger the snowflake, the thicker you need the lines to be
        var strokeWidth = Math.round(radius / 15 * 100) / 100;
        var d = getSnowflakeArm(x, 0, radius);
        for (var i = 0; i < 6; i++) {
            var path = document.createElementNS(SVG_NS, 'path');
            //path.setAttribute('id','Mine' + i);
            path.setAttribute('d', d);
            path.setAttribute('fill', 'none');
            path.setAttribute('stroke-width', strokeWidth);
            path.setAttribute('stroke', '#ffffff');

            var animate = document.createElementNS(SVG_NS, 'animateTransform');
            animate.setAttribute('attributeName', 'transform');
            animate.setAttribute('type', 'rotate');
            animate.setAttribute('from', (i + 0) * 60 * sign + ' ' + x + ' ' + 0);
            animate.setAttribute('to', (i + 1) * 60 * sign + ' ' + x + ' ' + 0);
            animate.setAttribute('dur', secondsSpin + 's');
            animate.setAttribute('repeatCount', 'indefinite');
            path.appendChild(animate);

            g.appendChild(path);
        }

        var h = window.innerHeight;
        var secondsFall = h / speed;
        var fallenBeginSeconds = secondsFall * y / h;
        var animate = document.createElementNS(SVG_NS, 'animateTransform');
        animate.setAttribute('attributeName', 'transform');
        animate.setAttribute('type', 'translate');
        animate.setAttribute('from', '0 ' + (0 - radius));
        animate.setAttribute('to', '0 ' + (h + radius));
        animate.setAttribute('dur', secondsFall + 's');
        animate.setAttribute('begin', -fallenBeginSeconds + 's');
        animate.setAttribute('repeatCount', 'indefinite');
        g.appendChild(animate);

        return g;
    }

    { // validation/defaults for all used option values
        if (typeof options == 'undefined') options = {};
        var validOrDefault = function (value, min, max, defaultValue) {
            if (isNaN(value))
                return defaultValue;
            value = Number(value);
            if (value < min || value > max)
                return defaultValue;
            return value;
        }
        options.numFlakes = validOrDefault(options.numFlakes, 1, 500, 75);
        options.minSize = validOrDefault(options.minSize, 5, 50, 5);
        options.maxSize = validOrDefault(options.maxSize, 5, 50, 20);
        options.minSpin = validOrDefault(options.minSpin, 0, 10, 3);
        options.maxSpin = validOrDefault(options.maxSpin, 0, 10, 7);
        options.minSpeed = validOrDefault(options.minSpeed, 0, 100, 10);
        options.maxSpeed = validOrDefault(options.maxSpeed, 0, 100, 90);
        if (isNaN(options.zIndex)) options.zIndex = -1;
    }

    // create <svg>, set to size of page, add animated snowflakes
    var svg = document.createElementNS(SVG_NS, 'svg');
    svg.setAttribute('width', window.innerWidth);
    svg.setAttribute('height', window.innerHeight);
    svg.style.position = 'fixed';
    svg.style.left = 0;
    svg.style.top = 0;
    svg.style.zIndex = options.zIndex;

    for (var i = 0; i < options.numFlakes; i++) {
        var x = Math.random() * window.innerWidth;
        var y = Math.random() * window.innerHeight;
        var radius = Math.random() * (options.maxSize - options.minSize) + options.minSize;
        var spin = Math.random() * (options.maxSpin - options.minSpin) + options.minSpin;
        var clockwise = (Math.random() > 0.5);
        var speed = Math.random() * (options.maxSpeed - options.minSpeed) + options.minSpeed;
        var snowflake = getSnowflake(x, y, radius, speed, spin, clockwise);
        svg.appendChild(snowflake);
    }
    if (isNaN(options.delay) == false) {
        var delaySeconds = Number(options.delay);
        if (delaySeconds > 0) {
            svg.style.display = 'none';
            window.setTimeout(function () { svg.style.display = ''; },
             delaySeconds * 1000);
        }
    }
    document.body.appendChild(svg);
}

No comments:

Post a Comment