Skip to content

Commit 6629d41

Browse files
[Lens] Range event annotations (#129848)
* [Lens] add Range static annotations * range annotations tests * feedback applied * outsideDimension fix * colors manipulations * outsideDimension calculation * outside dimension calculation * reduce bundle * fix tests * custom swatches and comment * better swatches * types * types Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
1 parent 0745196 commit 6629d41

31 files changed

Lines changed: 1223 additions & 315 deletions

File tree

src/plugins/chart_expressions/expression_xy/common/expression_functions/annotation_layer_config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export function annotationLayerConfigFunction(): ExpressionFunctionDefinition<
3333
help: 'Show details',
3434
},
3535
annotations: {
36-
types: ['manual_event_annotation'],
36+
types: ['manual_point_event_annotation', 'manual_range_event_annotation'],
3737
help: '',
3838
multi: true,
3939
},

src/plugins/chart_expressions/expression_xy/public/components/__snapshots__/xy_chart.test.tsx.snap

Lines changed: 95 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/plugins/chart_expressions/expression_xy/public/components/annotations.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,7 @@
1616
transform: rotate(45deg);
1717
transform-origin: center;
1818
}
19+
20+
.xyAnnotationTooltipDetail {
21+
padding: $euiSizeXS ($euiSizeXS * 2);
22+
}

src/plugins/chart_expressions/expression_xy/public/components/annotations.tsx

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,19 @@ import {
1616
AnnotationTooltipFormatter,
1717
LineAnnotation,
1818
Position,
19+
RectAnnotation,
1920
} from '@elastic/charts';
2021
import moment from 'moment';
21-
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
22-
import type { EventAnnotationArgs } from '@kbn/event-annotation-plugin/common';
22+
import { EuiFlexGroup, EuiFlexItem, EuiText } from '@elastic/eui';
23+
import type {
24+
ManualPointEventAnnotationArgs,
25+
ManualRangeEventAnnotationOutput,
26+
} from '@kbn/event-annotation-plugin/common';
2327
import type { FieldFormat } from '@kbn/field-formats-plugin/common';
24-
import { defaultAnnotationColor } from '@kbn/event-annotation-plugin/public';
28+
import {
29+
defaultAnnotationColor,
30+
defaultAnnotationRangeColor,
31+
} from '@kbn/event-annotation-plugin/public';
2532
import type { AnnotationLayerArgs, AnnotationLayerConfigResult } from '../../common/types';
2633
import { AnnotationIcon, hasIcon, Marker, MarkerBody } from '../helpers';
2734
import { mapVerticalToHorizontalPlacement, LINES_MARKER_SIZE } from '../helpers';
@@ -34,16 +41,18 @@ const getRoundedTimestamp = (timestamp: number, firstTimestamp?: number, minInte
3441
};
3542

3643
export interface AnnotationsProps {
37-
groupedAnnotations: CollectiveConfig[];
44+
groupedLineAnnotations: CollectiveConfig[];
45+
rangeAnnotations: ManualRangeEventAnnotationOutput[];
3846
formatter?: FieldFormat;
3947
isHorizontal: boolean;
4048
paddingMap: Partial<Record<Position, number>>;
4149
hide?: boolean;
4250
minInterval?: number;
4351
isBarChart?: boolean;
52+
outsideDimension: number;
4453
}
4554

46-
interface CollectiveConfig extends EventAnnotationArgs {
55+
interface CollectiveConfig extends ManualPointEventAnnotationArgs {
4756
roundedTimestamp: number;
4857
axisMode: 'bottom';
4958
customTooltipDetails?: AnnotationTooltipFormatter | undefined;
@@ -55,9 +64,11 @@ const groupVisibleConfigsByInterval = (
5564
firstTimestamp?: number
5665
) => {
5766
return layers
58-
.flatMap(({ annotations }) => annotations.filter((a) => !a.isHidden))
67+
.flatMap(({ annotations }) =>
68+
annotations.filter((a) => !a.isHidden && a.type === 'manual_point_event_annotation')
69+
)
5970
.sort((a, b) => moment(a.time).valueOf() - moment(b.time).valueOf())
60-
.reduce<Record<string, EventAnnotationArgs[]>>((acc, current) => {
71+
.reduce<Record<string, ManualPointEventAnnotationArgs[]>>((acc, current) => {
6172
const roundedTimestamp = getRoundedTimestamp(
6273
moment(current.time).valueOf(),
6374
firstTimestamp,
@@ -72,7 +83,7 @@ const groupVisibleConfigsByInterval = (
7283

7384
const createCustomTooltipDetails =
7485
(
75-
config: EventAnnotationArgs[],
86+
config: ManualPointEventAnnotationArgs[],
7687
formatter?: FieldFormat
7788
): AnnotationTooltipFormatter | undefined =>
7889
() => {
@@ -95,8 +106,8 @@ const createCustomTooltipDetails =
95106
);
96107
};
97108

98-
function getCommonProperty<T, K extends keyof EventAnnotationArgs>(
99-
configArr: EventAnnotationArgs[],
109+
function getCommonProperty<T, K extends keyof ManualPointEventAnnotationArgs>(
110+
configArr: ManualPointEventAnnotationArgs[],
100111
propertyName: K,
101112
fallbackValue: T
102113
) {
@@ -107,9 +118,9 @@ function getCommonProperty<T, K extends keyof EventAnnotationArgs>(
107118
return fallbackValue;
108119
}
109120

110-
const getCommonStyles = (configArr: EventAnnotationArgs[]) => {
121+
const getCommonStyles = (configArr: ManualPointEventAnnotationArgs[]) => {
111122
return {
112-
color: getCommonProperty<EventAnnotationArgs['color'], 'color'>(
123+
color: getCommonProperty<ManualPointEventAnnotationArgs['color'], 'color'>(
113124
configArr,
114125
'color',
115126
defaultAnnotationColor
@@ -120,6 +131,20 @@ const getCommonStyles = (configArr: EventAnnotationArgs[]) => {
120131
};
121132
};
122133

134+
export const getRangeAnnotations = (layers: AnnotationLayerConfigResult[]) => {
135+
return layers
136+
.flatMap(({ annotations }) =>
137+
annotations.filter(
138+
(a): a is ManualRangeEventAnnotationOutput =>
139+
a.type === 'manual_range_event_annotation' && !a.isHidden
140+
)
141+
)
142+
.sort((a, b) => moment(a.time).valueOf() - moment(b.time).valueOf());
143+
};
144+
145+
export const OUTSIDE_RECT_ANNOTATION_WIDTH = 8;
146+
export const OUTSIDE_RECT_ANNOTATION_WIDTH_SUGGESTION = 2;
147+
123148
export const getAnnotationsGroupedByInterval = (
124149
layers: AnnotationLayerConfigResult[],
125150
minInterval?: number,
@@ -147,18 +172,23 @@ export const getAnnotationsGroupedByInterval = (
147172
});
148173
};
149174

175+
// todo: remove when closed https://github.com/elastic/elastic-charts/issues/1647
176+
RectAnnotation.displayName = 'RectAnnotation';
177+
150178
export const Annotations = ({
151-
groupedAnnotations,
179+
groupedLineAnnotations,
180+
rangeAnnotations,
152181
formatter,
153182
isHorizontal,
154183
paddingMap,
155184
hide,
156185
minInterval,
157186
isBarChart,
187+
outsideDimension,
158188
}: AnnotationsProps) => {
159189
return (
160190
<>
161-
{groupedAnnotations.map((annotation) => {
191+
{groupedLineAnnotations.map((annotation) => {
162192
const markerPositionVertical = Position.Top;
163193
const markerPosition = isHorizontal
164194
? mapVerticalToHorizontalPlacement(markerPositionVertical)
@@ -229,6 +259,40 @@ export const Annotations = ({
229259
/>
230260
);
231261
})}
262+
{rangeAnnotations.map(({ label, time, color, endTime, outside }) => {
263+
const id = snakeCase(label);
264+
265+
return (
266+
<RectAnnotation
267+
id={id}
268+
key={id}
269+
customTooltip={() => (
270+
<div className="echTooltip">
271+
<EuiText size="xs" className="echTooltip__header">
272+
<h4>
273+
{formatter
274+
? `${formatter.convert(time)}${formatter?.convert(endTime)}`
275+
: `${moment(time).toISOString()}${moment(endTime).toISOString()}`}
276+
</h4>
277+
</EuiText>
278+
<div className="xyAnnotationTooltipDetail">{label}</div>
279+
</div>
280+
)}
281+
dataValues={[
282+
{
283+
coordinates: {
284+
x0: moment(time).valueOf(),
285+
x1: moment(endTime).valueOf(),
286+
},
287+
details: label,
288+
},
289+
]}
290+
style={{ fill: color || defaultAnnotationRangeColor, opacity: 1 }}
291+
outside={Boolean(outside)}
292+
outsideDimension={outsideDimension}
293+
/>
294+
);
295+
})}
232296
</>
233297
);
234298
};

0 commit comments

Comments
 (0)