Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate color values from green to red

I would like to calculate color value according to given number.

0 -> pure red
100 -> pure green

example: 75 -> color, which is 75% from red to green.

I need this for expiration counter, which shows appropriate colors as days count down.

like image 832
Biker John Avatar asked Jul 08 '13 11:07

Biker John


People also ask

How do you calculate RGB values?

The function R*0.2126+ G*0.7152+ B*0.0722 is said to calculate the perceived brightness (or equivalent grayscale color) for a given an RGB color. Assuming we use the interval [0,1] for all RGB values, we can calculate the following: yellow = RGB(1,1,0) => brightness=0.9278.

What color is RGB 0 255 255?

The RGB color 0, 255, 255 is a light color, and the websafe version is hex 00FFFF, and the color name is aqua. The color can be described as light saturated cyan. A complement of this color would be 128, 128, 128, and the grayscale version is 179, 179, 179.

How do you decode a color code?

Hex color codes start with a pound sign or hashtag (#) and are followed by six letters and/or numbers. The first two letters/numbers refer to red, the next two refer to green, and the last two refer to blue. The color values are defined in values between 00 and FF (instead of from 0 to 255 in RGB).


2 Answers

You could indeed go for the solution provided by @KamilT. Disadvantage of this method (imo) is that the colors in the middle (around 50) will get brownish and not very nice compared to your full red and green.

I think it would be much nicer to follow the color spectrum, and passing over orange and yellow, in stead of that ugly brownish.

This can easily by achieved by working with HSL values rather then RGB values. If you set the Hue value based on your number between 0 and 100 to a value between 0°(red) and 120°(green), and keep your Saturation at 100% and your Lightness at 50%, you should get nice bright colors.

I found a way to convert between rgb and hsl here: HSL to RGB color conversion

And I wrote a simple function to calculate your rgb value using the conversion function from the answer above:

// convert a number to a color using hsl
function numberToColorHsl(i) {
    // as the function expects a value between 0 and 1, and red = 0° and green = 120°
    // we convert the input to the appropriate hue value
    var hue = i * 1.2 / 360;
    // we convert hsl to rgb (saturation 100%, lightness 50%)
    var rgb = hslToRgb(hue, 1, .5);
    // we format to css value and return
    return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')'; 
}

And I set up a fiddle to demonstrate the diffrences between the HSL method and the RGB method: http://jsfiddle.net/rE6Rk/1/

update a more versatile version:

If you do not want to work with a range from red to green, you can slightly adapt the above method. The value that determines the actual color in a hsl representation is the hue, so that's the one we'll need to calculate.

enter image description here

If you define the range of your hue, by providing the 0 and 1 value as parameters, the calculation of the hue value becomes basic math. Have a look at the updated method:

function percentageToHsl(percentage, hue0, hue1) {
    var hue = (percentage * (hue1 - hue0)) + hue0;
    return 'hsl(' + hue + ', 100%, 50%)';
}

As you can see I changed the API a bit. The parameters are as follows:

  • percentage: a value between 0 and 1
  • hue0: the hue value of the color you want to get when the percentage is 0
  • hue1: the hue value of the color you want to get when the percentage is 1

Also, there is no longer a need to calculate the rgb value, modern browsers support hsl values as is.

So now you can use the method as follows:

// green(120) to red(0)
color = percentageToHsl(perc, 120, 0);

// blue(225) to pink(315)
color = percentageToHsl(perc, 225, 315);

// blue (225) to yellow(45 + 360) 
color = percentageToHsl(perc, 225, 405);

So if you want to go clockwise you have to make hue0 < hue1. If you want to go counter clockwise you have to make hue0 > hue1. And since these are degrees, you can just add or subtract 360 to force the direction. You can even use this technique to wrap around the hue circle multiple times.

I've created a new fiddle to demonstrate: https://jsfiddle.net/r438s65s/

like image 158
Pevara Avatar answered Sep 17 '22 00:09

Pevara


The answer by Pevara is great. I have adapted his jsfiddle to my needs, and maybe it is useful for others too: http://jsfiddle.net/rE6Rk/8/

It allows to have an uneven distribution of colors. In my case I wanted everything below 0.5 (50) to be red. And a 0.75 would be in the middle between red and green. So instead of working with hard borders 0 and 1, they can both be shifted.

The changes are in the numberToColorHsl() function only: * the i is a floating point 0-1 instead of the int 0-100 * additional params min/max

/**
 * Convert a number to a color using hsl, with range definition.
 * Example: if min/max are 0/1, and i is 0.75, the color is closer to green.
 * Example: if min/max are 0.5/1, and i is 0.75, the color is in the middle between red and green.
 * @param i (floating point, range 0 to 1)
 * param min (floating point, range 0 to 1, all i at and below this is red)
 * param max (floating point, range 0 to 1, all i at and above this is green)
 */
function numberToColorHsl(i, min, max) {
    var ratio = i;
    if (min> 0 || max < 1) {
        if (i < min) {
            ratio = 0;
        } else if (i > max) {
            ratio = 1;
        } else {
            var range = max - min;
            ratio = (i-min) / range;
        }
    }

    // as the function expects a value between 0 and 1, and red = 0° and green = 120°
    // we convert the input to the appropriate hue value
    var hue = ratio * 1.2 / 3.60;
    //if (minMaxFactor!=1) hue /= minMaxFactor;
    //console.log(hue);

    // we convert hsl to rgb (saturation 100%, lightness 50%)
    var rgb = hslToRgb(hue, 1, .5);
    // we format to css value and return
    return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')'; 
}

The visuals explain it better than words.

range 0.5 to 1

like image 30
Fabian Kessler Avatar answered Sep 20 '22 00:09

Fabian Kessler