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



我正在使用以下方式生成随机颜色代码:

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

,但我想从中排除所有灰色阴影。我该如何实现?

事先感谢您的任何帮助。

一种方法是将一种颜色零件的范围限制为100个不同的值,而不是三个颜色零件中的256,然后在其中添加一些常数(即一个偏移)。

想象三个颜色部分的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 => p.toString(16).padStart(2, "0") ).join('');
}
// Sample
const divs = document.querySelectorAll('div');
for (const div of divs) {
    div.style.background = '#' + randomColor();
}
#container div {
   height: 20px; width: 60px;
   margin: 1px;
   display: inline-block
}
<span id="container">
<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>
</span>

您可以尝试两个较短的范围的大小:它们现在的大小为100,但是您可以使它们较小以排除更多颜色,您仍然可以找到"灰色"。您需要相应地调整常数rangeSize

替代

以上将排除一些您可能仍然会发现的颜色,例如带有R,G和B值的颜色,这些颜色均超过100,但不会产生(轻)类似灰色的颜色。如果您真的希望能够获得任何灰色不多的颜色,那么您可以:

  • 随机生成所有三个颜色零件
  • 如果它们不太亲密,请作为结果返回,否则:
  • 采用两个极端值,确定应将中间的范围重新安置为可接受的颜色
  • 生成一个留在这些可接受范围内的随机值

颜色零件太近在一起的情况如下:

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

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

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

,因此必须进入以下任何一个范围:

        *        *
|--|                  |----------| (allowed)
|                                |
0                               255
  

可以通过从两个范围的范围中取一个随机值来完成此重定位,然后检查该随机值是否落在第一范围内。如果不是,则将两者之间的差距添加到其中。

这是如何编码的:

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 => p.toString(16).padStart(2, "0") )
        .join('');
}
// Sample
const divs = document.querySelectorAll('div');
for (const div of divs) {
    div.style.background = '#' + randomColor();
    console.log(div.style.background);
}
#container div {
   height: 20px; width: 60px;
   margin: 1px;
   display: inline-block
}
<span id="container">
<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>
</span>

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

灰色频谱是: 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/

想法是创建所有灰色阴影的数组。

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

此处的灰色阴影列表

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
}

我会提取并比较三个八位位,以查看它们是否相同。当随机呈现灰色的阴影时,我只是将绿色部分倒转以避免多次呼叫随机,但是您的策略可能会有所不同,具体取决于您的需求&nbsp;:

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 ...这是一个更好的One&nbsp;:https://stackoverflow.com/a/47616597/1636522.

最明显的方法(保留均匀性)就是简单地拒绝它们

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

请注意,找到灰色的概率(从表格#rrr的意义上)是1/65536,这平均循环左右〜1次...

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

最新更新