export function normalizeColor(hex: string): string { hex = hex.toUpperCase() if (hex.length === 4) { return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}FF` } if (hex.length === 5) { return `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}${hex[4]}${hex[4]}` } if (hex.length === 7) { return `${hex}FF` } return hex } export function packHexColor(color: string): number { return parseInt(normalizeColor(color).substring(1), 16) } export function unpackHexColor(color: number): string { if (color > 2**32 || Math.floor(color) !== color) { throw Error("Packed color was too large or not an integer") } // this is 1 << 32, so it will produce a single hex digit above the others, even if the // R/G/B is 0 - which we can then trim off and replace with our # // a neat insight from https://stackoverflow.com/a/13397771 return "#" + ((color + 0x100000000).toString(16).substring(1)) }