@centreon/ui 23.10.18-MON-17793-create-graph-component-centreon-ui.6 → 23.10.18-MON-17793-create-graph-component-centreon-ui.7
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 +1 -1
- package/src/Graph/BasicComponents/Lines/{useDataRegularLines.ts → RegularLines/useDataRegularLines.ts} +3 -4
- package/src/Graph/BasicComponents/Lines/{useDataStackLines.ts → StackedLines/useDataStackLines.ts} +4 -5
- package/src/Graph/BasicComponents/Lines/Threshold/BasicThreshold.tsx +48 -0
- package/src/Graph/BasicComponents/Lines/Threshold/Circle.tsx +51 -0
- package/src/Graph/BasicComponents/Lines/Threshold/index.tsx +60 -20
- package/src/Graph/BasicComponents/Lines/Threshold/models.ts +14 -0
- package/src/Graph/BasicComponents/Lines/{useDataThreshold.ts → Threshold/useDataThreshold.ts} +41 -7
- package/src/Graph/BasicComponents/Lines/Threshold/usePointsOnline.ts +50 -0
- package/src/Graph/BasicComponents/Lines/index.tsx +38 -13
- package/src/Graph/BasicComponents/Lines/models.ts +5 -1
- package/src/Graph/BasicComponents/useFilterLines.ts +6 -15
- package/src/Graph/Graph.tsx +7 -6
- package/src/Graph/helpers/index.ts +28 -1
- package/src/Graph/index.stories.tsx +1 -1
- package/src/Graph/models.ts +5 -1
- package/src/Graph/timeSeries/models.ts +5 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@centreon/ui",
|
|
3
|
-
"version": "23.10.18-MON-17793-create-graph-component-centreon-ui.
|
|
3
|
+
"version": "23.10.18-MON-17793-create-graph-component-centreon-ui.7",
|
|
4
4
|
"description": "Centreon UI Components",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { ScaleLinear } from 'd3-scale';
|
|
2
2
|
|
|
3
|
-
import { Line, TimeValue } from '
|
|
4
|
-
import { displayArea } from '
|
|
5
|
-
|
|
6
|
-
import { AreaRegularLines } from './models';
|
|
3
|
+
import { Line, TimeValue } from '../../../timeSeries/models';
|
|
4
|
+
import { displayArea } from '../../../helpers/index';
|
|
5
|
+
import { AreaRegularLines } from '../models';
|
|
7
6
|
|
|
8
7
|
interface RegularLinesData {
|
|
9
8
|
display: boolean;
|
package/src/Graph/BasicComponents/Lines/{useDataStackLines.ts → StackedLines/useDataStackLines.ts}
RENAMED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ScaleLinear } from 'd3-scale';
|
|
2
2
|
|
|
3
|
-
import { getStackedYScale } from '
|
|
4
|
-
import { displayArea } from '
|
|
5
|
-
import { Line, TimeValue } from '
|
|
6
|
-
|
|
7
|
-
import { AreaStackedLines } from './models';
|
|
3
|
+
import { getStackedYScale } from '../../../timeSeries';
|
|
4
|
+
import { displayArea } from '../../../helpers/index';
|
|
5
|
+
import { Line, TimeValue } from '../../../timeSeries/models';
|
|
6
|
+
import { AreaStackedLines } from '../models';
|
|
8
7
|
|
|
9
8
|
interface StackedLinesData {
|
|
10
9
|
displayAreaInvertedStackedLines: boolean;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { curveBasis } from '@visx/curve';
|
|
2
|
+
import { ScaleLinear } from 'd3-scale';
|
|
3
|
+
import { Threshold } from '@visx/threshold';
|
|
4
|
+
|
|
5
|
+
import { TimeValue } from '../../../timeSeries/models';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
getX: ScaleLinear<number, number>;
|
|
9
|
+
getY0: ScaleLinear<number, number>;
|
|
10
|
+
getY1: ScaleLinear<number, number>;
|
|
11
|
+
graphHeight: number;
|
|
12
|
+
lineColorY0: string;
|
|
13
|
+
lineColorY1: string;
|
|
14
|
+
timeSeries: Array<TimeValue>;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const BasicThreshold = ({
|
|
18
|
+
getX,
|
|
19
|
+
getY0,
|
|
20
|
+
getY1,
|
|
21
|
+
lineColorY0,
|
|
22
|
+
lineColorY1,
|
|
23
|
+
graphHeight,
|
|
24
|
+
timeSeries
|
|
25
|
+
}: Props): JSX.Element => {
|
|
26
|
+
return (
|
|
27
|
+
<Threshold
|
|
28
|
+
aboveAreaProps={{
|
|
29
|
+
fill: lineColorY1,
|
|
30
|
+
fillOpacity: 0.1
|
|
31
|
+
}}
|
|
32
|
+
belowAreaProps={{
|
|
33
|
+
fill: lineColorY0,
|
|
34
|
+
fillOpacity: 0.1
|
|
35
|
+
}}
|
|
36
|
+
clipAboveTo={0}
|
|
37
|
+
clipBelowTo={graphHeight}
|
|
38
|
+
curve={curveBasis}
|
|
39
|
+
data={timeSeries}
|
|
40
|
+
id="threshold"
|
|
41
|
+
x={getX}
|
|
42
|
+
y0={getY0}
|
|
43
|
+
y1={getY1}
|
|
44
|
+
/>
|
|
45
|
+
);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export default BasicThreshold;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Shape } from '@visx/visx';
|
|
2
|
+
import { isEmpty, isNil, prop } from 'ramda';
|
|
3
|
+
import { ScaleLinear } from 'd3-scale';
|
|
4
|
+
|
|
5
|
+
import { getTime } from '../../../timeSeries/index';
|
|
6
|
+
import { TimeValue } from '../../../timeSeries/models';
|
|
7
|
+
|
|
8
|
+
import usePointsOnline from './usePointsOnline';
|
|
9
|
+
import { Data } from './models';
|
|
10
|
+
|
|
11
|
+
interface Circle {
|
|
12
|
+
dataY0: Data;
|
|
13
|
+
dataY1: Data;
|
|
14
|
+
dataYOrigin: Data;
|
|
15
|
+
timeValue: TimeValue;
|
|
16
|
+
variation: number;
|
|
17
|
+
xScale: ScaleLinear<number, number>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const Circle = ({
|
|
21
|
+
timeValue,
|
|
22
|
+
dataY0,
|
|
23
|
+
dataY1,
|
|
24
|
+
dataYOrigin,
|
|
25
|
+
xScale,
|
|
26
|
+
variation
|
|
27
|
+
}: Circle): JSX.Element | null => {
|
|
28
|
+
const { metric: metricY0, yScale: y0Scale } = dataY0;
|
|
29
|
+
const { metric: metricY1, yScale: y1Scale } = dataY1;
|
|
30
|
+
const { metric: metricYOrigin, yScale } = dataYOrigin;
|
|
31
|
+
|
|
32
|
+
const x = xScale(getTime(timeValue));
|
|
33
|
+
const y = yScale(prop(metricYOrigin, timeValue));
|
|
34
|
+
|
|
35
|
+
const y0 = y0Scale(prop(metricY0, timeValue) + variation);
|
|
36
|
+
|
|
37
|
+
const y1 = y1Scale(prop(metricY1, timeValue) - variation);
|
|
38
|
+
const coordinate = usePointsOnline({
|
|
39
|
+
pointLower: { x, y: y0 },
|
|
40
|
+
pointOrigin: { x, y },
|
|
41
|
+
pointUpper: { x, y: y1 }
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (isEmpty(coordinate) || isNil(coordinate)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return <Shape.Circle cx={coordinate.x} cy={coordinate.y} fill="red" r={2} />;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export default Circle;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { curveBasis } from '@visx/curve';
|
|
2
|
-
import {
|
|
2
|
+
import { LinePath } from '@visx/shape';
|
|
3
3
|
import { ScaleLinear } from 'd3-scale';
|
|
4
4
|
import { prop } from 'ramda';
|
|
5
5
|
|
|
6
|
+
import { useTheme } from '@mui/material/styles';
|
|
7
|
+
|
|
6
8
|
import { getTime } from '../../../timeSeries/index';
|
|
7
9
|
import { TimeValue } from '../../../timeSeries/models';
|
|
8
10
|
|
|
11
|
+
import BasicThreshold from './BasicThreshold';
|
|
9
12
|
import { Data } from './models';
|
|
10
13
|
|
|
11
14
|
interface Props {
|
|
@@ -13,6 +16,7 @@ interface Props {
|
|
|
13
16
|
dataY1: Data;
|
|
14
17
|
graphHeight: number;
|
|
15
18
|
timeSeries: Array<TimeValue>;
|
|
19
|
+
variation?: number;
|
|
16
20
|
xScale: ScaleLinear<number, number>;
|
|
17
21
|
}
|
|
18
22
|
|
|
@@ -21,30 +25,66 @@ const ThresholdLines = ({
|
|
|
21
25
|
dataY1,
|
|
22
26
|
timeSeries,
|
|
23
27
|
xScale,
|
|
24
|
-
graphHeight
|
|
28
|
+
graphHeight,
|
|
29
|
+
variation
|
|
25
30
|
}: Props): JSX.Element => {
|
|
31
|
+
const theme = useTheme();
|
|
32
|
+
|
|
26
33
|
const { lineColor: lineColorY0, metric: metricY0, yScale: y0Scale } = dataY0;
|
|
27
34
|
const { lineColor: lineColorY1, metric: metricY1, yScale: y1Scale } = dataY1;
|
|
28
35
|
|
|
36
|
+
const getX = (timeValue: TimeValue): number =>
|
|
37
|
+
xScale(getTime(timeValue)) as number;
|
|
38
|
+
|
|
39
|
+
if (!variation) {
|
|
40
|
+
const getY0 = (timeValue: TimeValue): number =>
|
|
41
|
+
y0Scale(prop(metricY0, timeValue)) ?? null;
|
|
42
|
+
const getY1 = (timeValue: TimeValue): number =>
|
|
43
|
+
y1Scale(prop(metricY1, timeValue)) ?? null;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<BasicThreshold
|
|
47
|
+
getX={getX}
|
|
48
|
+
getY0={getY0}
|
|
49
|
+
getY1={getY1}
|
|
50
|
+
graphHeight={graphHeight}
|
|
51
|
+
lineColorY0={lineColorY0}
|
|
52
|
+
lineColorY1={lineColorY1}
|
|
53
|
+
timeSeries={timeSeries}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const getY0 = (timeValue: TimeValue): number =>
|
|
59
|
+
y0Scale(prop(metricY0, timeValue) + variation) ?? null;
|
|
60
|
+
|
|
61
|
+
const getY1 = (timeValue: TimeValue): number =>
|
|
62
|
+
y1Scale(prop(metricY1, timeValue) - variation) ?? null;
|
|
63
|
+
|
|
64
|
+
const props = {
|
|
65
|
+
curve: curveBasis,
|
|
66
|
+
data: timeSeries,
|
|
67
|
+
stroke: theme.palette.secondary.main,
|
|
68
|
+
strokeDasharray: 5,
|
|
69
|
+
strokeOpacity: 0.8,
|
|
70
|
+
x: getX
|
|
71
|
+
};
|
|
72
|
+
|
|
29
73
|
return (
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
x={(timeValue: TimeValue): number => xScale(getTime(timeValue)) as number}
|
|
45
|
-
y0={(timeValue): number => y0Scale(prop(metricY0, timeValue)) ?? null}
|
|
46
|
-
y1={(timeValue): number => y1Scale(prop(metricY1, timeValue)) ?? null}
|
|
47
|
-
/>
|
|
74
|
+
<>
|
|
75
|
+
<BasicThreshold
|
|
76
|
+
getX={getX}
|
|
77
|
+
getY0={getY0}
|
|
78
|
+
getY1={getY1}
|
|
79
|
+
graphHeight={graphHeight}
|
|
80
|
+
lineColorY0={lineColorY0}
|
|
81
|
+
lineColorY1={lineColorY1}
|
|
82
|
+
timeSeries={timeSeries}
|
|
83
|
+
/>
|
|
84
|
+
|
|
85
|
+
<LinePath {...props} y={getY0} />
|
|
86
|
+
<LinePath {...props} y={getY1} />
|
|
87
|
+
</>
|
|
48
88
|
);
|
|
49
89
|
};
|
|
50
90
|
|
|
@@ -5,3 +5,17 @@ export interface Data {
|
|
|
5
5
|
metric: string;
|
|
6
6
|
yScale: ScaleLinear<number, number>;
|
|
7
7
|
}
|
|
8
|
+
|
|
9
|
+
export interface Point {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Props {
|
|
15
|
+
pointLower: Point;
|
|
16
|
+
pointOrigin: Point;
|
|
17
|
+
pointUpper: Point;
|
|
18
|
+
}
|
|
19
|
+
export interface Online extends Props {
|
|
20
|
+
maxDistance?: number;
|
|
21
|
+
}
|
package/src/Graph/BasicComponents/Lines/{useDataThreshold.ts → Threshold/useDataThreshold.ts}
RENAMED
|
@@ -1,26 +1,32 @@
|
|
|
1
1
|
import { equals, isNil } from 'ramda';
|
|
2
2
|
import { ScaleLinear } from 'd3-scale';
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import {
|
|
5
|
+
findLineOfOriginMetricThreshold,
|
|
6
|
+
lowerLineName,
|
|
7
|
+
upperLineName
|
|
8
|
+
} from '../../../helpers/index';
|
|
9
|
+
import { getUnits, getYScale } from '../../../timeSeries/index';
|
|
10
|
+
import { Line } from '../../../timeSeries/models';
|
|
7
11
|
|
|
8
|
-
import { Data } from './
|
|
12
|
+
import { Data } from './models';
|
|
9
13
|
|
|
10
14
|
interface DataThreshold {
|
|
11
15
|
dataY0?: Data;
|
|
12
16
|
dataY1?: Data;
|
|
17
|
+
dataYOrigin?: Data;
|
|
13
18
|
displayThreshold: boolean;
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
interface Props {
|
|
22
|
+
display: boolean;
|
|
17
23
|
leftScale: ScaleLinear<number, number>;
|
|
18
24
|
lines: Array<Line>;
|
|
19
25
|
rightScale: ScaleLinear<number, number>;
|
|
20
26
|
}
|
|
21
27
|
|
|
22
28
|
const useDataThreshold = (areaThreshold: Props): DataThreshold => {
|
|
23
|
-
const { lines, leftScale, rightScale } = areaThreshold;
|
|
29
|
+
const { lines, leftScale, rightScale, display } = areaThreshold;
|
|
24
30
|
|
|
25
31
|
const dataMetricUpper = lines.find((line) =>
|
|
26
32
|
equals(line.name, upperLineName)
|
|
@@ -30,10 +36,21 @@ const useDataThreshold = (areaThreshold: Props): DataThreshold => {
|
|
|
30
36
|
equals(line.name, lowerLineName)
|
|
31
37
|
);
|
|
32
38
|
|
|
33
|
-
const
|
|
39
|
+
const dataMetricOrigin = findLineOfOriginMetricThreshold(lines);
|
|
40
|
+
|
|
41
|
+
const displayThreshold =
|
|
42
|
+
!isNil(dataMetricLower) &&
|
|
43
|
+
!isNil(dataMetricUpper) &&
|
|
44
|
+
display &&
|
|
45
|
+
!isNil(dataMetricOrigin[0]);
|
|
34
46
|
|
|
35
47
|
if (!displayThreshold) {
|
|
36
|
-
return {
|
|
48
|
+
return {
|
|
49
|
+
dataY0: undefined,
|
|
50
|
+
dataY1: undefined,
|
|
51
|
+
dataYOrigin: undefined,
|
|
52
|
+
displayThreshold
|
|
53
|
+
};
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
const [, secondUnit, thirdUnit] = getUnits(lines);
|
|
@@ -52,6 +69,13 @@ const useDataThreshold = (areaThreshold: Props): DataThreshold => {
|
|
|
52
69
|
lineColor: lineColorY0
|
|
53
70
|
} = dataMetricLower;
|
|
54
71
|
|
|
72
|
+
const {
|
|
73
|
+
metric: metricOrigin,
|
|
74
|
+
unit: unitYOrigin,
|
|
75
|
+
invert: invertYOrigin,
|
|
76
|
+
lineColor: lineColorYOrigin
|
|
77
|
+
} = dataMetricOrigin[0];
|
|
78
|
+
|
|
55
79
|
const y1Scale = getYScale({
|
|
56
80
|
hasMoreThanTwoUnits: !isNil(thirdUnit),
|
|
57
81
|
invert: invertY1,
|
|
@@ -70,9 +94,19 @@ const useDataThreshold = (areaThreshold: Props): DataThreshold => {
|
|
|
70
94
|
unit: unitY0
|
|
71
95
|
});
|
|
72
96
|
|
|
97
|
+
const yScale = getYScale({
|
|
98
|
+
hasMoreThanTwoUnits: !isNil(thirdUnit),
|
|
99
|
+
invert: invertYOrigin,
|
|
100
|
+
leftScale,
|
|
101
|
+
rightScale,
|
|
102
|
+
secondUnit,
|
|
103
|
+
unit: unitYOrigin
|
|
104
|
+
});
|
|
105
|
+
|
|
73
106
|
return {
|
|
74
107
|
dataY0: { lineColor: lineColorY0, metric: metricY0, yScale: y0Scale },
|
|
75
108
|
dataY1: { lineColor: lineColorY1, metric: metricY1, yScale: y1Scale },
|
|
109
|
+
dataYOrigin: { lineColor: lineColorYOrigin, metric: metricOrigin, yScale },
|
|
76
110
|
displayThreshold
|
|
77
111
|
};
|
|
78
112
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { isNil } from 'ramda';
|
|
2
|
+
|
|
3
|
+
import { Online, Point, Props } from './models';
|
|
4
|
+
|
|
5
|
+
const usePointsOnline = ({
|
|
6
|
+
pointOrigin,
|
|
7
|
+
pointUpper,
|
|
8
|
+
pointLower
|
|
9
|
+
}: Props): Point | null => {
|
|
10
|
+
const isPointDefined = ({ x, y }: Point): boolean => !isNil(x) && !isNil(y);
|
|
11
|
+
|
|
12
|
+
const arePointsDefined =
|
|
13
|
+
isPointDefined(pointOrigin) &&
|
|
14
|
+
isPointDefined(pointUpper) &&
|
|
15
|
+
isPointDefined(pointLower);
|
|
16
|
+
|
|
17
|
+
const isOnLine = ({
|
|
18
|
+
pointOrigin: origin,
|
|
19
|
+
pointLower: firstPoint,
|
|
20
|
+
pointUpper: secondPoint,
|
|
21
|
+
maxDistance = 0
|
|
22
|
+
}: Online): boolean => {
|
|
23
|
+
const { x, y } = origin;
|
|
24
|
+
const { x: x1, y: y1 } = firstPoint;
|
|
25
|
+
const { x: x2, y: y2 } = secondPoint;
|
|
26
|
+
|
|
27
|
+
const dxL = x2 - x1;
|
|
28
|
+
const dyL = y2 - y1;
|
|
29
|
+
const dxP = x - x1;
|
|
30
|
+
const dyP = y - y1;
|
|
31
|
+
|
|
32
|
+
const squareLen = dxL * dxL + dyL * dyL;
|
|
33
|
+
const dotProd = dxP * dxL + dyP * dyL;
|
|
34
|
+
const crossProd = dyP * dxL - dxP * dyL;
|
|
35
|
+
|
|
36
|
+
const distance = Math.abs(crossProd) / Math.sqrt(squareLen);
|
|
37
|
+
|
|
38
|
+
return distance <= maxDistance && dotProd >= 0 && dotProd <= squareLen;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const arePointsOnline = isOnLine({
|
|
42
|
+
pointLower,
|
|
43
|
+
pointOrigin,
|
|
44
|
+
pointUpper
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
return !arePointsOnline && arePointsDefined ? pointOrigin : null;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default usePointsOnline;
|
|
@@ -10,13 +10,14 @@ import { getUnits, getYScale } from '../../timeSeries';
|
|
|
10
10
|
import { Line } from '../../timeSeries/models';
|
|
11
11
|
|
|
12
12
|
import RegularLine from './RegularLines';
|
|
13
|
+
import useDataRegularLines from './RegularLines/useDataRegularLines';
|
|
13
14
|
import StackedLines from './StackedLines';
|
|
15
|
+
import useDataStackedLines from './StackedLines/useDataStackLines';
|
|
14
16
|
import ThresholdLines from './Threshold';
|
|
15
|
-
import
|
|
16
|
-
import useDataRegularLines from './useDataRegularLines';
|
|
17
|
-
import useDataStackedLines from './useDataStackLines';
|
|
18
|
-
import useDataThreshold from './useDataThreshold';
|
|
17
|
+
import AwesomeCircles from './Threshold/Circle';
|
|
19
18
|
import { Data } from './Threshold/models';
|
|
19
|
+
import useDataThreshold from './Threshold/useDataThreshold';
|
|
20
|
+
import { Shape } from './models';
|
|
20
21
|
|
|
21
22
|
interface AnchorPoint {
|
|
22
23
|
renderRegularLinesAnchorPoint: (args: RegularLinesAnchorPoint) => ReactNode;
|
|
@@ -33,7 +34,8 @@ const Lines = ({ height, shape, anchorPoint }: Props): JSX.Element => {
|
|
|
33
34
|
const { areaRegularLines, areaStackedLines, areaThreshold } = shape;
|
|
34
35
|
const { renderRegularLinesAnchorPoint, renderStackedAnchorPoint } =
|
|
35
36
|
anchorPoint;
|
|
36
|
-
const { lines, leftScale, rightScale, timeSeries, xScale } =
|
|
37
|
+
const { lines, leftScale, rightScale, timeSeries, xScale, display } =
|
|
38
|
+
areaThreshold;
|
|
37
39
|
|
|
38
40
|
const {
|
|
39
41
|
displayAreaInvertedStackedLines,
|
|
@@ -55,7 +57,8 @@ const Lines = ({ height, shape, anchorPoint }: Props): JSX.Element => {
|
|
|
55
57
|
lines: regularLines
|
|
56
58
|
} = useDataRegularLines(areaRegularLines);
|
|
57
59
|
|
|
58
|
-
const { dataY0, dataY1, displayThreshold } = useDataThreshold({
|
|
60
|
+
const { dataY0, dataY1, dataYOrigin, displayThreshold } = useDataThreshold({
|
|
61
|
+
display,
|
|
59
62
|
leftScale,
|
|
60
63
|
lines,
|
|
61
64
|
rightScale
|
|
@@ -83,13 +86,35 @@ const Lines = ({ height, shape, anchorPoint }: Props): JSX.Element => {
|
|
|
83
86
|
)}
|
|
84
87
|
|
|
85
88
|
{displayThreshold && (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
<>
|
|
90
|
+
<ThresholdLines
|
|
91
|
+
dataY0={dataY0 as Data}
|
|
92
|
+
dataY1={dataY1 as Data}
|
|
93
|
+
graphHeight={height}
|
|
94
|
+
timeSeries={timeSeries}
|
|
95
|
+
xScale={xScale}
|
|
96
|
+
/>
|
|
97
|
+
<ThresholdLines
|
|
98
|
+
dataY0={dataY0 as Data}
|
|
99
|
+
dataY1={dataY1 as Data}
|
|
100
|
+
graphHeight={height}
|
|
101
|
+
timeSeries={timeSeries}
|
|
102
|
+
variation={areaThreshold?.variation}
|
|
103
|
+
xScale={xScale}
|
|
104
|
+
/>
|
|
105
|
+
{areaThreshold?.variation &&
|
|
106
|
+
timeSeries.map((timeValue) => (
|
|
107
|
+
<AwesomeCircles
|
|
108
|
+
dataY0={dataY0 as Data}
|
|
109
|
+
dataY1={dataY1 as Data}
|
|
110
|
+
dataYOrigin={dataYOrigin as Data}
|
|
111
|
+
key={timeValue.timeTick}
|
|
112
|
+
timeValue={timeValue}
|
|
113
|
+
variation={areaThreshold?.variation as number}
|
|
114
|
+
xScale={xScale}
|
|
115
|
+
/>
|
|
116
|
+
))}
|
|
117
|
+
</>
|
|
93
118
|
)}
|
|
94
119
|
|
|
95
120
|
{displayAreaRegularLines
|
|
@@ -26,8 +26,12 @@ export interface AreaRegularLines extends ShapeGraphData {
|
|
|
26
26
|
timeSeries: Array<TimeValue>;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
export interface AreaThreshold extends AreaRegularLines {
|
|
30
|
+
variation?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
29
33
|
export interface Shape {
|
|
30
34
|
areaRegularLines: AreaRegularLines;
|
|
31
35
|
areaStackedLines: AreaStackedLines;
|
|
32
|
-
areaThreshold:
|
|
36
|
+
areaThreshold: AreaThreshold;
|
|
33
37
|
}
|
|
@@ -4,7 +4,11 @@ import { useAtom } from 'jotai';
|
|
|
4
4
|
import { equals, propEq, reject } from 'ramda';
|
|
5
5
|
|
|
6
6
|
import { linesGraphAtom } from '../graphAtoms';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
findLineOfOriginMetricThreshold,
|
|
9
|
+
lowerLineName,
|
|
10
|
+
upperLineName
|
|
11
|
+
} from '../helpers';
|
|
8
12
|
import { Line } from '../timeSeries/models';
|
|
9
13
|
|
|
10
14
|
interface UseFilterLines {
|
|
@@ -25,20 +29,7 @@ const useFilterLines = ({
|
|
|
25
29
|
|
|
26
30
|
const displayedLines = reject(propEq('display', false), linesGraph ?? lines);
|
|
27
31
|
const filterLines = (): Array<Line> => {
|
|
28
|
-
const
|
|
29
|
-
const { metric } = line;
|
|
30
|
-
|
|
31
|
-
return metric.includes('_upper_thresholds')
|
|
32
|
-
? metric.replace('_upper_thresholds', '')
|
|
33
|
-
: null;
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
const originMetric = metrics.find((element) => element);
|
|
37
|
-
|
|
38
|
-
const lineOriginMetric = reject(
|
|
39
|
-
(line: Line) => !equals(line.name, originMetric),
|
|
40
|
-
lines
|
|
41
|
-
);
|
|
32
|
+
const lineOriginMetric = findLineOfOriginMetricThreshold(lines);
|
|
42
33
|
|
|
43
34
|
const findLinesUpperLower = lines.map((line) =>
|
|
44
35
|
equals(line.name, lowerLineName) || equals(line.name, upperLineName)
|
package/src/Graph/Graph.tsx
CHANGED
|
@@ -113,7 +113,6 @@ const Graph = ({
|
|
|
113
113
|
});
|
|
114
114
|
|
|
115
115
|
const commonLinesProps = {
|
|
116
|
-
display: true,
|
|
117
116
|
leftScale,
|
|
118
117
|
rightScale,
|
|
119
118
|
xScale
|
|
@@ -122,21 +121,23 @@ const Graph = ({
|
|
|
122
121
|
const areaThreshold = {
|
|
123
122
|
lines: displayedLines,
|
|
124
123
|
timeSeries,
|
|
125
|
-
...commonLinesProps
|
|
124
|
+
...commonLinesProps,
|
|
125
|
+
...shapeLines?.areaThresholdLines,
|
|
126
|
+
display: shapeLines?.areaThresholdLines?.display ?? true
|
|
126
127
|
};
|
|
127
128
|
|
|
128
129
|
const areaRegularLines = {
|
|
130
|
+
display: shapeLines?.areaRegularLines?.display ?? true,
|
|
129
131
|
lines: regularLines,
|
|
130
132
|
timeSeries,
|
|
131
|
-
...commonLinesProps
|
|
132
|
-
...shapeLines?.areaRegularLines
|
|
133
|
+
...commonLinesProps
|
|
133
134
|
};
|
|
134
135
|
|
|
135
136
|
const areaStackedLines = {
|
|
137
|
+
display: shapeLines?.areaStackedLines?.display ?? true,
|
|
136
138
|
invertedStackedLinesData,
|
|
137
139
|
stackedLinesData,
|
|
138
|
-
...commonLinesProps
|
|
139
|
-
...shapeLines?.areaStackedLines
|
|
140
|
+
...commonLinesProps
|
|
140
141
|
};
|
|
141
142
|
|
|
142
143
|
const displayRegularLinesAnchorPoint =
|
|
@@ -1,10 +1,21 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
gte,
|
|
3
|
+
isNil,
|
|
4
|
+
prop,
|
|
5
|
+
propEq,
|
|
6
|
+
reject,
|
|
7
|
+
sortBy,
|
|
8
|
+
gt,
|
|
9
|
+
isEmpty,
|
|
10
|
+
equals
|
|
11
|
+
} from 'ramda';
|
|
2
12
|
import dayjs from 'dayjs';
|
|
3
13
|
|
|
4
14
|
import { getLineData, getTimeSeries } from '../timeSeries';
|
|
5
15
|
import { LinesData } from '../BasicComponents/Lines/models';
|
|
6
16
|
import { GraphData, GraphInterval } from '../models';
|
|
7
17
|
import { dateFormat, timeFormat } from '../common';
|
|
18
|
+
import { Line } from '../timeSeries/models';
|
|
8
19
|
|
|
9
20
|
export const adjustGraphData = (graphData: GraphData): LinesData => {
|
|
10
21
|
const lines = getLineData(graphData);
|
|
@@ -49,3 +60,19 @@ export const displayArea = (data: unknown): boolean =>
|
|
|
49
60
|
|
|
50
61
|
export const lowerLineName = 'Lower Threshold';
|
|
51
62
|
export const upperLineName = 'Upper Threshold';
|
|
63
|
+
|
|
64
|
+
export const findLineOfOriginMetricThreshold = (
|
|
65
|
+
lines: Array<Line>
|
|
66
|
+
): Array<Line> => {
|
|
67
|
+
const metrics = lines.map((line) => {
|
|
68
|
+
const { metric } = line;
|
|
69
|
+
|
|
70
|
+
return metric.includes('_upper_thresholds')
|
|
71
|
+
? metric.replace('_upper_thresholds', '')
|
|
72
|
+
: null;
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const originMetric = metrics.find((element) => element);
|
|
76
|
+
|
|
77
|
+
return reject((line: Line) => !equals(line.name, originMetric), lines);
|
|
78
|
+
};
|
|
@@ -165,7 +165,7 @@ const GraphAndTimePeriod = (args): JSX.Element => {
|
|
|
165
165
|
annotationEvent={annotationEventData}
|
|
166
166
|
end={end}
|
|
167
167
|
loading={false}
|
|
168
|
-
shapeLines={{ areaThresholdLines: { display: true } }}
|
|
168
|
+
shapeLines={{ areaThresholdLines: { display: true, variation: 1.5 } }}
|
|
169
169
|
start={start}
|
|
170
170
|
timeShiftZones={{ enable: true, getInterval }}
|
|
171
171
|
tooltip={{
|
package/src/Graph/models.ts
CHANGED
|
@@ -98,8 +98,12 @@ export interface Area {
|
|
|
98
98
|
display: boolean;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
export interface ThresholdArea extends Area {
|
|
102
|
+
variation?: number;
|
|
103
|
+
}
|
|
104
|
+
|
|
101
105
|
export interface GlobalAreaLines {
|
|
102
106
|
areaRegularLines: Area;
|
|
103
107
|
areaStackedLines: Area;
|
|
104
|
-
areaThresholdLines:
|
|
108
|
+
areaThresholdLines: ThresholdArea;
|
|
105
109
|
}
|
|
@@ -22,10 +22,11 @@ export interface Metric {
|
|
|
22
22
|
unit: string;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
type TimeSeries = { timeTick: string };
|
|
26
|
+
|
|
27
|
+
export type TimeValue = TimeSeries & {
|
|
28
|
+
[field: string]: number;
|
|
29
|
+
};
|
|
29
30
|
|
|
30
31
|
export interface Line {
|
|
31
32
|
areaColor: string;
|