Reputation: 6040
I have a table of action logs in my application. I want to assign rows a random colour based on the sessionID of that entry to help see patterns/grouped actions.
I have this so far:
console.log(stringToColorCode('mj3bPTCbIAVoNr93me1I'));
function stringToColorCode(str) {
return '#'+ ('000000' + (Math.random()*0xFFFFFF<<0).toString(16)).slice(-6);
}
However I need to replace Math.random() with my string-integer, are there any techniques for converting a string to a random number that remains consistent with the random string?
Upvotes: 15
Views: 9692
Reputation: 1537
I resolved this on backing bean. This works for me in Java:
private void createDefaultColorFromName(final String name) {
String md5 = "#" + md5(name).substring(0, 6);
defaultColor = Color.decode(md5);
int darkness = ((defaultColor.getRed() * 299) + (defaultColor.getGreen() * 587) + (defaultColor.getBlue() * 114)) / 1000;
if (darkness > 125) {
defaultColor = defaultColor.darker();
}
}
I made the generated color a little darker for a white background...
Upvotes: -1
Reputation: 66334
As requested, posting this as an awswer
var stringHexNumber = ( // 1
parseInt( // 2
parseInt('mj3bPTCbIAVoNr93me1I', 36) // 3
.toExponential() // 4
.slice(2,-5) // 5
, 10) & 0xFFFFFF // 6
).toString(16).toUpperCase(); // "32EF01" // 7
So, what's going on?
3
where 'mj3bPTCbIAVoNr93me1I'
gets converted to an Integer, say x
, by interpreting it as a base-36 number. x
is put into it's exponential form as a String on line 4
. This is because with that many characters, x
can be huge, this example is around 8e30
, so convert it to a form that will be pretty standard. 5
trims off the beginning and end so you'll be left with just digits, e.g. '8.123e+30'.slice(2, -5)
becomes '12'
.2
, where this gets converted back into an Integer again, this time in base 10.6
truncates this number down to the range 0..16777215 (=== 0xFFFFFF)
using a fast bitwise AND. This will also convert NaN
to 0
.7
converts this back into the upper case hex format we are used to seeing colours in, by writing the number in base 16
and changing the case.If you want to use this, you may also want to ensure that the final number is 6
digits and stick a #
on the front, which can be done via
'#' + ('000000' + stringHexNumber).slice(-6); // "#32EF01"
Upvotes: 22
Reputation: 6674
Sweet question. What I did is create a global variable so you can consistently get the same color for a given input string. Once you have called stringToColorCode, it will only generate a random color for that string ONCE. You can rely on this to be consistent, so that if you call the function back to back with the same string, it will return the same random color. Only flaw I see is that it's possibly (but unlikely) that two different strings could be mapped to the same color, but that could be worked around if necessary.
Edit: When first answering, I didn't realize @Nirk had practically the same answer. To make this one a little more unique, use this which will give you consistent colors across page reloads.
console.log(stringToColorCode('mj3bPTCbIAVoNr93me1I'));
function stringToColorCode(str) {
var sessionStoreKey = "myStringColors" + str;
if (!sessionStorage[sessionStoreKey ]) {
sessionStorage[sessionStoreKey] = Math.random()*0xFFFFFF<<0;
}
var randomColor = sessionStorage[sessionStoreKey];
return '#'+ randomColor;
}
Upvotes: 2
Reputation: 22905
var color_codes = {};
function stringToColorCode(str) {
return (str in color_codes) ? color_codes[str] : (color_codes[str] = '#'+ ('000000' + (Math.random()*0xFFFFFF<<0).toString(16)).slice(-6));
}
Upvotes: 10