Generieren Sie zufällige Farben, die für Menschen unterscheidbar sind
Lesezeit: 17 Minuten
Ich versuche, zufällig eine Farbe in Hex in Javascript zu generieren.
Die erzeugten Farben sind jedoch kaum voneinander zu unterscheiden.
Gibt es eine Möglichkeit, es zu verbessern?
Hier ist der Code, den ich verwende:
function randomColor(){
var allowed = "ABCDEF0123456789", S = "#";
while(S.length < 7){
S += allowed.charAt(Math.floor((Math.random()*16)+1));
}
return S;
}
Ich habe etwas darüber gehört HSL und HSV Farbmodell, kann es aber in meinem Code nicht zum Laufen bringen. Bitte helfen Sie.
Danke im Voraus
Haben Sie einige Beispiele für die generierten Codes? Denken Sie daran, dass Hex-Codes bestimmten Konventionen folgen
– Barry Chapman
4. April 2012 um 15:33 Uhr
Was genau heißt hier „unkenntlich“? Ich meine, leuchten die Pixel so auf, dass Ihre Augen die Strahlung nicht wahrnehmen können?
– Spitze
4. April 2012 um 15:36 Uhr
@Pointy Die Brille, sie tut nichts!
– Schnuffelupagus
4. April 2012 um 15:37 Uhr
@Pointy im Grunde verwende ich diese Farben zum Einfärben von Knoten eines Diagramms. Aber wenn sie auf einem Projektor angezeigt werden, sehen viele der Knoten fast identisch aus.
Der einfachste Weg, maximal unterschiedliche Farben auszuwählen, wäre, HSL-Werte anstelle von RGB zu verwenden und dann den Farbton zu manipulieren, da er einen Wert von 0 bis 360 hat und herumläuft (0 ist rot, ebenso 360);
Wenn Sie 10 unterscheidbare Farben benötigen, können Sie 360 durch 10 teilen und dann die einzelne Farbe auswählen, indem Sie den Wert mit dem Index (nullbasiert) multiplizieren. Hier ist eine Beispielfunktion, mit der Sie eine Farbe auswählen können:
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%)";
}
Auf diese Weise können Sie die Farbauswahl durch Zufallsindex randomisieren, aber die Farben befinden sich immer in derselben Palette.
Dadurch wird eine zufällige Farbe aus einer Palette von 10 ausgewählt:
var color = selectColor(Math.floor(Math.random() * 10), 10);
und so wird das:
var color = selectColor(Math.floor(Math.random() * 999), 10);
oder Sie können eine bestimmte Farbe aus der Palette auswählen, z. B. die 9. Farbe (Index 8) aus der Palette von 13:
Also brauchte ich heute eine Lösung für dasselbe Problem. Als ich hier nach dieser Antwort googelte (ich weiß, eine sehr seltsame Art, auf SO nach Dingen zu suchen), stieß ich auf die Goldener Winkel Konzept. Es würde das obige Beispiel noch trivialer machen und würde nicht erfordern, dass eine vorbestimmte Anzahl von Farben bereitgestellt wird:
function selectColor(number) {
const hue = number * 137.508; // use golden angle approximation
return `hsl(${hue},50%,75%)`;
}
Dies beantwortet die Frage von @netoperator-wibby
Ich weiß, dass dies ein sehr später Kommentar ist, aber was ist, wenn Sie nicht wissen, wie viele Divs Sie für zufällige Farben haben werden?
– NetOperator Wibby
10. April 2017 um 16:46 Uhr
Das funktioniert nicht, weil es zum Beispiel bei Grüntönen einen großen Bereich gibt, der von Menschen nicht leicht unterscheidbar ist.
– Shital Shah
22. Februar 2018 um 2:55 Uhr
@ShitalShah Ich stimme zu, dass es keine perfekte Lösung ist und es viel bessere Möglichkeiten gibt, differenzierbare Farben auszuwählen. Dies ist eine schnelle und schmutzige Methode, um das Problem zu lösen, ohne zu sehr ins Unkraut zu gehen, und die bei Bedarf leicht mit einem ausgefeilteren und besser geeigneten Algorithmus aktualisiert werden kann. Ein MVP, wenn man so will 😉
– goran
12. November 2019 um 15:40 Uhr
@NetOperatorWibby Hier ist eine sehr späte Antwort: Sie könnten einen vordefinierten Satz von Farben für Ihren Anwendungsfall verwenden, sagen wir 20, von denen Sie optimistisch erwarten, dass sie niemals vollständig verwendet werden. Wenn Ihr Anwendungsfall mehr als 200-300 verschiedene Divs hat, bezweifle ich, dass eine individuelle Farbcodierung überhaupt ein guter Ansatz wäre. An diesem Punkt ist es eher eine Heatmap.
Ich weiß, dass ich sehr spät zu dieser Party komme, aber ich habe eine ausgefeiltere Funktion geschrieben, um eine Reihe kontrastierender Zufallsfarben für ein anderes Projekt zu erzeugen. Sie sind beide (zumindest etwas) attraktiv und wirklich zufällig (basieren nicht auf vordefinierten Farben), aber mein Code ist etwas komplizierter als einige der anderen Antworten (es geht also nicht nur darum, die Grundlagen zu erhalten).
Dies ist für Benutzer gedacht, die mehr als eine zufällige Farbe auf ihrer Seite haben möchten und sicherstellen möchten, dass keine zwei Farben zu ähnlich sind.
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
});
}
Bitte beachten Sie, obwohl ich dies in meinem Beispiel nicht tue, dass dies auch verwendet werden kann, um einem Satz neue unterschiedliche, zufällige Farben hinzuzufügen:
generateRandomColors(1,generateRandomColors(10))
Das ist cool, aber führen Sie dies einmal durch eine js-Fluseninspektion. Ihnen fehlen eine Menge Semikolons und andere Leckerbissen.
– Akousmata
24. Juni 2019 um 17:01 Uhr
Es wäre cool, sich zu verwandeln rgba dann fügen Sie auch Transparenz hinzu.
– Loretoparisi
20. Februar 2020 um 15:10 Uhr
Alexander
Sie könnten einen festen Farbsatz verwenden, wie z. B. die in der aufgeführten jquery.color.js-Plugin.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="placeholder"></div>
<span id="color">Click the square above.</span>
Danke Alexander, ich habe dein Beispiel ausprobiert und bekomme eine ziemlich große Auswahl an verschiedenen Farben. Da ich bereits jQuery verwende, scheint es auch angemessener zu sein.
– Benutzer1231969
4. April 2012 um 16:09 Uhr
Ich suchte nach einer Methode, um eine zufällige, lebendige, lesbare Farbe basierend auf der relativen Leuchtdichte zu erzeugen (Blau, Gelb und Grün sind dunkler), aber dies kommt in meine Liste der “think simple” -Antworten. Mir wurde klar, dass ich nur eine “zufällige, lebhaft lesbare Farbe” wollte, nicht unbedingt eine erzeugen.
– Heu
29. April 2016 um 22:57 Uhr
Ich möchte verschiedene Farben in Diagrammen anzeigen, gibt es also die Möglichkeit, dass Farben doppelt vorhanden sind? Sie möchten nicht dieselbe Farbe für zwei verschiedene Entitäten in Diagrammen anzeigen.
– Parth Akbari
10. Februar 2020 um 7:20 Uhr
Diese Lösung funktioniert nur, wenn Sie bestimmte vordefinierte Farben für unterschiedliche erforderliche Mengen haben. Wenn Sie zu viele vordefinierte haben und nur wenige benötigen, besteht die Möglichkeit für ähnliche Farben. Wenn Sie ein paar vordefinierte haben, können sie ausgehen, wenn Sie viel brauchen.
– totymedli
8. Juli 2021 um 3:17 Uhr
Eine Hybridlösung besteht darin, vordefinierte Farben zu verwenden, wenn Sie weniger als 7 oder 8 benötigen, und den Generator von Goran zu verwenden, wenn Sie mehr benötigen.
– totymedli
8. Juli 2021 um 3:20 Uhr
Barry Chapman
Versuche dies:
function getRandomColor() {
var letters="0123456789ABCDEF".split('');
var color="#";
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
Was Sie sagen, ist, dass Sie keine zufälligen Farben erzeugen möchten, Sie sagen, dass Sie verschiedene Farben erzeugen möchten.
Eine gute Anleitung dazu findest du hier: http://krazydad.com/tutorials/makecolors.php .
Ich habe diese Fummelei mit dem relevanten Code aus dem Tutorial gemacht, um zu zeigen, wie Sie sich nicht wiederholende Farben erzeugen würden:
Der einzige Unterschied zum Tutorial-Code besteht darin, dass die Funktion makegradient() ein Array von Farben zurückgibt, die Sie später nach Belieben auf Ihrer Seite anwenden können.
Ich denke, sein Wissen hat ihn verrückt gemacht (siehe Site-Name). Das war großartig.
– toterManN
11. April 2016 um 7:39 Uhr
Ich habe eine größere Anzahl ausprobiert, und sie erzeugt zu ununterscheidbare Farben, wobei viele Farben nicht verwendet werden. Z.B. es gibt viele Grüntöne, aber kein knalliges Gelb.
– Andrej Michailow – Lolmaus
5. April 2020 um 16:05 Uhr
Robert Messerle
Um Farben zufällig zu erzeugen, neige ich dazu, etwas Einfaches wie das Folgende zu wählen:
function randomColor () {
var max = 0xffffff;
return '#' + Math.round( Math.random() * max ).toString( 16 );
}
Ich bin mir nicht sicher, was du mit nicht erkennbar meinst. Diese Methode bietet nicht viele Anpassungsmöglichkeiten, macht es aber zumindest einfach, Zahlen davon abzuhalten, zu hell oder zu dunkel zu sein.
Wenn Sie größere Lücken zwischen den generierten Farben haben möchten, können Sie versuchen, die Anzahl der zulässigen Zeichen zu verringern. Ich habe eine solche Methode in der Vergangenheit verwendet, wo ich nur verwendet habe 0369cf als Pool von Charakteren, aus denen man ziehen kann. Wenn Sie dies mit einer Überprüfung auf Duplikate kombinieren, erhalten Sie tendenziell besser unterscheidbare Farben und verwenden nur die #fff 3-Zeichen-Syntax.
Hier ist Ihre ursprüngliche Funktion, die geändert wurde, um diese Methode zu verwenden:
function randomColor(){
var allowed = "0369cf".split( '' ), s = "#";
while ( s.length < 4 ) {
s += allowed.splice( Math.floor( ( Math.random() * allowed.length ) ), 1 );
}
return s;
}
Ich denke, sein Wissen hat ihn verrückt gemacht (siehe Site-Name). Das war großartig.
– toterManN
11. April 2016 um 7:39 Uhr
Ich habe eine größere Anzahl ausprobiert, und sie erzeugt zu ununterscheidbare Farben, wobei viele Farben nicht verwendet werden. Z.B. es gibt viele Grüntöne, aber kein knalliges Gelb.
– Andrej Michailow – Lolmaus
5. April 2020 um 16:05 Uhr
Scott bedeutet
Ich musste dieses Problem heute für einen neuen Kurs lösen, den ich schreibe, also hier ist meine Lösung:
function getUniqueColor(n) {
const rgb = [0, 0, 0];
for (let i = 0; i < 24; i++) {
rgb[i%3] <<= 1;
rgb[i%3] |= n & 0x01;
n >>= 1;
}
return '#' + rgb.reduce((a, c) => (c > 0x0f ? c.toString(16) : '0' + c.toString(16)) + a, '')
}
Es “spreizt” die Bits von der Eingabenummer durch die RGB-Werte rückwärts. Es ist nicht perfekt, aber der Code ist kompakt und benachbarte Farben sind unterscheidbar. Hier ist die Geige.
8332600cookie-checkGenerieren Sie zufällige Farben, die für Menschen unterscheidbar sindyes
Haben Sie einige Beispiele für die generierten Codes? Denken Sie daran, dass Hex-Codes bestimmten Konventionen folgen
– Barry Chapman
4. April 2012 um 15:33 Uhr
Was genau heißt hier „unkenntlich“? Ich meine, leuchten die Pixel so auf, dass Ihre Augen die Strahlung nicht wahrnehmen können?
– Spitze
4. April 2012 um 15:36 Uhr
@Pointy Die Brille, sie tut nichts!
– Schnuffelupagus
4. April 2012 um 15:37 Uhr
@Pointy im Grunde verwende ich diese Farben zum Einfärben von Knoten eines Diagramms. Aber wenn sie auf einem Projektor angezeigt werden, sehen viele der Knoten fast identisch aus.
– Benutzer1231969
4. April 2012 um 15:39 Uhr
Es gibt einige Studien zur Farbdifferenzierung. Vor allem in der HCI-Forschung. en.wikipedia.org/wiki/Color_difference ist eine anständige Einführung.
– idbentley
4. April 2012 um 15:44 Uhr