bebraw
12/28/2014 - 4:54 PM

gradient_animation.js

main();

function main() {
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext('2d');

    animate(function(i) {
        var matrix = generateMatrix(20, 20, function(x, y, xlen, ylen) {
            var fac = fromBoundToBound(0, 1, i / 2000);
            var a = 200000;
            var b = 100000;

            return cycle([fac, 1 - fac, 0, 1], x * y * ((i % a) / b) + y * ((i % a) / b));
        });

        latticeGradient(ctx, matrix);
    });
}

function cycle(arr, amount) {
    amount = amount % arr.length;

    return arr.slice(amount).concat(arr.slice(0, amount));
}

function generateMatrix(rows, columns, fn) {
    var ret = [];
    var i, j, row;

    for (i = 0; i < rows; i++) {
        row = [];

        for (j = 0; j < columns; j++) {
            row.push(fn(i, j, rows, columns));
        }

        ret.push(row);
    }

    return ret;
}

function fromBoundToBound(min, max, t) {
    var mantissa = t % 1;

    if ((t - mantissa) % 2) {
        return max - mantissa;
    }

    return mantissa;
}

function animate(cb) {
    var start = new Date();

    window.requestAnimationFrame(render);

    function render() {
        var now = new Date();
        var diff = now - start;

        cb(diff);

        window.requestAnimationFrame(render);
    }
}

function latticeGradient(ctx, rows) {
    var w = canvas.width;
    var h = canvas.height;
    var rowLength = rows[0].length;
    var columnLength = rows.length;
    var gradient, startColor, endColor, color, fac;
    var upperRow, lowerRow, rowIndex;
    var i, j;

    for (i = 0; i < h; i++) {
        gradient = ctx.createLinearGradient(0, i, w, i);
        rowIndex = Math.floor(i / h * (columnLength - 1));
        upperRow = rows[rowIndex];
        lowerRow = rows[rowIndex + 1];

        fac = (i * (columnLength - 1) / h) % 1;

        for (j = 0; j < rowLength; j++) {
            color = arrayToRGBA(
                lerp(upperRow[j], lowerRow[j], fac)
            );

            gradient.addColorStop(j / (rowLength - 1), color);
        }

        ctx.fillStyle = gradient;
        ctx.fillRect(0, i, w, i);
    }
}

function arrayToRGBA(arr) {
    var ret = arr.map(function(v) {
        // map to [0, 255] and clamp
        return Math.max(Math.min(Math.round(v * 255), 255), 0);
    });

    // alpha should retain its value
    ret[3] = arr[3];

    return 'rgba(' + ret.join(',') + ')';
}

function lerp(a, b, fac) {
    return a.map(function(v, i) {
        return v * (1 - fac) + b[i] * fac;
    });
}