如何在生成随机十六进制颜色代码时排除所有灰度;

时间:2017-12-03 07:46:29

标签: javascript

我使用这个生成随机颜色代码:

var color = Math.floor(Math.random()*16777215).toString(16);
    if( color.length === 5 )
    {
        color.concat('0');
    }

但我想从中排除所有灰色阴影。我怎样才能做到这一点?

提前感谢您的帮助。

5 个答案:

答案 0 :(得分:4)

一种方法是将一个颜色部分的范围限制为仅100个不同的值,而不是三个颜色部分中的2个,然后为它添加一些常量(即移位)。

要拍摄三个颜色部分的3个范围:

********************
************************************************
                            ********************
|                  |        |                  |
0                 100      156                256

然后你会将这三个数字中的每一个分配给RGB组件,也可以随机分配,这样第一个值就可以用于R,G,B组件,第二个值用于剩下的两个组件,第三个用于剩下的那个。

最接近的颜色可以达到灰度级是第一个颜色部分最大化(99),最后一个最小化(156),中间颜色是这些值的一半(128)。如果你的颜色不是灰色,那么这个方案就可以了。否则,您可以根据需要减小两个较短范围的大小。

这导致以下代码:



function randomColor() {
    const rangeSize = 100; // adapt as needed
    const parts = [
        Math.floor(Math.random()*256),
        Math.floor(Math.random()*rangeSize),
        Math.floor(Math.random()*rangeSize) + 256-rangeSize 
    ].sort( (a, b) => Math.random() < 0.5 );

    return parts.map( p => ('0' + p.toString(16)).substr(-2) ).join('');
}

// Sample
const divs = document.querySelectorAll('div');
for (const div of divs) {
    div.style.background = '#' + randomColor();
}
&#13;
div {
   height: 20px; width: 60px;
   margin: 1px;
   display: inline-block
}
   
&#13;
<div></div> <div></div> <div></div> <div></div> <div></div> <div></div> 
<div></div> <div></div> <div></div> <div></div> <div></div> <div></div>
<div></div> <div></div> <div></div> <div></div> <div></div> <div></div>
&#13;
&#13;
&#13;

您可以尝试两个较短范围的大小:它们现在的大小为100,但您可以将它们缩小以排除更多您仍可以找到的颜色&#34;灰色&#34;。您需要相应地调整常量rangeSize

替代

以上将排除您可能仍然感兴趣的一些颜色,例如R,G和B的值都高于100的颜色,但不会产生(浅色)灰色的颜色。如果你真的希望能够得到任何颜色不是太灰,那么你可以:

  • 随机生成所有三个颜色部分
  • 如果它们不是太靠近,那么将其作为结果返回,否则:
  • 取两个极值,确定中间值应重新定位的允许范围,使其成为可接受的颜色
  • 生成一个保持在可接受范围内的随机值

颜色部分太靠近的情况可以描述如下:

        *   *    *
      |-------------|      
|                                |
0                               255

连字符显示最外层值必须具有的最小距离,因此将重新定位中间值。它必须放在以下两个范围之外:

        *        *
   |-------------|                 (forbidden)
        |-------------|            (forbidden)
|                                |
0                               255

所以必须进入以下任一范围:

        *        *
|--|                  |----------| (allowed)

|                                |
0                               255

这种重定位可以通过从两个范围一起取一个范围内的随机值,然后检查该随机值是否落在第一个范围内来完成。如果没有,两者之间的差距就会增加。

以下是如何编码:

&#13;
&#13;
function randomColor() {
    // Threshold can be between 0 and 127: 
    //    the higher it is, the more colors are considered to be too grey-like.
    const threshold = 50;
    // Generate three color parts randomly
    const parts = Array.from(Array(3), _ => 
            Math.floor(Math.random()*256)
        ).sort( (a, b) => a-b );
    
    // Check whether they are too close to the same value:
    if (parts[2] - parts[0] < threshold) { // color is too greyish
        // Replace the middle one with a random value outside of the "too close" range
        const exclude = Math.min(255, parts[0] + threshold) 
                      - Math.max(0, parts[2] - threshold);
        parts[1] = Math.floor(Math.random()*(256-exclude));
        if (parts[1] >= parts[2] - threshold) parts[1] += exclude;
    }
    // Shuffle and format the color parts and return the resulting string
    return parts
        .sort( (a, b) => Math.random() < 0.5 )
        .map( p => ('0' + p.toString(16)).substr(-2) )
        .join('');
}

// Sample
const divs = document.querySelectorAll('div');
for (const div of divs) {
    div.style.background = '#' + randomColor();
    console.log(div.style.background);
}
&#13;
div {
   height: 20px; width: 60px;
   margin: 1px;
   display: inline-block
}
   
&#13;
<div></div> <div></div> <div></div> <div></div> <div></div> <div></div> 
<div></div> <div></div> <div></div> <div></div> <div></div> <div></div>
<div></div> <div></div> <div></div> <div></div> <div></div> <div></div>
&#13;
&#13;
&#13;

与第一种解决方案一样,您可以更改一个值以影响灵敏度。它越高,重新定位的颜色部分必须离其他两个部分越远。

答案 1 :(得分:0)

最明显的方法(保持一致性)就是简单地拒绝它们

do
{
  color = ...;
}
while( color[0]==color[2] && color[0]==color[4] &&
  color[1]==color[3] && color[1]==color[5] );

请注意,找到灰色的概率(在形式为#RRR的意义上)是1/65536,这将平均只循环约1次......

基于拒绝的抽样具有一般优势:如果您稍后改变主意,则只需更改拒绝标准。此外,只要拒绝概率足够小(但不 小,即使循环的一半的概率平均只评估两次),它也很快。

答案 2 :(得分:0)

灰色色谱为:R = G = B

编辑代码:

var color = Math.floor(Math.random() * 255).toString(16);
    if (color.length === 1)
    {
        color.concat('0');
    }
    console.log('#'+color+color+color); 

示例:https://jsfiddle.net/6jjp17sx/1/

答案 3 :(得分:0)

想法是创建一个包含所有灰色阴影的数组。

创建十六进制代码,检查它是否在数组中并执行操作。

整个灰色阴影列表here

&#13;
&#13;
let allGreyShades = ['#000000','#080808','#101010']
// actually there is lot more .. 3 just for demo purposes;

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

if(allGreyShades.indexOf(colorGenerated) == -1) {
 // your logic comes here
}
&#13;
&#13;
&#13;

答案 4 :(得分:0)

我会提取并比较三个八位字节,看看它们是否相同。当随机给出灰色阴影时,我只是将绿色部分反转以避免多次随机调用,但根据您的需要,您的策略可能会有所不同:

for (let i = 0; i < 20; i++) {
  var div = document.createElement("div");
  paint(div, randomColorExceptGray());
  document.body.appendChild(div);
}

function paint (el, color) {
  var rgb = colorToRgb(color);
  el.style.backgroundColor = (
    "rgb(" + rgb.join(",") + ")"
  );
}

function randomColorExceptGray () {
  var white = 0xFFFFFF;
  var random = Math.random();
  var color = Math.ceil(random * white);
  var rgb = colorToRgb(color);
  if (rgb[0] === rgb[1] === rgb[2]) {
    return color ^ 0x00FF00;
  } else {
    return color;
  }
}

function colorToRgb (color) {
  var R = (color & 0xFF0000) >> 16;
  var G = (color & 0x00FF00) >> 8;
  var B = (color & 0x0000FF);
  return [R, G, B];
}
div{height:50px;width:50px;float:left;margin:0 10px 10px 0}

这个解决方案真的很笨拙,但它并不关心0x000001例如......这是一个更好的解决方案:https://stackoverflow.com/a/47616597/1636522