Skip to content

Instantly share code, notes, and snippets.

@trezy
Last active October 13, 2021 21:10
Show Gist options
  • Save trezy/be8058b6a9c3e21c71d57a0b7c83e877 to your computer and use it in GitHub Desktop.
Save trezy/be8058b6a9c3e21c71d57a0b7c83e877 to your computer and use it in GitHub Desktop.
Uses the first character of a string to choose a color within a range. Can take a color pair, otherwise defaults to to full color spectrum.
const strings = [
'Fruit', // #0002ee
'Blorp', // #0000a2
'Fig', // #0002ee
'Bridge', // #0000a2
'Macintosh', // #0006f3
'Apple', // #00000f
'Speakers', // #000a65
'Stream', // #000a65
]
const colorRange = [
'#f00', // red
'#00f', // blue
]
strings.forEach(string => {
// Generates a color for {string} within {colorRange}
getColorForString(string, colorRange)
})
// Constants
const POSSIBLE_HEX_LENGTHS = [3, 6]
/**
* Uses the first character of a string to choose a color within a range. Can
* take a color pair, otherwise defaults to to full color spectrum.
*
* @param {string} string The input string
* @param {[string, string]} [colorRange=[0x000000, 0xffffff]] The range within which colors should be generated. This will be broken into 26 steps (one for each letter of the alphabet)
*
* @returns {string} A hex color string within the specified range
*/
export function getColorForString (string, colorRange = [0x000000, 0xffffff]) {
if (!Array.isArray(colorRange)) {
throw new TypeError(`colorRange must be an array with at least 2 items; received ${typeof colorRange}`)
}
if (colorRange.length !== 2) {
throw new RangeError(`colorRange must be a pair; received an array with ${colorRange.length} items`)
}
// Lowercase the string (upper vs lowercase letters have different char
// codes), then get the charcode of the first character
const charCode = string.toLowerCase().charCodeAt(0)
// Offset the index by 97 (which is the char code for lowercase a)
const index = charCode - 97
// Ensure the color range is a hex literal
const colorValues = colorRange.map(value => {
let parsedValue = value
if (typeof parsedValue === 'string') {
const hexValue = parsedValue.trim().replace(/^#/, '')
if (!POSSIBLE_HEX_LENGTHS.includes(hexValue.length)) {
throw new TypeError(`${value} is not a valid color code`)
}
parsedValue = parseInt(hexValue, 16)
}
if (typeof parsedValue === 'number') {
if ((parsedValue <= 0x000000) && (parsedValue >= 0xffffff)) {
throw new RangeError(`${value} is not within range; must be between 0x000000 and 0xffffff`)
}
return parsedValue
}
throw new TypeError(`Can't parse ${value} into a color code`)
})
// Convert the color range to a mathematical upper limit
const highValue = Math.max(colorValues[0])
const lowValue = Math.min(colorValues[1])
const range = highValue - lowValue
// Determine the increment between color values
const increment = Math.round(range / 26)
// Calculate where the string sits within the specified range
const rangeValue = index * increment
const resultValue = lowValue + rangeValue
// Convert the resulting integer to a hex string, then pad with 0 in case
// it's not a full 6 digits
const resultHexValue = resultValue.toString(16).padStart(6, '0')
// Add an octothorpe to the front of the string for use in CSS
return `#${resultHexValue}`
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment