@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.
- package/package.json +2 -1
- package/src/Graph/Axes/UnitLabel.tsx +20 -0
- package/src/Graph/Axes/index.tsx +99 -0
- package/src/Graph/Axes/models.ts +26 -0
- package/src/Graph/Axes/useAxisY.ts +100 -0
- package/src/Graph/Graph.tsx +231 -0
- package/src/Graph/Grids/index.tsx +20 -0
- package/src/Graph/Header/index.tsx +34 -0
- package/src/Graph/InteractionWithGraph/AnchorPoint/RegularAnchorPoint.tsx +88 -0
- package/src/Graph/InteractionWithGraph/AnchorPoint/StackedAnchorPoint.tsx +97 -0
- package/src/Graph/InteractionWithGraph/AnchorPoint/index.tsx +56 -0
- package/src/Graph/InteractionWithGraph/AnchorPoint/models.ts +25 -0
- package/src/Graph/InteractionWithGraph/AnchorPoint/useAnchorPoint.ts +109 -0
- package/src/Graph/InteractionWithGraph/Bar.tsx +21 -0
- package/src/Graph/InteractionWithGraph/ZoomPreview/index.tsx +38 -0
- package/src/Graph/InteractionWithGraph/ZoomPreview/models.ts +17 -0
- package/src/Graph/InteractionWithGraph/ZoomPreview/useZoomPreview.ts +101 -0
- package/src/Graph/InteractionWithGraph/ZoomPreview/zoomPreviewAtoms.ts +5 -0
- package/src/Graph/InteractionWithGraph/index.tsx +93 -0
- package/src/Graph/InteractionWithGraph/interactionWithGraphAtoms.ts +7 -0
- package/src/Graph/InteractionWithGraph/mouseTimeValueAtoms.ts +49 -0
- package/src/Graph/Lines/RegularLines/index.tsx +99 -0
- package/src/Graph/Lines/RegularLines/useRegularLines.ts +15 -0
- package/src/Graph/Lines/StackedLines/index.tsx +74 -0
- package/src/Graph/Lines/StackedLines/useStackedLines.ts +39 -0
- package/src/Graph/Lines/index.tsx +153 -0
- package/src/Graph/Lines/models.ts +32 -0
- package/src/Graph/LoadingProgress.tsx +46 -0
- package/src/Graph/common/index.ts +33 -0
- package/src/Graph/data.json +1338 -0
- package/src/Graph/helpers/doc.ts +323 -0
- package/src/Graph/helpers/index.ts +15 -0
- package/src/Graph/index.stories.tsx +30 -0
- package/src/Graph/index.tsx +66 -0
- package/src/Graph/models.ts +68 -0
- package/src/Graph/timeSeries/index.test.ts +484 -0
- package/src/Graph/timeSeries/index.ts +512 -0
- package/src/Graph/timeSeries/models.ts +119 -0
- package/src/Graph/useGraphData.ts +117 -0
- package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.styles.ts +57 -0
- package/src/TimePeriods/CustomTimePeriod/CompactCustomTimePeriod.tsx +78 -0
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/ErrorText.tsx +14 -0
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/PickersStartEndDate.tsx +169 -0
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/index.tsx +76 -0
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/models.ts +61 -0
- package/src/TimePeriods/CustomTimePeriod/PopoverCustomTimePeriod/usePickersStartEndDate.ts +91 -0
- package/src/TimePeriods/CustomTimePeriod/index.tsx +63 -0
- package/src/TimePeriods/DateTimePickerInput.tsx +99 -0
- package/src/TimePeriods/SelectedTimePeriod.tsx +99 -0
- package/src/TimePeriods/TimePeriods.cypress.spec.tsx +497 -0
- package/src/TimePeriods/helpers/index.ts +25 -0
- package/src/TimePeriods/index.stories.tsx +74 -0
- package/src/TimePeriods/index.tsx +77 -0
- package/src/TimePeriods/models.ts +103 -0
- package/src/TimePeriods/timePeriods.styles.ts +20 -0
- package/src/TimePeriods/timePeriodsAtoms.ts +113 -0
- package/src/TimePeriods/useDateTimePickerAdapter.ts +329 -0
- 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.
|
|
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
|
+
);
|