This commit is contained in:
Lani Aung
2025-06-07 16:45:53 -07:00
parent aa58a30b6d
commit 660dd859d1
4 changed files with 63 additions and 25 deletions
+23 -13
View File
@@ -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)
})
}
})
+19
View File
@@ -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)
})
}
})
+13 -11
View File
@@ -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 {
+7
View File
@@ -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)
}
}