javascriptcanvascolorscolor-blending

Blend colors between values


I am trying to create like a time countdown using canvas arc, the drawing is ok, but the arc will have a stroke color, which I want to sort of blend.

The way I draw the arc is by using a number between 0 to 100, 100 is basically the full arc, 0 is nothing. When the value is over 66 and under (or equal to) 100 it'll be a blend between green and orange, 100 is total green and 66 is total orange. 65 and down will be a mix between orange and red, where total red is 0.

I am clueless on where to start, no ideas on what to search for to do research on how to get the values.

Can anybody please point me in the right direction?

Here's my code so far x)

static color (value)
{
    const StartColor  = 0x66BB6A; // Green
    const MiddleColor = 0xFFA726; // Orange
    const EndColor    = 0xEF5350; // Red  
}

EDIT: This is the result I was looking for. It's now working exactly like I want it to. Cheers.

https://youtu.be/IeR_zMzSaAU


Solution

  • Of course, using a library dedicated to this will be easier. But just in case anyone is interested in doing the math, you can break the hex integers into components and then interpolate each component separately to get the color at a specific place:

    // break hex integer into components:
    const getComonents = (color) => Array.from({length: 3}, (_, i) => Math.floor(color / 16 ** (2 * i) % 16 ** 2))
    
    // interpolate arrays by component
    const interpolate = (arr1, arr2, percent) => arr1.map((v, index) => Math.floor(v + (arr2[index] - v) * (percent / 100)))
    
    function colors(value) {
      const StartColor  = 0x11FF11; // Green
      const MiddleColor = 0xFFA726; // Orange
      const EndColor    = 0xEF5350; // Red
      
      let [start, end, v] = value < 50 
          ? [StartColor, MiddleColor, value * 2 ] 
          : [MiddleColor, EndColor, (value - 50) * 2]
    
      let interpoled = interpolate(getComonents(start), getComonents(end), v)
      
      return interpoled.reduce((n, component, index) => n + component * (16 ** (index * 2)), 0)
    }
    
    const canvas = document.getElementById('the_canvas')
    const ctx = canvas.getContext('2d')
    
    for (let i = 0; i<100; i++){
      ctx.beginPath();
      
      // padStart is needed to make sure a value of `ff` becomes `0000ff`
      ctx.fillStyle = "#" + colors(i).toString(16).padStart(6, '0')
      ctx.rect(i*5, 0, i*5+5, 300);
      ctx.fill()
    }
    <canvas id="the_canvas" width="500" height="300"></canvas>