From 1c78ab3522bfa8edf94c2959617dde8652bf444c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=BCdiger=20Diedrich?= Date: Fri, 10 Sep 2021 11:44:50 +0200 Subject: [PATCH] hsl rgb color conversion --- src/assets/favicon.ico | Bin 0 -> 15086 bytes src/components/color-input.tsx | 17 +++++++-- src/components/colorer.tsx | 67 ++++++++++++++++++++++++++++++++- tsconfig.json | 1 + 4 files changed, 79 insertions(+), 6 deletions(-) create mode 100644 src/assets/favicon.ico diff --git a/src/assets/favicon.ico b/src/assets/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..b836b2bccac650e0e7d90514083add91d2c027ff GIT binary patch literal 15086 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 void; + step?: number +} + +function ColorInput(props: ColorInputProps) { const options = mergeProps({ step: 1 }, props); - const setValue = (e) => { - let value = parseFloat(e.currentTarget.value); - options.onInput(value); + const setValue = (e: InputEvent) => { + let eventTarget = e.currentTarget as HTMLInputElement; + options.onInput(parseFloat(eventTarget.value)); } return ( diff --git a/src/components/colorer.tsx b/src/components/colorer.tsx index bfa7b37..a143268 100644 --- a/src/components/colorer.tsx +++ b/src/components/colorer.tsx @@ -1,11 +1,74 @@ import { useHslaContext } from "/@/hsla-context"; import ColorInput from "/@lib/color-input"; -function Colorer(props) { +function Colorer() { const [hsla, { setH, setS, setL, setA }] = useHslaContext(); const hslColor = () => `hsla(${hsla().h}, ${hsla().s}%, ${hsla().l}%, ${hsla().a})`; + const rgbColor = () => { + const [r, g, b] = hsl2rgb(hsla().h, hsla().s / 100, hsla().l / 100) + return `rbga(${r}, ${g}, ${b}, ${hsla().a})` + } + + const hsl2rgb = (h: number, s: number, l: number) => { + const defrange = { + h: (h: number) => 0 <= h && h < 360, + s: (s: number) => 0 <= s && s <= 1, + l: (l: number) => 0 <= l && l <= 1 + } + if (!defrange.h(h)) throw "h out of range" + if (!defrange.s(s)) throw "s out of range" + if (!defrange.l(l)) throw "l out of range" + + let c = (1 - Math.abs(2 * l - 1)) * s + let x = c * (1 - Math.abs((h / 60) % 2 - 1)) + let m = l - (c / 2) + + const rgb = (rd: number, gd: number, bd: number) => [ + Math.ceil((rd + m) * 255), + Math.ceil((gd + m) * 255), + Math.ceil((bd + m) * 255) + ] + + if (h < 60) return rgb(c, x, 0) + else if (h < 120) return rgb(x, c, 0) + else if (h < 180) return rgb(0, c, x) + else if (h < 240) return rgb(0, x, c) + else if (h < 300) return rgb(x, 0, c) + else return rgb(c, 0, x) + } + + const rgb2hsl = (r: number, g: number, b: number) => { + const + rd = r / 255, + gd = g / 255, + bd = b / 255, + cmax = Math.max(rd, gd, bd), + cmin = Math.min(rd, gd, bd), + delta = (cmax - cmin), + l = (cmax + cmin) / 2 + + let + h: number = 0, + s: number = 0 + // for this case h and s == 0 + if (delta === 0) + return [h, s, l] + + if (cmax == rd) + h = ((gd - bd) / delta) + (gd < bd ? 6 : 0) + else if (cmax == gd) + h = ((bd - rd) / delta) + 2 + else if (cmax == bd) + h = ((rd - gd) / delta) + 4 + h = 60 * h + + s = delta / (1 - Math.abs(2 * l - 1)) + + return [h, s, l] + } + return (
@@ -17,7 +80,7 @@ function Colorer(props) {
-
{hslColor()}
+
{rgbColor()} {hslColor()}
); } diff --git a/tsconfig.json b/tsconfig.json index b75c63e..fde71f9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "allowSyntheticDefaultImports": true, "resolveJsonModule": true, "esModuleInterop": true, + "strict": true, "jsx": "preserve", "jsxImportSource": "solid-js", "types": ["vite/client"]