I want to create a function that will accept any old string (will usually be a single word) and from that somehow generate a hexadecimal value between #000000
and #FFFFFF
, so I can use it as a colour for a HTML element.
Maybe even a shorthand hex value (e.g: #FFF
) if that's less complicated. In fact, a colour from a 'web-safe' palette would be ideal.
This question is related to
javascript
string
colors
hex
Yet another solution for random colors:
function colorize(str) {
for (var i = 0, hash = 0; i < str.length; hash = str.charCodeAt(i++) + ((hash << 5) - hash));
color = Math.floor(Math.abs((Math.sin(hash) * 10000) % 1 * 16777216)).toString(16);
return '#' + Array(6 - color.length + 1).join('0') + color;
}
It's a mixed of things that does the job for me. I used JFreeman Hash function (also an answer in this thread) and Asykäri pseudo random function from here and some padding and math from myself.
I doubt the function produces evenly distributed colors, though it looks nice and does that what it should do.
I have opened a pull request to Please.js that allows generating a color from a hash.
You can map the string to a color like so:
const color = Please.make_color({
from_hash: "any string goes here"
});
For example, "any string goes here"
will return as "#47291b"
and "another!"
returns as "#1f0c3d"
I find that generating random colors tends to create colors that do not have enough contrast for my taste. The easiest way I have found to get around that is to pre-populate a list of very different colors. For every new string, assign the next color in the list:
// Takes any string and converts it into a #RRGGBB color.
var StringToColor = (function(){
var instance = null;
return {
next: function stringToColor(str) {
if(instance === null) {
instance = {};
instance.stringToColorHash = {};
instance.nextVeryDifferntColorIdx = 0;
instance.veryDifferentColors = ["#000000","#00FF00","#0000FF","#FF0000","#01FFFE","#FFA6FE","#FFDB66","#006401","#010067","#95003A","#007DB5","#FF00F6","#FFEEE8","#774D00","#90FB92","#0076FF","#D5FF00","#FF937E","#6A826C","#FF029D","#FE8900","#7A4782","#7E2DD2","#85A900","#FF0056","#A42400","#00AE7E","#683D3B","#BDC6FF","#263400","#BDD393","#00B917","#9E008E","#001544","#C28C9F","#FF74A3","#01D0FF","#004754","#E56FFE","#788231","#0E4CA1","#91D0CB","#BE9970","#968AE8","#BB8800","#43002C","#DEFF74","#00FFC6","#FFE502","#620E00","#008F9C","#98FF52","#7544B1","#B500FF","#00FF78","#FF6E41","#005F39","#6B6882","#5FAD4E","#A75740","#A5FFD2","#FFB167","#009BFF","#E85EBE"];
}
if(!instance.stringToColorHash[str])
instance.stringToColorHash[str] = instance.veryDifferentColors[instance.nextVeryDifferntColorIdx++];
return instance.stringToColorHash[str];
}
}
})();
// Get a new color for each string
StringToColor.next("get first color");
StringToColor.next("get second color");
// Will return the same color as the first time
StringToColor.next("get first color");
While this has a limit to only 64 colors, I find most humans can't really tell the difference after that anyway. I suppose you could always add more colors.
While this code uses hard-coded colors, you are at least guaranteed to know during development exactly how much contrast you will see between colors in production.
Color list has been lifted from this SO answer, there are other lists with more colors.
Here's an adaptation of CD Sanchez' answer that consistently returns a 6-digit colour code:
var stringToColour = function(str) {
var hash = 0;
for (var i = 0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 5) - hash);
}
var colour = '#';
for (var i = 0; i < 3; i++) {
var value = (hash >> (i * 8)) & 0xFF;
colour += ('00' + value.toString(16)).substr(-2);
}
return colour;
}
Usage:
stringToColour("greenish");
// -> #9bc63b
Example:
(An alternative/simpler solution might involve returning an 'rgb(...)'-style colour code.)
This function does the trick. It's an adaptation of this, fairly longer implementation this repo ..
const color = (str) => {
let rgb = [];
// Changing non-hexadecimal characters to 0
str = [...str].map(c => (/[0-9A-Fa-f]/g.test(c)) ? c : 0).join('');
// Padding string with zeroes until it adds up to 3
while (str.length % 3) str += '0';
// Dividing string into 3 equally large arrays
for (i = 0; i < str.length; i += str.length / 3)
rgb.push(str.slice(i, i + str.length / 3));
// Formatting a hex color from the first two letters of each portion
return `#${rgb.map(string => string.slice(0, 2)).join('')}`;
}
Here is another try:
function stringToColor(str){
var hash = 0;
for(var i=0; i < str.length; i++) {
hash = str.charCodeAt(i) + ((hash << 3) - hash);
}
var color = Math.abs(hash).toString(16).substring(0, 6);
return "#" + '000000'.substring(0, 6 - color.length) + color;
}
Using the hashCode
as in Cristian Sanchez's answer with hsl
and modern javascript, you can create a color picker with good contrast like this:
function hashCode(str) {_x000D_
let hash = 0;_x000D_
for (var i = 0; i < str.length; i++) {_x000D_
hash = str.charCodeAt(i) + ((hash << 5) - hash);_x000D_
}_x000D_
return hash;_x000D_
}_x000D_
_x000D_
function pickColor(str) {_x000D_
return `hsl(${hashCode(str) % 360}, 100%, 80%)`;_x000D_
}_x000D_
_x000D_
one.style.backgroundColor = pickColor(one.innerText)_x000D_
two.style.backgroundColor = pickColor(two.innerText)
_x000D_
div {_x000D_
padding: 10px;_x000D_
}
_x000D_
<div id="one">One</div>_x000D_
<div id="two">Two</div>
_x000D_
Since it's hsl, you can scale luminance to get the contrast you're looking for.
function hashCode(str) {_x000D_
let hash = 0;_x000D_
for (var i = 0; i < str.length; i++) {_x000D_
hash = str.charCodeAt(i) + ((hash << 5) - hash);_x000D_
}_x000D_
return hash;_x000D_
}_x000D_
_x000D_
function pickColor(str) {_x000D_
// Note the last value here is now 50% instead of 80%_x000D_
return `hsl(${hashCode(str) % 360}, 100%, 50%)`;_x000D_
}_x000D_
_x000D_
one.style.backgroundColor = pickColor(one.innerText)_x000D_
two.style.backgroundColor = pickColor(two.innerText)
_x000D_
div {_x000D_
color: white;_x000D_
padding: 10px;_x000D_
}
_x000D_
<div id="one">One</div>_x000D_
<div id="two">Two</div>
_x000D_
I wanted similar richness in colors for HTML elements, I was surprised to find that CSS now supports hsl() colors, so a full solution for me is below:
Also see How to automatically generate N "distinct" colors? for more alternatives more similar to this.
function colorByHashCode(value) {_x000D_
return "<span style='color:" + value.getHashCode().intToHSL() + "'>" + value + "</span>";_x000D_
}_x000D_
String.prototype.getHashCode = function() {_x000D_
var hash = 0;_x000D_
if (this.length == 0) return hash;_x000D_
for (var i = 0; i < this.length; i++) {_x000D_
hash = this.charCodeAt(i) + ((hash << 5) - hash);_x000D_
hash = hash & hash; // Convert to 32bit integer_x000D_
}_x000D_
return hash;_x000D_
};_x000D_
Number.prototype.intToHSL = function() {_x000D_
var shortened = this % 360;_x000D_
return "hsl(" + shortened + ",100%,30%)";_x000D_
};_x000D_
_x000D_
document.body.innerHTML = [_x000D_
"javascript",_x000D_
"is",_x000D_
"nice",_x000D_
].map(colorByHashCode).join("<br/>");
_x000D_
span {_x000D_
font-size: 50px;_x000D_
font-weight: 800;_x000D_
}
_x000D_
In HSL its Hue, Saturation, Lightness. So the hue between 0-359 will get all colors, saturation is how rich you want the color, 100% works for me. And Lightness determines the deepness, 50% is normal, 25% is dark colors, 75% is pastel. I have 30% because it fit with my color scheme best.
If your inputs are not different enough for a simple hash to use the entire color spectrum, you can use a seeded random number generator instead of a hash function.
I'm using the color coder from Joe Freeman's answer, and David Bau's seeded random number generator.
function stringToColour(str) {
Math.seedrandom(str);
var rand = Math.random() * Math.pow(255,3);
Math.seedrandom(); // don't leave a non-random seed in the generator
for (var i = 0, colour = "#"; i < 3; colour += ("00" + ((rand >> i++ * 8) & 0xFF).toString(16)).slice(-2));
return colour;
}
All you really need is a good hash function. On node, I just use
const crypto = require('crypto');
function strToColor(str) {
return '#' + crypto.createHash('md5').update(str).digest('hex').substr(0, 6);
}
I convert this for Java.
Tanks for all.
public static int getColorFromText(String text)
{
if(text == null || text.length() < 1)
return Color.BLACK;
int hash = 0;
for (int i = 0; i < text.length(); i++)
{
hash = text.charAt(i) + ((hash << 5) - hash);
}
int c = (hash & 0x00FFFFFF);
c = c - 16777216;
return c;
}
Here's a solution I came up with to generate aesthetically pleasing pastel colours based on an input string. It uses the first two chars of the string as a random seed, then generates R/G/B based on that seed.
It could be easily extended so that the seed is the XOR of all chars in the string, rather than just the first two.
Inspired by David Crow's answer here: Algorithm to randomly generate an aesthetically-pleasing color palette
//magic to convert strings to a nice pastel colour based on first two chars
//
// every string with the same first two chars will generate the same pastel colour
function pastel_colour(input_str) {
//TODO: adjust base colour values below based on theme
var baseRed = 128;
var baseGreen = 128;
var baseBlue = 128;
//lazy seeded random hack to get values from 0 - 256
//for seed just take bitwise XOR of first two chars
var seed = input_str.charCodeAt(0) ^ input_str.charCodeAt(1);
var rand_1 = Math.abs((Math.sin(seed++) * 10000)) % 256;
var rand_2 = Math.abs((Math.sin(seed++) * 10000)) % 256;
var rand_3 = Math.abs((Math.sin(seed++) * 10000)) % 256;
//build colour
var red = Math.round((rand_1 + baseRed) / 2);
var green = Math.round((rand_2 + baseGreen) / 2);
var blue = Math.round((rand_3 + baseBlue) / 2);
return { red: red, green: green, blue: blue };
}
GIST is here: https://gist.github.com/ro-sharp/49fd46a071a267d9e5dd
Source: Stackoverflow.com