Ollie
Ollie

Reputation: 1134

Calculate a colour in a linear gradient

I'd like to implement something like the powerpoint image below. A gradient that goes between three values.

It starts at A (-1), the mid point is B (0), and the end is C (1).

I have realised that I can save some effort by calculating the 'start' as a-to-b, and the 'end' as b-to-c. I can do as 2 sets of 2 gradients, instead of 1 gradient with three values.

But I'm stumped (despite googling) on how to get from one colour to another - ideally in the RGB colour space.

I'd like to be able to have something like this -

const colourSpace = (value, startColor, endColor) => {...}

colorSpace(-0.25, red, yellow) // some sort of orangey color
colorSpace(1, yellow, green) // fully green
colorSpace(0.8, yellow, green) // mostly green

This isn't a front-end application, so no CSS gradients - which is what google was mostly referencing.

Thanks all, Ollie

a three point gradient

Upvotes: 1

Views: 4605

Answers (2)

Ollie
Ollie

Reputation: 1134

I ended up using Chroma for converting between colour spaces.

Upvotes: 0

Mark
Mark

Reputation: 92440

If you aren't too worried about being perceptually consistent across the color space (you would need to work in something like LAB mode to do that), you can just take the linear interpolation in RGB space. Basically you take a distance (between 0 and 1), multiply it by the different in the coordinates, and add it to the first one. This will allow you to find arbitrary points (i.e colors) along the line between any two colors.

For example between red and yellow:

let canvas = document.getElementById('canvas')
var ctx = canvas.getContext('2d');

let rgb1 = [255, 0, 0]    // red
let rgb2 = [255, 255, 0]  // yellow

function getPoint(d, a1, a2) {
  // find a color d% between a1 and a2
  return a1.map((p, i) => Math.floor(a1[i] + d * (a2[i] - a1[i])))
}

// for demo purposes fill a canvas
for (let i = 0, j = 0; i < 1; i += .002, j++) {
  let rgb = getPoint(i, rgb1, rgb2)
  ctx.fillStyle = `rgba(${rgb.join(",")}, 1)`
  ctx.fillRect(j, 0, 1, 200);
}
<canvas id="canvas" width="500"></canvas>

You can repeat this to get multiple 'stops' in the gradient.

Upvotes: 1

Related Questions