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): Metric visualization #1658

Merged
merged 35 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0b3265e
Basic chart template
markov00 Apr 20, 2022
0c2357a
feat(new_chart): metric
markov00 May 19, 2022
2b27347
Merge branch 'master' into single_metric
markov00 May 19, 2022
7060f59
test: add vrt test for dark mode and other config
markov00 May 19, 2022
d939d4e
test: add screnshots for added VRTs
markov00 May 19, 2022
51e5977
Merge branch 'master' into single_metric
markov00 May 20, 2022
be80e67
fix: run prettier on added scss
markov00 May 27, 2022
5dc1fcf
Merge branch 'master' into single_metric
markov00 May 27, 2022
bb06992
fix: use Metric type instead of Goal
markov00 Jun 6, 2022
8768f0f
refactor: DRY getSpecs method
markov00 Jun 6, 2022
4e72633
fix: empty description for now
markov00 Jun 6, 2022
e538ac0
refactor: rename style barBg to barBackground
markov00 Jun 6, 2022
bc406cf
refactor: simplify Metric component generation
markov00 Jun 6, 2022
e9842b4
docs: update APIs
markov00 Jun 6, 2022
8777acd
style: align sizes to BEM
markov00 Jun 6, 2022
ea28f38
style: use 8px margin
markov00 Jun 6, 2022
2213696
refactor: use an explicit min, max domain
markov00 Jun 6, 2022
14805b6
test: uprate VRT
markov00 Jun 6, 2022
84f9802
test: update VRTs
markov00 Jun 6, 2022
c70c557
Merge branch 'master' into single_metric
markov00 Jun 6, 2022
a0df3bc
a11y: improve a11y
markov00 Jun 6, 2022
897a664
fix: prettier...
markov00 Jun 7, 2022
5d398b4
refactor: moved and improved the resposivness of the chart
markov00 Jun 7, 2022
fc03e21
test: create single metric and grid stories
markov00 Jun 8, 2022
3c080b1
test: update VRTs
markov00 Jun 8, 2022
6d011a8
api: update doc
markov00 Jun 8, 2022
fc91ca4
feat: shape type and extra in storybook
markov00 Jun 8, 2022
b2abab6
Update vrts
markov00 Jun 8, 2022
4784459
fix: show full color when progress is none
markov00 Jun 8, 2022
b34deef
refactor: simplified specs and use progress bar direction only for pr…
markov00 Jun 8, 2022
cfd1e3b
test: update VRTs
markov00 Jun 8, 2022
55da629
fix: expose TrendShape as enum
markov00 Jun 9, 2022
5f57e2b
refactor: less noise on chart state
markov00 Jun 9, 2022
031a232
refactor: find ranges with single expression
markov00 Jun 9, 2022
b09c05f
Merge branch 'master' into single_metric
markov00 Jun 10, 2022
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.
37 changes: 37 additions & 0 deletions integration/tests/metric_stories.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import { common } from '../page_objects';

describe('Metric', () => {
it('should render horizontal progress bar', async () => {
await common.expectChartAtUrlToMatchScreenshot(
'http://localhost:9001/?path=/story/metric-alpha--grid&globals=theme:light&knob-use progress bar=true&knob-progress bar direction=horizontal&knob-max trend data points=30&knob-layout=grid',
);
});
it('should render no progress bar', async () => {
await common.expectChartAtUrlToMatchScreenshot(
'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',
);
});
it('should render vertical progress bar in dark mode', async () => {
await common.expectChartAtUrlToMatchScreenshot(
'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',
);
});
it('should render horizontal progress bar in dark mode', async () => {
await common.expectChartAtUrlToMatchScreenshot(
'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',
);
});
it('should render no progress bar in dark mode', async () => {
await common.expectChartAtUrlToMatchScreenshot(
'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=',
);
});
});
74 changes: 74 additions & 0 deletions packages/charts/api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { LegacyRef } from 'react';
import { OptionalKeys } from 'utility-types';
import { default as React_2 } from 'react';
import { ReactChild } from 'react';
import { ReactElement } from 'react';
import { ReactNode } from 'react';
import { RequiredKeys } from 'utility-types';

Expand Down Expand Up @@ -523,6 +524,7 @@ export const ChartType: Readonly<{
XYAxis: "xy_axis";
Heatmap: "heatmap";
Wordcloud: "wordcloud";
Metric: "metric";
}>;

// @public (undocumented)
Expand Down Expand Up @@ -1663,6 +1665,76 @@ export function mergeWithDefaultAnnotationRect(config?: RecursivePartial<RectAnn
// @public @deprecated
export function mergeWithDefaultTheme(theme: PartialTheme, defaultTheme?: Theme, auxiliaryThemes?: PartialTheme[]): Theme;

// @alpha (undocumented)
export const Metric: FC<SFProps<MetricSpec, "chartType" | "specType", "data", never, "id">>;

// @alpha (undocumented)
export type MetricBase = {
value: number;
valueFormatter: (d: number) => string;
color: Color;
title?: string;
subtitle?: string;
extra?: ReactElement;
};

// @alpha (undocumented)
export interface MetricSpec extends Spec {
// (undocumented)
chartType: typeof ChartType.Metric;
// (undocumented)
data: (MetricBase | MetricWProgress | MetricWTrend | undefined)[][];
Copy link
Contributor

Choose a reason for hiding this comment

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

Can MetricSpec be generic on the use case? Ternaries have some extra cost compared to generics. Also, why do we need to admit undefined?

Copy link
Member Author

Choose a reason for hiding this comment

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

  • MetricSpec with generic: with the current config no. Because you can mix a simple metric with a static background color with one with a trend and with another with a progress bar.

  • why undefined because we allow gaps between metrics in a row/column.

// (undocumented)
specType: typeof SpecType.Series;
}

// @alpha (undocumented)
export type MetricSpecProps = ComponentProps<typeof Metric>;

// @public (undocumented)
Copy link
Contributor

Choose a reason for hiding this comment

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

All the docs are for a next PR, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, unfortunately docs are always for the next PR....

export interface MetricStyle {
// (undocumented)
background: Color;
// (undocumented)
barBackground: Color;
// (undocumented)
nonFiniteText: string;
// (undocumented)
text: {
darkColor: Color;
lightColor: Color;
};
}

// @alpha (undocumented)
export const MetricTrendShape: Readonly<{
Bars: "bars";
Area: "area";
}>;

// @alpha (undocumented)
export type MetricTrendShape = $Values<typeof MetricTrendShape>;

// @alpha (undocumented)
export type MetricWProgress = MetricBase & {
domain: {
min: number;
max: number;
};
progressBarDirection?: LayoutDirection;
};

// @alpha (undocumented)
export type MetricWTrend = MetricBase & {
trend: {
x: number;
y: number;
}[];
trendShape?: MetricTrendShape;
trendA11yTitle?: string;
trendA11yDescription?: string;
Comment on lines +1733 to +1735
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the strings non-optional, if necessary, using the empty string if none is supplied?
Also, any reason not to use a default metric trend shape?

Copy link
Member Author

@markov00 markov00 Jun 9, 2022

Choose a reason for hiding this comment

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

I can make them optional on the API and required in the code, sure.
I replied too quickly. It is a bit more tricky than that, because this lives within a data array, and the only way to do that is to loop through it before and update the optional params.
From the point of view of the API these are optional, the user doesn't need to fill them out if they don't want to.

};

// @public (undocumented)
export const MODEL_KEY = "parent";

Expand Down Expand Up @@ -2532,6 +2604,8 @@ export interface Theme {
legend: LegendStyle;
lineSeriesStyle: LineSeriesStyle;
markSizeRatio?: number;
// (undocumented)
metric: MetricStyle;
partition: PartitionStyle;
// (undocumented)
scales: ScalesConfig;
Expand Down
1 change: 1 addition & 0 deletions packages/charts/src/chart_types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const ChartType = Object.freeze({
XYAxis: 'xy_axis' as const,
Heatmap: 'heatmap' as const,
Wordcloud: 'wordcloud' as const,
Metric: 'metric' as const,
});
/** @public */
export type ChartType = $Values<typeof ChartType>;
38 changes: 38 additions & 0 deletions packages/charts/src/chart_types/metric/renderer/_index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.echMetricContainer {
display: grid;
width: 100%;
height: 100%;
align-content: start;
justify-content: stretch;
align-items: stretch;
user-select: text;
}

.echMetric {
position: relative;
overflow: hidden;

&--rightBorder {
border-right: 1px solid #343741;
nickofthyme marked this conversation as resolved.
Show resolved Hide resolved
}

&--bottomBorder {
border-bottom: 1px solid #343741;
}

&--vertical {
&.echMetric--small {
padding-left: 10px;
}
}

&--horizontal {
&.echMetric--small {
padding-bottom: 10px;
}
}
}

@import 'dom/text';
@import 'dom/progress';
@import 'dom/sparkline';
47 changes: 47 additions & 0 deletions packages/charts/src/chart_types/metric/renderer/dom/_progress.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.echSingleMetricProgress {
position: absolute;
overflow: hidden;

&--vertical {
left: 0;
right: 0;
top: 0;
bottom: 0;
height: 100%;
width: 100%;
&.echSingleMetricProgress--small {
right: auto;
width: 10px;
}
}

&--horizontal {
left: 0;
right: 0;
width: 100%;
top: 0;
bottom: 0;
height: 100%;
&.echSingleMetricProgress--small {
top: auto;
height: 10px;
}
}
}

.echSingleMetricProgressBar {
&--vertical {
position: absolute;
left: 0;
right: 0;
bottom: 0;
width: 100%;
}
&--horizontal {
position: absolute;
top: 0;
bottom: 0;
left: 0;
height: 100%;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.echSingleMetricSparkline {
position: absolute;
overflow: hidden;
top: 0;
bottom: 0;
left: 0;
right: 0;
}

.echSingleMetricSparkline__svg {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
}

.echSingleMetricChart--small {
position: absolute;
top: auto;
left: auto;
bottom: 0;
right: 0;
width: 100px;
height: 30px;
}
47 changes: 47 additions & 0 deletions packages/charts/src/chart_types/metric/renderer/dom/_text.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@mixin lineClamp($maxLines) {
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: $maxLines; /* number of lines to show */
line-clamp: $maxLines;
-webkit-box-orient: vertical;
overflow: hidden;
}

.echMetricText {
position: relative;
padding: 8px;
height: 100%;
z-index: 1;
display: grid;
grid-template-columns: 100%;
grid-template-rows: min-content min-content auto min-content min-content;

&__title {
font-weight: 400;
}

&__subtitle {
padding-top: 5px;
font-weight: 300;
}

&__extra {
text-align: right;
font-weight: 400;
}

&__value {
position: relative;
font-weight: 600;
text-align: right;
white-space: nowrap;
}

&__part {
font-weight: 400;
}

&__gap {
position: relative;
}
}
Loading