From 0a01974b917e74c80dc919f86f6ed8b9ffb8a285 Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Wed, 29 Nov 2023 20:58:28 -0500 Subject: [PATCH 1/2] fix(color-generator): contrast color calculation --- src/components/page/theming/_utils/color.ts | 31 +++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/components/page/theming/_utils/color.ts b/src/components/page/theming/_utils/color.ts index c825c8e8604..886f09398a4 100755 --- a/src/components/page/theming/_utils/color.ts +++ b/src/components/page/theming/_utils/color.ts @@ -133,6 +133,30 @@ const rgbToYIQ = ({ r, g, b }: RGB): number => { return (r * 299 + g * 587 + b * 114) / 1000; }; +const RED = 0.2126; +const GREEN = 0.7152; +const BLUE = 0.0722; +const GAMMA = 2.4; + +const luminance = (r, g, b) => { + var a = [r, g, b].map((v) => { + v /= 255; + return v <= 0.03928 + ? v / 12.92 + : Math.pow((v + 0.055) / 1.055, GAMMA); + }); + return a[0] * RED + a[1] * GREEN + a[2] * BLUE; +} + +// Source: https://stackoverflow.com/a/9733420 +const contrast = (rgb1, rgb2) => { + var lum1 = luminance(...rgb1); + var lum2 = luminance(...rgb2); + var brightest = Math.max(lum1, lum2); + var darkest = Math.min(lum1, lum2); + return (brightest + 0.05) / (darkest + 0.05); +} + export class Color { readonly hex: string; readonly hsl: HSL; @@ -176,8 +200,11 @@ export class Color { return /(^#[0-9a-fA-F]+)/.test(value.trim()); } - contrast(threshold = 128): Color { - return new Color(this.yiq >= threshold ? '#000' : '#fff'); + contrast(): Color { + const blackContrastRatio = contrast([this.rgb.r, this.rgb.g, this.rgb.b], [0, 0, 0]); + const whiteContrastRatio = contrast([this.rgb.r, this.rgb.g, this.rgb.b], [255, 255, 255]); + + return new Color(blackContrastRatio >= whiteContrastRatio ? '#000' : '#fff'); } mix(from: string | RGB | HSL | Color, amount = 0.5): Color { From b0ef2d46d8a991d984ce4f7e4dc5688f167b9966 Mon Sep 17 00:00:00 2001 From: Sean Perkins Date: Wed, 29 Nov 2023 21:08:03 -0500 Subject: [PATCH 2/2] refactor: apply types and code style --- src/components/page/theming/_utils/color.ts | 28 ++++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/components/page/theming/_utils/color.ts b/src/components/page/theming/_utils/color.ts index 886f09398a4..7511fbb630a 100755 --- a/src/components/page/theming/_utils/color.ts +++ b/src/components/page/theming/_utils/color.ts @@ -138,24 +138,22 @@ const GREEN = 0.7152; const BLUE = 0.0722; const GAMMA = 2.4; -const luminance = (r, g, b) => { - var a = [r, g, b].map((v) => { +const luminance = ({ r, g, b }: RGB) => { + const a = [r, g, b].map((v) => { v /= 255; - return v <= 0.03928 - ? v / 12.92 - : Math.pow((v + 0.055) / 1.055, GAMMA); + return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, GAMMA); }); return a[0] * RED + a[1] * GREEN + a[2] * BLUE; -} +}; -// Source: https://stackoverflow.com/a/9733420 -const contrast = (rgb1, rgb2) => { - var lum1 = luminance(...rgb1); - var lum2 = luminance(...rgb2); - var brightest = Math.max(lum1, lum2); - var darkest = Math.min(lum1, lum2); +// Original source: https://stackoverflow.com/a/9733420 +const contrast = (rgb1: RGB, rgb2: RGB) => { + const lum1 = luminance(rgb1); + const lum2 = luminance(rgb2); + const brightest = Math.max(lum1, lum2); + const darkest = Math.min(lum1, lum2); return (brightest + 0.05) / (darkest + 0.05); -} +}; export class Color { readonly hex: string; @@ -201,8 +199,8 @@ export class Color { } contrast(): Color { - const blackContrastRatio = contrast([this.rgb.r, this.rgb.g, this.rgb.b], [0, 0, 0]); - const whiteContrastRatio = contrast([this.rgb.r, this.rgb.g, this.rgb.b], [255, 255, 255]); + const blackContrastRatio = contrast(this.rgb, { r: 0, g: 0, b: 0 }); + const whiteContrastRatio = contrast(this.rgb, { r: 255, g: 255, b: 255 }); return new Color(blackContrastRatio >= whiteContrastRatio ? '#000' : '#fff'); }