Skip to content

Instantly share code, notes, and snippets.

@nandi95
Last active May 4, 2023 20:04
Show Gist options
  • Save nandi95/e7acf38a2aad12eeb725bcef72c3067d to your computer and use it in GitHub Desktop.
Save nandi95/e7acf38a2aad12eeb725bcef72c3067d to your computer and use it in GitHub Desktop.
Generate and validate colors
/**
* Class Color
*/
export default class Color {
constructor(color = null) {
if (color) {
this.setColour(color)
} else {
this.colour = this.generateRandomColor();
}
this.setThresh();
}
static isValidColorName(color) {
const style = new Option().style;
style.color = color;
return style.color === color;
}
static isValidHexCode(color) {
return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(color);
}
setColour(color) {
const colorStr = this.getHexCodeFromName(color);
if (this.constructor.isValidHexCode(color)) {
this.colour = color;
} else if (this.constructor.isValidColorName(color) && colorStr) {
this.colour = colorStr;
} else {
this.colour = this.generateSeededColor(color)
}
}
setThresh() {
const luminance = {r: 0.2126, g: 0.7152, b: 0.0722};
const color = this.colour;
const r = parseInt(color.substring(1, 3), 16);
const g = parseInt(color.substring(3, 5), 16);
const b = parseInt(color.substring(5), 16);
const rgb = [r / 255, g / 255, b / 255];
for (let i = rgb.length; i--;)
rgb[i] =
rgb[i] <= 0.03928
? rgb[i] / 12.92
: Math.pow((rgb[i] + 0.055) / 1.055, 2.4);
this.thresh =
luminance.r * rgb[0] + luminance.g * rgb[1] + luminance.b * rgb[2];
}
getHexCodeFromName(color) {
const div = document.createElement('div');
div.style.display = 'hidden';
div.style.color = color;
const colors = window.getComputedStyle(document.body.appendChild(div))
.color
.match(/\d+/g)
.map(div => parseInt(div,10));
document.body.removeChild(div);
return colors.length >= 3
? '#' + ((1 << 24) + (colors[0] << 16) + (colors[1] << 8) + colors[2])
.toString(16)
.slice(1)
: false;
}
generateRandomColor() {
return this.generateSeededColor(Math.random())
}
generateSeededColor(seed) {
let seederNum = 0;
for (const char of seed) {
seederNum += char.charCodeAt(0)
}
let color = Math.floor((Math.abs(Math.sin(seederNum) * 16777215)) % 16777215);
color = color.toString(16);
// pad any colors shorter than 6 characters with leading 0s
while (color.length < 6) {
color = '0' + color;
}
return '#' + color;
}
/**
* Get the accent
* @return {string}
*/
get hoverColor() {
// strip the leading # if it's there
let hex = this.colour.replace(/^\s*#|\s*$/g, "");
// convert 3 char codes --> 6, e.g. `E0F` --> `EE00FF`
if (hex.length === 3) {
hex = hex.replace(/(.)/g, "$1$1");
}
const r = parseInt(hex.slice(0, 2), 16),
g = parseInt(hex.slice(2, 4), 16),
b = parseInt(hex.slice(4, 6), 16);
const percent = this.thresh < 0.39 ? 25 : -25;
return (
"#" +
(0 | ((1 << 8) + r + ((256 - r) * percent) / 100)).toString(16).slice(1) +
(0 | ((1 << 8) + g + ((256 - g) * percent) / 100)).toString(16).slice(1) +
(0 | ((1 << 8) + b + ((256 - b) * percent) / 100)).toString(16).slice(1)
);
}
get foregroundColor() {
return this.thresh > 0.39 ? "#222" : "#ffffff";
}
get color() {
return this.colour;
}
set color(color) {
this.setColour(color);
this.setThresh();
return this;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment