admin管理员组文章数量:1414605
I am generating random color codes using this:
var color = Math.floor(Math.random()*16777215).toString(16);
if( color.length === 5 )
{
color.concat('0');
}
But I want to exclude all shades of gray color from this. How can I achieve this?
Thanks in advance for any help.
I am generating random color codes using this:
var color = Math.floor(Math.random()*16777215).toString(16);
if( color.length === 5 )
{
color.concat('0');
}
But I want to exclude all shades of gray color from this. How can I achieve this?
Thanks in advance for any help.
Share Improve this question asked Dec 3, 2017 at 7:46 jarvisjarvis 651 silver badge10 bronze badges 2-
Why? Do you want only bright colours, or is it only extremely literal RGB greys that are disallowed (not
#222223
, for example)? Are you generating some kind of colour scheme? – Ry- ♦ Commented Dec 3, 2017 at 7:48 - @Ryan only rgb grays – jarvis Commented Dec 3, 2017 at 8:26
6 Answers
Reset to default 6One way would be to limit the range of one color part to only 100 different values instead of 256 for 2 out of three color parts, and then add some constant to it (i.e. a shift).
To picture the 3 ranges for the three color parts:
********************
************************************************
********************
| | | |
0 100 156 256
Then you would assign each of those three numbers to the RGB ponents, but also randomly, so that the first value could be used for either the R, G, B ponent, the second for the two remaining ones, and the third for the one left over.
The closest a color can e to a grey scale is when the first color part is maximised (99), the last one minimised (156), and the middle one is half way those values (128). If that color is not grey to you, then this scheme will be OK. Otherwise you could decrease the size of the two shorter ranges as needed.
This leads to the following code:
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>
You can experiment with the size of the two shorter ranges: they now have a size of 100, but you can make them smaller to exclude more colors which you may still find too "greyish". You would need to adapt the constant rangeSize
accordingly.
Alternative
The above will exclude some colors which you might still find interesting to get, for instance colors with values for R, G and B which are all above 100, but do not result in a (light) grey-like color. If you really want to be able to get any color that is not too much grey, then you could:
- Generate all three color parts randomly
- If they are not too close together, then return this as the result, otherwise:
- Taking the two extreme values, determine the allowable ranges that the middle one should be relocated to to make it an acceptable color
- Generate a random value that stays within those acceptable ranges
The case where the color parts are too close together can be depicted as follows:
* * *
|-------------|
| |
0 255
The hyphens show the minimum distance the outermost values must have, and so the middle value will be relocated. It must be put outside the following two ranges:
* *
|-------------| (forbidden)
|-------------| (forbidden)
| |
0 255
And so must go in either of the following ranges:
* *
|--| |----------| (allowed)
| |
0 255
This relocation can be done by taking a random value from a range that is as long as the two ranges together, and then checking whether that random value falls within the first range. If not, the gap between the two is added to it.
Here is how that could be coded:
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>
Like in the first solution there is a value you can change to influence the sensitivity. The higher it is, the further away the relocated color part must be from the other two parts.
gray Color spectrum is: R
= G
= B
edited code:
var color = Math.floor(Math.random() * 255).toString(16);
if (color.length === 1)
{
color.concat('0');
}
console.log('#'+color+color+color);
sample: https://jsfiddle/6jjp17sx/1/
Idea is to create an array of all grey shades.
on creating hex codes, check if it is in the array and perform your operations.
whole list of grey shades here
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 es here
}
I would extract and pare the three octets to see if they are the same. When random gives a shade of gray, I simply invert the green part in order to avoid calling random multiple times, but your strategy could be different depending on your needs :
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}
This solution is really clumsy though, it doesn't care about 0x000001
for example... Here is a better one : https://stackoverflow./a/47616597/1636522.
The most obvious way (preserving uniformity) is by simply rejecting them
do
{
color = ...;
}
while( color[0]==color[2] && color[0]==color[4] &&
color[1]==color[3] && color[1]==color[5] );
note that the probability of finding a grey color(in the sense of having the form #RRR) is 1/65536
, this will loop just ~1 times on average ...
Rejectance based sampling has the advantage of being general: if you change your mind later, you just need to change the rejectance criterion. Moreover, it's also fast as long as the rejectance probability is sufficiently small (but not that small, even with a probability of one-half the loop will evaluate just twice on average).
In case it helps anyone, I'm trying to avoid shades of brown with a random colour generator. Browns are hard to define a range for. It looks to me like the following covers all brown, though it may include a few slightly different hues too (like off coloured greens or purples), but you can tweak the limits: In terms of Hex codes for R,G,B: R < ee, R - 6 < G < R-3, B < G Eg: #993300 is brown. So if you want to avoid brown, then NOT this.
- Having R less then ee allows for inclusion of oranges and yellows.
- The most important thing is that G is a little less than R (if
they're about the same or more you get yellows and greens), but not
too much less than R (where you get reds). - If B is larger than G, you get purples.
I need this for dots on a satellite map, which are hard to see if brown.
本文标签: javascriptHow to exclude all shades of gray while generating random hex color codeStack Overflow
版权声明:本文标题:javascript - How to exclude all shades of gray while generating random hex color code? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745194274a2647061.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论