yesman
yesman

Reputation: 7838

JavaScript - how do you programmatically calculate colours?

In a JavaScript/jQuery app, I want to set the color of a div element based on an external variable. From low to high values of this variable, you go past the colors green to red. Now, I could do this:

setColor: function(quantity)
{
    var color;
    if(quantity <= -1000)
    {
       color = '#00ff00'
    }
    else if(quantity > -1000 && quantity <= -900)
    {
       color = '#11ee00'
    }

    // a million more else if statements

    return color;
} 

Anything that's -1000 or below is #00ff00 (green), and everything that's +1000 or above is #ff0000 (red), with 0 being #ffff00 (yellow). There's lots of color variations in between these 3 extremes: for example, a value of -950 would be a slightly more redder shade of green than -951.

But isn't there a formula for this kind of stuff, so that I don't end with a 1000 line function?

Upvotes: 1

Views: 349

Answers (3)

Martin Ernst
Martin Ernst

Reputation: 3289

"A slightly more redder shade of green" becomes yellowish, because the color in the middle between red and green is yellow. So this function returns an RGB-string beeing pure green when value is <= lower limit, red when value >= upper limit and yellow when value is middle (0 in your case), and all shades in between.

var low = -1000, upp = 1000,
    mid = (upp + low) / 2, dif = (upp - low) / 2;

function grade(value) {
    var r = 255, g = 255, b = 0;
    if (value <= low) r = 0;
    else if (value >= upp) g = 0;
    else if (value < mid) r = Math.round(255 * Math.abs(low - value) / dif);
    else if (value > mid) g = Math.round(255 * Math.abs(upp - value) / dif);
    return  'rgb(' + r + ',' + g + ',' + b + ')';
}

Adjust vars low and upp to your usecase. The function is easy to adapt to colorchanges between green/cyan/blue or red/purple/blue. If you need a full rainbow some more effort is required.

Upvotes: 1

Maurice Perry
Maurice Perry

Reputation: 32831

There is a color manipulation library that's called TinyColor. What you want to do, is vary the hue. This would be done like this:

var red = tinycolor("#FF0000").toHsv();
var green = tinycolor("#00FF00").toHsv(), h, col, hex;

h = green.h + (red.h-green.h)*(quantity+1000)/2000;
col = tinycolor({h: h, s: 0.5, v: 0.5});
hex = col.toHex();

See demo here

Upvotes: 0

Nik Terentyev
Nik Terentyev

Reputation: 2310

First of all it is good to separate decoration logic(color value) and set classes for the different colors and set those to the div. I had a task of that kind and used sin fuctions of every chanel with different amplitude, period and shift for every channel:

var ColorPicker = {

  colors: {},


  init: function(range){
    var ra = 190,
      rp = 8/3*range,
      rs = range*2/3;

    var ga = 190,
      gp = range,
      gs = 0;

    var ba = 150,
      bp = 8/3*range,
      bs = range;

    var pipi = 2*Math.PI;
    var r, g, b, w;

    for (var i = 0; i < range; i++) {
      r = ra*Math.cos(i*pipi/rp + rs*pipi/range);
      g = ga*Math.cos(i*pipi/gp + gs*pipi/range);
      b = ba*Math.cos(i*pipi/bp + bs*pipi/range);

      r = Math.round( ( r > 0 ) ? r : 0 );
      g = Math.round( ( g > 0 ) ? g : 0 );
      b = Math.round( ( b > 0 ) ? b : 0 );
      w = Math.round( i/range*255);

      this.colors[i] = {red: r, green: g, blue: b, white: w};   
    };
  },


  getColorObj: function(grade){
    return this.colors[grade];
  },

  getRGB: function(grade, coef){
    var o = this.colors[grade];
    if (!coef){
      coef = 1;
    }
    var r = (Math.round(o.red*coef)>255)?255:Math.round(o.red*coef),
      g = (Math.round(o.green*coef)>255)?255:Math.round(o.green*coef),
      b = (Math.round(o.blue*coef)>255)?255:Math.round(o.blue*coef);
    return 'rgb(' + r + ','
            + g + ',' 
            + b + ')'; 
  },

  // get shades of BW
  getW: function(grade){
    var o = this.colors[grade];
    return 'rgb(' + o.white + ','
            + o.white + ',' 
            + 0.9*o.white + ')'; 
  },

  // opposite to BW
  getB: function(grade){
    var o = this.colors[grade],
      b = 255 - o.white;
    // console.log(b);
    return 'rgb(' + b + ','
            + b + ',' 
            + .9*b + ')'; 
  },

};

May need to rewrite it though. Don't think it is an optimal solution now.

Upvotes: 0

Related Questions