html5画布渐变在4个角落

时间:2014-12-20 14:12:54

标签: javascript html5 canvas gradient

在2d空间中创建具有多个停靠点的渐变是否有某种技巧?我想要做的是在画布上创建一个矩形,然后在每个角落都有不同的颜色停止。

我尝试创建4个渐变,每个角落一个,指向对角。 (试过线性和圆形)。但这并没有产生我想要的效果,因为中心总是以圆形方式变色。

我想要的效果类似于将2个线性水平渐变放在彼此之上。然后是第3个垂直线性渐变,它不会影响前两个渐变的颜色,但只是在它向下时将底部渐变淡入顶部渐变。所以前两个角是第一个线性渐变,而下两个角是第二个线性渐变。

我尝试过使用globalCompositeOperation但最接近我能够实现的是3面渐变。不是4。

我能想到的唯一方法是一次构建一行矩形。每条线都有一个线性渐变,重新计算并稍微改变,以便在绘制底线时绘制第二个渐变。但这似乎不是最有效(或最容易编程)的方式。

图片

我想我在这里太新了,无法链接到照片。但这里有一个链接到我的谷歌照片上的3张图片。

https://plus.google.com/photos/116764547896287695338/albums/6094993027344790369?authkey=CJnZ0I3JxbOMag

图像1:第一个渐变(设置前两个角落颜色)

图像2:第二个渐变(设置底部两个角落颜色)

图像3:图像1和图像1都是2垂直混合在一起,使前两种颜色淡入底部两种颜色。

1 个答案:

答案 0 :(得分:4)

这样的事情没有直接的操作。在某些特殊情况下(即colorpicker),您可以使用两个单独的渐变来逃避。

如果你想要每个角落任意颜色,你必须以像素为单位执行它。换句话说,对每个像素在x和y上进行线性插值。我自己为triangle gradients做了类似的事。

与没有任何特殊转换的四角变体相比,这很简单。你只需要遍历画布的每个x和y,同时跟踪状态(每个像素两个lerps)。

代码示例

HTML

<canvas id="canvas" width="300" height="300"></canvas>

JS

main();

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

    quadGradient(canvas, {
      topLeft: [1, 1, 1, 1],
      topRight: [0, 0, 0, 1],
      bottomLeft: [0, 0, 0, 1],
      bottomRight: [1, 1, 1, 1]
    });
}

function quadGradient(canvas, corners) {
    var ctx = canvas.getContext('2d');
    var w = canvas.width;
    var h = canvas.height;
    var gradient, startColor, endColor, fac;

    for(var i = 0; i < h; i++) {
        gradient = ctx.createLinearGradient(0, i, w, i);
        fac = i / (h - 1);

        startColor = arrayToRGBA(
          lerp(corners.topLeft, corners.bottomLeft, fac)
        );
        endColor = arrayToRGBA(
          lerp(corners.topRight, corners.bottomRight, fac)
        );

        gradient.addColorStop(0, startColor);
        gradient.addColorStop(1, endColor);

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

JSbin