UNPKG

@leafer-in/color

Version:
169 lines (133 loc) 4.79 kB
import { IColor, IObject, IRGBA } from '@leafer-ui/interface' import { colorNames } from './colors' const rgbMatch = /^rgb\((\d+),\s*(\d+),\s*(\d+)/i const rgbaMatch = /^rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d*\.?\d+)/i const hslMatch = /^hsl\((\d+),\s*(\d+)%\s*,\s*(\d+)%/i const hslaMatch = /^hsla\((\d+),\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d*\.?\d+)/i const int = parseInt, float = parseFloat, { round } = Math let cache: IObject = {}, totalCache = 0 export function colorToRGBA(color: IColor, opacity?: number): IRGBA { let RGBA: IRGBA let useOpacity = opacity !== undefined && opacity !== 1 if (typeof color === 'string') { const cacheColor = cache[color] if (cacheColor) { RGBA = { ...cacheColor } } else { switch (color[0]) { case '#': RGBA = hexToRGBA(color) break case 'R': case 'r': if (color[4] === '(' && rgbaMatch.test(color)) RGBA = rgbaToRGBA(color) else if (color[3] === '(' && rgbMatch.test(color)) RGBA = rgbToRGBA(color) break case 'H': case 'h': if (color[4] === '(' && hslaMatch.test(color)) RGBA = hslaToRGBA(color) else if (color[3] === '(' && hslMatch.test(color)) RGBA = hslToRGBA(color) break } if (!RGBA) { const value = colorNames[color.toLowerCase()] if (value) RGBA = hexToRGBA('#' + value) } if (RGBA) { totalCache++ if (totalCache > 10000) cache = {}, totalCache = 0 cache[color] = { ...RGBA } } } } else if (typeof color === 'object') { if (color.a === undefined) color.a = 1 if (useOpacity) color = { ...color } RGBA = color as IRGBA } if (!RGBA) RGBA = { r: 255, g: 255, b: 255, a: 1 } if (useOpacity) RGBA.a *= opacity return RGBA } function hexToRGBA(color: string): IRGBA { let r, g, b, a = 1 switch (color.length) { case 9: // #FF0000FF r = int(color.slice(1, 3), 16) g = int(color.slice(3, 5), 16) b = int(color.slice(5, 7), 16) a = int(color.slice(7, 9), 16) / 255 break case 7: // #FF0000 r = int(color.slice(1, 3), 16) g = int(color.slice(3, 5), 16) b = int(color.slice(5, 7), 16) break case 5: // #F00F => #FF0000FF r = int(color[1] + color[1], 16) g = int(color[2] + color[2], 16) b = int(color[3] + color[3], 16) a = int(color[4] + color[4], 16) / 255 break case 4: // #F00 => #FF0000 r = int(color[1] + color[1], 16) g = int(color[2] + color[2], 16) b = int(color[3] + color[3], 16) break case 3: // #F0 => #F0F0F0 非标准 r = g = b = int(color[1] + color[2], 16) break case 2: // #F => #FFFFFF 非标准 r = g = b = int(color[1] + color[1], 16) break } return { r, g, b, a } } function rgbToRGBA(color: string): IRGBA { const match = rgbMatch.exec(color) // rgb(255, 255, 255) return { r: int(match[1]), g: int(match[2]), b: int(match[3]), a: 1 } } function rgbaToRGBA(color: string): IRGBA { const match = rgbaMatch.exec(color) // rgba(255, 255, 255, 1) return { r: int(match[1]), g: int(match[2]), b: int(match[3]), a: float(match[4]) } } function hslToRGBA(color: string): IRGBA { const match = hslMatch.exec(color) // hsl(360,100%, 100%) return hsla(float(match[1]), float(match[2]), float(match[3]), 1) } function hslaToRGBA(color: string): IRGBA { const match = hslaMatch.exec(color) // hsl(360,100%, 100%, 1) return hsla(float(match[1]), float(match[2]), float(match[3]), float(match[4])) } const n1 = 1 / 6, n2 = 0.5, n3 = 2 / 3, n4 = 1 / 3 function hue(p: number, q: number, t: number) { if (t < 0) t++ else if (t > 1) t-- if (t < n1) return p + (q - p) * 6 * t if (t < n2) return q if (t < n3) return p + (q - p) * (n3 - t) * 6 return p } function hsla(h: number, s: number, l: number, a = 1): IRGBA { let r, g, b h /= 360, s /= 100, l /= 100 if (s === 0) { r = g = b = l } else { let q = l < 0.5 ? l * (1 + s) : l + s - l * s let p = 2 * l - q r = hue(p, q, h + n4) g = hue(p, q, h) b = hue(p, q, h - n4) } return { r: round(r * 255), g: round(g * 255), b: round(b * 255), a } }