I have setup a basic getRandomColor function in javascript but I am having trouble figuring out how to limit the color spectrum that it uses. I want it to be more White & Grey colors. Is this possible?
My code is as follows:
function getRandomColor() {
var letters = "0123456789ABCDEF".split("");
var color = "#";
for (var i = 0; i < 6; i++ ) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
Go to an online color picker like this one, and look through a bunch of grey/white/black colors. On the webpage I linked to, you can do this by clicking to the verrrry left of the color box.
Look and see if you can find a pattern in the ratio between red/blue/green in the colors you want. Let me know if you find the pattern.
Edit
Alright, I'll let the cat out of the bag like the other answer has already done. When we have a 6-digit hex code, we have 2 digits for red, 2 digits for blue, and 2 digits for green.
# 80 80 80
^ ^ ^
red amount | |-----green amount
|---------------- blue amount
Numbers with a high red amount are very red, (like #990000 or #ff0000) numbers with a high blue amount are very blue (#00ff00), etc...
If the amount of red, green, and blue are all the same, then the color will look grey. So, all of the following colors will be grey-ish
#757575
#343434
#a3a3a3
Because I copied the same 2 numbers over and over. In the first one, the red amount is the same as the blue amount is the same as the green amount, which is 75.
Now how do you get this into your code? Generate 2 random letters to get the first color, and then add that to the end of your string 2 more times.
Edit 2
Let's talk about the code in "The Low Flying Pelican"'s answer really quick.
The first line will construct an array with letters from "A" to "F" in it. This means that our resulting color will only have letters in its hex code from "A" to "F". If we want other digits, we need to add them to the start of this string. Because we are picking numbers randomly, the order of digits in this string does not matter.
The 4th and 5th lines (var digit1 = Math.floor(Math.random() * 6);) pick an INDEX into this array. Pretty much it works like this. If our array has the elements A, B, C, D, E, F, then the 0th one is A, the 1st one is B, and so on. This means that if we do
letters[0]
We will get A, and if we do
letters[1]
We will get B.
We want to do
letters[<some random number>]
Which gives us a surprise letter between A and F. We do this twice to get two surprise letters, like EB or CC. In the given code it works like this:
//Pick 2 random numbers between 0 and 5.
//Math.floor() rounds the random numbers down, so instead of
//getting 3.42123, we just get 3. This is necessary because
//we can't take the 3.4th element of our array!
var digit1 = Math.floor(Math.random() * 6);
var digit2 = Math.floor(Math.random() * 6);
Later you see this code
letters[digit1]
which fetches the letter associated with the random number named "digit1"
If we are only picking random letters between A and F, we can't get the full range of greyscale. For that we need to pick random numbers from 0 to F. To do this, we need to add "0123...89" to the start of the array in the given code, AND we need to change the code so it picks a number between 0 and 15, instead of 0 and 5.
White/Gray colors do have all components the same, so,
function getRandomColor() {
var letters = "ABCDEF".split("");
var color = "#";
var digit1 = Math.floor(Math.random() * 6);
var digit2 = Math.floor(Math.random() * 6);
for (var i = 0; i < 3; i++ ) {
color += letters[digit1];
color += letters[digit2];
}
return color;
}
change to use only ABCDEF values so that it would be more towards white and gray, also to make sure all 3 components are the same
Related
So if I use randomColor to generate a pretty random variation of "green", I get this for example:
This is a bit chaotic for my liking, I would instead like to get a list of green colors that have some sort of order or sorting to them. That look like they flow into each other. Something more like this:
The question is what principles are being used to sort the colors in that way. I would like to know how I could go about building a grid of colors that would look more pleasant than a random assortment of colors of a specific hue.
The code I used is simply this:
var randomColor = require('randomcolor')
var input = process.argv[2]
var colors = randomColor({
count: 20,
hue: input
})
If it makes a difference, I would like to be able to specify the number of rows and columns to divide the colors into as well. Any language or pseudocode would be fine to figure this out, but seeing it in JavaScript, especially if it involves bit manipulation like bitshifts, would be helpful but not necessary.
This doesn't quite seem to do what I want.
The greens on the image run across various hues they then go down in value (get less black) as you move down.
Your pretty color generator randomColor is predicated on an odd theory that colors that move through the golden ratio within the color space will be prettier, basically it just makes sure you tend to get linear steps. But, the code is CC0-Licensed and includes a number of useful things for your purposes. First they define what green is. And they define how to convert from RGB to HSL. I'd just alter that code to make linear steps through the correct hues and then in the row direction step along in value.
However, this is going to just create the same colors each time, so you might just define the list of green colors you like.
If you actually want to sort these colors, you can sort them by literally just sorting them. Use HexToHSB() in the code randomColor, then sort the values based on it's resulting hue value. This generally will have lighter and brighter colors but you can clearly see a less chaotic pattern throughout.
All color spaces tend to be 3 values so putting them in 2d tends to be a bit kludgy, so you might as well pick one or two metrics and use those.
function HexToHSB(hex) {
hex = hex.replace(/^#/, '');
hex = hex.length === 3 ? hex.replace(/(.)/g, '$1$1') : hex;
var red = parseInt(hex.substr(0, 2), 16) / 255,
green = parseInt(hex.substr(2, 2), 16) / 255,
blue = parseInt(hex.substr(4, 2), 16) / 255;
var cMax = Math.max(red, green, blue),
cMin = Math.min(red, green, blue),
delta = cMax - cMin,
saturation = cMax ? (delta / cMax) : 0;
switch (cMax) {
case 0:
return [0, 0, 0];
case cMin:
return [0, 0, cMax];
case red:
return [60 * (((green - blue) / delta) % 6) || 0, saturation, cMax];
case green:
return [60 * (((blue - red) / delta) + 2) || 0, saturation, cMax];
case blue:
return [60 * (((red - green) / delta) + 4) || 0, saturation, cMax];
}
}
var input = 'green'
var colors = randomColor({
count: 200,
hue: input
})
colors = colors.sort(function(a, b) {
var hsva = HexToHSB(a);
var hsvb = HexToHSB(b);
return hsva[0] - hsvb[0];
});
div = document.createElement("div");
document.body.appendChild(div);
colors.forEach(function(element) {
var d = document.createElement("button");
d.style.cssText = 'padding:5px; font-size:22px; width:50px; height:50px; background-color:' + element;
div.appendChild(d);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.5.4/randomColor.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
(Not intending this to be a full code inclusive answer)
Your greens in the second image, across the top run from a blue green to a yellow green. In practical terms this means the top left green is “0 red, maybe 255 green and 200 blue”. At the other side, in the top right, it’s maybe “200 red, 255 green, 0 blue”. (I would have made these more accurate by using a colour detector but I’m on a phone)
Descending down the rows they’re tending towards black by reducing the r g b values, so for the middle row they might go from rgb 0,127,100 to rgb 100,127,0
Algorithmically, though this might be easier to do by using hsv colours rather than rgb, as the columns across go from some higher hue to a lower hue and the rows downwards tend from a high value to a low value. This would probably be easier to implement than doing the rgb math as you just need to accept a hue that will vary from maybe h+40 to h-40 (from a full wheel of 360) and a matrix (and you probably will need to ask for rows and columns not just 20, otherwise how will you know to output 5x4 or 4x5)
Here is a little challenge, I hope it will be useful for others too.
Task is to obtain an ID character from alphabets of english language. a-to-z
My solution currently allows ID (words) of 26 diff length (max possible). with 90 possible words.
I know this can be increased if we pick random characters after single character IDs are obtained (done with.) (But) I am finding it hard to figure out how to manage NOT hitting a combination already found (ID has to be unique). As we see it takes a long time if it starts finding the same combinations over and over. this probability increases as we obtain more and more ID-combinations.
Here is my code and fiddle to test and check:
fiddle
code:
html
<p>
start
</p>
jquery:
function addto(t) {
$("p").append("<b>" + t + "</b>");
}
global_ID_array = [];
lowerAlpha = "abcdefghijklmnopqrstuvwxyz";
var myIDlength = 1;
function getIDChar (){
do {
var myIDchar = lowerAlpha.substr(0, myIDlength);
lowerAlpha = lowerAlpha.replace(myIDchar,'');
if (lowerAlpha.length < myIDlength){
lowerAlpha = "abcdefghijklmnopqrstuvwxyz"; //reset
myIDlength++;
}
} while (global_ID_array.indexOf(myIDchar) > -1)
global_ID_array.push(myIDchar);
addto(myIDlength+':'+global_ID_array.length+',');
}
do{
getIDChar();
}while (myIDlength < 26);
addto('<br \>myIDlength='+myIDlength);
addto('<br \>global_ID_array last val='+global_ID_array[global_ID_array.length-1]+'<p>');
To get started, instead of thinking about the IDs in terms of letters, think about it in terms of numbers.
Since there are 26 possible characters, each character can be considered as a digit of a base-26 numeric system, with a == 0, and z == 25. The problem now boils down to generating a number and converting it to base-26 using the alphabets as digits. Since the ID length is 26 characters, we can generate up to 26^26 unique IDs.
Now, to make sure that the ID generated is unique (up to 26^26 generated IDs), we need to find a way to generate a unique number every time. The simplest way to do this is to initialize a counter at 0 and use it to generate the ID. Every time an ID is done generating, increment the counter. Of course, this is a very deterministic generation algorithm, but you could use a seeded random number generator that guarantees the uniqueness of random numbers generated in a range.
The algorithm may look as follows:
n = random(0, 26^26 - 1)
id = "a" * 26
// chars[i] is the character representing the base-26 digit i;
// you may change/shuffle the list as you please
chars = ['a', 'b', 'c', ..., 'y', 'z']
for i in 0..26 {
// Get the character corresponding to the next base-26 digit of n (n % 26)
id[26 - i] = chars[n % 26]
n /= 26
}
I have been working on a Rubik’s Cube Timer website, and I need to make a scrambling algorithm. I’ll go over how the scrambling algorithm should work:
Each face has it’s own letter, it’s initial. for examble, if you want to move the front face, you would write “ F “. If you want to move the the right face, you would write “ R “, and so on. just note that the bottom face is D, as for down. So you have D U R L B F.
If there is nothing after that letter, you turn it clockwise. If there is an appostrophe “ ‘ “, you turn it counter-clockwise. If there is a 2, you turn it two times. Now the thing is that you cannot have 2 same letters next to oneanother, as they would cancel (For example “.. U U’ ...” would be the same as doing nothing. So far, I have this taken care of in my algorithm.
The problem comes when you have one letter, then it’s opposite, then again the first letter, ( For example “.. U D U’...” (would mean Up clockwise, Down clockwise, Up counterclokwise)).
I have no idea how to check for these and avoid them automatically. Here’s the code:
<div id=“Scramble”></div>
<script>
generateScramble();
function generateScramble() {
// Possible Letters
var array = new Array(" U", " D", " R", " L", " F", " B")
// Possible switches
var switches = ["", "\'", "2"];
var array2 = new Array(); // The Scramble.
var last = ''; // Last used letter
var random = 0;
for (var i = 0; i < 20; i++) {
// the following loop runs until the last one
// letter is another of the new one
do {
random = Math.floor(Math.random() * array.length);
} while (last == array[random])
// assigns the new one as the last one
last = array[random];
// the scramble item is the letter
// with (or without) a switch
var scrambleItem = array[random] + switches[parseInt(Math.random()*switches.length)];
array2.push(scrambleItem); // Get letters in random order in the array.
}
var scramble = "Scramble: ";
// Appends all scramble items to scramble variable
for(i=0; i<20; i++) {
scramble += array2[i];
}
document.getElementById("Scramble").innerHTML = scramble; // Display the scramble
}
</script>
For starters God's Number is 20 for Rubik;s cube so you got only 20 moves instead of 25. I assume you are not doing scrambling (as your title suggest) but instead generate solution command strings for genere&test solver type. There are too many sequences that cancel each other and to check for all of them would be most likely slower than try them out actually.
The problem is that even O(n^20) is huge and you need to lower the 20. That is done by LUT holding semi solved states. For example create table holding states for all combinations of 5 turn scrambling. Then use that as end condition turning your solver into O(n^15 + n^5) = O(n^15) ...
This problem popped up when I looked at an almost perfect bit of jQuery code called Jar Two Wheel Color Picker:
http://www.jar2.net/projects/jquery-wheelcolorpicker/demo
If you notice in their demo when you move your cursor over the wheel, the developer appears to be using an inverse color algorithm that's slightly imperfect. I mean, if you use it and paste in 8072ff, you end up with something you can't read in the textbox.
The fix in my mind was to change the algorithm so that it shows black when over lighter colors, and white when over darker colors.
I looked into the source and found where it's updating the color of the textbox field. There, I'm able to get the R, G, and B color values from 0 to 255.
In Javascript and jQuery, knowing the R, G, and B values of a background color, how can I switch the foreground color to either white or black so that it is readable?
The conversion to hsl makes finding contrasting colors easy-
but it takes a bit to convert between rgb and hsl.
This works well enough for most cases- but it won't replace your eye.
function bW(r){
//r must be an rgb color array of 3 integers between 0 and 255.
var contrast= function(B, F){
var abs= Math.abs,
BG= (B[0]*299 + B[1]*587 + B[2]*114)/1000,
FG= (F[0]*299 + F[1]*587 + F[2]*114)/1000,
bright= Math.round(Math.abs(BG - FG)),
diff= abs(B[0]-F[0])+abs(B[1]-F[1])+abs(B[2]-F[2]);
return [bright, diff];
}
var c, w= [255, 255, 255], b= [0, 0, 0];
if(r[1]> 200 && (r[0]+r[2])<50) c= b;
else{
var bc= contrast(b, r);
var wc= contrast(w, r);
if((bc[0]*4+bc[1])> (wc[0]*4+wc[1])) c= b;
else if((wc[0]*4+wc[1])> (bc[0]*4+bc[1])) c= w;
else c= (bc[0]< wc[0])? w:b;
}
return 'rgb('+c.join(',')+')';
}
Given the RGB/HSV conversion functions from Michael Jackson and this bit of HTML to play with:
<input type="text" id="pancakes">
<button id="margie">go</button>
Then something like this might be a decent starting point:
$('#margie').click(function() {
var bg = $('#pancakes').val();
var rgb = bg.match(/../g);
for(var i = 0; i < 3; ++i)
rgb[i] = parseInt(rgb[i], 16);
var hsv = rgbToHsv(rgb[0], rgb[1], rgb[2]);
var fg = 'ffffff';
if(hsv[2] > 0.5)
fg = '000000';
$('#pancakes').css({
color: '#' + fg,
background: '#' + bg
});
});
Demo: http://jsfiddle.net/ambiguous/xyA4a/
You might want to play with the hsv[2] > 0.5 and possibly look at the hue and saturation as well but just a simple value check should get you started. You might want to play with HSL rather than HSV and see which one works better for you.
What is the best way to pick random colors for a bar chart / histogram such that each color is different from the other.. and possibly in contrast
The most talked about way is
'#'+(Math.random()*0xFFFFFF<<0).toString(16);
but this can generate similar colors.. and sometimes distinguishing them might be a problem..
Example
I would generate colors using HSV (hue, saturation, value) instead of RGB. In HSV, the color is defined by the hue, ranging from 0-360. Thus, if you want e.g. 6 different colors, you can simply divide 360 by 5 (because we want to include 0) and get 72, so each color should increment with 72. Use a function like this one to convert the generated HSV color to RGB.
The following function returns an array of total different colors in RGB format. Note that the colors won't be "random" in this example, as they will always range from red to pink.
function randomColors(total)
{
var i = 360 / (total - 1); // distribute the colors evenly on the hue range
var r = []; // hold the generated colors
for (var x=0; x<total; x++)
{
r.push(hsvToRgb(i * x, 100, 100)); // you can also alternate the saturation and value for even more contrast between the colors
}
return r;
}
The best way is to convert from HSV values. You can divide the maximum value of "Hue" by the amount of colors you need and then increment by this result.
For improved contrast, you can also alternate between high and low values of lightness.
The existing answers which mention the Hue, Saturation, Value representation of colors are very elegant, are closer to how humans perceive color, and it is probably best to follow their advice. Also creating a long precalculated list of colors and choosing subsets of them as needed is fast and reliable.
However, here is some code that answers your question directly: it will generate random colors in RGB that are sufficiently different. There are two drawbacks to this technique that I can see. First, these colors are really random and could look kind of gross together, and second it might take a while for the code to stumble on colors that work, depending on how "far apart" you require the colors to be.
function hex2rgb(h) {
return [(h & (255 << 16)) >> 16, (h & (255 << 8)) >> 8, h & 255];
}
function distance(a, b) {
var d = [a[0] - b[0], a[1] - b[1], a[2] - b[2]];
return Math.sqrt((d[0]*d[0]) + (d[1]*d[1]) + (d[2]*d[2]));
}
function freshColor(sofar, d) {
var n, ok;
while(true) {
ok = true;
n = Math.random()*0xFFFFFF<<0;
for(var c in sofar) {
if(distance(hex2rgb(sofar[c]), hex2rgb(n)) < d) {
ok = false;
break;
}
}
if(ok) { return n; }
}
}
function getColors(n, d) {
var a = [];
for(; n > 0; n--) {
a.push(freshColor(a, d));
}
return a;
}
The distance between colors is the Euclidean distance measured by the R, G, and B components. Thus the furthest that two colors (black and white) can be is about 441.67.
To use this code, call getColors where the first parameter is the number of colors, and the second is the minimum distance between any two of them. It will return an array of numerical RGB values.
I like using hsl values for specifying colour this way.
So
"color: hsl(" + getRandomArbitary(0, 360) + ", 50%, 50%)";
would give you random results, but that won't give you your distinct separations. So I'd base it on the i value of a loop. Something like,
for (var i = 0; i < whateverYourValue; i += 1) {
color = "color: hsl(" + i * 10 + ", 50%, 50%)";
// set your colour on whatever
}
obviously the above is indicative, and not valid code on it's own.
Want to know more on hsl? Check http://mothereffinghsl.com/ 'cause, you know, it's fun.
'#'+(Math.random()*0xFFFFFF<<0).toString(16);
Isn't the best method to use because it can generate values like #4567 which is missing two digits instead of generating #004567
It's better to pick each character individually like:
'#'+Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16)+
Math.floor(Math.random()*16).toString(16);
But that can easily be reduced to picking three numbers since hex colours can be shortened. IE. #457 == #445577
Then if you want to decrease the number of posibilities and widen the gap between them you can use:
'#'+(5*Math.floor(Math.random()*4)).toString(16)+
(5*Math.floor(Math.random()*4)).toString(16)+
(5*Math.floor(Math.random()*4)).toString(16);
Which divides the number of choices for each color by 5, and then evens out the distribution equally.
I second what kbok and Harpyon say about working in HSV colorspace, and this little library makes it super easy to switch between RGB and HSV - and others.