diff --git a/packages/charts/api/charts.api.md b/packages/charts/api/charts.api.md index 2e0fe49bd5..6c7de0386b 100644 --- a/packages/charts/api/charts.api.md +++ b/packages/charts/api/charts.api.md @@ -1709,6 +1709,8 @@ export type MetricWTrend = MetricBase & { x: number; y: number; }[]; + trendA11yTitle?: string; + trendA11yDescription?: string; }; // @public (undocumented) diff --git a/packages/charts/src/chart_types/metric/renderer/dom/_text.scss b/packages/charts/src/chart_types/metric/renderer/dom/_text.scss index 8be9294633..849b6976b7 100644 --- a/packages/charts/src/chart_types/metric/renderer/dom/_text.scss +++ b/packages/charts/src/chart_types/metric/renderer/dom/_text.scss @@ -12,8 +12,9 @@ padding: 8px; display: grid; grid-template-columns: 100%; - grid-template-rows: min-content min-content auto min-content min-content; + grid-template-rows: min-content auto min-content min-content; height: 100%; + z-index: 1; &__title { font-weight: 400; @include lineClamp(3); diff --git a/packages/charts/src/chart_types/metric/renderer/dom/index.tsx b/packages/charts/src/chart_types/metric/renderer/dom/index.tsx index 06d3a4a987..9eab866e6a 100644 --- a/packages/charts/src/chart_types/metric/renderer/dom/index.tsx +++ b/packages/charts/src/chart_types/metric/renderer/dom/index.tsx @@ -35,6 +35,7 @@ import { MetricText } from './text'; interface ReactiveChartStateProps { initialized: boolean; + chartId: string; size: { width: number; height: number; @@ -66,6 +67,7 @@ class Component extends React.Component { render() { const { + chartId, initialized, size: { width, height }, a11y, @@ -98,6 +100,7 @@ class Component extends React.Component { .map((columns, ri) => { return [ ...columns.map((d, ci) => { + const metricHTMLId = `echMetric-${chartId}-${ri}-${ci}`; // fill undefined with empty panels const emptyMetricClassName = classNames('echMetric', { 'echMetric--rightBorder': ci < maxColumns - 1, @@ -115,11 +118,21 @@ class Component extends React.Component { return (
- {isMetricWTrend(d) && } + + {isMetricWTrend(d) && } {isMetricWProgress(d) && progressBarMode !== ProgressBarMode.None && ( { }} /> )} -
); }), @@ -176,6 +182,7 @@ const mapDispatchToProps = (dispatch: Dispatch): ReactiveChartDispatchProps => const DEFAULT_PROPS: ReactiveChartStateProps = { initialized: false, + chartId: '', specs: [], size: { width: 0, @@ -190,6 +197,7 @@ const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => { } return { initialized: true, + chartId: state.chartId, specs: getMetricSpecs(state), size: chartSize(state), a11y: getA11ySettingsSelector(state), diff --git a/packages/charts/src/chart_types/metric/renderer/dom/progress.tsx b/packages/charts/src/chart_types/metric/renderer/dom/progress.tsx index 782ebff081..9b061d2bfc 100644 --- a/packages/charts/src/chart_types/metric/renderer/dom/progress.tsx +++ b/packages/charts/src/chart_types/metric/renderer/dom/progress.tsx @@ -15,14 +15,14 @@ import { MetricWProgress, MetricSpec, ProgressBarMode } from '../../specs'; /** @internal */ export const ProgressBar: React.FunctionComponent<{ - datum: Pick; + datum: Pick; mode: MetricSpec['progressBarMode']; orientation: MetricSpec['progressBarOrientation']; barBackground: Color; -}> = ({ datum: { domain, value, color }, mode, orientation, barBackground }) => { +}> = ({ datum: { title, domain, value, color }, mode, orientation, barBackground }) => { const isVertical = orientation === LayoutDirection.Vertical; const isSmall = mode === ProgressBarMode.Small; - const percent = clamp((domain ? value / (domain.max - domain.min) : 1) * 100, 0, 100); + const percent = Number(clamp((domain ? value / (domain.max - domain.min) : 1) * 100, 0, 100).toFixed(2)); const bgClassName = classNames('echSingleMetricProgress', { 'echSingleMetricProgress--vertical': isVertical, @@ -37,7 +37,15 @@ export const ProgressBar: React.FunctionComponent<{ const percentProp = isVertical ? { height: `${percent}%` } : { width: `${percent}%` }; return (
-
+
); }; diff --git a/packages/charts/src/chart_types/metric/renderer/dom/sparkline.tsx b/packages/charts/src/chart_types/metric/renderer/dom/sparkline.tsx index dd4219cc6b..6a8d9615cd 100644 --- a/packages/charts/src/chart_types/metric/renderer/dom/sparkline.tsx +++ b/packages/charts/src/chart_types/metric/renderer/dom/sparkline.tsx @@ -16,10 +16,11 @@ import { CurveType } from '../../../../utils/curves'; import { MetricWTrend } from '../../specs'; /** @internal */ -export const SparkLine: FunctionComponent<{ datum: MetricWTrend; curve: 'linear' | 'step' }> = ({ - datum: { color, trend }, - curve, -}) => { +export const SparkLine: FunctionComponent<{ + id: string; + datum: MetricWTrend; + curve: 'linear' | 'step'; +}> = ({ id, datum: { color, trend, trendA11yTitle, trendA11yDescription }, curve }) => { if (!trend) { return null; } @@ -38,6 +39,8 @@ export const SparkLine: FunctionComponent<{ datum: MetricWTrend; curve: 'linear' const [h, s, l] = colorToHsl(color); const pathColor = hslToColor(h, s, l >= 0.8 ? l - 0.1 : l + 0.1); + const titleId = `${id}-trend-title`; + const descriptionId = `${id}-trend-description`; return (
+ + {trendA11yTitle} + + + {trendA11yDescription} + = ({ datum, panel, progressBarMode, progressBarOrientation, style }) => { +}> = ({ id, datum, panel, progressBarMode, progressBarOrientation, style }) => { const isVertical = progressBarOrientation === LayoutDirection.Vertical; const isSmall = progressBarMode === ProgressBarMode.Small; const { title, subtitle, extra, value } = datum; @@ -78,8 +79,14 @@ export const MetricText: React.FunctionComponent<{ return (
-
{title &&

{title}

}
-
{showSubtitle && subtitle &&

{subtitle}

}
+
+ {title && ( +

+ {title} + {showSubtitle && subtitle && {subtitle}} +

+ )} +
{extra &&
{extra}
}
diff --git a/packages/charts/src/chart_types/metric/specs/index.ts b/packages/charts/src/chart_types/metric/specs/index.ts index 46b0ce9b0d..6940a1db17 100644 --- a/packages/charts/src/chart_types/metric/specs/index.ts +++ b/packages/charts/src/chart_types/metric/specs/index.ts @@ -34,6 +34,8 @@ export type MetricWProgress = MetricBase & { /** @alpha */ export type MetricWTrend = MetricBase & { trend: { x: number; y: number }[]; + trendA11yTitle?: string; + trendA11yDescription?: string; }; /** @alpha */ diff --git a/storybook/stories/metric/1_basic.story.tsx b/storybook/stories/metric/1_basic.story.tsx index b915d5473c..473d355755 100644 --- a/storybook/stories/metric/1_basic.story.tsx +++ b/storybook/stories/metric/1_basic.story.tsx @@ -41,6 +41,9 @@ export const Example = () => { title: 'CPU Usage', subtitle: 'Overall percentage', trend: KIBANA_METRICS.metrics.kibana_os_load[1].data.map(([x, y]) => ({ x, y })), + trendA11yTitle: 'Last hour CPU percentage trend', + trendA11yDescription: + 'The trend shows the CPU Usage in percentage in the last hour. The trend shows a general flat behaviour with peaks every 10 minutes', valueFormatter: defaultValueFormatter, }, { @@ -49,6 +52,9 @@ export const Example = () => { title: 'Memory Usage', subtitle: 'Overall percentage', trend: KIBANA_METRICS.metrics.kibana_memory[1].data.map(([x, y]) => ({ x, y })), + trendA11yTitle: 'Last hour Memory usage trend', + trendA11yDescription: + 'The trend shows the memory usage in the last hour. The trend shows a general flat behaviour across the entire time window', valueFormatter: (d) => `${d} %`, }, { @@ -57,6 +63,9 @@ export const Example = () => { title: 'Cloud Revenue', subtitle: 'Quarterly', trend: KIBANA_METRICS.metrics.kibana_os_load[1].data.map(([x, y]) => ({ x, y })), + trendA11yTitle: 'Last quarter, daily Cloud Revenue trend', + trendA11yDescription: + 'The trend shows the daily Cloud revenue in the last quarter, showing peaks during weekends.', extra: ( This Year 10M