|
| 1 | +/** |
| 2 | + * Given a color in RGB format, convert it to HSL format. |
| 3 | + * |
| 4 | + * For more info: https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/ |
| 5 | + * |
| 6 | + * @param {number[]} colorRgb - One dimensional array of integers (RGB color format). |
| 7 | + * @returns {number[]} - One dimensional array of integers (HSL color format). |
| 8 | + * |
| 9 | + * @example |
| 10 | + * const colorRgb = [24, 98, 118] |
| 11 | + * |
| 12 | + * const result = rgbToHsl(colorRgb) |
| 13 | + * |
| 14 | + * // The function returns the corresponding color in HSL format: |
| 15 | + * // result = [193, 66, 28] |
| 16 | + */ |
| 17 | + |
| 18 | +const checkRgbFormat = (colorRgb) => colorRgb.every((c) => c >= 0 && c <= 255) |
| 19 | + |
| 20 | +const rgbToHsl = (colorRgb) => { |
| 21 | + if (!checkRgbFormat(colorRgb)) { |
| 22 | + throw new Error('Input is not a valid RGB color.') |
| 23 | + } |
| 24 | + |
| 25 | + let colorHsl = colorRgb |
| 26 | + |
| 27 | + let red = Math.round(colorRgb[0]) |
| 28 | + let green = Math.round(colorRgb[1]) |
| 29 | + let blue = Math.round(colorRgb[2]) |
| 30 | + |
| 31 | + const limit = 255 |
| 32 | + |
| 33 | + colorHsl[0] = red / limit |
| 34 | + colorHsl[1] = green / limit |
| 35 | + colorHsl[2] = blue / limit |
| 36 | + |
| 37 | + let minValue = Math.min(...colorHsl) |
| 38 | + let maxValue = Math.max(...colorHsl) |
| 39 | + |
| 40 | + let channel = 0 |
| 41 | + |
| 42 | + if (maxValue === colorHsl[1]) { |
| 43 | + channel = 1 |
| 44 | + } else if (maxValue === colorHsl[2]) { |
| 45 | + channel = 2 |
| 46 | + } |
| 47 | + |
| 48 | + let luminance = (minValue + maxValue) / 2 |
| 49 | + |
| 50 | + let saturation = 0 |
| 51 | + |
| 52 | + if (minValue !== maxValue) { |
| 53 | + if (luminance <= 0.5) { |
| 54 | + saturation = (maxValue - minValue) / (maxValue + minValue) |
| 55 | + } else { |
| 56 | + saturation = (maxValue - minValue) / (2 - maxValue - minValue) |
| 57 | + } |
| 58 | + } |
| 59 | + |
| 60 | + let hue = 0 |
| 61 | + |
| 62 | + if (saturation !== 0) { |
| 63 | + if (channel === 0) { |
| 64 | + hue = (colorHsl[1] - colorHsl[2]) / (maxValue - minValue) |
| 65 | + } else if (channel === 1) { |
| 66 | + hue = 2 + (colorHsl[2] - colorHsl[0]) / (maxValue - minValue) |
| 67 | + } else { |
| 68 | + hue = 4 + (colorHsl[0] - colorHsl[1]) / (maxValue - minValue) |
| 69 | + } |
| 70 | + } |
| 71 | + |
| 72 | + hue *= 60 |
| 73 | + |
| 74 | + if (hue < 0) { |
| 75 | + hue += 360 |
| 76 | + } |
| 77 | + |
| 78 | + colorHsl[0] = Math.round(hue) |
| 79 | + colorHsl[1] = Math.round(saturation * 100) |
| 80 | + colorHsl[2] = Math.round(luminance * 100) |
| 81 | + |
| 82 | + return colorHsl |
| 83 | +} |
| 84 | + |
| 85 | +export { rgbToHsl } |
0 commit comments