Instantly share code, notes, and snippets.

# blueandhack/colors.md

forked from 0x263b/colors.md
Created Aug 15, 2019
Random color from string in javascript

# Random color from string in javascript

Consider a list of strings you need to permanently assign a random color.

First you should turn the string into a hash.

```var string = "string"
var hash = 0

for (var i = 0; i < string.length; i++) {
hash = string.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}

console.log(hash) // -891985903```
• `string.charCodeAt(i)` returns the UTF-16 code for the character at index `i`
• Bit operators work on 32 bits numbers. Any numeric operand in the operation is converted into a 32 bit number.
• `hash << 5` is equivalent to `hash * Math.pow(2, 5)` (`hash * 32`), except the bit operator `<<` makes sure our result is a 32 bit number.
• `hash & hash` again, makes sure we only return a 32 bit number.

Now we have something to play around with.

### RGB

The simplest method is to turn our hash into an RGB string:

```String.prototype.toRGB = function() {
var hash = 0;
if (this.length === 0) return hash;
for (var i = 0; i < this.length; i++) {
hash = this.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}
var rgb = [0, 0, 0];
for (var i = 0; i < 3; i++) {
var value = (hash >> (i * 8)) & 255;
rgb[i] = value;
}
return `rgb(\${rgb[0]}, \${rgb[1]}, \${rgb[2]})`;
}

"string".toRGB() // rgb(17, 96, 213)```

```String.prototype.toHex = function() {
var hash = 0;
if (this.length === 0) return hash;
for (var i = 0; i < this.length; i++) {
hash = this.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}
var color = '#';
for (var i = 0; i < 3; i++) {
var value = (hash >> (i * 8)) & 255;
color += ('00' + value.toString(16)).substr(-2);
}
return color;
}

"string".toHex() // #1160d5```

The issue is this can potentially spit out any color value. Ideally we'd want to filter out values too similar to our background color, and some gray/bland colors.

### Color from array

What if we hand pick some colors, and assign each string one of those? (fiddle)

```String.prototype.toColor = function() {
var colors = ["#e51c23", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#5677fc", "#03a9f4", "#00bcd4", "#009688", "#259b24", "#8bc34a", "#afb42b", "#ff9800", "#ff5722", "#795548", "#607d8b"]

var hash = 0;
if (this.length === 0) return hash;
for (var i = 0; i < this.length; i++) {
hash = this.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}
hash = ((hash % colors.length) + colors.length) % colors.length;
return colors[hash];
}

"string".toColor() // #e91e63```

This method is better if we want to be very particular over what colors are allowed, but selecting a large number colors can get tedious.

### HSL

How about we use the hash to pick a hue, then hardcode the intensity/lightness. (fiddle)

```String.prototype.toHue = function() {
var hash = 0;
if (this.length === 0) return hash;
for (var i = 0; i < this.length; i++) {
hash = this.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}
return hash % 360;
}

"string".toHue() // -223```

Note: This can result in a negative value. CSS's `hsl()` handles values outside of `0..360` perfectly, but not everything does.

For the sake of engineering, lets expand this out a bit more to include range values. (fiddle)

```String.prototype.toHSL = function(opts) {
var h, s, l;
opts = opts || {};
opts.hue = opts.hue || [0, 360];
opts.sat = opts.sat || [75, 100];
opts.lit = opts.lit || [40, 60];

var range = function(hash, min, max) {
var diff = max - min;
var x = ((hash % diff) + diff) % diff;
return x + min;
}

var hash = 0;
if (this.length === 0) return hash;
for (var i = 0; i < this.length; i++) {
hash = this.charCodeAt(i) + ((hash << 5) - hash);
hash = hash & hash;
}

h = range(hash, opts.hue[0], opts.hue[1]);
s = range(hash, opts.sat[0], opts.sat[1]);
l = range(hash, opts.lit[0], opts.lit[1]);

return `hsl(\${h}, \${s}%, \${l}%)`;
}

"string".toHSL() // hsl(137, 97%, 57%)

"string".toHSL({
hue: [-45, 45],
sat: [75, 95],
lit: [45, 55]
}) // hsl(2, 92%, 52%)```