0

I'm calculating a hex color value from a set of HSL sliders.

When I change the sliders (which are bound to the HSL inputs via x-model), the hex input changes accordingly.

I am completely stuck when trying to get it to work backwards.

How can I change the HSL values when I type in a hex value in the bottom input?

https://codesandbox.io/s/agitated-williams-p54t1?file=/index.html

  <body x-data="{h1: h1, s1: s1, l1: l1 }">
    <input type="range" min="0" max="360" step="1" x-model="h1" />
    <input type="number"  min="0" max="360" x-model="h1"/>
    <br>
    <input type="range" min="0" max="100" step="1" x-model="s1" />
    <input type="number"  min="0" max="100" x-model="s1"/>
    <br>
    <input type="range" min="0" max="100" step="1" x-model="l1" />
    <input type="number" min="0" max="100"  x-model="l1"/>
    <br>
    <input type="text" id="hex1" x-bind:value="hslToHex(h1, s1, l1)" />
    <input type="color" id="hex1" x-bind:value="hslToHex(h1, s1, l1)" />
  </body>

  <script>
    var h1 = 50;
    var s1 = 50;
    var l1 = 50;

    function hslToHex(h, s, l) {
        l /= 100;
        const a = s * Math.min(l, 1 - l) / 100;
        const f = n => {
          const k = (n + h / 30) % 12;
          const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
          return Math.round(255 * color).toString(16).padStart(2, '0');   // convert to Hex and prefix "0" if needed
        };
        return myHex = `#${f(0)}${f(8)}${f(4)}`;
    };
  </script>

1 Answers1

0

To get the reverse scenario working, you first need a hexToHsl function since the input is going to be a hex color code (string).

I have made use of the question to get the function that does the conversion from hex string to the HSL values.

Moreover, I have extracted the alphine.js component logic according to the documentaion to a function since it has more complex functions (it is optional, but a best practice to follow) with the relevant data and functions in it.

I have used the input event handler to the text input so that, it will trigger on any input given to it. (@input="setHSL")

So finally, your component will be as follows,


<body x-data="app()">
    <input type="range" min="0" max="360" step="1" x-model="h1" />
    <input type="number" min="0" max="360" x-model="h1" />
    <br />
    <input type="range" min="0" max="100" step="1" x-model="s1" />
    <input type="number" min="0" max="100" x-model="s1" />
    <br />
    <input type="range" min="0" max="100" step="1" x-model="l1" />
    <input type="number" min="0" max="100" x-model="l1" />
    <br />
    <input type="text" id="hex-text" @input="setHSL" :value="hslToHex(h1, s1, l1)" />
    <input type="color" id="hex-color" :value="hslToHex(h1, s1, l1)" />
</body>

<script>
    function app() {
        return {
            h1: 50,
            s1: 50,
            l1: 50,
            setHSL(event) {
                let hex = event.target.value;
                // do this only if its a valid hex string
                if(/^(#)((?:[A-Fa-f0-9]{3}){1,2})$/.exec(hex)){
                    let hsl = this.hexToHsl(hex);
                    this.h1 = hsl.h;
                    this.l1 = hsl.l;
                    this.s1 = hsl.s;
                }
            },
            hslToHex(h, s, l) {
                l /= 100;
                const a = (s * Math.min(l, 1 - l)) / 100;
                const f = (n) => {
                    const k = (n + h / 30) % 12;
                    const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
                    return Math.round(255 * color)
                        .toString(16)
                        .padStart(2, "0"); // convert to Hex and prefix "0" if needed
                };
                return (myHex = `#${f(0)}${f(8)}${f(4)}`);
            },
            hexToHsl(hex) {
                var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);

                var r = parseInt(result[1], 16);
                var g = parseInt(result[2], 16);
                var b = parseInt(result[3], 16);

                r /= 255, g /= 255, b /= 255;
                var max = Math.max(r, g, b),
                    min = Math.min(r, g, b);
                var h, s, l = (max + min) / 2;

                if (max == min) {
                    h = s = 0; // achromatic
                } else {
                    var d = max - min;
                    s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
                    switch (max) {
                        case r:
                            h = (g - b) / d + (g < b ? 6 : 0);
                            break;
                        case g:
                            h = (b - r) / d + 2;
                            break;
                        case b:
                            h = (r - g) / d + 4;
                            break;
                    }
                    h /= 6;
                }
                s = s * 100;
                s = Math.round(s);
                l = l * 100;
                l = Math.round(l);
                h = Math.round(360*h);
                return {h : h, s: s, l:l};
            }
        };
    }
</script>



I also have done an additional check before converting the string to HSL, since there can be invalid inputs for the functions. So the regular expression used here to filter out the hex color codes only. So the conversion will take place only for valid inputs.

Irfan
  • 922
  • 1
  • 7
  • 14