24

Вопрос по javascript, jquery – Создать случайный цвет, различимый для людей

Я пытаюсь случайным образом создать цвет в шестнадцатеричном формате в JavaScript.

Однако сгенерированные цвета практически неотличимы друг от друга.
Есть ли способ улучшить это?


Вот код, который я использую:

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

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

Я что-то слышал оHSL а такжеHSV цветовая модель, но не могу получить это работать в моем коде. Пожалуйста помоги.

Заранее спасибо

  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от anuragsn7
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от anuragsn7
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Error: User Rate Limit Exceeded

    от
  • Есть много исследований о цветовой дифференциации. Особенно в исследованиях HCI.en.wikipedia.org/wiki/Color_difference это достойное введение.

    от idbentley
  • Что именно делает "неузнаваемым"? значит здесь? Я имею в виду, светятся ли пиксели так, что ваши глаза не могут воспринимать излучение?

    от Pointy
  • у вас есть образцы кодов, которые были сгенерированы? помните, что шестнадцатеричные коды следуют определенным соглашениям

    от Barry Chapman
  • @Pointy в основном я использую эти цвета в окраске узлов графа. Но при отображении на проекторе многие узлы выглядят практически одинаково.

    от anuragsn7
  • @ Pointy Очки, они ничего не делают!

    от Snuffleupagus
9 ответов
  • 4

    Попробуй это:

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

    Посмотрите это в действии: http://jsfiddle.net/3wjgG/1/

  • 15

    Вы можете использовать фиксированный набор цветов

    таких как перечисленные вплагин jquery.color.js.

    Список цветов из плагина jquery.color.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"
    };
    

    Остальное простовыбор случайного свойства из объекта Javascript.

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

    С помощьюColors.random() может дать вам читабельный цвет. Я даже запиталпример здесь.

  • 0

    Я написал небольшой скрипт под названием SwitchColors.js

    который можно найти здесь:https://github.com/akulmehta/SwitchColors.js

    Сценарий выдает более насыщенные цвета, а яркостью можно управлять. Хотя он может не давать визуально различимых цветов, он дает высокую насыщенность и яркие цвета, которые также могут быть привлекательными.

  • 5

    Для случайной генерации цветов я склоняюсь к чему-то простому:

    ​function randomColor () {
        var max = 0xffffff;
        return '#' + Math.round( Math.random() * max ).toString( 16 );
    }
    ​
    

    Я не уверен, что вы подразумеваете под неузнаваемым. Этот способ не предлагает много настроек, но, по крайней мере, позволяет легко избежать слишком светлых или слишком темных чисел.

    Если вы хотите увеличить разрыв между сгенерированными цветами, попробуйте уменьшить количество разрешенных символов. Я использовал такой метод в прошлом, когда использовал только0369cf как пул символов, чтобы вытащить из. Комбинируя это с проверкой на наличие дубликатов, можно получить более различимые цвета, а также использовать только#fff 3-х символьный синтаксис.

    Вот ваша оригинальная функция, модифицированная для использования этого метода:

    function randomColor(){
        var allowed = "0369cf".split( '' ), s = "#";
        while ( s.length < 4 ) {
           s += allowed.splice( Math.floor( ( Math.random() * allowed.length ) ), 1 );
        }
        return s;
    }
    

  • 1

    Я согласен со всеми ответами

    мы действительно не знаем, что вы ожидаете здесь ...

    Это возможность, которая может дать вам выбор между выводом rgb (r, g, b) для элементов css и шестнадцатеричным выводом ...

    Это быстрый пример, вы просто должны адаптировать этот черновик, но он работает как в 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>
    

    Затем вы можете получить значение, как показано ниже:

    <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>
    

    Я надеюсь это тебе поможет. С наилучшими пожеланиями.

  • 6

    Вы говорите

    что вы не хотите генерировать случайные цвета, вы говорите, что хотите создавать разные цвета.
    Вы можете найти хороший учебник о том, как это сделать, здесь:http://krazydad.com/tutorials/makecolors.php .

    Я сделал эту скрипку с соответствующим кодом из учебника, демонстрирующим, как вы будете генерировать неповторяющиеся цвета:

    http://jsfiddle.net/rGL52/

    Единственное отличие от учебного кода состоит в том, что функция makegradient () возвращает массив цветов, которые вы можете позже применить по желанию на своей странице.

  • 0

    Прежде всего

    почему вы строите шестнадцатеричные значения из строк? Просто используйте числа для значений, а затем выведите что-то вродеyourNumber.toString(16).

    Затем, чтобы сделать цвета более четкими, не используйте полный диапазон от 0 до 255 для каждого цветового компонента, но, возможно, делайте прыжки по 10 или 20, или что угодно, чтобы генерировать достаточно широкие различия.

  • 20

    Example

    Я знаю, что очень опоздал на эту вечеринку, но я написал более сложную функцию для генерации набора контрастных случайных цветов для другого проекта. Они оба (по крайней мере, в некоторой степени) привлекательны и действительно случайны (не основаны на предопределенных цветах), но мой код немного сложнее, чем некоторые другие ответы (так что это не просто для получения основ)

    Это для пользователей, которые хотят иметь более одного случайного цвета на своей странице и хотят убедиться, что никакие два цвета не слишком похожи.

    скрипка

    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
        });
    }
    

    Обратите внимание, что, хотя в моем примере я этого не делаю, это также может быть использовано для добавления новых отдельных случайных цветов в набор:

    generateRandomColors(1,generateRandomColors(10))
    

  • 27

    Самый простой способ выбрать максимально разные цвета - это использова

    ть значения HSL вместо RGB, а затем манипулировать оттенком, поскольку он имеет значение от 0 до 360 и оборачивается (0 - красный, а значит - 360);

    если вам нужно 10 различимых цветов, вы можете разделить 360 на 10, а затем выбрать отдельный цвет, умножив значение на индекс (на основе нуля). Вот пример функции, которая позволяет выбрать цвет из:

    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%)";
    }
    

    Таким образом, вы можете рандомизировать выбор цвета путем рандомизации индекса, но цвета всегда будут в одной палитре.

    Это выберет случайный цвет из палитры 10:

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

    и так будет это:

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

    или вы можете выбрать определенный цвет из палитры, например, 9-й цвет (индекс 8) из палитры из 13:

    var color = selectColor(8, 13);
    

    Вот скрипка, с которой можно поиграть:http://jsfiddle.net/2UE2B/