@centreon/ui 23.10.17 → 23.10.18-MON-17793-create-graph-component-centreon-ui.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/package.json +2 -1
  2. package/src/Graph/Axes/UnitLabel.tsx +20 -0
  3. package/src/Graph/Axes/index.tsx +99 -0
  4. package/src/Graph/Axes/models.ts +26 -0
  5. package/src/Graph/Axes/useAxisY.ts +100 -0
  6. package/src/Graph/Graph.tsx +231 -0
  7. package/src/Graph/Grids/index.tsx +20 -0
  8. package/src/Graph/Header/index.tsx +34 -0
  9. package/src/Graph/InteractionWithGraph/AnchorPoint/RegularAnchorPoint.tsx +88 -0
  10. package/src/Graph/InteractionWithGraph/AnchorPoint/StackedAnchorPoint.tsx +97 -0
  11. package/src/Graph/InteractionWithGraph/AnchorPoint/index.tsx +56 -0
  12. package/src/Graph/InteractionWithGraph/AnchorPoint/models.ts +25 -0
  13. package/src/Graph/InteractionWithGraph/AnchorPoint/useAnchorPoint.ts +109 -0
  14. package/src/Graph/InteractionWithGraph/Bar.tsx +21 -0
  15. package/src/Graph/InteractionWithGraph/ZoomPreview/index.tsx +38 -0
  16. package/src/Graph/InteractionWithGraph/ZoomPreview/models.ts +17 -0
  17. package/src/Graph/InteractionWithGraph/ZoomPreview/useZoomPreview.ts +101 -0
  18. package/src/Graph/InteractionWithGraph/ZoomPreview/zoomPreviewAtoms.ts +5 -0
  19. package/src/Graph/InteractionWithGraph/index.tsx +93 -0
  20. package/src/Graph/InteractionWithGraph/interactionWithGraphAtoms.ts +7 -0
  21. package/src/Graph/InteractionWithGraph/mouseTimeValueAtoms.ts +49 -0
  22. package/src/Graph/Lines/RegularLines/index.tsx +99 -0
  23. package/src/Graph/Lines/RegularLines/useRegularLines.ts +15 -0
  24. package/src/Graph/Lines/StackedLines/index.tsx +74 -0
  25. package/src/Graph/Lines/StackedLines/useStackedLines.ts +39 -0
  26. package/src/Graph/Lines/index.tsx +153 -0
  27. package/src/Graph/Lines/models.ts +32 -0
  28. package/src/Graph/LoadingProgress.tsx +46 -0
  29. package/src/Graph/common/index.ts +33 -0
  30. package/src/Graph/data.json +1338 -0
  31. package/src/Graph/helpers/doc.ts +323 -0
  32. package/src/Graph/helpers/index.ts +15 -0
  33. package/src/Graph/index.stories.tsx +30 -0
  34. package/src/Graph/index.tsx +66 -0
  35. package/src/Graph/models.ts +68 -0
  36. package/src/Graph/timeSeries/index.test.ts +484 -0
  37. package/src/Graph/timeSeries/index.ts +512 -0
  38. package/src/Graph/timeSeries/models.ts +119 -0
  39. package/src/Graph/useGraphData.ts +117 -0
  40. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +57 -0
  41. package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.tsx +78 -0
  42. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/ErrorText.tsx +14 -0
  43. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +169 -0
  44. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/index.tsx +76 -0
  45. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +61 -0
  46. package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/usePickersStartEndDate.ts +91 -0
  47. package/src/TimePeriods/CustomTimePeriod/index.tsx +63 -0
  48. package/src/TimePeriods/DateTimePickerInput.tsx +99 -0
  49. package/src/TimePeriods/SelectedTimePeriod.tsx +99 -0
  50. package/src/TimePeriods/TimePeriods.cypress.spec.tsx +497 -0
  51. package/src/TimePeriods/helpers/index.ts +25 -0
  52. package/src/TimePeriods/index.stories.tsx +74 -0
  53. package/src/TimePeriods/index.tsx +77 -0
  54. package/src/TimePeriods/models.ts +103 -0
  55. package/src/TimePeriods/timePeriods.styles.ts +20 -0
  56. package/src/TimePeriods/timePeriodsAtoms.ts +113 -0
  57. package/src/TimePeriods/useDateTimePickerAdapter.ts +329 -0
  58. package/src/TimePeriods/useSortTimePeriods.ts +24 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "23.10.17",
3
+ "version": "23.10.18-MON-17793-create-graph-component-centreon-ui.0",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -85,6 +85,7 @@
85
85
  "@lexical/selection": "0.8.0",
86
86
  "@lexical/utils": "0.8.0",
87
87
  "anylogger": "^1.0.11",
88
+ "d3-array": "3.2.0",
88
89
  "humanize-duration": "^3.27.3",
89
90
  "lexical": "0.8.0",
90
91
  "notistack": "^2.0.8",
@@ -0,0 +1,20 @@
1
+ import { commonTickLabelProps } from '../common';
2
+
3
+ interface UnitLabelProps {
4
+ unit: string;
5
+ x: number;
6
+ y?: number;
7
+ }
8
+
9
+ const UnitLabel = ({ x, y = 16, unit }: UnitLabelProps): JSX.Element => (
10
+ <text
11
+ fontFamily={commonTickLabelProps.fontFamily}
12
+ fontSize={commonTickLabelProps.fontSize}
13
+ x={x}
14
+ y={-y}
15
+ >
16
+ {unit}
17
+ </text>
18
+ );
19
+
20
+ export default UnitLabel;
@@ -0,0 +1,99 @@
1
+ import { Axis } from '@visx/visx';
2
+ import { ScaleLinear } from 'd3-scale';
3
+ import dayjs from 'dayjs';
4
+ import { gte } from 'ramda';
5
+
6
+ import useLocaleDateTimeFormat, {
7
+ dateFormat,
8
+ timeFormat
9
+ } from '../../utils/useLocaleDateTimeFormat';
10
+ import { GraphParameters } from '../models';
11
+ import { getUnits } from '../timeSeries';
12
+
13
+ import UnitLabel from './UnitLabel';
14
+ import { Data } from './models';
15
+ import useAxisY from './useAxisY';
16
+
17
+ interface Props {
18
+ data: Data;
19
+ height: number;
20
+ leftScale: ScaleLinear<number, number>;
21
+ queryParameters?: GraphParameters;
22
+ rightScale: ScaleLinear<number, number>;
23
+ width: number;
24
+ xScale: ScaleLinear<number, number>;
25
+ }
26
+
27
+ const Axes = ({
28
+ height,
29
+ width,
30
+ data,
31
+ rightScale,
32
+ leftScale,
33
+ xScale,
34
+ queryParameters
35
+ }: Props): JSX.Element => {
36
+ const { format } = useLocaleDateTimeFormat();
37
+ const { lines } = data;
38
+
39
+ const { axisLeft, axisRight } = useAxisY({ data, graphHeight: height });
40
+
41
+ const [firstUnit, secondUnit] = getUnits(lines);
42
+
43
+ const xTickCount = Math.ceil(width / 82);
44
+
45
+ const getXAxisTickFormat = (): string => {
46
+ const parameters = queryParameters;
47
+ if (!parameters) {
48
+ return timeFormat;
49
+ }
50
+
51
+ const numberDays = dayjs
52
+ .duration(dayjs(parameters.end).diff(dayjs(parameters.start)))
53
+ .asDays();
54
+
55
+ return gte(numberDays, 2) ? dateFormat : timeFormat;
56
+ };
57
+
58
+ const tickFormat = data?.axisX?.xAxisTickFormat || getXAxisTickFormat();
59
+
60
+ const formatAxisTick = (tick): string =>
61
+ format({ date: new Date(tick), formatString: tickFormat });
62
+
63
+ return (
64
+ <g>
65
+ <Axis.AxisBottom
66
+ numTicks={xTickCount}
67
+ scale={xScale}
68
+ tickFormat={formatAxisTick}
69
+ top={height}
70
+ />
71
+
72
+ {axisLeft.displayUnit && <UnitLabel unit={firstUnit} x={-4} />}
73
+
74
+ <Axis.AxisLeft
75
+ numTicks={axisLeft.numTicks}
76
+ orientation="left"
77
+ scale={leftScale}
78
+ tickFormat={axisLeft.tickFormat}
79
+ tickLabelProps={axisLeft.tickLabelProps}
80
+ tickLength={2}
81
+ />
82
+
83
+ {axisRight.display && (
84
+ <Axis.AxisRight
85
+ left={width}
86
+ numTicks={axisRight.numTicks}
87
+ orientation="right"
88
+ scale={rightScale}
89
+ tickFormat={axisRight.tickFormat}
90
+ tickLabelProps={axisRight.tickLabelProps}
91
+ tickLength={2}
92
+ />
93
+ )}
94
+ {axisRight.displayUnit && <UnitLabel unit={secondUnit} x={width} />}
95
+ </g>
96
+ );
97
+ };
98
+
99
+ export default Axes;
@@ -0,0 +1,26 @@
1
+ import { Line, TimeValue } from '../timeSeries/models';
2
+
3
+ export interface LabelProps {
4
+ [x: string]: unknown;
5
+ textAnchor?: string;
6
+ }
7
+
8
+ export interface Axis {
9
+ displayUnit?: boolean;
10
+ }
11
+
12
+ export interface AxisYRight extends Axis {
13
+ display?: boolean;
14
+ }
15
+
16
+ export interface AxisX {
17
+ xAxisTickFormat?: string;
18
+ }
19
+ export interface Data {
20
+ axisX?: AxisX;
21
+ axisYLeft?: Axis;
22
+ axisYRight?: AxisYRight;
23
+ baseAxis: number;
24
+ lines: Array<Line>;
25
+ timeSeries: Array<TimeValue>;
26
+ }
@@ -0,0 +1,100 @@
1
+ import { isNil } from 'ramda';
2
+ import { Axis } from '@visx/visx';
3
+
4
+ import { useTheme } from '@mui/material';
5
+
6
+ import { formatMetricValue, getUnits } from '../timeSeries';
7
+ import { commonTickLabelProps } from '../common';
8
+
9
+ import { Data, LabelProps } from './models';
10
+
11
+ interface AxisYData {
12
+ displayUnit: boolean;
13
+ numTicks: number;
14
+ tickFormat: Axis.TickFormatter<unknown>;
15
+ tickLabelProps: Axis.TickLabelProps<unknown>;
16
+ }
17
+
18
+ interface AxisRightData extends AxisYData {
19
+ display: boolean;
20
+ }
21
+
22
+ interface AxisY {
23
+ axisLeft: AxisYData;
24
+ axisRight: AxisRightData;
25
+ }
26
+
27
+ interface Props {
28
+ data: Data;
29
+ graphHeight: number;
30
+ }
31
+
32
+ const useAxisY = ({ data, graphHeight }: Props): AxisY => {
33
+ const theme = useTheme();
34
+
35
+ const { lines } = data;
36
+ const [firstUnit, secondUnit, thirdUnit] = getUnits(lines);
37
+
38
+ const numTicks = Math.ceil(graphHeight / 30);
39
+
40
+ const hasMoreThanTwoUnits = !isNil(thirdUnit);
41
+ const hasTwoUnits = !isNil(secondUnit) && !hasMoreThanTwoUnits;
42
+
43
+ const displayAxisRight = data?.axisYRight?.display ?? hasTwoUnits;
44
+ const displayUnitAxisRight = data?.axisYRight?.displayUnit ?? hasTwoUnits;
45
+ const displayUnitAxisLeft =
46
+ data?.axisYLeft?.displayUnit ?? !hasMoreThanTwoUnits;
47
+
48
+ const formatTick =
49
+ ({ unit }) =>
50
+ (value): string => {
51
+ if (isNil(value)) {
52
+ return '';
53
+ }
54
+
55
+ return formatMetricValue({ base: data.baseAxis, unit, value }) as string;
56
+ };
57
+
58
+ const labelProps = ({
59
+ textAnchor,
60
+ ...rest
61
+ }: LabelProps): Record<string, unknown> => ({
62
+ ...commonTickLabelProps,
63
+ textAnchor,
64
+ ...rest
65
+ });
66
+
67
+ const tickLabelPropsAxisLeft = (): Record<string, unknown> =>
68
+ labelProps({
69
+ dx: theme.spacing(-1),
70
+ dy: theme.spacing(0.5),
71
+ textAnchor: 'end'
72
+ });
73
+
74
+ const tickLabelPropsAxisRight = (): Record<string, unknown> =>
75
+ labelProps({
76
+ dx: theme.spacing(0.5),
77
+ dy: theme.spacing(0.5),
78
+ textAnchor: 'start'
79
+ });
80
+
81
+ return {
82
+ axisLeft: {
83
+ displayUnit: displayUnitAxisLeft,
84
+ numTicks,
85
+ tickFormat: formatTick({
86
+ unit: hasMoreThanTwoUnits ? '' : firstUnit
87
+ }),
88
+ tickLabelProps: tickLabelPropsAxisLeft
89
+ },
90
+ axisRight: {
91
+ display: displayAxisRight,
92
+ displayUnit: displayUnitAxisRight,
93
+ numTicks,
94
+ tickFormat: formatTick({ unit: secondUnit }),
95
+ tickLabelProps: tickLabelPropsAxisRight
96
+ }
97
+ };
98
+ };
99
+
100
+ export default useAxisY;
@@ -0,0 +1,231 @@
1
+ import { useMemo, useRef } from 'react';
2
+
3
+ import { Group } from '@visx/visx';
4
+
5
+ import Axes from './Axes';
6
+ import Grids from './Grids';
7
+ import Header from './Header';
8
+ import InteractionWithGraph from './InteractionWithGraph';
9
+ import RegularAnchorPoint from './InteractionWithGraph/AnchorPoint/RegularAnchorPoint';
10
+ import StackedAnchorPoint from './InteractionWithGraph/AnchorPoint/StackedAnchorPoint';
11
+ import {
12
+ RegularLinesAnchorPoint,
13
+ StackValue,
14
+ StackedAnchorPoint as StackedAnchorPointModel
15
+ } from './InteractionWithGraph/AnchorPoint/models';
16
+ import useAnchorPoint from './InteractionWithGraph/AnchorPoint/useAnchorPoint';
17
+ import Lines from './Lines';
18
+ import useRegularLines from './Lines/RegularLines/useRegularLines';
19
+ import useStackedLines from './Lines/StackedLines/useStackedLines';
20
+ import LoadingProgress from './LoadingProgress';
21
+ import { margin } from './common';
22
+ import { Data, GlobalAreaLines, GraphProps } from './models';
23
+ import { getLeftScale, getRightScale, getXScale } from './timeSeries';
24
+
25
+ interface Props extends GraphProps {
26
+ graphData: Data;
27
+ loading: boolean;
28
+ shapeLines: GlobalAreaLines;
29
+ }
30
+
31
+ const Graph = ({
32
+ graphData,
33
+ height,
34
+ width,
35
+ shapeLines,
36
+ axis,
37
+ anchorPoint,
38
+ loading,
39
+ zoomPreview
40
+ }: Props): JSX.Element => {
41
+ const graphSvgRef = useRef<SVGSVGElement | null>(null);
42
+
43
+ const graphWidth = width > 0 ? width - margin.left - margin.right : 0;
44
+ const graphHeight = height > 0 ? height - margin.top - margin.bottom : 0;
45
+
46
+ const { title, timeSeries, lines, baseAxis, queryParameters } = graphData;
47
+
48
+ const xScale = useMemo(
49
+ () =>
50
+ getXScale({
51
+ dataTime: timeSeries,
52
+ valueWidth: graphWidth
53
+ }),
54
+ [timeSeries, graphWidth]
55
+ );
56
+
57
+ const leftScale = useMemo(
58
+ () =>
59
+ getLeftScale({
60
+ dataLines: lines,
61
+ dataTimeSeries: timeSeries,
62
+ valueGraphHeight: graphHeight
63
+ }),
64
+ [lines, timeSeries, graphHeight]
65
+ );
66
+
67
+ const rightScale = useMemo(
68
+ () =>
69
+ getRightScale({
70
+ dataLines: lines,
71
+ dataTimeSeries: timeSeries,
72
+ valueGraphHeight: graphHeight
73
+ }),
74
+ [timeSeries, lines, graphHeight]
75
+ );
76
+
77
+ const { timeTick, positionX, positionY } = useAnchorPoint({
78
+ graphSvgRef,
79
+ timeSeries,
80
+ xScale
81
+ });
82
+
83
+ const { stackedLinesData, invertedStackedLinesData } = useStackedLines({
84
+ lines,
85
+ timeSeries
86
+ });
87
+
88
+ const { regularLines } = useRegularLines({ lines });
89
+
90
+ const commonLinesProps = {
91
+ display: true,
92
+ leftScale,
93
+ rightScale,
94
+ xScale
95
+ };
96
+
97
+ const areaRegularLines = {
98
+ lines: regularLines,
99
+ timeSeries,
100
+ ...commonLinesProps,
101
+ ...shapeLines?.areaRegularLines
102
+ };
103
+
104
+ const areaStackedLines = {
105
+ invertedStackedLinesData,
106
+ stackedLinesData,
107
+ ...commonLinesProps,
108
+ ...shapeLines?.areaStackedLines
109
+ };
110
+
111
+ const displayRegularLinesAnchorPoint =
112
+ anchorPoint?.areaRegularLinesAnchorPoint?.display ?? true;
113
+
114
+ const displayStackedAnchorPoint =
115
+ anchorPoint?.areaStackedLinesAnchorPoint?.display ?? true;
116
+
117
+ const displayTimeTick =
118
+ displayRegularLinesAnchorPoint ?? displayStackedAnchorPoint;
119
+
120
+ const commonAnchorPoint = {
121
+ displayTimeValues: true,
122
+ graphHeight,
123
+ graphWidth,
124
+ positionX,
125
+ positionY,
126
+ timeTick
127
+ };
128
+
129
+ const renderRegularLinesAnchorPoint = ({
130
+ areaColor,
131
+ lineColor,
132
+ metric,
133
+ timeSeries: regularLinesTimeSeries,
134
+ transparency,
135
+ xScale: xScaleRegularLines,
136
+ yScale
137
+ }: RegularLinesAnchorPoint): JSX.Element => (
138
+ <g>
139
+ {displayRegularLinesAnchorPoint && (
140
+ <RegularAnchorPoint
141
+ areaColor={areaColor}
142
+ lineColor={lineColor}
143
+ metric={metric}
144
+ timeSeries={regularLinesTimeSeries}
145
+ transparency={transparency}
146
+ xScale={xScaleRegularLines}
147
+ yScale={yScale}
148
+ {...commonAnchorPoint}
149
+ />
150
+ )}
151
+ </g>
152
+ );
153
+
154
+ const renderStackedAnchorPoint = ({
155
+ areaColor,
156
+ transparency,
157
+ lineColor,
158
+ stack,
159
+ xScale: x,
160
+ yScale: y
161
+ }: StackedAnchorPointModel): JSX.Element => (
162
+ <g>
163
+ {displayStackedAnchorPoint && (
164
+ <StackedAnchorPoint
165
+ areaColor={areaColor}
166
+ lineColor={lineColor}
167
+ stackValues={stack as unknown as Array<StackValue>}
168
+ transparency={transparency}
169
+ xScale={x}
170
+ yScale={y}
171
+ {...commonAnchorPoint}
172
+ />
173
+ )}
174
+ </g>
175
+ );
176
+
177
+ return (
178
+ <>
179
+ <Header
180
+ displayTimeTick={displayTimeTick}
181
+ timeTick={timeTick}
182
+ title={title}
183
+ />
184
+ <LoadingProgress display={loading} height={height} width={width} />
185
+ <svg height={height} ref={graphSvgRef} width="100%">
186
+ <Group.Group left={margin.left} top={margin.top}>
187
+ <Grids
188
+ height={graphHeight}
189
+ leftScale={leftScale}
190
+ width={graphWidth}
191
+ xScale={xScale}
192
+ />
193
+
194
+ <Axes
195
+ data={{
196
+ baseAxis,
197
+ lines,
198
+ timeSeries,
199
+ ...axis
200
+ }}
201
+ height={graphHeight}
202
+ leftScale={leftScale}
203
+ queryParameters={queryParameters}
204
+ rightScale={rightScale}
205
+ width={graphWidth}
206
+ xScale={xScale}
207
+ />
208
+
209
+ <Lines
210
+ anchorPoint={{
211
+ renderRegularLinesAnchorPoint,
212
+ renderStackedAnchorPoint
213
+ }}
214
+ height={graphHeight}
215
+ shape={{ areaRegularLines, areaStackedLines }}
216
+ />
217
+
218
+ <InteractionWithGraph
219
+ commonData={{ graphHeight, graphSvgRef, graphWidth }}
220
+ zoomData={{
221
+ xScale,
222
+ ...zoomPreview
223
+ }}
224
+ />
225
+ </Group.Group>
226
+ </svg>
227
+ </>
228
+ );
229
+ };
230
+
231
+ export default Graph;
@@ -0,0 +1,20 @@
1
+ import { Grid } from '@visx/visx';
2
+ import { ScaleLinear } from 'd3-scale';
3
+
4
+ interface Props {
5
+ height: number;
6
+ leftScale: ScaleLinear<number, number>;
7
+ width: number;
8
+ xScale: ScaleLinear<number, number>;
9
+ }
10
+
11
+ const Grids = ({ height, width, leftScale, xScale }: Props): JSX.Element => {
12
+ return (
13
+ <g>
14
+ <Grid.GridRows height={height} scale={leftScale} width={width} />
15
+ <Grid.GridColumns height={height} scale={xScale} width={width} />
16
+ </g>
17
+ );
18
+ };
19
+
20
+ export default Grids;
@@ -0,0 +1,34 @@
1
+ import { isNil } from 'ramda';
2
+
3
+ import Typography from '@mui/material/Typography';
4
+
5
+ import useLocaleDateTimeFormat from '../../utils/useLocaleDateTimeFormat';
6
+
7
+ interface Props {
8
+ displayTimeTick?: boolean;
9
+ timeTick?: Date;
10
+ title: string;
11
+ }
12
+
13
+ const Header = ({
14
+ title,
15
+ timeTick,
16
+ displayTimeTick = true
17
+ }: Props): JSX.Element => {
18
+ const { toDateTime } = useLocaleDateTimeFormat();
19
+ const time =
20
+ displayTimeTick && !isNil(timeTick) ? toDateTime(timeTick) : null;
21
+
22
+ return (
23
+ <>
24
+ <Typography align="center" variant="body1">
25
+ {title}
26
+ </Typography>
27
+
28
+ <Typography align="center" style={{ height: 20 }} variant="body1">
29
+ {time}
30
+ </Typography>
31
+ </>
32
+ );
33
+ };
34
+ export default Header;
@@ -0,0 +1,88 @@
1
+ import { memo } from 'react';
2
+
3
+ import { equals, isNil, not, prop } from 'ramda';
4
+ import { ScaleLinear, ScaleTime } from 'd3-scale';
5
+
6
+ import { getDates, bisectDate } from '../../timeSeries';
7
+ import { TimeValue } from '../../timeSeries/models';
8
+
9
+ import AnchorPoint from '.';
10
+
11
+ interface Props {
12
+ areaColor: string;
13
+ displayTimeValues: boolean;
14
+ graphHeight: number;
15
+ graphWidth: number;
16
+ lineColor: string;
17
+ metric: string;
18
+ positionX?: number;
19
+ positionY?: number;
20
+ timeSeries: Array<TimeValue>;
21
+ timeTick?: Date;
22
+ transparency: number;
23
+ xScale: ScaleTime<number, number>;
24
+ yScale: ScaleLinear<number, number>;
25
+ }
26
+
27
+ const getYAnchorPoint = ({
28
+ timeTick,
29
+ timeSeries,
30
+ yScale,
31
+ metric
32
+ }: Pick<Props, 'timeTick' | 'timeSeries' | 'yScale' | 'metric'>): number => {
33
+ const index = bisectDate(getDates(timeSeries), timeTick);
34
+ const timeValue = timeSeries[index];
35
+
36
+ return yScale(prop(metric, timeValue) as number);
37
+ };
38
+
39
+ const RegularAnchorPoint = ({
40
+ xScale,
41
+ yScale,
42
+ metric,
43
+ timeSeries,
44
+ timeTick,
45
+ areaColor,
46
+ transparency,
47
+ lineColor,
48
+ displayTimeValues,
49
+ ...rest
50
+ }: Props): JSX.Element | null => {
51
+ if (isNil(timeTick) || not(displayTimeValues)) {
52
+ return null;
53
+ }
54
+
55
+ if (isNil(timeTick) || not(displayTimeValues)) {
56
+ return null;
57
+ }
58
+ const xAnchorPoint = xScale(timeTick);
59
+
60
+ const yAnchorPoint = getYAnchorPoint({
61
+ metric,
62
+ timeSeries,
63
+ timeTick,
64
+ yScale
65
+ });
66
+
67
+ if (isNil(yAnchorPoint)) {
68
+ return null;
69
+ }
70
+
71
+ return (
72
+ <AnchorPoint
73
+ areaColor={areaColor}
74
+ lineColor={lineColor}
75
+ transparency={transparency}
76
+ x={xAnchorPoint}
77
+ y={yAnchorPoint}
78
+ {...rest}
79
+ />
80
+ );
81
+ };
82
+
83
+ export default memo(
84
+ RegularAnchorPoint,
85
+ (prevProps, nextProps) =>
86
+ equals(prevProps.timeTick, nextProps.timeTick) &&
87
+ equals(prevProps.timeSeries, nextProps.timeSeries)
88
+ );