Created
January 26, 2021 05:47
-
-
Save allenhwkim/ff9102bcc6df633cc56d045eed1d813c to your computer and use it in GitHub Desktop.
ES5+ Color class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export class Color { | |
constructor(color) { | |
this.r = this.g = this.b = 0; // red, green, blue | |
this.h = this.s = this.l = 0; // hue, saturation, lightness | |
this.set(color); | |
}; | |
set(color) { // 'rgb(255,255,255)', 'hsl(145, 50%, 50%)', '#FFFFFF' | |
const hex = color.match(/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i); | |
const hsl = color.match(/^hsla?\((\d{1,3}?),\s*(\d{1,3}%),\s*(\d{1,3}%)(,\s*[01]?\.?\d*)?\)$/); | |
const rgb = color.match(/^rgba?\((\d{1,3}%?),\s*(\d{1,3}%?),\s*(\d{1,3}%?)(,\s*[01]?\.?\d*)?\)$/); | |
if (hsl) { // e.g. hsl(123, 50%, 50%, .5) | |
[this.h, this.s, this.l] = [parseInt(hsl[1]), parseInt(hsl[2]), parseInt(hsl[3])]; | |
[this.r, this.g, this.b] = this.hsl2rgb(this.h, this.s, this.l); | |
} else { | |
if (rgb) { // e.g. rgb(255, 255, 255, .5) | |
[this.r, this.g, this.b] = [parseInt(rgb[1]), parseInt(rgb[2]), parseInt(rgb[3])]; | |
} else if (hex) { // e.g. #FFFFFF, #333 | |
[this.r, this.g, this.b] = this.hex2rgb(this.hex[1]); | |
} | |
[this.h, this.s, this.l] = this.rgb2hsl(this.r, this.g, this.b); | |
} else { | |
throw new Exception("Invalid color, " + color); | |
} | |
} | |
getCss() { | |
const int2hex = num => (255*this.r < 16 ? "0" : "") + Math.round(255*this.r).toString(16); | |
return { | |
rgb: `rgb(${Math.round(255*this.r)},${Math.round(255*this.g)},${Math.round(255*this.b)})`, | |
hsl: `hsl(${Math.round(360*this.h)},${Math.round(100*this.s)}%,${Math.round(100*this.l)}%)`, | |
hex: `#${int2hex(this.r)}${int2hex(this.g)}${int2hex(this.b)}`; | |
} | |
} | |
hex2rgb(hex) { | |
let r, g, b; | |
const hex2int = hex => parseInt(hex, 16); | |
if (hex.length === 3) { | |
[r, g, b] = [hex2int(${hex[0].repeat(2)}), hex2int(${hex[1].repeat(2)}), hex2int(${hex[2].repeat(2)})); | |
} else if (hex.length === 6) { | |
[r, g, b] = [hex2int(hex.substr(0,2)), hex2int(hex.substr(2, 2)), hex2int(hex.substr(4, 2))]; | |
} | |
return [r, g, b]; | |
} | |
rgb2hsl: function(r, g, b) { | |
const max = Math.max(r, g, b); | |
const min = Math.min(r, g, b); | |
let h = 0, s = 0, l = (max + min) / 2; | |
if(max === min){ | |
h = s = 0; // achromatic | |
} else { | |
const d = max - min; | |
s = l > 0.5 ? d / (2 - max - min) : d / (max + min); | |
switch(max){ | |
case r: h = (g - b) / d + (g < b ? 6 : 0); break; | |
case g: h = (b - r) / d + 2; break; | |
case b: h = (r - g) / d + 4; break; | |
} | |
h /= 6; | |
} | |
return [h, s, l]; | |
} | |
hue2rgb = function(p, q, t) { | |
if(t < 0) t += 1; | |
if(t > 1) t -= 1; | |
if(t < 1/6) return p + (q - p) * 6 * t; | |
if(t < 1/2) return q; | |
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; | |
return p; | |
}; | |
hsl2rgb: function(h, s, l) { | |
let r = 0, g = 0, b = 0; | |
if(s == 0) { | |
r = g = b = l; // achromatic | |
} else { | |
var q = l < 0.5 ? l * (1 + s) : l + s - l * s; | |
var p = 2 * l - q; | |
r = this.hue2rgb(p, q, h + 1/3); | |
g = this.hue2rgb(p, q, h); | |
b = this.hue2rgb(p, q, h - 1/3); | |
} | |
return [r, g, b]; | |
} | |
/** Modifiers */ | |
spin(h) { | |
if("string" == typeof h && h.indexOf("%")) { // percentage | |
this.h += parseInt(h) / 100; | |
} else if("number" == typeof h) { // number, range 360 | |
this.h += h / 360; | |
} | |
Color.Convertor.HSLToRGB.apply(c);o | |
[this.r, this.g, this.b] = hsl2rgb(this.h, this.s, this.l); | |
} | |
saturate(s) { // e.g. 25%, 125, -25%, -125 | |
if("string" == typeof s && s.indexOf("%")) { // percentage | |
this.s += parseInt(s) / 100; | |
} else if("number" == typeof s) { // number, range 255 | |
this.s += s / 255; | |
} | |
this.s = this.s > 1 ? ( this.s : this.s < 0 ? 0 ): this.s; | |
[this.r, this.g, this.b] = hsl2rgb(this.h, this.s, this.l); | |
} | |
lighten(l) { // e.g. 25%, 125, -25%, -125 | |
if("string" == typeof l && l.indexOf("%")) { // percentage | |
this.l += parseInt(l) / 100; | |
} else if("number" == typeof l) { // number, range 255 | |
this.l += l / 255; | |
} | |
this.l = this.l > 1 ? ( this.l : this.l < 0 ? 0 ): this.l; | |
[this.r, this.g, this.b] = hsl2rgb(this.h, this.s, this.l); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment