Gerar uma cor aleatória distinguível para os humanos

Estou a tentar gerar aleatoriamente uma cor em hex em javascript.

No entanto, as cores geradas são quase indistinguíveis umas das outras.
Há alguma forma de O melhorar?


Aqui está o código que estou a usar:

function randomColor(){
   var allowed = "ABCDEF0123456789", S = "#";

   while(S.length < 7){
       S += allowed.charAt(Math.floor((Math.random()*16)+1));
   }
   return S;
}

ouvi algo sobre HSL eHSV modelo de cores mas não consigo obter funciona no meu código. Ajudar.

obrigado antecipadamente

Author: vsync, 2012-04-04

9 answers

Você poderia usar um conjunto fixo de cores, tais como as listadas no jquery .cor.plugin js .

Lista de cores de jquery.cor.plugin js:

Colors = {};
Colors.names = {
    aqua: "#00ffff",
    azure: "#f0ffff",
    beige: "#f5f5dc",
    black: "#000000",
    blue: "#0000ff",
    brown: "#a52a2a",
    cyan: "#00ffff",
    darkblue: "#00008b",
    darkcyan: "#008b8b",
    darkgrey: "#a9a9a9",
    darkgreen: "#006400",
    darkkhaki: "#bdb76b",
    darkmagenta: "#8b008b",
    darkolivegreen: "#556b2f",
    darkorange: "#ff8c00",
    darkorchid: "#9932cc",
    darkred: "#8b0000",
    darksalmon: "#e9967a",
    darkviolet: "#9400d3",
    fuchsia: "#ff00ff",
    gold: "#ffd700",
    green: "#008000",
    indigo: "#4b0082",
    khaki: "#f0e68c",
    lightblue: "#add8e6",
    lightcyan: "#e0ffff",
    lightgreen: "#90ee90",
    lightgrey: "#d3d3d3",
    lightpink: "#ffb6c1",
    lightyellow: "#ffffe0",
    lime: "#00ff00",
    magenta: "#ff00ff",
    maroon: "#800000",
    navy: "#000080",
    olive: "#808000",
    orange: "#ffa500",
    pink: "#ffc0cb",
    purple: "#800080",
    violet: "#800080",
    red: "#ff0000",
    silver: "#c0c0c0",
    white: "#ffffff",
    yellow: "#ffff00"
};

O resto é simplesmente escolher uma propriedade aleatória de um objecto Javascript .

Colors.random = function() {
    var result;
    var count = 0;
    for (var prop in this.names)
        if (Math.random() < 1/++count)
           result = prop;
    return result;
};

Usar Colors.random() pode dar-te uma cor legível. Até alimentei um exemplo aqui.

 15
Author: Alexander, 2017-05-23 12:18:03

A maneira mais fácil de escolher cores maximalmente diferentes seria usar valores HSL em vez de RGB e depois manipular Matiz, uma vez que tem um valor de 0 a 360 e se envolve (0 é vermelho, e assim é 360);

Se precisar de 10 cores distinguíveis, pode dividir 360 por 10 e escolher a cor individual multiplicando o valor pelo índice (com base em zero). Aqui está uma função de exemplo que lhe permite escolher uma cor de:

function selectColor(colorNum, colors){
    if (colors < 1) colors = 1; // defaults to one color - avoid divide by zero
    return "hsl(" + (colorNum * (360 / colors) % 360) + ",100%,50%)";
}
Assim, podes aleatorizar a cor. selecção por índice aleatório, mas as cores estarão sempre na mesma paleta.

Isto irá Seleccionar uma cor aleatória a partir de uma paleta de 10:

var color = selectColor(Math.floor(Math.random() * 10), 10);

E isto também:

var color = selectColor(Math.floor(Math.random() * 999), 10);

Ou pode seleccionar uma cor específica da paleta, como a 9ª cor (Índice 8) da paleta de 13:

var color = selectColor(8, 13);
Aqui está um violino para brincar com: http://jsfiddle.net/2UE2B/
 23
Author: goran, 2013-11-21 18:55:29

Example

Sei que estou muito atrasado para esta festa, mas escrevi uma função mais elaborada para gerar um conjunto de cores aleatórias contrastantes para outro projecto. Eles são ambos (pelo menos um pouco) atraentes e genuinamente aleatórios (Não baseado em cores predefinidas), mas o meu código é um pouco mais complicado do que algumas das outras respostas (então não é apenas para obter o básico)

Isto é para os utilizadores que querem ter mais do que uma cor aleatória na sua página, e querem certifique-se de que não há duas cores muito semelhantes.

Violino

var generateRandomColors=function(number){
/*
This generates colors using the following algorithm:
Each time you create a color:
    Create a random, but attractive, color{
        Red, Green, and Blue are set to random luminosity.
        One random value is reduced significantly to prevent grayscale.
        Another is increased by a random amount up to 100%.
        They are mapped to a random total luminosity in a medium-high range (bright but not white).
    }
    Check for similarity to other colors{
        Check if the colors are very close together in value.
        Check if the colors are of similar hue and saturation.
        Check if the colors are of similar luminosity.
        If the random color is too similar to another,
        and there is still a good opportunity to change it:
            Change the hue of the random color and try again.
    }
    Output array of all colors generated
*/
    //if we've passed preloaded colors and they're in hex format
    if(typeof(arguments[1])!='undefined'&&arguments[1].constructor==Array&&arguments[1][0]&&arguments[1][0].constructor!=Array){
        for(var i=0;i<arguments[1].length;i++){ //for all the passed colors
            var vals = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(arguments[1][i]); //get RGB values
            arguments[1][i]=[parseInt(vals[1], 16),parseInt(vals[2], 16),parseInt(vals[3], 16)]; //and convert them to base 10
        }
    }
    var loadedColors=typeof(arguments[1])=='undefined'?[]:arguments[1],//predefine colors in the set
        number=number+loadedColors.length,//reset number to include the colors already passed
        lastLoadedReduction=Math.floor(Math.random()*3),//set a random value to be the first to decrease
        rgbToHSL=function(rgb){//converts [r,g,b] into [h,s,l]
            var r=rgb[0],g=rgb[1],b=rgb[2],cMax=Math.max(r,g,b),cMin=Math.min(r,g,b),delta=cMax-cMin,l=(cMax+cMin)/2,h=0,s=0;if(delta==0)h=0;else if(cMax==r)h=60*((g-b)/delta%6);else if(cMax==g)h=60*((b-r)/delta+2);else h=60*((r-g)/delta+4);if(delta==0)s=0;else s=delta/(1-Math.abs(2*l-1));return[h,s,l]
        },hslToRGB=function(hsl){//converts [h,s,l] into [r,g,b]
            var h=hsl[0],s=hsl[1],l=hsl[2],c=(1-Math.abs(2*l-1))*s,x=c*(1-Math.abs(h/60%2-1)),m=l-c/2,r,g,b;if(h<60){r=c;g=x;b=0}else if(h<120){r=x;g=c;b=0}else if(h<180){r=0;g=c;b=x}else if(h<240){r=0;g=x;b=c}else if(h<300){r=x;g=0;b=c}else{r=c;g=0;b=x}return[r,g,b]
        },shiftHue=function(rgb,degree){//shifts [r,g,b] by a number of degrees
            var hsl=rgbToHSL(rgb); //convert to hue/saturation/luminosity to modify hue
            hsl[0]+=degree; //increment the hue
            if(hsl[0]>360){ //if it's too high
                hsl[0]-=360 //decrease it mod 360
            }else if(hsl[0]<0){ //if it's too low
                hsl[0]+=360 //increase it mod 360
            }
            return hslToRGB(hsl); //convert back to rgb
        },differenceRecursions={//stores recursion data, so if all else fails we can use one of the hues already generated
            differences:[],//used to calculate the most distant hue
            values:[]//used to store the actual colors
        },fixDifference=function(color){//recursively asserts that the current color is distinctive
            if(differenceRecursions.values.length>23){//first, check if this is the 25th recursion or higher. (can we try any more unique hues?)
                //if so, get the biggest value in differences that we have and its corresponding value
                var ret=differenceRecursions.values[differenceRecursions.differences.indexOf(Math.max.apply(null,differenceRecursions.differences))];
                differenceRecursions={differences:[],values:[]}; //then reset the recursions array, because we're done now
                return ret; //and then return up the recursion chain
            } //okay, so we still have some hues to try.
            var differences=[]; //an array of the "difference" numbers we're going to generate.
            for(var i=0;i<loadedColors.length;i++){ //for all the colors we've generated so far
                var difference=loadedColors[i].map(function(value,index){ //for each value (red,green,blue)
                    return Math.abs(value-color[index]) //replace it with the difference in that value between the two colors
                }),sumFunction=function(sum,value){ //function for adding up arrays
                    return sum+value
                },sumDifference=difference.reduce(sumFunction), //add up the difference array
                loadedColorLuminosity=loadedColors[i].reduce(sumFunction), //get the total luminosity of the already generated color
                currentColorLuminosity=color.reduce(sumFunction), //get the total luminosity of the current color
                lumDifference=Math.abs(loadedColorLuminosity-currentColorLuminosity), //get the difference in luminosity between the two
                //how close are these two colors to being the same luminosity and saturation?
                differenceRange=Math.max.apply(null,difference)-Math.min.apply(null,difference),
                luminosityFactor=50, //how much difference in luminosity the human eye should be able to detect easily
                rangeFactor=75; //how much difference in luminosity and saturation the human eye should be able to dect easily
                if(luminosityFactor/(lumDifference+1)*rangeFactor/(differenceRange+1)>1){ //if there's a problem with range or luminosity
                    //set the biggest difference for these colors to be whatever is most significant
                    differences.push(Math.min(differenceRange+lumDifference,sumDifference));
                }
                differences.push(sumDifference); //otherwise output the raw difference in RGB values
            }
            var breakdownAt=64, //if you're generating this many colors or more, don't try so hard to make unique hues, because you might fail.
            breakdownFactor=25, //how much should additional colors decrease the acceptable difference
            shiftByDegrees=15, //how many degrees of hue should we iterate through if this fails
            acceptableDifference=250, //how much difference is unacceptable between colors
            breakVal=loadedColors.length/number*(number-breakdownAt), //break down progressively (if it's the second color, you can still make it a unique hue)
            totalDifference=Math.min.apply(null,differences); //get the color closest to the current color
            if(totalDifference>acceptableDifference-(breakVal<0?0:breakVal)*breakdownFactor){ //if the current color is acceptable
                differenceRecursions={differences:[],values:[]} //reset the recursions object, because we're done
                return color; //and return that color
            } //otherwise the current color is too much like another
            //start by adding this recursion's data into the recursions object
            differenceRecursions.differences.push(totalDifference);
            differenceRecursions.values.push(color);
            color=shiftHue(color,shiftByDegrees); //then increment the color's hue
            return fixDifference(color); //and try again
        },color=function(){ //generate a random color
            var scale=function(x){ //maps [0,1] to [300,510]
                return x*210+300 //(no brighter than #ff0 or #0ff or #f0f, but still pretty bright)
            },randVal=function(){ //random value between 300 and 510
                return Math.floor(scale(Math.random()))
            },luminosity=randVal(), //random luminosity
                red=randVal(), //random color values
                green=randVal(), //these could be any random integer but we'll use the same function as for luminosity
                blue=randVal(),
                rescale, //we'll define this later
                thisColor=[red,green,blue], //an array of the random values
                /*
                #ff0 and #9e0 are not the same colors, but they are on the same range of the spectrum, namely without blue.
                Try to choose colors such that consecutive colors are on different ranges of the spectrum.
                This shouldn't always happen, but it should happen more often then not.
                Using a factor of 2.3, we'll only get the same range of spectrum 15% of the time.
                */
                valueToReduce=Math.floor(lastLoadedReduction+1+Math.random()*2.3)%3, //which value to reduce
                /*
                Because 300 and 510 are fairly close in reference to zero,
                increase one of the remaining values by some arbitrary percent betweeen 0% and 100%,
                so that our remaining two values can be somewhat different.
                */
                valueToIncrease=Math.floor(valueToIncrease+1+Math.random()*2)%3, //which value to increase (not the one we reduced)
                increaseBy=Math.random()+1; //how much to increase it by
            lastLoadedReduction=valueToReduce; //next time we make a color, try not to reduce the same one
            thisColor[valueToReduce]=Math.floor(thisColor[valueToReduce]/16); //reduce one of the values
            thisColor[valueToIncrease]=Math.ceil(thisColor[valueToIncrease]*increaseBy) //increase one of the values
            rescale=function(x){ //now, rescale the random numbers so that our output color has the luminosity we want
                return x*luminosity/thisColor.reduce(function(a,b){return a+b}) //sum red, green, and blue to get the total luminosity
            };
            thisColor=fixDifference(thisColor.map(function(a){return rescale(a)})); //fix the hue so that our color is recognizable
            if(Math.max.apply(null,thisColor)>255){ //if any values are too large
                rescale=function(x){ //rescale the numbers to legitimate hex values
                    return x*255/Math.max.apply(null,thisColor)
                }
                thisColor=thisColor.map(function(a){return rescale(a)});
            }
            return thisColor;
        };
    for(var i=loadedColors.length;i<number;i++){ //Start with our predefined colors or 0, and generate the correct number of colors.
        loadedColors.push(color().map(function(value){ //for each new color
            return Math.round(value) //round RGB values to integers
        }));
    }
    //then, after you've made all your colors, convert them to hex codes and return them.
    return loadedColors.map(function(color){
        var hx=function(c){ //for each value
            var h=c.toString(16);//then convert it to a hex code
            return h.length<2?'0'+h:h//and assert that it's two digits
        }
        return "#"+hx(color[0])+hx(color[1])+hx(color[2]); //then return the hex code
    });
}

Por favor, note, Embora eu não o faça no meu exemplo, que isto também pode ser usado para adicionar novas cores distintas e aleatórias a um conjunto:

generateRandomColors(1,generateRandomColors(10))
 19
Author: Scelesto, 2015-08-04 19:38:27

Para gerar cores aleatoriamente, tenho tendência para algo simples como isto:

​function randomColor () {
    var max = 0xffffff;
    return '#' + Math.round( Math.random() * max ).toString( 16 );
}
​
Não sei o que quer dizer com irreconhecível. Este método não oferece muita personalização, mas pelo menos torna fácil manter os números de ser muito leve ou muito escuro.

Se quiser dar maiores diferenças entre as cores geradas, pode tentar reduzir o número de caracteres permitidos. Eu usei um método como esse no passado onde eu só usei 0369cf como a piscina de personagens para tirar. Combinando isso com uma verificação para duplicados tende a dar cores mais distinguíveis, bem como apenas utilizando a sintaxe de #fff 3 caracteres.

Aqui está a sua função original modificada para usar este método:

function randomColor(){
    var allowed = "0369cf".split( '' ), s = "#";
    while ( s.length < 4 ) {
       s += allowed.splice( Math.floor( ( Math.random() * allowed.length ) ), 1 );
    }
    return s;
}
 5
Author: Robert Messerle, 2012-04-04 15:41:46

O que estás a dizer é que não queres gerar cores aleatórias, estás a dizer que queres gerar cores diferentes.
Você pode encontrar um bom tutorial sobre como fazê-lo aqui: http://krazydad.com/tutorials/makecolors.php .

Eu fiz este violino com o código relevante do tutorial demonstrando como você geraria cores não-repetitivas:

Http://jsfiddle.net/rGL52/

A única diferença do código de tutorial é que o a função makegradient () devolve uma lista de cores que poderá aplicar à vontade na sua página.

 5
Author: Michal, 2012-04-04 22:01:07

Tenta isto:

function getRandomColor() {
    var letters = '0123456789ABCDEF'.split('');
    var color = '#';
    for (var i = 0; i < 6; i++ ) {
        color += letters[Math.round(Math.random() * 15)];
    }
    return color;
}

Vê - lo em acção: http://jsfiddle.net/3wjgG/1/

 4
Author: Barry Chapman, 2012-04-04 16:19:36
Concordo com todas as respostas, não sabemos o que esperas daqui...

Esta é uma possibilidade que lhe pode dar a escolha entre a saída rgb(r, g, b) para os elementos css, e a saída hex...

Este é um exemplo rápido, você só tem que adaptar este rascunho, mas ele funciona como no Firefox:

<script type="text/javascript">
    //<![CDATA[
        function RndColor(){
        var maximum = 255;
        var minimum = 100;
        var range = maximum - minimum;
        var red = Math.floor(Math.random()*range)+minimum;
        var green = Math.floor(Math.random()*range)+minimum;
        var blue = Math.floor(Math.random()*range)+minimum;
        var redToHex = red.toString(16);
        var greenToHex = green.toString(16);
        var blueToHex = blue.toString(16);
        this.rgbValue = "rgb(" + red + "," + green + "," + blue + ")";
        this.hexValue = "#" + redToHex + "" + greenToHex + "" + blueToHex;
    }
    RndColor.prototype.getRGB = function(){
        return this.rgbValue;
    }
    RndColor.prototype.getHex = function(){
        return this.hexValue;
    }
    //]]>
</script>

Então você pode recuperar o valor como aqui abaixo:

<script type="text/javascript">
//<![CDATA[
    rndCol = new RndColor();
    document.write("<div style = width:150px;height:100px;background-color:" + rndCol.getHex() + ">" + rndCol.getHex() + "</div><br /><br />");
    document.write("<div style = width:150px;height:100px;background-color:" + rndCol.getRGB() + ">" + rndCol.getRGB() + "</div>");
//]]>
</script>
Espero que isto te possa ajudar. Cumprimento.
 1
Author: tatactic, 2012-04-04 23:31:31
Em primeiro lugar, porque estás a construir valores de hex a partir de cordas? Basta usar números para os valores, em seguida, sair com algo como yourNumber.toString(16).

Então, para tornar as cores mais distintas, não use a gama completa de 0 a 255 para cada componente de cor, mas talvez vá em saltos de 10, ou 20, ou o que você precisa para gerar diferenças suficientemente grandes.

 0
Author: Cylindric, 2012-04-04 16:30:20
Escrevi um pequeno guião chamado SwitchColors.JS que podem ser encontrados aqui: https://github.com/akulmehta/SwitchColors.js

O script produz cores mais saturadas e o brilho pode ser controlado. Embora possa não produzir cores visualmente distinguíveis, produz alta saturação e cores brilhantes que também podem ser atraentes.

 0
Author: Coola, 2018-09-24 01:29:27