Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(metric): allow alpha colors and improve contrast logic #2184

Merged
merged 23 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
48f2076
fix: hsl color logic to preserve alpha channel
nickofthyme Oct 2, 2023
ca3b11d
feat: allow alpha colors and improve contrast logic
nickofthyme Oct 2, 2023
0786046
fix: api changes
nickofthyme Oct 3, 2023
d42138b
test(vrt): update screenshots [skip ci]
elastic-datavis[bot] Oct 3, 2023
29f198d
fix: pass text colors to contrast logic
nickofthyme Oct 4, 2023
a52acb3
test(vrt): update screenshots [skip ci]
elastic-datavis[bot] Oct 4, 2023
f4cea4e
fix: bad vrt case [update-vrt]
nickofthyme Oct 5, 2023
65d4449
test(vrt): update screenshots [skip ci]
elastic-datavis[bot] Oct 5, 2023
edf8e67
test: add vrt for transparent metric bg colors
nickofthyme Oct 5, 2023
50b5046
Merge branch 'main' into fix-metric-opacity
nickofthyme Oct 5, 2023
3d00b28
test(vrt): update screenshots [skip ci]
elastic-datavis[bot] Oct 5, 2023
e7c9b93
chore: remove bg color check/error
nickofthyme Oct 5, 2023
8d7c1e2
test: fix theme params in url [update-vrt]
nickofthyme Oct 5, 2023
05859c3
test(vrt): update screenshots [skip ci]
elastic-datavis[bot] Oct 5, 2023
290ab5b
Merge branch 'main' into fix-metric-opacity
nickofthyme Oct 6, 2023
6bd75a4
fix: split background and sparkline with alpha mask
nickofthyme Oct 6, 2023
ac205ac
Merge remote-tracking branch 'origin/fix-metric-opacity' into fix-met…
nickofthyme Oct 6, 2023
e254ac8
fix: add contrast check for text over sparkline
nickofthyme Oct 6, 2023
acde825
test(vrt): update screenshots [skip ci]
elastic-datavis[bot] Oct 6, 2023
c362e79
test: fix failing jest tests
nickofthyme Oct 10, 2023
e3b90fc
Merge branch 'main' into fix-metric-opacity
nickofthyme Oct 10, 2023
092a680
Merge remote-tracking branch 'origin/fix-metric-opacity' into fix-met…
nickofthyme Oct 10, 2023
9442cc7
Merge branch 'main' into fix-metric-opacity
nickofthyme Oct 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 18 additions & 3 deletions e2e/tests/metric_stories.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import { test } from '@playwright/test';

import { eachTheme, pwEach } from '../helpers';
import { common } from '../page_objects';

test.describe('Metric', () => {
Expand All @@ -21,7 +22,7 @@ test.describe('Metric', () => {
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:light&knob-use progress bar=&knob-progress bar direction=horizontal&knob-max trend data points=30&knob-layout=grid',
);
});
test('should render vertical progress bar in dark mode', async ({ page }) => {
test('should render vertical progress bar in dark mode', async ({ page }) => {
await common.expectChartAtUrlToMatchScreenshot(page)(
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:eui-dark&knob-layout=grid&knob-max trend data points=30&knob-progress bar direction=vertical&knob-use progress bar=true',
);
Expand All @@ -31,19 +32,33 @@ test.describe('Metric', () => {
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:eui-dark&knob-layout=grid&knob-max trend data points=30&knob-progress bar direction=horizontal&knob-use progress bar=true',
);
});
test('should render no progress bar in dark mode', async ({ page }) => {
test('should render no progress bar in dark mode', async ({ page }) => {
await common.expectChartAtUrlToMatchScreenshot(page)(
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:eui-dark&knob-layout=grid&knob-max trend data points=30&knob-progress bar direction=horizontal&knob-use progress bar=',
);
});
test('text value with trend', async ({ page }) => {
await common.expectChartAtUrlToMatchScreenshot(page)(
'http://localhost:9001/?path=/story/metric-alpha--basic&globals=theme:light&knob-EUI icon glyph name=warning&knob-color=rgba(166, 219, 208, 0.47)&knob-extra=1310 (-74% week before)&knob-is numeric metric=false&knob-progress bar direction=vertical&knob-progress max=100&knob-progress or trend=trend&knob-subtitle=&knob-title=Most used in&knob-trend a11y description=The trend shows a peak of CPU usage in the last 5 minutes&knob-trend a11y title=The Cluster CPU Usage trend&knob-trend data points=30&knob-trend shape=area&knob-value=United States&knob-value postfix=&knob-value prefix=&knob-show icon=',
'http://localhost:9001/?path=/story/metric-alpha--basic&globals=theme:light&knob-EUI icon glyph name=warning&knob-color=rgba(166, 219, 208, 1)&knob-extra=1310 (-74% week before)&knob-is numeric metric=false&knob-progress bar direction=vertical&knob-progress max=100&knob-progress or trend=trend&knob-subtitle=&knob-title=Most used in&knob-trend a11y description=The trend shows a peak of CPU usage in the last 5 minutes&knob-trend a11y title=The Cluster CPU Usage trend&knob-trend data points=30&knob-trend shape=area&knob-value=United States&knob-value postfix=&knob-value prefix=&knob-show icon=',
);
});
test('value icon and value color', async ({ page }) => {
await common.expectChartAtUrlToMatchScreenshot(page)(
'http://localhost:9001/?path=/story/metric-alpha--basic&globals=theme:light&knob-title=Network out&knob-subtitle=host: 1dc4e&knob-progress or trend=trend&knob-progress bar direction=vertical&knob-trend data points=30&knob-trend shape=area&knob-trend a11y title=The Cluster CPU Usage trend&knob-trend a11y description=The trend shows a peak of CPU usage in the last 5 minutes&knob-extra=last <b>5m</b>&knob-progress max=100&knob-is numeric metric=true&knob-value=55.23&knob-value prefix=&knob-value postfix=GB&knob-color=rgba(255, 255, 255, 1)&knob-use value color=true&knob-value color=rgba(189, 0, 0, 1)&knob-show icon=true&knob-EUI icon glyph name=warning&knob-show value icon=true&knob-EUI value icon glyph name=sortUp',
);
});

pwEach.describe(['trend', 'bar', 'none'])(
(v) => `Metric - ${v} type`,
(type) => {
eachTheme.test(
async ({ page, urlParam }) => {
await common.expectChartAtUrlToMatchScreenshot(page)(
`http://localhost:9001/?path=/story/metric-alpha--basic&globals=toggles.showHeader:true;toggles.showChartTitle:false;toggles.showChartDescription:false;theme:light&knob-EUI icon glyph name=warning&knob-EUI value icon glyph name=sortUp&knob-color=rgba(157, 66, 66, 0.44)&knob-extra=last <b>5m</b>&knob-is numeric metric=true&knob-progress bar direction=vertical&knob-progress max=100&knob-progress or trend=${type}&knob-subtitle=Cluster CPU usage&knob-title=21d7f8b7-92ea-41a0-8c03-0db0ec7e11b9&knob-trend a11y description=The trend shows a peak of CPU usage in the last 5 minutes&knob-trend a11y title=The Cluster CPU Usage trend&knob-trend data points=30&knob-trend shape=area&knob-value=55.23&knob-value color=#3c3c3c&knob-value prefix=&knob-value postfix= %&knob-use value color=&knob-show icon=&knob-show value icon=&${urlParam}`,
);
},
(t) => `should render metric with transparent bg color - ${t} theme`,
);
},
);
});
2 changes: 0 additions & 2 deletions packages/charts/api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1840,8 +1840,6 @@ export type MetricSpecProps = ComponentProps<typeof Metric>;

// @public (undocumented)
export interface MetricStyle {
// (undocumented)
background: Color;
// (undocumented)
barBackground: Color;
// (undocumented)
Expand Down
24 changes: 21 additions & 3 deletions packages/charts/src/chart_types/metric/renderer/dom/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Metric as MetricComponent } from './metric';
import { highContrastColor } from '../../../../common/color_calcs';
import { colorToRgba } from '../../../../common/color_library_wrappers';
import { Colors } from '../../../../common/colors';
import { getResolvedBackgroundColor } from '../../../../common/fill_text_color';
import { BasicListener, ElementClickListener, ElementOverListener, settingsBuildProps } from '../../../../specs';
import { onChartRendered } from '../../../../state/actions/chart';
import { GlobalChartState } from '../../../../state/chart_state';
Expand All @@ -29,8 +30,9 @@ import {
import { getChartThemeSelector } from '../../../../state/selectors/get_chart_theme';
import { getInternalIsInitializedSelector, InitStatus } from '../../../../state/selectors/get_internal_is_intialized';
import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_spec';
import { Logger } from '../../../../utils/logger';
import { LIGHT_THEME } from '../../../../utils/themes/light_theme';
import { MetricStyle } from '../../../../utils/themes/theme';
import { BackgroundStyle, MetricStyle } from '../../../../utils/themes/theme';
import { MetricSpec } from '../../specs';
import { chartSize } from '../../state/selectors/chart_size';
import { getMetricSpecs } from '../../state/selectors/data';
Expand All @@ -47,6 +49,7 @@ interface StateProps {
specs: MetricSpec[];
a11y: A11ySettings;
style: MetricStyle;
background: BackgroundStyle;
locale: string;
onElementClick?: ElementClickListener;
onElementOut?: BasicListener;
Expand Down Expand Up @@ -76,6 +79,7 @@ class Component extends React.Component<StateProps & DispatchProps> {
a11y,
specs: [spec], // ignoring other specs
style,
background,
onElementClick,
onElementOut,
onElementOver,
Expand All @@ -94,8 +98,18 @@ class Component extends React.Component<StateProps & DispatchProps> {

const panel = { width: width / maxColumns, height: height / totalRows };

if (colorToRgba(background.color)[3] < 1) {
// TODO: centralize this check and bg color fallback across all chart types
Logger.expected(
'Text contrast requires an opaque background color, using fallbackColor blend',
'an opaque color',
background.color,
);
}
nickofthyme marked this conversation as resolved.
Show resolved Hide resolved

const backgroundColor = getResolvedBackgroundColor(background.fallbackColor, background.color);
const emptyForegroundColor =
highContrastColor(colorToRgba(style.background)) === Colors.White.rgba
highContrastColor(colorToRgba(backgroundColor)) === Colors.White.rgba
? style.text.lightColor
: style.text.darkColor;

Expand Down Expand Up @@ -138,6 +152,7 @@ class Component extends React.Component<StateProps & DispatchProps> {
columnIndex={columnIndex}
panel={panel}
style={style}
backgroundColor={backgroundColor}
onElementClick={onElementClick}
onElementOut={onElementOut}
onElementOver={onElementOver}
Expand Down Expand Up @@ -185,6 +200,7 @@ const DEFAULT_PROPS: StateProps = {
},
a11y: DEFAULT_A11Y_SETTINGS,
style: LIGHT_THEME.metric,
background: LIGHT_THEME.background,
locale: settingsBuildProps.defaults.locale,
};

Expand All @@ -193,6 +209,7 @@ const mapStateToProps = (state: GlobalChartState): StateProps => {
return DEFAULT_PROPS;
}
const { onElementClick, onElementOut, onElementOver, locale } = getSettingsSpecSelector(state);
const { metric: style, background } = getChartThemeSelector(state);
return {
initialized: true,
chartId: state.chartId,
Expand All @@ -203,7 +220,8 @@ const mapStateToProps = (state: GlobalChartState): StateProps => {
onElementClick,
onElementOver,
onElementOut,
style: getChartThemeSelector(state).metric,
background,
style,
locale,
};
};
Expand Down
32 changes: 17 additions & 15 deletions packages/charts/src/chart_types/metric/renderer/dom/metric.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import React, { CSSProperties, useState } from 'react';
import { ProgressBar } from './progress';
import { SparkLine } from './sparkline';
import { MetricText } from './text';
import { highContrastColor } from '../../../../common/color_calcs';
import { changeColorLightness, colorToRgba } from '../../../../common/color_library_wrappers';
import { Colors } from '../../../../common/colors';
import { Color } from '../../../../common/colors';
import { DEFAULT_CSS_CURSOR } from '../../../../common/constants';
import { fillTextColor } from '../../../../common/fill_text_color';
import {
BasicListener,
ElementClickListener,
Expand All @@ -39,6 +39,7 @@ export const Metric: React.FunctionComponent<{
datum: MetricDatum;
panel: Size;
style: MetricStyle;
backgroundColor: Color;
locale: string;
onElementClick?: ElementClickListener;
onElementOver?: ElementOverListener;
Expand All @@ -53,6 +54,7 @@ export const Metric: React.FunctionComponent<{
datum,
panel,
style,
backgroundColor,
locale,
onElementClick,
onElementOver,
Expand All @@ -75,34 +77,34 @@ export const Metric: React.FunctionComponent<{

const lightnessAmount = mouseState === 'leave' ? 0 : mouseState === 'enter' ? 0.05 : 0.1;
const interactionColor = changeColorLightness(datum.color, lightnessAmount, 0.8);
const backgroundInteractionColor = changeColorLightness(style.background, lightnessAmount, 0.8);

const datumWithInteractionColor: MetricDatum = {
...datum,
color: interactionColor,
};
const updatedStyle: MetricStyle = {
...style,
background: backgroundInteractionColor,
};

const event: MetricElementEvent = { type: 'metricElementEvent', rowIndex, columnIndex };

const containerStyle: CSSProperties = {
backgroundColor:
!isMetricWTrend(datumWithInteractionColor) && !isMetricWProgress(datumWithInteractionColor)
? datumWithInteractionColor.color
: updatedStyle.background,
: undefined,
cursor: onElementClick ? 'pointer' : DEFAULT_CSS_CURSOR,
borderColor: style.border,
};

const bgColor = isMetricWTrend(datum) || !isMetricWProgress(datum) ? datum.color : style.background;

const highContrastTextColor =
highContrastColor(colorToRgba(bgColor)) === Colors.White.rgba ? style.text.lightColor : style.text.darkColor;

const highContrastTextColor = fillTextColor(
backgroundColor,
isMetricWProgress(datum) ? backgroundColor : datum.color,
undefined,
{
lightColor: colorToRgba(style.text.lightColor),
darkColor: colorToRgba(style.text.darkColor),
},
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we should improve this a bit because the text could be above the background but also above the area background that has a different luminosity and that could change the contrast.
I think we can do the following:

  • find the color contrast ratios of each text color for both background colors (metric and area)
  • pick the text color that is more close to pass the WCAG threshold in both situations

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you talking about the checking between the background and the sparkline area?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok I took a stab at this and indeed there is a small range where the text color contrast selection is opposing.

So I'm checking when there is a trend line for the contrast over the sparkline, then if different I take the color with the higher ratio. This is the part I'm not sure about, if it should be the higher one but also if we are even comaring the right ration since one is based on the light color and the other on the dark.

The main logic is here...

const highContrastTextColor = fillTextColor(
backgroundColor,
isMetricWProgress(datum) ? backgroundColor : datum.color,
undefined,
contrastOptions,
);
let finalTextColor = highContrastTextColor.color;
if (isMetricWTrend(datum)) {
const { ratio, color, shade } = fillTextColor(
backgroundColor,
getSparkLineColor(datum.color),
undefined,
contrastOptions,
);
// TODO verify this check is applied correctly
if (shade !== highContrastTextColor.shade && ratio > highContrastTextColor.ratio) {
finalTextColor = color;
}
}

const onElementClickHandler = () => onElementClick && onElementClick([event]);

return (
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions,jsx-a11y/click-events-have-key-events
<div
Expand Down Expand Up @@ -142,14 +144,14 @@ export const Metric: React.FunctionComponent<{
id={metricHTMLId}
datum={datumWithInteractionColor}
panel={panel}
style={updatedStyle}
style={style}
onElementClick={onElementClick ? onElementClickHandler : undefined}
highContrastTextColor={highContrastTextColor}
locale={locale}
/>
{isMetricWTrend(datumWithInteractionColor) && <SparkLine id={metricHTMLId} datum={datumWithInteractionColor} />}
{isMetricWProgress(datumWithInteractionColor) && (
<ProgressBar datum={datumWithInteractionColor} barBackground={updatedStyle.barBackground} />
<ProgressBar datum={datumWithInteractionColor} barBackground={style.barBackground} />
)}
<div className="echMetric--outline" style={{ color: highContrastTextColor }}></div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ export const SparkLine: FunctionComponent<{
trendShape === MetricTrendShape.Bars ? CurveType.CURVE_STEP_AFTER : CurveType.LINEAR,
);

const [h, s, l] = colorToHsl(color);
const pathColor = hslToColor(h, s, l >= 0.8 ? l - 0.1 : l + 0.1);
const [h, s, l, a] = colorToHsl(color);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you have to blend first the color with a valid opaque background before changing the lightning, preserving the alpha is not the same thing as we where looking at doing here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure what you're saying here, I need to blend the sparkline color with an opaque background?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are right here since the transparent sparkline would be rendered on top of the transparent back area. I think a good fix of this is to just mask the filled sparkline from the background. See 6bd75a4

Screen Recording 2023-10-06 at 02 14 49 PM

const pathColor = hslToColor(h, s, l >= 0.8 ? l - 0.1 : l + 0.1, a);
const titleId = `${id}-trend-title`;
const descriptionId = `${id}-trend-description`;
return (
Expand Down
40 changes: 30 additions & 10 deletions packages/charts/src/common/color_calcs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* Side Public License, v 1.
*/

import { Required } from 'utility-types';

import { APCAContrast } from './apca_color_contrast';
import { RgbaTuple, RGBATupleToString, RgbTuple } from './color_library_wrappers';
import { Colors } from './colors';
Expand Down Expand Up @@ -45,16 +47,30 @@ export function combineColors([fgR, fgG, fgB, fgA]: RgbaTuple, [bgR, bgG, bgB, b
return [r, g, b, alpha];
}

function getHighContrastColorWCAG2(background: RgbTuple): RgbaTuple {
const wWhite = getWCAG2ContrastRatio(Colors.White.rgba, background);
const wBlack = getWCAG2ContrastRatio(Colors.Black.rgba, background);
return wWhite >= wBlack ? Colors.White.rgba : Colors.Black.rgba;
/** @internal */
export interface ColorContrastOptions {
darkColor?: RgbaTuple;
lightColor?: RgbaTuple;
}

const getOptionWithDefaults = (options: ColorContrastOptions = {}): Required<ColorContrastOptions> => ({
darkColor: Colors.Black.rgba,
lightColor: Colors.White.rgba,
...options,
});

function getHighContrastColorWCAG2(background: RgbTuple, options: ColorContrastOptions = {}): RgbaTuple {
const { lightColor, darkColor } = getOptionWithDefaults(options);
const wWhite = getWCAG2ContrastRatio(lightColor, background);
const wBlack = getWCAG2ContrastRatio(darkColor, background);
return wWhite >= wBlack ? lightColor : darkColor;
}

function getHighContrastColorAPCA(background: RgbTuple): RgbaTuple {
const wWhiteText = Math.abs(APCAContrast(background, Colors.White.rgba));
const wBlackText = Math.abs(APCAContrast(background, Colors.Black.rgba));
return wWhiteText > wBlackText ? Colors.White.rgba : Colors.Black.rgba;
function getHighContrastColorAPCA(background: RgbTuple, options: ColorContrastOptions = {}): RgbaTuple {
const { lightColor, darkColor } = getOptionWithDefaults(options);
const wWhiteText = Math.abs(APCAContrast(background, lightColor));
const wBlackText = Math.abs(APCAContrast(background, darkColor));
return wWhiteText > wBlackText ? lightColor : darkColor;
}

const HIGH_CONTRAST_FN = {
Expand All @@ -66,6 +82,10 @@ const HIGH_CONTRAST_FN = {
* Use white or black text depending on the high contrast mode used
* @internal
*/
export function highContrastColor(background: RgbTuple, mode: keyof typeof HIGH_CONTRAST_FN = 'WCAG2'): RgbaTuple {
return HIGH_CONTRAST_FN[mode](background);
export function highContrastColor(
background: RgbTuple,
mode: keyof typeof HIGH_CONTRAST_FN = 'WCAG2',
options?: ColorContrastOptions,
): RgbaTuple {
return HIGH_CONTRAST_FN[mode](background, options);
}
16 changes: 9 additions & 7 deletions packages/charts/src/common/color_library_wrappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,20 @@ export function colorToRgba(color: Color): RgbaTuple {
}

/** @internal */
export function colorToHsl(color: Color) {
const [r, g, b] = colorToRgba(color);
return chroma.rgb(r, g, b).hsl();
export function colorToHsl(color: Color): [h: number, s: number, l: number, a: number] {
const [r, g, b, a] = colorToRgba(color);
const [h, s, l] = chroma.rgb(r, g, b).hsl(); // alpha not preserved
return [h, s, l, a];
nickofthyme marked this conversation as resolved.
Show resolved Hide resolved
}

/** @internal */
export function hslToColor(h: number, s: number, l: number): Color {
const rgba = chroma.hsl(h, s, l).rgba();
export function hslToColor(h: number, s: number, l: number, a = 1): Color {
const rgba = chroma.hsl(h, s, l).alpha(a).rgba();
nickofthyme marked this conversation as resolved.
Show resolved Hide resolved
return RGBATupleToString(rgba);
}

/** @internal */
export function changeColorLightness(color: Color, lightnessAmount: number, lightnessThreshold: number): Color {
const [h, s, l] = colorToHsl(color);
return hslToColor(h, s, l >= lightnessThreshold ? l - lightnessAmount : l + lightnessAmount);
const [h, s, l, a] = colorToHsl(color);
return hslToColor(h, s, l >= lightnessThreshold ? l - lightnessAmount : l + lightnessAmount, a);
}
19 changes: 17 additions & 2 deletions packages/charts/src/common/fill_text_color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Side Public License, v 1.
*/

import { combineColors, highContrastColor } from './color_calcs';
import { ColorContrastOptions, combineColors, highContrastColor } from './color_calcs';
import { colorToRgba, RGBATupleToString } from './color_library_wrappers';
import { Color, Colors } from './colors';

Expand All @@ -26,6 +26,7 @@ export function fillTextColor(
fallbackBGColor: Color,
foreground: Color | null,
background: Color = Colors.Transparent.keyword,
options?: ColorContrastOptions,
): Color {
let backgroundRGBA = colorToRgba(background);

Expand All @@ -36,8 +37,22 @@ export function fillTextColor(
if (foreground) {
const foregroundRGBA = colorToRgba(foreground);
const blendedFgBg = combineColors(foregroundRGBA, backgroundRGBA);
return RGBATupleToString(highContrastColor(blendedFgBg));
return RGBATupleToString(highContrastColor(blendedFgBg, 'WCAG2', options));
}

return RGBATupleToString(highContrastColor(backgroundRGBA));
}

/** @internal */
export function getResolvedBackgroundColor(
fallbackBGColor: Color,
background: Color = Colors.Transparent.keyword,
): Color {
let backgroundRGBA = colorToRgba(background);

if (backgroundRGBA[3] < TRANSPARENT_LIMIT) {
backgroundRGBA = colorToRgba(fallbackBGColor);
}

return RGBATupleToString(backgroundRGBA);
}
1 change: 0 additions & 1 deletion packages/charts/src/utils/themes/dark_theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,6 @@ export const DARK_THEME: Theme = {
},
border: '#343741',
barBackground: '#343741',
background: '#1D1E23',
nonFiniteText: 'N/A',
nickofthyme marked this conversation as resolved.
Show resolved Hide resolved
minHeight: 64,
},
Expand Down
1 change: 0 additions & 1 deletion packages/charts/src/utils/themes/light_theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,6 @@ export const LIGHT_THEME: Theme = {
},
border: '#EDF0F5',
barBackground: '#EDF0F5',
background: '#FFFFFF',
nonFiniteText: 'N/A',
minHeight: 64,
},
Expand Down
Loading