@centreon/ui 25.2.2 → 25.2.4
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/BarChart/BarChart.cypress.spec.tsx +2 -2
- package/src/Graph/BarChart/BarGroup.tsx +19 -59
- package/src/Graph/BarChart/MemoizedGroup.tsx +123 -0
- package/src/Graph/BarChart/ResponsiveBarChart.tsx +17 -4
- package/src/Graph/Chart/Chart.cypress.spec.tsx +13 -21
- package/src/Graph/Chart/Chart.stories.tsx +1 -1
- package/src/Graph/Chart/Chart.tsx +50 -33
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/GuidingLines.tsx +3 -3
- package/src/Graph/Chart/InteractiveComponents/AnchorPoint/useTickGraph.ts +19 -6
- package/src/Graph/common/Axes/index.tsx +1 -1
- package/src/Graph/common/Axes/useAxisY.ts +8 -4
- package/src/Graph/common/BaseChart/ChartSvgWrapper.tsx +12 -4
- package/src/Graph/common/BaseChart/useComputeBaseChartDimensions.ts +6 -4
- package/src/Graph/common/BaseChart/useComputeYAxisMaxCharacters.ts +92 -0
- package/src/Graph/common/models.ts +7 -8
- package/src/Graph/common/timeSeries/index.test.ts +1 -1
- package/src/Graph/common/timeSeries/index.ts +1 -7
- package/src/Graph/common/utils.ts +49 -1
- package/src/Graph/mockedData/lastDayWithNullValues.json +46 -12
- package/src/Graph/mockedData/pingServiceLinesBars.json +47 -47
- package/src/components/Zoom/Zoom.tsx +1 -1
- package/src/components/Zoom/ZoomContent.tsx +140 -133
- package/src/components/Zoom/models.ts +0 -2
- package/src/Graph/common/timeSeries/index.test.ts-E +0 -622
package/package.json
CHANGED
|
@@ -61,14 +61,14 @@ const checkWidth = (orientation): void => {
|
|
|
61
61
|
cy.get('g[class*="visx-rows"] > line')
|
|
62
62
|
.eq(0)
|
|
63
63
|
.should('have.attr', 'x2')
|
|
64
|
-
.and('equal', '
|
|
64
|
+
.and('equal', '1145');
|
|
65
65
|
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
cy.get('g[class*="visx-rows"] > line')
|
|
69
69
|
.eq(0)
|
|
70
70
|
.should('have.attr', 'x2')
|
|
71
|
-
.and('equal', '
|
|
71
|
+
.and('equal', '1180');
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
describe('Bar chart', () => {
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import { memo, useMemo } from 'react';
|
|
2
|
-
|
|
3
|
-
import { Group } from '@visx/group';
|
|
4
1
|
import { scaleBand, scaleOrdinal } from '@visx/scale';
|
|
5
2
|
import { BarGroupHorizontal, BarGroup as VisxBarGroup } from '@visx/shape';
|
|
6
3
|
import { ScaleLinear } from 'd3-scale';
|
|
7
4
|
import { difference, equals, keys, omit, pick, pluck, uniq } from 'ramda';
|
|
5
|
+
import { memo, useMemo } from 'react';
|
|
8
6
|
|
|
9
7
|
import { useDeepMemo } from '../../utils';
|
|
10
8
|
import {
|
|
@@ -14,8 +12,7 @@ import {
|
|
|
14
12
|
getUnits
|
|
15
13
|
} from '../common/timeSeries';
|
|
16
14
|
import { Line, TimeValue } from '../common/timeSeries/models';
|
|
17
|
-
|
|
18
|
-
import BarStack from './BarStack';
|
|
15
|
+
import MemoizedGroup from './MemoizedGroup';
|
|
19
16
|
import { BarStyle } from './models';
|
|
20
17
|
|
|
21
18
|
// Minimum value for logarithmic scale to avoid log(0)
|
|
@@ -161,60 +158,23 @@ const BarGroup = ({
|
|
|
161
158
|
{...barComponentBaseProps}
|
|
162
159
|
>
|
|
163
160
|
{(barGroups) =>
|
|
164
|
-
barGroups.map((barGroup) =>
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
: notStackedTimeSeries.map((timeSerie) => ({
|
|
182
|
-
timeTick: timeSerie.timeTick,
|
|
183
|
-
[bar.key]: timeSerie[Number(bar.key)]
|
|
184
|
-
}));
|
|
185
|
-
|
|
186
|
-
return isStackedBar ? (
|
|
187
|
-
<BarStack
|
|
188
|
-
key={`bar-${barGroup.index}-${bar.width}-${bar.y}-${bar.height}-${bar.x}`}
|
|
189
|
-
barIndex={barGroup.index}
|
|
190
|
-
barPadding={isHorizontal ? bar.x : bar.y}
|
|
191
|
-
barStyle={barStyle}
|
|
192
|
-
barWidth={isHorizontal ? bar.width : bar.height}
|
|
193
|
-
isHorizontal={isHorizontal}
|
|
194
|
-
isTooltipHidden={isTooltipHidden}
|
|
195
|
-
lines={linesBar}
|
|
196
|
-
timeSeries={timeSeriesBar}
|
|
197
|
-
yScale={yScalesPerUnit[bar.key.replace('stacked-', '')]}
|
|
198
|
-
neutralValue={neutralValue}
|
|
199
|
-
/>
|
|
200
|
-
) : (
|
|
201
|
-
<BarStack
|
|
202
|
-
key={`bar-${barGroup.index}-${bar.width}-${bar.y}-${bar.height}-${bar.x}`}
|
|
203
|
-
barIndex={barGroup.index}
|
|
204
|
-
barPadding={isHorizontal ? bar.x : bar.y}
|
|
205
|
-
barStyle={barStyle}
|
|
206
|
-
barWidth={isHorizontal ? bar.width : bar.height}
|
|
207
|
-
isHorizontal={isHorizontal}
|
|
208
|
-
isTooltipHidden={isTooltipHidden}
|
|
209
|
-
lines={[linesBar]}
|
|
210
|
-
timeSeries={timeSeriesBar}
|
|
211
|
-
yScale={yScalesPerUnit[linesBar.unit]}
|
|
212
|
-
neutralValue={neutralValue}
|
|
213
|
-
/>
|
|
214
|
-
);
|
|
215
|
-
})}
|
|
216
|
-
</Group>
|
|
217
|
-
))
|
|
161
|
+
barGroups.map((barGroup, index) => {
|
|
162
|
+
return (
|
|
163
|
+
<MemoizedGroup
|
|
164
|
+
key={`bar-group-${barGroup.index}-${barGroup.x0}`}
|
|
165
|
+
barGroup={barGroup}
|
|
166
|
+
barStyle={barStyle}
|
|
167
|
+
stackedLinesTimeSeriesPerUnit={stackedLinesTimeSeriesPerUnit}
|
|
168
|
+
notStackedTimeSeries={notStackedTimeSeries}
|
|
169
|
+
notStackedLines={notStackedLines}
|
|
170
|
+
isTooltipHidden={isTooltipHidden}
|
|
171
|
+
isHorizontal={isHorizontal}
|
|
172
|
+
neutralValue={neutralValue}
|
|
173
|
+
yScalesPerUnit={yScalesPerUnit}
|
|
174
|
+
barIndex={index}
|
|
175
|
+
/>
|
|
176
|
+
);
|
|
177
|
+
})
|
|
218
178
|
}
|
|
219
179
|
</BarComponent>
|
|
220
180
|
);
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Group } from '@visx/group';
|
|
2
|
+
import { BarGroup } from '@visx/shape/lib/types';
|
|
3
|
+
import { ScaleLinear } from 'd3-scale';
|
|
4
|
+
import { equals, omit } from 'ramda';
|
|
5
|
+
import { memo } from 'react';
|
|
6
|
+
import { Line, TimeValue } from '../common/timeSeries/models';
|
|
7
|
+
import BarStack from './BarStack';
|
|
8
|
+
import { BarStyle } from './models';
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
neutralValue: number;
|
|
12
|
+
isTooltipHidden: boolean;
|
|
13
|
+
barStyle: BarStyle;
|
|
14
|
+
yScalesPerUnit: Record<string, ScaleLinear<number, number>>;
|
|
15
|
+
stackedLinesTimeSeriesPerUnit: Record<
|
|
16
|
+
string,
|
|
17
|
+
{ lines: Array<Line>; timeSeries: Array<TimeValue> }
|
|
18
|
+
>;
|
|
19
|
+
notStackedLines: Array<Line>;
|
|
20
|
+
notStackedTimeSeries: Array<TimeValue>;
|
|
21
|
+
isHorizontal: boolean;
|
|
22
|
+
barGroup: BarGroup<'id'>;
|
|
23
|
+
barIndex: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const MemoizedGroup = ({
|
|
27
|
+
barGroup,
|
|
28
|
+
stackedLinesTimeSeriesPerUnit,
|
|
29
|
+
notStackedLines,
|
|
30
|
+
notStackedTimeSeries,
|
|
31
|
+
isHorizontal,
|
|
32
|
+
barStyle,
|
|
33
|
+
isTooltipHidden,
|
|
34
|
+
neutralValue,
|
|
35
|
+
yScalesPerUnit,
|
|
36
|
+
barIndex
|
|
37
|
+
}: Props): JSX.Element | null => {
|
|
38
|
+
const hasEmptyValues = barGroup.bars.every(({ key, value }) => {
|
|
39
|
+
if (key.startsWith('stacked-')) {
|
|
40
|
+
const timeValueBar =
|
|
41
|
+
stackedLinesTimeSeriesPerUnit[key.replace('stacked-', '')].timeSeries[
|
|
42
|
+
barIndex
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
return Object.values(omit(['timeTick'], timeValueBar)).every(
|
|
46
|
+
(value) => !value
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return !value;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
if (hasEmptyValues) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Group left={barGroup.x0} top={barGroup.y0}>
|
|
59
|
+
{barGroup.bars.map((bar) => {
|
|
60
|
+
const isStackedBar = bar.key.startsWith('stacked-');
|
|
61
|
+
const linesBar = isStackedBar
|
|
62
|
+
? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')].lines
|
|
63
|
+
: (notStackedLines.find(({ metric_id }) =>
|
|
64
|
+
equals(metric_id, Number(bar.key))
|
|
65
|
+
) as Line);
|
|
66
|
+
const timeSeriesBar = isStackedBar
|
|
67
|
+
? stackedLinesTimeSeriesPerUnit[bar.key.replace('stacked-', '')]
|
|
68
|
+
.timeSeries
|
|
69
|
+
: notStackedTimeSeries.map((timeSerie) => ({
|
|
70
|
+
timeTick: timeSerie.timeTick,
|
|
71
|
+
[bar.key]: timeSerie[Number(bar.key)]
|
|
72
|
+
}));
|
|
73
|
+
|
|
74
|
+
return isStackedBar ? (
|
|
75
|
+
<BarStack
|
|
76
|
+
key={`bar-${barGroup.index}-${bar.width}-${bar.y}-${bar.height}-${bar.x}`}
|
|
77
|
+
barIndex={barGroup.index}
|
|
78
|
+
barPadding={isHorizontal ? bar.x : bar.y}
|
|
79
|
+
barStyle={barStyle}
|
|
80
|
+
barWidth={isHorizontal ? bar.width : bar.height}
|
|
81
|
+
isHorizontal={isHorizontal}
|
|
82
|
+
isTooltipHidden={isTooltipHidden}
|
|
83
|
+
lines={linesBar as Array<Line>}
|
|
84
|
+
timeSeries={timeSeriesBar}
|
|
85
|
+
yScale={yScalesPerUnit[bar.key.replace('stacked-', '')]}
|
|
86
|
+
neutralValue={neutralValue}
|
|
87
|
+
/>
|
|
88
|
+
) : (
|
|
89
|
+
<BarStack
|
|
90
|
+
key={`bar-${barGroup.index}-${bar.width}-${bar.y}-${bar.height}-${bar.x}`}
|
|
91
|
+
barIndex={barGroup.index}
|
|
92
|
+
barPadding={isHorizontal ? bar.x : bar.y}
|
|
93
|
+
barStyle={barStyle}
|
|
94
|
+
barWidth={isHorizontal ? bar.width : bar.height}
|
|
95
|
+
isHorizontal={isHorizontal}
|
|
96
|
+
isTooltipHidden={isTooltipHidden}
|
|
97
|
+
lines={[linesBar as Line]}
|
|
98
|
+
timeSeries={timeSeriesBar}
|
|
99
|
+
yScale={yScalesPerUnit[(linesBar as Line).unit]}
|
|
100
|
+
neutralValue={neutralValue}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
})}
|
|
104
|
+
</Group>
|
|
105
|
+
);
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export default memo(
|
|
109
|
+
MemoizedGroup,
|
|
110
|
+
(prevProps, nextProps) =>
|
|
111
|
+
equals(prevProps.barGroup, nextProps.barGroup) &&
|
|
112
|
+
equals(
|
|
113
|
+
prevProps.stackedLinesTimeSeriesPerUnit,
|
|
114
|
+
nextProps.stackedLinesTimeSeriesPerUnit
|
|
115
|
+
) &&
|
|
116
|
+
equals(prevProps.notStackedLines, nextProps.notStackedLines) &&
|
|
117
|
+
equals(prevProps.notStackedTimeSeries, nextProps.notStackedTimeSeries) &&
|
|
118
|
+
equals(prevProps.isHorizontal, nextProps.isHorizontal) &&
|
|
119
|
+
equals(prevProps.barStyle, nextProps.barStyle) &&
|
|
120
|
+
equals(prevProps.isTooltipHidden, nextProps.isTooltipHidden) &&
|
|
121
|
+
equals(prevProps.neutralValue, nextProps.neutralValue) &&
|
|
122
|
+
equals(prevProps.barIndex, nextProps.barIndex)
|
|
123
|
+
);
|
|
@@ -13,6 +13,7 @@ import { useIntersection } from '../Chart/useChartIntersection';
|
|
|
13
13
|
import BaseChart from '../common/BaseChart/BaseChart';
|
|
14
14
|
import ChartSvgWrapper from '../common/BaseChart/ChartSvgWrapper';
|
|
15
15
|
import { useComputeBaseChartDimensions } from '../common/BaseChart/useComputeBaseChartDimensions';
|
|
16
|
+
import { useComputeYAxisMaxCharacters } from '../common/BaseChart/useComputeYAxisMaxCharacters';
|
|
16
17
|
import Thresholds from '../common/Thresholds/Thresholds';
|
|
17
18
|
import { Thresholds as ThresholdsModel } from '../common/models';
|
|
18
19
|
import {
|
|
@@ -22,7 +23,6 @@ import {
|
|
|
22
23
|
} from '../common/timeSeries';
|
|
23
24
|
import { Line } from '../common/timeSeries/models';
|
|
24
25
|
import { useTooltipStyles } from '../common/useTooltipStyles';
|
|
25
|
-
|
|
26
26
|
import BarGroup from './BarGroup';
|
|
27
27
|
import BarChartTooltip from './Tooltip/BarChartTooltip';
|
|
28
28
|
import { tooltipDataAtom } from './atoms';
|
|
@@ -58,7 +58,7 @@ const ResponsiveBarChart = ({
|
|
|
58
58
|
barStyle,
|
|
59
59
|
skipIntersectionObserver
|
|
60
60
|
}: Props): JSX.Element => {
|
|
61
|
-
const { title, timeSeries, baseAxis, lines } = graphData;
|
|
61
|
+
const { title, timeSeries, baseAxis, lines } = graphData || {};
|
|
62
62
|
|
|
63
63
|
const { classes, cx } = useTooltipStyles();
|
|
64
64
|
|
|
@@ -70,19 +70,30 @@ const ResponsiveBarChart = ({
|
|
|
70
70
|
const { isInViewport } = useIntersection({ element: graphRef?.current });
|
|
71
71
|
|
|
72
72
|
const displayedLines = useMemo(
|
|
73
|
-
() => linesGraph.filter(({ display }) => display),
|
|
73
|
+
() => (linesGraph || []).filter(({ display }) => display),
|
|
74
74
|
[linesGraph]
|
|
75
75
|
);
|
|
76
76
|
|
|
77
77
|
const [firstUnit, secondUnit] = getUnits(displayedLines);
|
|
78
78
|
const allUnits = getUnits(lines);
|
|
79
79
|
|
|
80
|
+
const { maxLeftAxisCharacters, maxRightAxisCharacters } =
|
|
81
|
+
useComputeYAxisMaxCharacters({
|
|
82
|
+
graphData,
|
|
83
|
+
thresholds,
|
|
84
|
+
thresholdUnit,
|
|
85
|
+
axis,
|
|
86
|
+
firstUnit,
|
|
87
|
+
secondUnit
|
|
88
|
+
});
|
|
89
|
+
|
|
80
90
|
const { legendRef, graphWidth, graphHeight } = useComputeBaseChartDimensions({
|
|
81
91
|
hasSecondUnit: Boolean(secondUnit),
|
|
82
92
|
height,
|
|
83
93
|
legendDisplay: legend?.display,
|
|
84
94
|
legendPlacement: legend?.placement,
|
|
85
|
-
width
|
|
95
|
+
width,
|
|
96
|
+
maxAxisCharacters: maxRightAxisCharacters || maxLeftAxisCharacters
|
|
86
97
|
});
|
|
87
98
|
|
|
88
99
|
const thresholdValues = flatten([
|
|
@@ -216,6 +227,8 @@ const ResponsiveBarChart = ({
|
|
|
216
227
|
svgRef={graphSvgRef}
|
|
217
228
|
timeSeries={timeSeries}
|
|
218
229
|
xScale={xScale}
|
|
230
|
+
maxAxisCharacters={maxLeftAxisCharacters}
|
|
231
|
+
hasSecondUnit={Boolean(secondUnit)}
|
|
219
232
|
>
|
|
220
233
|
<>
|
|
221
234
|
<BarGroup
|
|
@@ -129,13 +129,13 @@ const initializeCustomUnits = ({
|
|
|
129
129
|
};
|
|
130
130
|
|
|
131
131
|
const checkGraphWidth = (): void => {
|
|
132
|
-
cy.findByTestId('graph-interaction-zone')
|
|
133
|
-
.should('have.attr', 'width')
|
|
134
|
-
.and('equal', '1170');
|
|
135
|
-
|
|
136
132
|
cy.findByTestId('graph-interaction-zone')
|
|
137
133
|
.should('have.attr', 'height')
|
|
138
134
|
.and('equal', '393');
|
|
135
|
+
|
|
136
|
+
cy.findByTestId('graph-interaction-zone').then((graph) => {
|
|
137
|
+
expect(Number(graph[0].attributes.width.value)).to.be.greaterThan(1170);
|
|
138
|
+
});
|
|
139
139
|
};
|
|
140
140
|
|
|
141
141
|
describe('Line chart', () => {
|
|
@@ -158,8 +158,7 @@ describe('Line chart', () => {
|
|
|
158
158
|
cy.contains('06/18/2023').should('be.visible');
|
|
159
159
|
|
|
160
160
|
cy.contains('0.45 s').should('be.visible');
|
|
161
|
-
cy.contains('
|
|
162
|
-
cy.contains('0.43 s').should('be.visible');
|
|
161
|
+
cy.contains('73.65%').should('be.visible');
|
|
163
162
|
|
|
164
163
|
cy.makeSnapshot();
|
|
165
164
|
});
|
|
@@ -181,7 +180,7 @@ describe('Line chart', () => {
|
|
|
181
180
|
cy.get('[data-metric="connTime"]').should(
|
|
182
181
|
'have.attr',
|
|
183
182
|
'data-highlight',
|
|
184
|
-
'
|
|
183
|
+
'false'
|
|
185
184
|
);
|
|
186
185
|
|
|
187
186
|
cy.makeSnapshot();
|
|
@@ -194,7 +193,7 @@ describe('Line chart', () => {
|
|
|
194
193
|
|
|
195
194
|
cy.contains('Min: 70.31').should('be.visible');
|
|
196
195
|
|
|
197
|
-
cy.findByTestId('graph-interaction-zone').realMouseMove(
|
|
196
|
+
cy.findByTestId('graph-interaction-zone').realMouseMove(1198, 100);
|
|
198
197
|
|
|
199
198
|
cy.get('[data-metric="querytime"]').should('not.exist');
|
|
200
199
|
|
|
@@ -208,10 +207,10 @@ describe('Line chart', () => {
|
|
|
208
207
|
|
|
209
208
|
cy.contains('Min: 70.31').should('be.visible');
|
|
210
209
|
|
|
211
|
-
cy.findByTestId('graph-interaction-zone').realMouseMove(
|
|
210
|
+
cy.findByTestId('graph-interaction-zone').realMouseMove(1170, 100);
|
|
212
211
|
|
|
213
212
|
cy.get('[data-metric="querytime"]').should('be.visible');
|
|
214
|
-
cy.get('[data-metric="hitratio"]').should('
|
|
213
|
+
cy.get('[data-metric="hitratio"]').should('be.visible');
|
|
215
214
|
|
|
216
215
|
cy.makeSnapshot();
|
|
217
216
|
});
|
|
@@ -225,12 +224,12 @@ describe('Line chart', () => {
|
|
|
225
224
|
|
|
226
225
|
cy.findByTestId('graph-interaction-zone').realMouseMove(452, 26);
|
|
227
226
|
|
|
228
|
-
cy.get('[data-metric="
|
|
227
|
+
cy.get('[data-metric="hitratio"]').should(
|
|
229
228
|
'have.attr',
|
|
230
229
|
'data-highlight',
|
|
231
230
|
'true'
|
|
232
231
|
);
|
|
233
|
-
cy.get('[data-metric="
|
|
232
|
+
cy.get('[data-metric="querytime"]').should('not.exist');
|
|
234
233
|
|
|
235
234
|
cy.makeSnapshot();
|
|
236
235
|
});
|
|
@@ -286,7 +285,7 @@ describe('Line chart', () => {
|
|
|
286
285
|
|
|
287
286
|
cy.findByTestId('graph-interaction-zone')
|
|
288
287
|
.should('have.attr', 'width')
|
|
289
|
-
.and('equal', '
|
|
288
|
+
.and('equal', '1200');
|
|
290
289
|
|
|
291
290
|
cy.findByLabelText('Centreon-Server: Round-Trip Average Time')
|
|
292
291
|
.find('[data-icon="true"]')
|
|
@@ -362,8 +361,6 @@ describe('Line chart', () => {
|
|
|
362
361
|
cy.get('[data-as-list="true"]').should('exist');
|
|
363
362
|
|
|
364
363
|
cy.contains(':00 AM').should('be.visible');
|
|
365
|
-
|
|
366
|
-
cy.makeSnapshot();
|
|
367
364
|
});
|
|
368
365
|
|
|
369
366
|
it('displays the legend on the right side of the graph as list when the corresponding props are set', () => {
|
|
@@ -373,8 +370,6 @@ describe('Line chart', () => {
|
|
|
373
370
|
cy.get('[data-as-list="true"]').should('exist');
|
|
374
371
|
|
|
375
372
|
cy.contains(':00 AM').should('be.visible');
|
|
376
|
-
|
|
377
|
-
cy.makeSnapshot();
|
|
378
373
|
});
|
|
379
374
|
});
|
|
380
375
|
|
|
@@ -530,8 +525,7 @@ describe('Line chart', () => {
|
|
|
530
525
|
|
|
531
526
|
checkGraphWidth();
|
|
532
527
|
cy.contains(':00 AM').should('be.visible');
|
|
533
|
-
cy.get('circle[cx="
|
|
534
|
-
cy.get('circle[cy="105.21757370835121"]').should('be.visible');
|
|
528
|
+
cy.get('circle[cx="37.625"]').should('be.visible');
|
|
535
529
|
|
|
536
530
|
cy.makeSnapshot();
|
|
537
531
|
});
|
|
@@ -583,7 +577,6 @@ describe('Lines and bars', () => {
|
|
|
583
577
|
cy.get('path[data-metric="3"]').should('be.visible');
|
|
584
578
|
cy.get('path[data-metric="3"]').should('be.visible');
|
|
585
579
|
cy.findByTestId('stacked-bar-10-0-7650.368581547736').should('be.visible');
|
|
586
|
-
cy.findByTestId('stacked-bar-2-0-10').should('be.visible');
|
|
587
580
|
|
|
588
581
|
cy.makeSnapshot();
|
|
589
582
|
});
|
|
@@ -634,7 +627,6 @@ describe('Lines and bars', () => {
|
|
|
634
627
|
cy.get('path[data-metric="3"]').should('be.visible');
|
|
635
628
|
cy.get('path[data-metric="3"]').should('be.visible');
|
|
636
629
|
cy.findByTestId('stacked-bar-10-0-7650.368581547736').should('be.visible');
|
|
637
|
-
cy.findByTestId('stacked-bar-2-0-10').should('be.visible');
|
|
638
630
|
|
|
639
631
|
cy.makeSnapshot();
|
|
640
632
|
});
|
|
@@ -669,7 +669,7 @@ export const linesAndBarsMixedCenteredZero: Story = {
|
|
|
669
669
|
)
|
|
670
670
|
};
|
|
671
671
|
const CustomYUnits = (props): JSX.Element => {
|
|
672
|
-
const [leftUnit, setLeftUnit] = useState('
|
|
672
|
+
const [leftUnit, setLeftUnit] = useState('B');
|
|
673
673
|
const [rightUnit, setRightUnit] = useState('ms');
|
|
674
674
|
|
|
675
675
|
return (
|
|
@@ -16,6 +16,7 @@ import BarGroup from '../BarChart/BarGroup';
|
|
|
16
16
|
import BaseChart from '../common/BaseChart/BaseChart';
|
|
17
17
|
import ChartSvgWrapper from '../common/BaseChart/ChartSvgWrapper';
|
|
18
18
|
import { useComputeBaseChartDimensions } from '../common/BaseChart/useComputeBaseChartDimensions';
|
|
19
|
+
import { useComputeYAxisMaxCharacters } from '../common/BaseChart/useComputeYAxisMaxCharacters';
|
|
19
20
|
import Thresholds from '../common/Thresholds/Thresholds';
|
|
20
21
|
import type { Thresholds as ThresholdsModel } from '../common/models';
|
|
21
22
|
import {
|
|
@@ -25,7 +26,6 @@ import {
|
|
|
25
26
|
getYScalePerUnit
|
|
26
27
|
} from '../common/timeSeries';
|
|
27
28
|
import type { Line } from '../common/timeSeries/models';
|
|
28
|
-
|
|
29
29
|
import Lines from './BasicComponents/Lines';
|
|
30
30
|
import {
|
|
31
31
|
canDisplayThreshold,
|
|
@@ -140,13 +140,24 @@ const Chart = ({
|
|
|
140
140
|
[displayedLines]
|
|
141
141
|
);
|
|
142
142
|
|
|
143
|
+
const { maxLeftAxisCharacters, maxRightAxisCharacters } =
|
|
144
|
+
useComputeYAxisMaxCharacters({
|
|
145
|
+
graphData,
|
|
146
|
+
thresholds,
|
|
147
|
+
thresholdUnit,
|
|
148
|
+
axis,
|
|
149
|
+
firstUnit,
|
|
150
|
+
secondUnit
|
|
151
|
+
});
|
|
152
|
+
|
|
143
153
|
const { legendRef, graphWidth, graphHeight } = useComputeBaseChartDimensions({
|
|
144
154
|
hasSecondUnit: Boolean(secondUnit),
|
|
145
155
|
height,
|
|
146
156
|
legendDisplay: legend?.display,
|
|
147
157
|
legendHeight: legend?.height,
|
|
148
158
|
legendPlacement: legend?.placement,
|
|
149
|
-
width
|
|
159
|
+
width,
|
|
160
|
+
maxAxisCharacters: maxRightAxisCharacters || maxLeftAxisCharacters
|
|
150
161
|
});
|
|
151
162
|
|
|
152
163
|
const xScale = useMemo(
|
|
@@ -283,39 +294,45 @@ const Chart = ({
|
|
|
283
294
|
svgRef={graphSvgRef}
|
|
284
295
|
timeSeries={timeSeries}
|
|
285
296
|
xScale={xScale}
|
|
297
|
+
maxAxisCharacters={maxLeftAxisCharacters}
|
|
298
|
+
hasSecondUnit={Boolean(secondUnit)}
|
|
286
299
|
>
|
|
287
300
|
<>
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
301
|
+
{!isEmpty(linesDisplayedAsBar) && (
|
|
302
|
+
<BarGroup
|
|
303
|
+
barStyle={barStyle}
|
|
304
|
+
isTooltipHidden={false}
|
|
305
|
+
lines={linesDisplayedAsBar}
|
|
306
|
+
orientation="horizontal"
|
|
307
|
+
size={graphHeight - margin.top - 5}
|
|
308
|
+
timeSeries={timeSeries}
|
|
309
|
+
xScale={xScaleBand}
|
|
310
|
+
yScalesPerUnit={yScalesPerUnit}
|
|
311
|
+
/>
|
|
312
|
+
)}
|
|
313
|
+
{!isEmpty(linesDisplayedAsLine) && (
|
|
314
|
+
<Lines
|
|
315
|
+
areaTransparency={lineStyle?.areaTransparency}
|
|
316
|
+
curve={lineStyle?.curve || 'linear'}
|
|
317
|
+
dashLength={lineStyle?.dashLength}
|
|
318
|
+
dashOffset={lineStyle?.dashOffset}
|
|
319
|
+
displayAnchor={displayAnchor}
|
|
320
|
+
displayedLines={linesDisplayedAsLine}
|
|
321
|
+
dotOffset={lineStyle?.dotOffset}
|
|
322
|
+
graphSvgRef={graphSvgRef}
|
|
323
|
+
height={graphHeight - margin.top}
|
|
324
|
+
lineWidth={lineStyle?.lineWidth}
|
|
325
|
+
scale={axis?.scale}
|
|
326
|
+
scaleLogarithmicBase={axis?.scaleLogarithmicBase}
|
|
327
|
+
showArea={lineStyle?.showArea}
|
|
328
|
+
showPoints={lineStyle?.showPoints}
|
|
329
|
+
timeSeries={timeSeries}
|
|
330
|
+
width={graphWidth}
|
|
331
|
+
xScale={xScale}
|
|
332
|
+
yScalesPerUnit={yScalesPerUnit}
|
|
333
|
+
{...shapeLines}
|
|
334
|
+
/>
|
|
335
|
+
)}
|
|
319
336
|
<InteractionWithGraph
|
|
320
337
|
annotationData={{ ...annotationEvent }}
|
|
321
338
|
commonData={{
|
|
@@ -11,7 +11,7 @@ const GuidingLines = ({
|
|
|
11
11
|
graphHeight,
|
|
12
12
|
graphWidth
|
|
13
13
|
}: GuidingLinesModel): JSX.Element | null => {
|
|
14
|
-
const { positionX, positionY } = useTickGraph({
|
|
14
|
+
const { positionX, positionY, guidingLinesRef } = useTickGraph({
|
|
15
15
|
timeSeries,
|
|
16
16
|
xScale
|
|
17
17
|
});
|
|
@@ -20,7 +20,7 @@ const GuidingLines = ({
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
return (
|
|
23
|
-
|
|
23
|
+
<g ref={guidingLinesRef}>
|
|
24
24
|
<Shape.Line
|
|
25
25
|
fill="dotted"
|
|
26
26
|
from={{ x: positionX, y: 0 }}
|
|
@@ -38,7 +38,7 @@ const GuidingLines = ({
|
|
|
38
38
|
strokeWidth={1}
|
|
39
39
|
to={{ x: graphWidth, y: positionY }}
|
|
40
40
|
/>
|
|
41
|
-
|
|
41
|
+
</g>
|
|
42
42
|
);
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react';
|
|
1
|
+
import { MutableRefObject, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { ScaleLinear } from 'd3-scale';
|
|
4
4
|
import { useAtomValue } from 'jotai';
|
|
@@ -15,6 +15,7 @@ interface AnchorPointResult {
|
|
|
15
15
|
tickAxisBottom: Date | null;
|
|
16
16
|
tickAxisLeft: string | null;
|
|
17
17
|
tickAxisRight: string | null;
|
|
18
|
+
guidingLinesRef: MutableRefObject<SVGGElement | null>;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
interface Props {
|
|
@@ -34,6 +35,7 @@ const useTickGraph = ({
|
|
|
34
35
|
lines = [],
|
|
35
36
|
baseAxis = 1000
|
|
36
37
|
}: Props): AnchorPointResult => {
|
|
38
|
+
const guidingLinesRef = useRef<SVGGElement | null>(null);
|
|
37
39
|
const [tickAxisBottom, setTickAxisBottom] = useState<Date | null>(null);
|
|
38
40
|
const [tickAxisLeft, setTickAxisLeft] = useState<string | null>(null);
|
|
39
41
|
const [tickAxisRight, setTickAxisRight] = useState<string | null>(null);
|
|
@@ -42,12 +44,22 @@ const useTickGraph = ({
|
|
|
42
44
|
|
|
43
45
|
const mousePosition = useAtomValue(mousePositionAtom);
|
|
44
46
|
|
|
47
|
+
const paddingLeftString = useMemo(
|
|
48
|
+
() =>
|
|
49
|
+
(
|
|
50
|
+
guidingLinesRef.current?.parentElement?.parentElement?.attributes
|
|
51
|
+
?.transform.value || ''
|
|
52
|
+
).match(/translate\(([0-9\.]+), ([0-9\.]+)\)/)?.[1] || '0',
|
|
53
|
+
[
|
|
54
|
+
guidingLinesRef.current?.parentElement?.parentElement?.attributes
|
|
55
|
+
?.transform.value
|
|
56
|
+
]
|
|
57
|
+
);
|
|
58
|
+
|
|
45
59
|
const positionX = mousePosition
|
|
46
|
-
? mousePosition[0] -
|
|
47
|
-
: undefined;
|
|
48
|
-
const positionY = mousePosition
|
|
49
|
-
? mousePosition[1] - margin.top + 2
|
|
60
|
+
? mousePosition[0] - Number(paddingLeftString) - 1
|
|
50
61
|
: undefined;
|
|
62
|
+
const positionY = mousePosition ? mousePosition[1] - margin.top : undefined;
|
|
51
63
|
|
|
52
64
|
useEffect(() => {
|
|
53
65
|
if (!mousePosition) {
|
|
@@ -86,7 +98,8 @@ const useTickGraph = ({
|
|
|
86
98
|
positionY,
|
|
87
99
|
tickAxisBottom,
|
|
88
100
|
tickAxisLeft,
|
|
89
|
-
tickAxisRight
|
|
101
|
+
tickAxisRight,
|
|
102
|
+
guidingLinesRef
|
|
90
103
|
};
|
|
91
104
|
};
|
|
92
105
|
export default useTickGraph;
|