我正在使用以下方式生成随机颜色代码:
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次...
基于拒绝的抽样具有一般的优势:如果您以后改变主意,则只需要更改拒绝标准即可。此外,只要拒绝概率足够小(但 的概率平均也只能平均评估两次)。