bebraw
12/24/2014 - 8:20 AM

lattice_gradient.js

main();

function main() {
    var canvas = document.getElementById("canvas");

    latticeGradient(canvas, [
      [[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [1, 0, 0, 1]],
      [[0, 1, 0, 1], [0, 0, 1, 1], [1, 0, 0, 1], [0, 1, 0, 1]],
      [[0, 0, 1, 1], [1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1]],
      [[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [1, 0, 0, 1]]
    ]);
}

function latticeGradient(canvas, rows) {
    var ctx = canvas.getContext('2d');
    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;
    });
}