Create unique colors using javascript

13,538

Solution 1

The best way is to convert from HSV values. You can divide the maximum value of "Hue" by the amount of colors you need and then increment by this result.

For improved contrast, you can also alternate between high and low values of lightness.

Solution 2

I would generate colors using HSV (hue, saturation, value) instead of RGB. In HSV, the color is defined by the hue, ranging from 0-360. Thus, if you want e.g. 6 different colors, you can simply divide 360 by 5 (because we want to include 0) and get 72, so each color should increment with 72. Use a function like this one to convert the generated HSV color to RGB.

The following function returns an array of total different colors in RGB format. Note that the colors won't be "random" in this example, as they will always range from red to pink.

function randomColors(total)
{
    var i = 360 / (total - 1); // distribute the colors evenly on the hue range
    var r = []; // hold the generated colors
    for (var x=0; x<total; x++)
    {
        r.push(hsvToRgb(i * x, 100, 100)); // you can also alternate the saturation and value for even more contrast between the colors
    }
    return r;
}

Solution 3

The existing answers which mention the Hue, Saturation, Value representation of colors are very elegant, are closer to how humans perceive color, and it is probably best to follow their advice. Also creating a long precalculated list of colors and choosing subsets of them as needed is fast and reliable.

However, here is some code that answers your question directly: it will generate random colors in RGB that are sufficiently different. There are two drawbacks to this technique that I can see. First, these colors are really random and could look kind of gross together, and second it might take a while for the code to stumble on colors that work, depending on how "far apart" you require the colors to be.

function hex2rgb(h) {
    return [(h & (255 << 16)) >> 16, (h & (255 << 8)) >> 8, h & 255];
}
function distance(a, b) {
    var d = [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
    return Math.sqrt((d[0]*d[0]) + (d[1]*d[1]) + (d[2]*d[2]));
}
function freshColor(sofar, d) {
    var n, ok;
    while(true) {
        ok = true;
        n = Math.random()*0xFFFFFF<<0;
        for(var c in sofar) {
            if(distance(hex2rgb(sofar[c]), hex2rgb(n)) < d) {
                ok = false;
                break;
            }
        }
        if(ok) { return n; }
    }
}
function getColors(n, d) {
    var a = [];
    for(; n > 0; n--) {
        a.push(freshColor(a, d));
    }
    return a;
}

The distance between colors is the Euclidean distance measured by the R, G, and B components. Thus the furthest that two colors (black and white) can be is about 441.67.

To use this code, call getColors where the first parameter is the number of colors, and the second is the minimum distance between any two of them. It will return an array of numerical RGB values.

Solution 4

I like using hsl values for specifying colour this way.

So

"color: hsl(" + getRandomArbitary(0, 360) + ", 50%, 50%)";

would give you random results, but that won't give you your distinct separations. So I'd base it on the i value of a loop. Something like,

for (var i = 0; i < whateverYourValue; i += 1) {
    color = "color: hsl(" + i * 10 + ", 50%, 50%)";

    // set your colour on whatever
}

obviously the above is indicative, and not valid code on it's own.

Want to know more on hsl? Check http://mothereffinghsl.com/ 'cause, you know, it's fun.

Solution 5

'#'+(Math.random()*0xFFFFFF<<0).toString(16);

Isn't the best method to use because it can generate values like #4567 which is missing two digits instead of generating #004567

It's better to pick each character individually like:

'#'+Math.floor(Math.random()*16).toString(16)+
    Math.floor(Math.random()*16).toString(16)+
    Math.floor(Math.random()*16).toString(16)+
    Math.floor(Math.random()*16).toString(16)+
    Math.floor(Math.random()*16).toString(16)+
    Math.floor(Math.random()*16).toString(16);

But that can easily be reduced to picking three numbers since hex colours can be shortened. IE. #457 == #445577

Then if you want to decrease the number of posibilities and widen the gap between them you can use:

'#'+(5*Math.floor(Math.random()*4)).toString(16)+
    (5*Math.floor(Math.random()*4)).toString(16)+
    (5*Math.floor(Math.random()*4)).toString(16);

Which divides the number of choices for each color by 5, and then evens out the distribution equally.

Share:
13,538

Related videos on Youtube

Kartik Dinesh
Author by

Kartik Dinesh

Updated on June 12, 2022

Comments

  • Kartik Dinesh
    Kartik Dinesh about 2 years

    What is the best way to pick random colors for a bar chart / histogram such that each color is different from the other.. and possibly in contrast

    The most talked about way is

    '#'+(Math.random()*0xFFFFFF<<0).toString(16);
    

    but this can generate similar colors.. and sometimes distinguishing them might be a problem.. Example enter image description here

    • James Gaunt
      James Gaunt almost 13 years
      Any method to pick random colours is sometimes going to generate similar colours. If you never want them to be similar just prepare a list of suitable colours and pick from it (at random if you like).
    • Nicole
      Nicole almost 13 years
      The biggest reason why you don't want to use the method suggested is that what people visually perceive as the color spectrum is not linearly proportional to the hex color spectrum. That is why the "web safe colors" don't look anything like a rainbow.
    • Phrogz
      Phrogz almost 13 years
  • Phrogz
    Phrogz almost 13 years
    However, as @Renesis says, evenly dividing the hue is not the same as picking visually-distinct colors--we are far less sensitive to variations of green compared to our sensitivity to red and (to a lesser extent) blue. Differentiating grasses and leaves is less important than seeing fire.
  • slaphappy
    slaphappy almost 13 years
    Good point, this method is only valid if you need a small amount of different colors.
  • Nicole
    Nicole almost 13 years
    See my comment on the question for a longer explanation, but this is bad, because web safe colors (colors divided evenly across RGB values) are ugly.
  • UpTheCreek
    UpTheCreek over 11 years
    +1, But I'm not a fan of the function name - as you say, there is no randomisation going on.
  • Al Dass
    Al Dass over 8 years
    Here's a JSFiddle showing the implementation above. I've made some small modifications.