| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224 |
- import { round } from "./round";
- import { RgbaColor, RgbColor, HslaColor, HslColor, HsvaColor, HsvColor } from "../types";
- /**
- * Valid CSS <angle> units.
- * https://developer.mozilla.org/en-US/docs/Web/CSS/angle
- */
- const angleUnits: Record<string, number> = {
- grad: 360 / 400,
- turn: 360,
- rad: 360 / (Math.PI * 2),
- };
- export const hexToHsva = (hex: string): HsvaColor => rgbaToHsva(hexToRgba(hex));
- export const hexToRgba = (hex: string): RgbaColor => {
- if (hex[0] === "#") hex = hex.substring(1);
- const hexToPercent = (str: string)=>{
- const decimal = parseInt(str, 16);
- if (!isNaN(decimal)) {
- const percent = decimal/255;
- return percent;
- }
- return 1;
- };
- return {
- r: parseInt(hex.substring(0, 2), 16),
- g: parseInt(hex.substring(2, 4), 16),
- b: parseInt(hex.substring(4, 6), 16),
- a: hexToPercent(hex.substring(6, 8)),
- };
- };
- export const parseHue = (value: string, unit = "deg"): number => {
- return Number(value) * (angleUnits[unit] || 1);
- };
- export const hslaStringToHsva = (hslString: string): HsvaColor => {
- const matcher = /hsla?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;
- const match = matcher.exec(hslString);
- if (!match) return { h: 0, s: 0, v: 0, a: 1 };
- return hslaToHsva({
- h: parseHue(match[1], match[2]),
- s: Number(match[3]),
- l: Number(match[4]),
- a: match[5] === undefined ? 1 : Number(match[5]) / (match[6] ? 100 : 1),
- });
- };
- export const hslStringToHsva = hslaStringToHsva;
- export const hslaToHsva = ({ h, s, l, a }: HslaColor): HsvaColor => {
- s *= (l < 50 ? l : 100 - l) / 100;
- return {
- h: h,
- s: s > 0 ? ((2 * s) / (l + s)) * 100 : 0,
- v: l + s,
- a,
- };
- };
- export const hsvaToHex = (hsva: HsvaColor): string => rgbaToHex(hsvaToRgba(hsva));
- export const hsvaToHsla = ({ h, s, v, a }: HsvaColor): HslaColor => {
- const hh = ((200 - s) * v) / 100;
- return {
- h: round(h),
- s: round(hh > 0 && hh < 200 ? ((s * v) / 100 / (hh <= 100 ? hh : 200 - hh)) * 100 : 0),
- l: round(hh / 2),
- a: round(a, 2),
- };
- };
- export const hsvaToHslString = (hsva: HsvaColor): string => {
- const { h, s, l } = hsvaToHsla(hsva);
- return `hsl(${h}, ${s}%, ${l}%)`;
- };
- export const hsvaToHsvString = (hsva: HsvaColor): string => {
- const { h, s, v } = roundHsva(hsva);
- return `hsv(${h}, ${s}%, ${v}%)`;
- };
- export const hsvaToHsvaString = (hsva: HsvaColor): string => {
- const { h, s, v, a } = roundHsva(hsva);
- return `hsva(${h}, ${s}%, ${v}%, ${a})`;
- };
- export const hsvaToHslaString = (hsva: HsvaColor): string => {
- const { h, s, l, a } = hsvaToHsla(hsva);
- return `hsla(${h}, ${s}%, ${l}%, ${a})`;
- };
- export const hsvaToRgba = ({ h, s, v, a }: HsvaColor): RgbaColor => {
- h = (h / 360) * 6;
- s = s / 100;
- v = v / 100;
- const hh = Math.floor(h),
- b = v * (1 - s),
- c = v * (1 - (h - hh) * s),
- d = v * (1 - (1 - h + hh) * s),
- module = hh % 6;
- return {
- r: round([v, c, b, b, d, v][module] * 255),
- g: round([d, v, v, c, b, b][module] * 255),
- b: round([b, b, d, v, v, c][module] * 255),
- a: round(a, 2),
- };
- };
- export const hsvaToRgbString = (hsva: HsvaColor): string => {
- const { r, g, b } = hsvaToRgba(hsva);
- return `rgb(${r}, ${g}, ${b})`;
- };
- export const hsvaToRgbaString = (hsva: HsvaColor): string => {
- const { r, g, b, a } = hsvaToRgba(hsva);
- return `rgba(${r}, ${g}, ${b}, ${a})`;
- };
- export const hsvaStringToHsva = (hsvString: string): HsvaColor => {
- const matcher = /hsva?\(?\s*(-?\d*\.?\d+)(deg|rad|grad|turn)?[,\s]+(-?\d*\.?\d+)%?[,\s]+(-?\d*\.?\d+)%?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;
- const match = matcher.exec(hsvString);
- if (!match) return { h: 0, s: 0, v: 0, a: 1 };
- return roundHsva({
- h: parseHue(match[1], match[2]),
- s: Number(match[3]),
- v: Number(match[4]),
- a: match[5] === undefined ? 1 : Number(match[5]) / (match[6] ? 100 : 1),
- });
- };
- export const hsvStringToHsva = hsvaStringToHsva;
- export const rgbaStringToHsva = (rgbaString: string): HsvaColor => {
- return rgbaToHsva(rgbaStringToRgba(rgbaString));
- };
- export const rgbaStringToRgba = (rgbaString: string): RgbaColor=>{
- const matcher = /rgba?\(?\s*(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?[,\s]+(-?\d*\.?\d+)(%)?,?\s*[/\s]*(-?\d*\.?\d+)?(%)?\s*\)?/i;
- const match = matcher.exec(rgbaString);
- if (!match) return { r: 0, g: 0, b: 0, a: 1 };
- return {
- r: Number(match[1]) / (match[2] ? 100 / 255 : 1),
- g: Number(match[3]) / (match[4] ? 100 / 255 : 1),
- b: Number(match[5]) / (match[6] ? 100 / 255 : 1),
- a: match[7] === undefined ? 1 : Number(match[7]) / (match[8] ? 100 : 1),
- };
- };
- export const rgbStringToHsva = rgbaStringToHsva;
- const format = (number: number) => {
- const hex = number.toString(16);
- return hex.length < 2 ? "0" + hex : hex;
- };
- export const rgbaToHex = ({ r, g, b, a }: RgbaColor): string => {
- const percentToHex = (p) => {
- //const percent = Math.max(0, Math.min(100, p)); // bound percent from 0 to 100
- const intValue = Math.round(p / 100 * 255); // map percent to nearest integer (0 - 255)
- const hexValue = intValue.toString(16); // get hexadecimal representation
- return hexValue.padStart(2, '0').toLowerCase(); // format with leading 0 and upper case characters
- };
- if (a===undefined || a===1) {
- return "#" + format(r) + format(g) + format(b);
- } else {
- return "#" + format(r) + format(g) + format(b) + percentToHex(a*100);
- }
- };
- export const rgbaToHsva = ({ r, g, b, a }: RgbaColor): HsvaColor => {
- const max = Math.max(r, g, b);
- const delta = max - Math.min(r, g, b);
- // prettier-ignore
- const hh = delta
- ? max === r
- ? (g - b) / delta
- : max === g
- ? 2 + (b - r) / delta
- : 4 + (r - g) / delta
- : 0;
- return {
- h: round(60 * (hh < 0 ? hh + 6 : hh)),
- s: round(max ? (delta / max) * 100 : 0),
- v: round((max / 255) * 100),
- a,
- };
- };
- export const roundHsva = (hsva: HsvaColor): HsvaColor => ({
- h: round(hsva.h),
- s: round(hsva.s),
- v: round(hsva.v),
- a: round(hsva.a, 2),
- });
- export const rgbaToRgb = ({ r, g, b }: RgbaColor): RgbColor => ({ r, g, b });
- export const hslaToHsl = ({ h, s, l }: HslaColor): HslColor => ({ h, s, l });
- export const hsvaToHsv = (hsva: HsvaColor): HsvColor => {
- const { h, s, v } = roundHsva(hsva);
- return { h, s, v };
- };
|