simple-color-picker
Version:
Simple Color picker for the web
185 lines (149 loc) • 3.84 kB
text/typescript
import { isNumber } from './types'
import { pad2 } from './utils'
// Each member has a range of 0-1\
export type RGBAColor = {
r: number
g: number
b: number
a?: number
}
// Each member has a range of 0-1
export type HSVAColor = {
h: number
s: number
v: number
a?: number
}
export class Color {
private _rgba: RGBAColor = { r: 0, g: 0, b: 0, a: 1 }
private _hsva: HSVAColor = { h: 0, s: 0, v: 0, a: 1 }
private _hexNumber: number
private _brightness: number
private _hexString: string
private _isDark: boolean
private _isLight: boolean
constructor(color: number | string) {
this.fromHex(color)
}
public fromHex(color: number | string): void {
if (!color) color = 0
if (isNumber(color)) {
this._hexNumber = color as number
this._hexString = numberToHexString(this._hexNumber)
} else {
this._hexString = (color as string).toUpperCase()
this._hexNumber = hexStringToNumber(this._hexString)
}
const { r, g, b } = hexNumberToRgb(this._hexNumber)
this._rgba.r = r
this._rgba.g = g
this._rgba.b = b
const { h, s, v } = rgbToHsv(this._rgba)
this._hsva.h = h
this._hsva.s = s
this._hsva.v = v
this._updateBrightness()
}
public fromHsv(color: HSVAColor): void {
const { h, s, v } = color
this._hsva.h = h
this._hsva.s = s
this._hsva.v = v
const { r, g, b } = hsvToRgb(this._hsva)
this._rgba.r = r
this._rgba.g = g
this._rgba.b = b
this._hexString = rgbToHex(this._rgba)
this._hexNumber = hexStringToNumber(this._hexString)
this._updateBrightness()
}
private _updateBrightness(): void {
const { r, g, b } = this._rgba
this._brightness = (r * 299 + g * 587 + b * 114) / 1000
this._isDark = this._brightness < 0.5
this._isLight = !this._isDark
}
get rgb(): RGBAColor {
return this._rgba
}
get hsv(): HSVAColor {
return this._hsva
}
get hex(): number {
return this._hexNumber
}
get hexString(): string {
return this._hexString
}
get brightness(): number {
return this._brightness
}
get isDark(): boolean {
return this._isDark
}
get isLight(): boolean {
return this._isLight
}
}
export function hexNumberToRgb(color: number): RGBAColor {
const r = ((color >> 16) & 255) / 255
const g = ((color >> 8) & 255) / 255
const b = (color & 255) / 255
return { r, g, b }
}
export function rgbToHex(color: RGBAColor): string {
const { r, g, b } = color
var hex = [
'#',
pad2(Math.round(r * 255).toString(16)),
pad2(Math.round(g * 255).toString(16)),
pad2(Math.round(b * 255).toString(16))
]
return hex.join('').toUpperCase()
}
export function numberToHexString(color: number): string {
return '#' + ('00000' + (color | 0).toString(16)).substr(-6).toUpperCase()
}
export function hexStringToNumber(color: string): number {
return parseInt(color.replace('#', ''), 16)
}
export function hsvToRgb(color: HSVAColor): RGBAColor {
let { h, s, v } = color
h *= 6
const i = Math.floor(h)
const f = h - i
const p = v * (1 - s)
const q = v * (1 - f * s)
const t = v * (1 - (1 - f) * s)
const mod = i % 6
const r = [v, q, p, p, t, v][mod]
const g = [t, v, v, q, p, p][mod]
const b = [p, p, t, v, v, q][mod]
return { r, g, b }
}
export function rgbToHsv(color: RGBAColor): HSVAColor {
const { r, g, b } = color
const max = Math.max(r, g, b)
const min = Math.min(r, g, b)
const d = max - min
const s = max === 0 ? 0 : d / max
const v = max
let h
if (max == min) {
h = 0
} else {
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, v }
}