UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

232 lines (231 loc) 6.73 kB
import { namedColorToHex } from "./color/cssColorsLevel4.js"; function clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } function round(value, precision = 0) { const mult = 10 ** precision; return Math.round(value * mult) / mult; } function parseHex(hex) { const match = /^#([0-9a-f]{3,8})$/i.exec(hex); if (!match) { return null; } const hexStr = match[1]; if (hexStr.length === 3) { return { r: parseInt(hexStr[0] + hexStr[0], 16), g: parseInt(hexStr[1] + hexStr[1], 16), b: parseInt(hexStr[2] + hexStr[2], 16), a: 1, }; } if (hexStr.length === 4) { return { r: parseInt(hexStr[0] + hexStr[0], 16), g: parseInt(hexStr[1] + hexStr[1], 16), b: parseInt(hexStr[2] + hexStr[2], 16), a: parseInt(hexStr[3] + hexStr[3], 16) / 255, }; } if (hexStr.length === 6) { return { r: parseInt(hexStr.slice(0, 2), 16), g: parseInt(hexStr.slice(2, 4), 16), b: parseInt(hexStr.slice(4, 6), 16), a: 1, }; } if (hexStr.length === 8) { return { r: parseInt(hexStr.slice(0, 2), 16), g: parseInt(hexStr.slice(2, 4), 16), b: parseInt(hexStr.slice(4, 6), 16), a: parseInt(hexStr.slice(6, 8), 16) / 255, }; } return null; } function parseRgb(str) { const match = /^rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+)\s*)?\)$/i.exec(str); if (match) { return { r: parseInt(match[1], 10), g: parseInt(match[2], 10), b: parseInt(match[3], 10), a: match[4] ? parseFloat(match[4]) : 1, }; } return null; } function parseHsl(str) { const match = /^hsla?\(\s*([\d.]+)\s*,\s*([\d.]+)%\s*,\s*([\d.]+)%\s*(?:,\s*([\d.]+)\s*)?\)$/i.exec(str); if (match) { const h = parseFloat(match[1]); const s = parseFloat(match[2]) / 100; const l = parseFloat(match[3]) / 100; const a = match[4] ? parseFloat(match[4]) : 1; return { ...hslToRgb(h, s, l), a }; } return null; } function hslToRgb(h, s, l) { h = ((h % 360) + 360) % 360; const c = (1 - Math.abs(2 * l - 1)) * s; const x = c * (1 - Math.abs(((h / 60) % 2) - 1)); const m = l - c / 2; let r = 0; let g = 0; let b = 0; if (h < 60) { r = c; g = x; } else if (h < 120) { r = x; g = c; } else if (h < 180) { g = c; b = x; } else if (h < 240) { g = x; b = c; } else if (h < 300) { r = x; b = c; } else { r = c; b = x; } return { r: Math.round((r + m) * 255), g: Math.round((g + m) * 255), b: Math.round((b + m) * 255), }; } function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b); const min = Math.min(r, g, b); const l = (max + min) / 2; if (max === min) { return { h: 0, s: 0, l }; } const d = max - min; const s = l > 0.5 ? d / (2 - max - min) : d / (max + min); let h = 0; if (max === r) { h = ((g - b) / d + (g < b ? 6 : 0)) / 6; } else if (max === g) { h = ((b - r) / d + 2) / 6; } else { h = ((r - g) / d + 4) / 6; } return { h: h * 360, s, l }; } function parseColor(input) { if (typeof input === 'object') { const { h, s, l } = input; return { ...hslToRgb(h, s / 100, l / 100), a: 1 }; } const str = input.trim().toLowerCase(); const namedHex = namedColorToHex(str); if (namedHex) { return parseHex(namedHex); } if (str === 'transparent') { return { r: 0, g: 0, b: 0, a: 0 }; } const hex = parseHex(str); if (hex) { return hex; } const rgb = parseRgb(str); if (rgb) { return rgb; } const hsl = parseHsl(str); if (hsl) { return hsl; } return { r: 0, g: 0, b: 0, a: 1 }; } function toHex2(n) { return Math.round(clamp(n, 0, 255)) .toString(16) .padStart(2, '0'); } function createColord(rgba) { const obj = { alpha(value) { if (value === undefined) { return rgba.a; } return createColord({ ...rgba, a: clamp(value, 0, 1) }); }, toHex() { const { r, g, b, a } = rgba; if (a < 1) { return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}${toHex2(a * 255)}`; } return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}`; }, toRgbString() { const { r, g, b, a } = rgba; if (a < 1) { return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${round(a, 3)})`; } return `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`; }, toHsl() { const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b); return { h: round(h, 1), s: round(s * 100, 1), l: round(l * 100, 1), a: rgba.a, }; }, toHslString() { const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b); if (rgba.a < 1) { return `hsla(${round(h, 1)}, ${round(s * 100, 1)}%, ${round(l * 100, 1)}%, ${round(rgba.a, 3)})`; } return `hsl(${round(h, 1)}, ${round(s * 100, 1)}%, ${round(l * 100, 1)}%)`; }, mix(color2, ratio = 0.5) { const c2 = typeof color2 === 'string' ? parseColor(color2) : parseColor(color2.toHex()); const r = rgba.r + (c2.r - rgba.r) * ratio; const g = rgba.g + (c2.g - rgba.g) * ratio; const b = rgba.b + (c2.b - rgba.b) * ratio; const a = rgba.a + (c2.a - rgba.a) * ratio; return createColord({ r, g, b, a }); }, darken(amount = 0.1) { const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b); const newL = clamp(l - amount, 0, 1); const rgb = hslToRgb(h, s, newL); return createColord({ ...rgb, a: rgba.a }); }, lighten(amount = 0.1) { const { h, s, l } = rgbToHsl(rgba.r, rgba.g, rgba.b); const newL = clamp(l + amount, 0, 1); const rgb = hslToRgb(h, s, newL); return createColord({ ...rgb, a: rgba.a }); }, }; return obj; } export function colord(input) { return createColord(parseColor(input)); }