Is there some kind of trick for creating a gradient with multiple stops in 2d space? What I would like to do is create a rectangle in my canvas, and then have a different color stop at each corner.
I've tried creating 4 gradients, one at each corner, that points to the opposite corner. (tried linear and circular). but that doesn't produce the effect I want because the center is always off color in a circular manner.
The effect I want would be similar to having 2 linear horizontal gradients placed on top of each other. and then a 3rd vertical linear gradient which doesn't affect the colors of the first two gradients but just fades the bottom gradient into the top gradient as it goes down. so that the top two corners are the first linear gradient and the bottom two corners are the second linear gradient.
I've tried playing around with globalCompositeOperation but the closest I've been able to achieve is a 3 sided gradient. not 4.
The only method I can think of for doing this is building my rectangle one line at a time. with each line having a linear gradient that is recalculated and changed slightly so that it's the second gradient by the time to draws the bottom line. but that doesn't seem like the most efficient (or easiest to program) way to do it.
Pictures
I guess I'm too new here to link to photos. But here is a link to 3 images on my google photos.
https://plus.google.com/photos/116764547896287695338/albums/6094993027344790369?authkey=CJnZ0I3JxbOMag
image 1: First Gradient (setting the top two corner colors)
image 2: Second Gradient (setting the bottom two corner colors)
image 3: Both image 1 & 2 blended together vertically so that the top two colors fade into the bottom two colors.
There is no direct operation for something like this. In certain special cases (ie. colorpicker) you can get away with two separate gradients.
If you want arbitrary color per corner, you will have to perform it pixel-wise. In other words do linear interpolation on both x and y for each pixel. I've done something like this for triangle gradients myself.
Compared to that four corner variant without any special transformation would be simple. You would simply have to go through each x and y of the canvas while keeping track of the state (two lerps per pixel).
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With