diff --git a/spec/HslSpec.js b/spec/HslSpec.js index 4c7291a..519e092 100644 --- a/spec/HslSpec.js +++ b/spec/HslSpec.js @@ -2,20 +2,30 @@ import HSL from "../src/hsl" import RGB from "../src/rgb" describe("HSL", () => { - it("should match provided base RBG values", () => { - const red = HSL.fromRgb(new RGB(255, 0, 0)) - expect(red.hue).toEqual(0) - expect(red.lightness).toEqual(.5) - expect(red.saturation).toEqual(1) + const names = ["red", "green", "blue", "F0C80E", "7E7EB8"] - const green = HSL.fromRgb(new RGB(0, 255, 0)) - expect(green.hue).toEqual(120) - expect(green.lightness).toEqual(.5) - expect(green.saturation).toEqual(1) + const values = [ + new RGB(255, 0, 0), + new RGB(0, 255, 0), + new RGB(0, 0, 255), + new RGB(240, 200, 14), + new RGB(126, 126, 184) + ] - const blue = HSL.fromRgb(new RGB(0, 0, 255)) - expect(blue.hue).toEqual(240) - expect(blue.lightness).toEqual(.5) - expect(blue.saturation).toEqual(1) - }) + const expected = [ + new HSL(0, 1, .5), + new HSL(120, 1, .5), + new HSL(240, 1, .5), + new HSL(49, .89, .5), + new HSL(240, .29, .61) + ] + + for (let index = 0; index < names.length; index++) { + it(`should match provided value: ${names[index]}`, () => { + const value = HSL.fromRgb(values[index]) + expect(value.hue).toBeCloseTo(expected[index].hue, .1) + expect(value.lightness).toBeCloseTo(expected[index].lightness, .01) + expect(value.saturation).toBeCloseTo(expected[index].saturation, .01) + }) + } }) \ No newline at end of file diff --git a/spec/RgbSpec.js b/spec/RgbSpec.js new file mode 100644 index 0000000..92fd272 --- /dev/null +++ b/spec/RgbSpec.js @@ -0,0 +1,19 @@ +import RGB from "../src/rgb" + +describe("RGB", () => { + const hexes = [0xED7651, 0x1EAC41, 0xBF40BF] + const expected = [ + new RGB(237, 118, 81), + new RGB(30, 172, 65), + new RGB(191, 64, 191), + ] + + for (let index = 0; index < hexes.length; index++) { + it(`should match provided value: ${hexes[index].toString(16)}`, () => { + const value = RGB.fromHex(hexes[index]) + expect(value.red).toEqual(expected[index].red) + expect(value.blue).toEqual(expected[index].blue) + expect(value.green).toEqual(expected[index].green) + }) + } +}) \ No newline at end of file diff --git a/src/hsl.ts b/src/hsl.ts index ecb732f..5d7b67a 100644 --- a/src/hsl.ts +++ b/src/hsl.ts @@ -11,27 +11,29 @@ export default class HSL { this.lightness = lightness } - // https://en.wikipedia.org/wiki/RGB_color_model + // https://en.wikipedia.org/wiki/HSL_and_HSV public static fromRgb(rgb: RGB) { const redValue = rgb.red / 255, greenValue = rgb.green / 255, blueValue = rgb.blue / 255, - lightness = (redValue + greenValue + blueValue) / 3, + max = Math.max(redValue, greenValue, blueValue), + min = Math.min(redValue, greenValue, blueValue), + chroma = max - min, + lightness = .5 * (max + min), saturation = 1 - (3 / (redValue + greenValue + blueValue)) * Math.min(redValue, greenValue, blueValue) - const dividend = (redValue - greenValue) + (redValue - blueValue) - const divisor = 2 * Math.sqrt((redValue - greenValue) ^ 2 + (redValue - blueValue) * (greenValue - blueValue)) - let hue = (1 / Math.cos(dividend / divisor)) - if (greenValue > blueValue) hue = 360 - hue + let huePrime = 0 + if (chroma != 0) { + if (redValue == max) huePrime = ((greenValue - blueValue) / chroma) % 6 + else if (greenValue == max) huePrime = ((blueValue - redValue) / chroma) + 2 + else huePrime = ((redValue - greenValue) / chroma) + 4 + } - return new HSL(hue, saturation, lightness) + return new HSL(huePrime * 60, saturation, lightness) } public static fromHex(color: number): HSL { - const red = color >> 16 - const green = (color - (red << 16)) >> 8 - const blue = color - (red << 16) - (green << 8) - return HSL.fromRgb(new RGB(red, green, blue)) + return HSL.fromRgb(RGB.fromHex(color)) } public toHex(): number { diff --git a/src/rgb.ts b/src/rgb.ts index 5e3ae81..4a6b55b 100644 --- a/src/rgb.ts +++ b/src/rgb.ts @@ -49,4 +49,11 @@ export default class RGB { return new RGB((red + match) * 255, (green + match) * 255, (blue + match) * 255) } + + public static fromHex(color: number): RGB { + const red = color >> 16 + const green = (color - (red << 16)) >> 8 + const blue = color - (red << 16) - (green << 8) + return new RGB(red, green, blue) + } } \ No newline at end of file