diff --git a/packages/grafana-data/src/themes/colorManipulator.test.ts b/packages/grafana-data/src/themes/colorManipulator.test.ts index 7982fd1a701..a4df21d4c93 100644 --- a/packages/grafana-data/src/themes/colorManipulator.test.ts +++ b/packages/grafana-data/src/themes/colorManipulator.test.ts @@ -177,6 +177,10 @@ describe('utils/colorManipulator', () => { expect(getContrastRatio('#FFF', '#FFF')).toEqual(1); }); + it('Can also take into account opacity for background', () => { + expect(getContrastRatio('#FFF', 'rgba(255,255,255,0.1)', '#000')).toEqual(17.5); + }); + it('returns a ratio for dark-grey : light-grey', () => { //expect(getContrastRatio('#707070', '#E5E5E5'))to.be.approximately(3.93, 0.01); }); diff --git a/packages/grafana-data/src/themes/colorManipulator.ts b/packages/grafana-data/src/themes/colorManipulator.ts index 0b76bbc6875..6c63f57c6c0 100644 --- a/packages/grafana-data/src/themes/colorManipulator.ts +++ b/packages/grafana-data/src/themes/colorManipulator.ts @@ -175,12 +175,13 @@ export function recomposeColor(color: DecomposeColor) { * Formula: https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests * @param foreground - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla() * @param background - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla() + * @param canvas - A CSS color that alpha based backgrounds blends into * @returns A contrast ratio value in the range 0 - 21. * @beta */ -export function getContrastRatio(foreground: string, background: string) { +export function getContrastRatio(foreground: string, background: string, canvas?: string) { const lumA = getLuminance(foreground); - const lumB = getLuminance(background); + const lumB = getLuminance(background, canvas); return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05); } @@ -190,13 +191,23 @@ export function getContrastRatio(foreground: string, background: string) { * * Formula: https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests * @param color - CSS color, i.e. one of: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color() + * @param background - CSS color that needs to be take in to account to calculate luminance for colors with opacity * @returns The relative brightness of the color in the range 0 - 1 * @beta */ -export function getLuminance(color: string) { +export function getLuminance(color: string, background?: string) { const parts = decomposeColor(color); let rgb = parts.type === 'hsl' ? decomposeColor(hslToRgb(color)).values : parts.values; + + if (background && parts.type === 'rgba') { + const backgroundParts = decomposeColor(background); + const alpha = rgb[3]; + rgb[0] = rgb[0] * alpha + backgroundParts.values[0] * (1 - alpha); + rgb[1] = rgb[1] * alpha + backgroundParts.values[1] * (1 - alpha); + rgb[2] = rgb[2] * alpha + backgroundParts.values[2] * (1 - alpha); + } + const rgbNumbers = rgb.map((val: any) => { if (parts.type !== 'color') { val /= 255; // normalized diff --git a/packages/grafana-data/src/themes/createColors.ts b/packages/grafana-data/src/themes/createColors.ts index 17b1dafd403..afc23c41bdc 100644 --- a/packages/grafana-data/src/themes/createColors.ts +++ b/packages/grafana-data/src/themes/createColors.ts @@ -257,7 +257,9 @@ export function createColors(colors: ThemeColorsInput): ThemeColors { function getContrastText(background: string, threshold: number = contrastThreshold) { const contrastText = - getContrastRatio(dark.text.maxContrast, background) >= threshold ? dark.text.maxContrast : light.text.maxContrast; + getContrastRatio(dark.text.maxContrast, background, base.background.primary) >= threshold + ? dark.text.maxContrast + : light.text.maxContrast; // todo, need color framework return contrastText; }