@scality/core-ui 0.193.0 → 0.194.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/dist/components/charts/barchart/Barchart.d.ts.map +1 -1
- package/dist/components/charts/barchart/Barchart.js +29 -19
- package/dist/components/charts/common/chartUtils.d.ts +7 -2
- package/dist/components/charts/common/chartUtils.d.ts.map +1 -1
- package/dist/components/charts/common/chartUtils.js +55 -20
- package/dist/components/charts/index.d.ts +1 -1
- package/dist/components/charts/index.d.ts.map +1 -1
- package/dist/components/charts/linetimeseries/LineTimeSerieChart.d.ts +12 -47
- package/dist/components/charts/linetimeseries/LineTimeSerieChart.d.ts.map +1 -1
- package/dist/components/charts/linetimeseries/LineTimeSerieChart.js +46 -220
- package/dist/components/charts/linetimeseries/LineTimeSerieChart.types.d.ts +77 -0
- package/dist/components/charts/linetimeseries/LineTimeSerieChart.types.d.ts.map +1 -0
- package/dist/components/charts/linetimeseries/LineTimeSerieChart.types.js +6 -0
- package/dist/components/charts/linetimeseries/LineTimeSerieChartTooltip.d.ts +18 -0
- package/dist/components/charts/linetimeseries/LineTimeSerieChartTooltip.d.ts.map +1 -0
- package/dist/components/charts/linetimeseries/LineTimeSerieChartTooltip.js +65 -0
- package/dist/components/charts/linetimeseries/useChartData.d.ts +44 -0
- package/dist/components/charts/linetimeseries/useChartData.d.ts.map +1 -0
- package/dist/components/charts/linetimeseries/useChartData.js +207 -0
- package/dist/components/charts/linetimeseries/useChartHover.d.ts +15 -0
- package/dist/components/charts/linetimeseries/useChartHover.d.ts.map +1 -0
- package/dist/components/charts/linetimeseries/useChartHover.js +29 -0
- package/dist/components/checkbox/Checkbox.component.d.ts.map +1 -1
- package/dist/components/checkbox/Checkbox.component.js +15 -7
- package/dist/components/constrainedtext/Constrainedtext.component.js +2 -2
- package/dist/components/dropdown/Dropdown.component.d.ts.map +1 -1
- package/dist/components/dropdown/Dropdown.component.js +3 -0
- package/dist/components/error-pages/ErrorPage401.component.js +1 -1
- package/dist/components/error-pages/ErrorPage404.component.js +1 -1
- package/dist/components/error-pages/ErrorPage500.component.js +1 -1
- package/dist/components/icon/CustomsIcons.d.ts +10 -0
- package/dist/components/icon/CustomsIcons.d.ts.map +1 -1
- package/dist/components/icon/CustomsIcons.js +8 -0
- package/dist/components/icon/Icon.component.d.ts +0 -1
- package/dist/components/icon/Icon.component.d.ts.map +1 -1
- package/dist/components/icon/Icon.component.js +5 -2
- package/dist/components/infomessage/InfoMessage.component.js +1 -1
- package/dist/components/tablev2/Tablestyle.d.ts.map +1 -1
- package/dist/components/tablev2/Tablestyle.js +2 -3
- package/dist/components/tooltip/Tooltip.component.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/utils.d.ts +14 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +25 -0
- package/package.json +1 -1
- package/src/lib/components/charts/barchart/Barchart.tsx +123 -106
- package/src/lib/components/charts/common/chartUtils.test.ts +27 -12
- package/src/lib/components/charts/common/chartUtils.ts +67 -23
- package/src/lib/components/charts/index.ts +1 -1
- package/src/lib/components/charts/linetimeseries/LineTimeSerieChart.tsx +136 -516
- package/src/lib/components/charts/linetimeseries/LineTimeSerieChart.types.ts +93 -0
- package/src/lib/components/charts/linetimeseries/LineTimeSerieChartTooltip.tsx +137 -0
- package/src/lib/components/charts/linetimeseries/useChartData.ts +322 -0
- package/src/lib/components/charts/linetimeseries/useChartHover.ts +35 -0
- package/src/lib/components/checkbox/Checkbox.component.tsx +19 -20
- package/src/lib/components/constrainedtext/Constrainedtext.component.tsx +2 -2
- package/src/lib/components/dropdown/Dropdown.component.tsx +3 -0
- package/src/lib/components/error-pages/ErrorPage401.component.tsx +1 -1
- package/src/lib/components/error-pages/ErrorPage404.component.tsx +1 -1
- package/src/lib/components/error-pages/ErrorPage500.component.tsx +1 -1
- package/src/lib/components/icon/CustomsIcons.tsx +36 -0
- package/src/lib/components/icon/Icon.component.tsx +9 -2
- package/src/lib/components/infomessage/InfoMessage.component.tsx +1 -1
- package/src/lib/components/tablev2/Tablestyle.tsx +2 -4
- package/src/lib/components/tooltip/Tooltip.component.tsx +1 -1
- package/src/lib/index.ts +1 -0
- package/src/lib/utils.ts +38 -0
- package/stories/GlobalHealthBar/globalhealthbar.stories.tsx +1 -1
- package/stories/banner.stories.tsx +1 -1
- package/stories/linetimeseriechart.stories.tsx +325 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Barchart.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/charts/barchart/Barchart.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAiB7D,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,SAAS;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC;CACvE,EAAE,CAAC;AAEJ,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,YAAY,IAAI,CAAC,YAAY,EAAE;IACrE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CAC5E,KAAK,KAAK,CAAC,SAAS,CAAC;AAEtB,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,YAAY,IAAI,CACnD,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,EAC1E,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,KACvE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAEhB,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,YAAY,IAAI;IAClD,IAAI,EAAE,YAAY,GAAG,QAAQ,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAIF,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,YAAY,SAAS,aAAa,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"Barchart.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/charts/barchart/Barchart.tsx"],"names":[],"mappings":"AAwBA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAiB7D,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC5C,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,SAAS;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC;CACvE,EAAE,CAAC;AAEJ,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,YAAY,IAAI,CAAC,YAAY,EAAE;IACrE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,MAAM,EAAE;QAAE,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CAC5E,KAAK,KAAK,CAAC,SAAS,CAAC;AAEtB,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,YAAY,IAAI,CACnD,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,EAC1E,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,KACvE,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAEhB,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,YAAY,IAAI;IAClD,IAAI,EAAE,YAAY,GAAG,QAAQ,CAAC;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,OAAO,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC/B,WAAW,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAChC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AAIF,eAAO,MAAM,QAAQ,GAAI,CAAC,SAAS,YAAY,SAAS,aAAa,CAAC,CAAC,CAAC,4CA6KvE,CAAC"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState, useRef } from 'react';
|
|
2
|
+
import { useState, useRef, useMemo, useCallback } from 'react';
|
|
3
3
|
import { Bar, BarChart as RechartsBarChart, CartesianGrid, Tooltip, XAxis, YAxis, } from 'recharts';
|
|
4
4
|
import { useTheme } from 'styled-components';
|
|
5
5
|
import { Stack } from '../../../spacing';
|
|
6
6
|
import { chartColors, fontSize } from '../../../style/theme';
|
|
7
7
|
import { useChartLegend } from '../legend/ChartLegendWrapper';
|
|
8
8
|
import { BarchartTooltip } from './BarchartTooltip';
|
|
9
|
-
import {
|
|
9
|
+
import { formatTickValue, getTicks } from '../common/chartUtils';
|
|
10
10
|
import { useChartData } from './Barchart.utils';
|
|
11
11
|
import { ChartHeader, ChartError, ChartLoading, CustomTick, StyledResponsiveContainer, } from '../common/SharedComponents';
|
|
12
12
|
const CHART_CONSTANTS = {
|
|
@@ -29,28 +29,38 @@ export const Barchart = (props) => {
|
|
|
29
29
|
const chartRef = useRef(null);
|
|
30
30
|
const { height = CHART_CONSTANTS.DEFAULT_HEIGHT, bars, type = { type: 'category' }, unitRange, stacked, stackedBarSort = 'default', defaultSort, tooltip, title, secondaryTitle, helpTooltip, rightTitle, isLoading, isError, } = props;
|
|
31
31
|
// Create colorSet from ChartLegendWrapper
|
|
32
|
-
const colorSet = bars === null || bars === void 0 ? void 0 : bars.reduce((acc, bar) => {
|
|
32
|
+
const colorSet = useMemo(() => bars === null || bars === void 0 ? void 0 : bars.reduce((acc, bar) => {
|
|
33
33
|
const color = getColor(bar.label);
|
|
34
34
|
if (color) {
|
|
35
35
|
acc[bar.label] = color;
|
|
36
36
|
}
|
|
37
37
|
return acc;
|
|
38
|
-
}, {});
|
|
38
|
+
}, {}), [bars, getColor]);
|
|
39
39
|
const { rechartsBars, unitLabel, roundReferenceValue, rechartsData, topDomain, } = useChartData(bars || [], type, colorSet || {}, stacked, defaultSort, unitRange, stackedBarSort);
|
|
40
40
|
const titleWithUnit = unitLabel ? `${title} (${unitLabel})` : title;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
41
|
+
const tickFormatter = useCallback((value) => formatTickValue(value, roundReferenceValue), [roundReferenceValue]);
|
|
42
|
+
const renderChartContent = () => {
|
|
43
|
+
if (isError || (!bars && !isLoading)) {
|
|
44
|
+
return _jsx(ChartError, { height: height });
|
|
45
|
+
}
|
|
46
|
+
if (isLoading) {
|
|
47
|
+
return _jsx(ChartLoading, { height: height });
|
|
48
|
+
}
|
|
49
|
+
return (_jsx(StyledResponsiveContainer, { ref: chartRef, width: "100%", height: height, children: _jsxs(RechartsBarChart, { data: rechartsData, accessibilityLayer: true, barSize: type.type === 'category'
|
|
50
|
+
? type.gap === 0
|
|
51
|
+
? undefined
|
|
52
|
+
: CHART_CONSTANTS.BAR_SIZE
|
|
53
|
+
: CHART_CONSTANTS.BAR_SIZE, height: height, margin: CHART_CONSTANTS.CHART_MARGIN, barCategoryGap: type.type === 'category' ? type.gap : undefined, children: [_jsx(CartesianGrid, { vertical: true, horizontal: true, verticalPoints: [0], horizontalPoints: [0], stroke: theme.border, fill: theme.backgroundLevel4, strokeWidth: 1 }), rechartsBars.map((bar) => {
|
|
54
|
+
const { fill, dataKey, stackId } = bar;
|
|
55
|
+
return (_jsx(Bar, { dataKey: dataKey, fill: chartColors[fill] || fill, minPointSize: stacked ? 0 : CHART_CONSTANTS.MIN_POINT_SIZE, stackId: stackId, isAnimationActive: false, onMouseOver: () => setHoveredValue(dataKey), onMouseLeave: () => setHoveredValue(undefined) }, dataKey));
|
|
56
|
+
}), _jsx(YAxis, { interval: 0, domain: [0, topDomain], ticks: getTicks(roundReferenceValue, false), tickFormatter: tickFormatter, axisLine: { stroke: theme.border }, tick: {
|
|
57
|
+
fill: theme.textSecondary,
|
|
58
|
+
fontSize: fontSize.smaller,
|
|
59
|
+
}, orientation: "right" }), _jsx(XAxis, { dataKey: "category", tick: (props) => (_jsx(CustomTick, { ...props, type: type, tickWidthOffset: CHART_CONSTANTS.TICK_WIDTH_OFFSET })), type: "category", interval: 0, allowDataOverflow: true, tickLine: {
|
|
60
|
+
stroke: theme.border,
|
|
61
|
+
}, axisLine: {
|
|
62
|
+
stroke: theme.border,
|
|
63
|
+
} }), _jsx(Tooltip, { content: (props) => (_jsx(BarchartTooltip, { type: type, colorSet: colorSet, tooltipProps: props, hoveredValue: hoveredValue, tooltip: tooltip, unitLabel: unitLabel, chartContainerRef: chartRef })), cursor: false })] }) }));
|
|
64
|
+
};
|
|
65
|
+
return (_jsxs(Stack, { direction: "vertical", style: { gap: '0' }, children: [_jsx(ChartHeader, { title: titleWithUnit, secondaryTitle: secondaryTitle, helpTooltip: helpTooltip, rightTitle: rightTitle }), renderChartContent()] }));
|
|
56
66
|
};
|
|
@@ -48,7 +48,7 @@ export declare const normalizeChartDataWithUnits: <T extends Record<string, any>
|
|
|
48
48
|
* Missing data points are only added when the gap between consecutive data points is bigger than 2 intervals
|
|
49
49
|
* Used by LineTimeSerieChart and Sparkline
|
|
50
50
|
*
|
|
51
|
-
* @param
|
|
51
|
+
* @param originalValues - The array of the data points are already sorted according to the time series
|
|
52
52
|
* @param startingTimeStamp - The starting timestamp in seconds
|
|
53
53
|
* @param sampleDuration - The time span value in seconds
|
|
54
54
|
* @param sampleInterval - The time difference between two data points in seconds
|
|
@@ -87,5 +87,10 @@ export declare const formatXAxisDate: (duration: number) => "time" | "day-month-
|
|
|
87
87
|
* @returns Formatted string type
|
|
88
88
|
*/
|
|
89
89
|
export declare const getTooltipDateFormat: (duration: number) => TooltipDateFormat;
|
|
90
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Formats a tick value for chart Y-axis display.
|
|
92
|
+
* - Fixed decimals for alignment when topValue < 1 (e.g., 0.1 → 0.10)
|
|
93
|
+
* - Compact notation for large values (>= 10k)
|
|
94
|
+
*/
|
|
95
|
+
export declare const formatTickValue: (value: number, topValue: number) => string;
|
|
91
96
|
//# sourceMappingURL=chartUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chartUtils.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/charts/common/chartUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"chartUtils.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/charts/common/chartUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAOrC,eAAO,MAAM,eAAe;;CAAwB,CAAC;AA+BrD;;;GAGG;AACH,eAAO,MAAM,sBAAsB,UAAW,MAAM,KAAG,MA+BtD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,QAAQ,aACT,MAAM,iBACD,OAAO,KACrB,MAAM,EAmBR,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE;IACT,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf,EAAE,EACH,QAAQ,EAAE,MAAM,GACf;IACD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B,CAyCA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,GAAI,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,QACjE,CAAC,EAAE,YACC,MAAM,aACL,SAAS,GAAG,SAAS,cACpB,MAAM,KACjB;IACD,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,CAAC,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CAgCnB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,EAAE,EAClD,iBAAiB,CAAC,EAAE,MAAM,EAC1B,cAAc,CAAC,EAAE,MAAM,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,EAAE,CA4EpC;AACD;;;;;;;;;;;;;;;;;;GAkBG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,eAAe,aAChB,MAAM,KACf,MAAM,GAAG,uBAAuB,GAAG,sBAQrC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,iBAUxD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,UAAW,MAAM,YAAY,MAAM,KAAG,MAOjE,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { NAN_STRING } from '../../constants';
|
|
2
|
+
import { formatISONumber } from '../../../utils';
|
|
2
3
|
/* -------------------------------------------------------------------------- */
|
|
3
4
|
/* constants */
|
|
4
5
|
/* -------------------------------------------------------------------------- */
|
|
@@ -6,6 +7,28 @@ export const maxWidthTooltip = { maxWidth: '20rem' };
|
|
|
6
7
|
/* -------------------------------------------------------------------------- */
|
|
7
8
|
/* utils functions */
|
|
8
9
|
/* -------------------------------------------------------------------------- */
|
|
10
|
+
/**
|
|
11
|
+
* Get the appropriate rounding increment based on value magnitude.
|
|
12
|
+
* - For values < 5 * magnitude: use half magnitude (finer granularity)
|
|
13
|
+
* - For values >= 5 * magnitude: use full magnitude
|
|
14
|
+
*
|
|
15
|
+
* Examples:
|
|
16
|
+
* - 150 → increment 50 (150 < 500, so use 100/2)
|
|
17
|
+
* - 550 → increment 100 (550 >= 500, so use 100)
|
|
18
|
+
* - 1500 → increment 500 (1500 < 5000, so use 1000/2)
|
|
19
|
+
* - 5500 → increment 1000 (5500 >= 5000, so use 1000)
|
|
20
|
+
*/
|
|
21
|
+
const getIncrement = (value) => {
|
|
22
|
+
if (value < 10)
|
|
23
|
+
return 1;
|
|
24
|
+
const magnitude = Math.pow(10, Math.floor(Math.log10(value)));
|
|
25
|
+
// If value is in lower half of magnitude range, use half magnitude
|
|
26
|
+
if (value < 5 * magnitude) {
|
|
27
|
+
return magnitude / 2;
|
|
28
|
+
}
|
|
29
|
+
// Otherwise use full magnitude
|
|
30
|
+
return magnitude;
|
|
31
|
+
};
|
|
9
32
|
/**
|
|
10
33
|
* Round a value to a nice number for chart display
|
|
11
34
|
* Used by Barchart and LineTimeSerieChart for Y-axis scaling
|
|
@@ -16,23 +39,24 @@ export const getRoundReferenceValue = (value) => {
|
|
|
16
39
|
// Buffer the value by 10% to avoid being too close to the edge of the chart
|
|
17
40
|
const bufferedValue = value * 1.1;
|
|
18
41
|
if (value >= 10) {
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
42
|
+
const increment = getIncrement(value);
|
|
43
|
+
const remainder = value % increment;
|
|
44
|
+
const roundedDown = value - remainder;
|
|
45
|
+
const roundedUp = roundedDown + increment;
|
|
46
|
+
// If remainder is less than half the increment, round down
|
|
47
|
+
if (remainder < increment / 2) {
|
|
48
|
+
return roundedDown;
|
|
24
49
|
}
|
|
25
|
-
// If
|
|
26
|
-
if (
|
|
27
|
-
return
|
|
50
|
+
// If rounding up would exceed the buffered max, round down
|
|
51
|
+
if (roundedUp > bufferedValue) {
|
|
52
|
+
return roundedDown;
|
|
28
53
|
}
|
|
29
|
-
// Otherwise, round up
|
|
30
|
-
return
|
|
54
|
+
// Otherwise, round up
|
|
55
|
+
return roundedUp;
|
|
31
56
|
}
|
|
57
|
+
// For values < 10, use the magnitude-based approach
|
|
32
58
|
const magnitude = Math.pow(10, Math.floor(Math.log10(value)));
|
|
33
59
|
const remainder = bufferedValue % magnitude;
|
|
34
|
-
// Round to nice numbers based on normalized value
|
|
35
|
-
// appearance for small values
|
|
36
60
|
return remainder === 0 ? bufferedValue : bufferedValue - remainder;
|
|
37
61
|
};
|
|
38
62
|
/**
|
|
@@ -131,7 +155,7 @@ export const normalizeChartDataWithUnits = (data, maxValue, unitRange, excludeKe
|
|
|
131
155
|
* Missing data points are only added when the gap between consecutive data points is bigger than 2 intervals
|
|
132
156
|
* Used by LineTimeSerieChart and Sparkline
|
|
133
157
|
*
|
|
134
|
-
* @param
|
|
158
|
+
* @param originalValues - The array of the data points are already sorted according to the time series
|
|
135
159
|
* @param startingTimeStamp - The starting timestamp in seconds
|
|
136
160
|
* @param sampleDuration - The time span value in seconds
|
|
137
161
|
* @param sampleInterval - The time difference between two data points in seconds
|
|
@@ -146,9 +170,13 @@ export function addMissingDataPoint(originalValues, startingTimeStamp, sampleDur
|
|
|
146
170
|
sampleInterval <= 0) {
|
|
147
171
|
return [];
|
|
148
172
|
}
|
|
149
|
-
// If there are no original values,
|
|
173
|
+
// If there are no original values, generate placeholder timestamps for the entire duration
|
|
150
174
|
if (originalValues.length === 0) {
|
|
151
|
-
|
|
175
|
+
const newValues = [];
|
|
176
|
+
for (let i = startingTimeStamp; i < startingTimeStamp + sampleDuration; i += sampleInterval) {
|
|
177
|
+
newValues.push([i, NAN_STRING]);
|
|
178
|
+
}
|
|
179
|
+
return newValues;
|
|
152
180
|
}
|
|
153
181
|
const newValues = [];
|
|
154
182
|
// add missing data points for the starting time
|
|
@@ -235,9 +263,16 @@ export const getTooltipDateFormat = (duration) => {
|
|
|
235
263
|
return 'day-month-abbreviated-year-hour-minute';
|
|
236
264
|
}
|
|
237
265
|
};
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
266
|
+
/**
|
|
267
|
+
* Formats a tick value for chart Y-axis display.
|
|
268
|
+
* - Fixed decimals for alignment when topValue < 1 (e.g., 0.1 → 0.10)
|
|
269
|
+
* - Compact notation for large values (>= 10k)
|
|
270
|
+
*/
|
|
271
|
+
export const formatTickValue = (value, topValue) => {
|
|
272
|
+
const decimals = topValue < 1 ? Math.ceil(-Math.log10(topValue)) + 1 : 2;
|
|
273
|
+
return formatISONumber(value, {
|
|
274
|
+
decimals,
|
|
275
|
+
fixedDecimals: topValue < 1,
|
|
276
|
+
compact: topValue >= 10000,
|
|
277
|
+
});
|
|
243
278
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { Barchart } from './barchart/Barchart';
|
|
2
2
|
export type { BarchartProps, BarchartBars, BarchartTooltipFn, BarchartSortFn, Point, } from './barchart/Barchart';
|
|
3
3
|
export { LineTimeSerieChart } from './linetimeseries/LineTimeSerieChart';
|
|
4
|
-
export type { LineChartProps, Serie, } from './linetimeseries/LineTimeSerieChart';
|
|
4
|
+
export type { LineChartProps, Serie, } from './linetimeseries/LineTimeSerieChart.types';
|
|
5
5
|
export { GlobalHealthBar } from './globalhealthbar/GlobalHealthBar';
|
|
6
6
|
export type { GlobalHealthProps } from './globalhealthbar/GlobalHealthBar';
|
|
7
7
|
export type { Alert } from './globalhealthbar/GlobalHealthBar.hooks';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/charts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,YAAY,EACV,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,KAAK,GACN,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,YAAY,EACV,cAAc,EACd,KAAK,GACN,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/components/charts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,YAAY,EACV,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,KAAK,GACN,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,YAAY,EACV,cAAc,EACd,KAAK,GACN,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAC3E,YAAY,EAAE,KAAK,EAAE,MAAM,yCAAyC,CAAC;AAErE,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,cAAc,GACf,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,kBAAkB,EAClB,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EACL,sBAAsB,EACtB,QAAQ,EACR,YAAY,EACZ,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,2BAA2B,GAC5B,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EACL,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,2BAA2B,CAAC;AAGnC,YAAY,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -1,55 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { TooltipContentProps } from 'recharts';
|
|
3
|
-
export type Serie = {
|
|
4
|
-
resource: string;
|
|
5
|
-
data: [number, number | string | null][];
|
|
6
|
-
getTooltipLabel: (metricPrefix?: string, resource?: string) => string;
|
|
7
|
-
metricPrefix?: string;
|
|
8
|
-
isLineDashed?: boolean;
|
|
9
|
-
};
|
|
10
|
-
type NonSymmetricalChartSerie = {
|
|
11
|
-
yAxisType?: 'default' | 'percentage';
|
|
12
|
-
series: Serie[] | undefined;
|
|
13
|
-
};
|
|
14
|
-
type SymmetricalChartSerie = {
|
|
15
|
-
yAxisType: 'symmetrical';
|
|
16
|
-
series: {
|
|
17
|
-
above: Serie[] | undefined;
|
|
18
|
-
below: Serie[] | undefined;
|
|
19
|
-
} | undefined;
|
|
20
|
-
};
|
|
21
|
-
export type LineChartProps = (NonSymmetricalChartSerie | SymmetricalChartSerie) & {
|
|
22
|
-
title: string;
|
|
23
|
-
height: number;
|
|
24
|
-
startingTimeStamp: number;
|
|
25
|
-
interval: number;
|
|
26
|
-
duration: number;
|
|
27
|
-
unitRange?: {
|
|
28
|
-
threshold: number;
|
|
29
|
-
label: string;
|
|
30
|
-
}[];
|
|
31
|
-
syncId?: string;
|
|
32
|
-
isLoading?: boolean;
|
|
33
|
-
/**
|
|
34
|
-
* The format of the x axis, default is 'date-time' which is like 01 Sep 16:00
|
|
35
|
-
* If you want to display the date only, you can set it to 'date' which is like 2025-09-01
|
|
36
|
-
* This will affect the format of the tooltip as well
|
|
37
|
-
*/
|
|
38
|
-
timeFormat?: 'date-time' | 'date';
|
|
39
|
-
yAxisTitle?: string;
|
|
40
|
-
helpText?: string;
|
|
41
|
-
renderTooltip?: (tooltipProps: TooltipContentProps<number, string>, unitLabel?: string, duration?: number) => React.ReactNode;
|
|
42
|
-
};
|
|
1
|
+
import { LineChartProps } from './LineTimeSerieChart.types';
|
|
43
2
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
3
|
+
* LineTimeSerieChart - A time series line chart component
|
|
4
|
+
*
|
|
5
|
+
* @param series - The data series to display (can be symmetrical with above/below)
|
|
46
6
|
* @param title - The title of the chart
|
|
47
7
|
* @param height - The height of the chart in pixels
|
|
48
8
|
* @param startingTimeStamp - Starting timestamp in seconds
|
|
49
9
|
* @param interval - Interval between data points in seconds
|
|
50
10
|
* @param duration - Total duration of the chart in seconds
|
|
51
|
-
*
|
|
11
|
+
* @param unitRange - Configuration for automatic unit scaling
|
|
12
|
+
* @param syncId - ID to synchronize multiple charts
|
|
13
|
+
* @param isLoading - Whether to show loading state
|
|
14
|
+
* @param yAxisType - Type of Y-axis: 'default', 'percentage', or 'symmetrical'
|
|
15
|
+
* @param yAxisTitle - Label for the Y-axis
|
|
16
|
+
* @param helpText - Help text shown as tooltip
|
|
17
|
+
* @param renderTooltip - Custom tooltip renderer
|
|
52
18
|
*/
|
|
53
|
-
export declare function LineTimeSerieChart({ series, title, height, startingTimeStamp, interval, duration, unitRange, isLoading,
|
|
54
|
-
export {};
|
|
19
|
+
export declare function LineTimeSerieChart({ series, title, height, startingTimeStamp, interval, duration, unitRange, isLoading, yAxisType, yAxisTitle, helpText, syncId, renderTooltip, }: LineChartProps): import("react/jsx-runtime").JSX.Element;
|
|
55
20
|
//# sourceMappingURL=LineTimeSerieChart.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LineTimeSerieChart.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/charts/linetimeseries/LineTimeSerieChart.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"LineTimeSerieChart.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/charts/linetimeseries/LineTimeSerieChart.tsx"],"names":[],"mappings":"AAoBA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAW5D;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,MAAM,EACN,KAAK,EACL,MAAM,EACN,iBAAiB,EACjB,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,SAAiB,EACjB,SAAqB,EACrB,UAAU,EACV,QAAQ,EACR,MAAM,EACN,aAAa,GACd,EAAE,cAAc,2CAgJhB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useRef } from 'react';
|
|
3
3
|
import { CartesianGrid, Line, LineChart, ReferenceLine, Tooltip, XAxis, YAxis, } from 'recharts';
|
|
4
4
|
import styled, { useTheme } from 'styled-components';
|
|
5
5
|
import { Stack } from '../../../spacing';
|
|
@@ -7,241 +7,67 @@ import { fontSize } from '../../../style/theme';
|
|
|
7
7
|
import { IconHelp } from '../../iconhelper/IconHelper';
|
|
8
8
|
import { Loader } from '../../loader/Loader.component';
|
|
9
9
|
import { ChartTitleText } from '../../text/Text.component';
|
|
10
|
-
import { LegendShape } from '../legend/ChartLegend';
|
|
11
|
-
import { useChartLegend } from '../legend/ChartLegendWrapper';
|
|
12
10
|
import { StyledResponsiveContainer } from '../common/SharedComponents';
|
|
13
|
-
import {
|
|
14
|
-
import { addMissingDataPoint, formatToISONumber, getTicks, maxWidthTooltip, normalizeChartDataWithUnits, } from '../common/chartUtils';
|
|
11
|
+
import { formatTickValue, getTicks, maxWidthTooltip } from '../common/chartUtils';
|
|
15
12
|
import { formatXAxisLabel } from './LineTimeSerieChart.utils';
|
|
13
|
+
import { LineTimeSerieChartTooltip } from './LineTimeSerieChartTooltip';
|
|
14
|
+
import { useChartHover } from './useChartHover';
|
|
15
|
+
import { useChartData } from './useChartData';
|
|
16
16
|
const LineTemporalChartWrapper = styled.div `
|
|
17
17
|
display: flex;
|
|
18
18
|
flex-direction: column;
|
|
19
19
|
justify-content: flex-start;
|
|
20
20
|
`;
|
|
21
|
-
const LineTimeSerieChartTooltip = ({ unitLabel, duration, isChartActive, tooltipProps, renderTooltip, hoveredValue, isSymmetrical, chartContainerRef, }) => {
|
|
22
|
-
const { active, payload, label, coordinate } = tooltipProps;
|
|
23
|
-
if (!active || !payload || !payload.length || !label || !isChartActive)
|
|
24
|
-
return null;
|
|
25
|
-
const tooltipContent = renderTooltip ? (renderTooltip(tooltipProps, unitLabel, duration)) : (_jsxs(_Fragment, { children: [_jsx(ChartTooltipHeader, { children: _jsx(TooltipHeader, { duration: duration, value: label }) }), _jsx(ChartTooltipItemsContainer, { children: (() => {
|
|
26
|
-
// We can't use the default itemSorter method because it's a custom tooltip.
|
|
27
|
-
// Sort the payload here instead
|
|
28
|
-
const sortedPayload = [...payload].sort((a, b) => {
|
|
29
|
-
const aValue = a.value;
|
|
30
|
-
const bValue = b.value;
|
|
31
|
-
if (aValue >= 0 && bValue >= 0) {
|
|
32
|
-
return bValue - aValue; // Higher positive values first
|
|
33
|
-
}
|
|
34
|
-
if (aValue < 0 && bValue < 0) {
|
|
35
|
-
return bValue - aValue; // Lower negative values first
|
|
36
|
-
}
|
|
37
|
-
return bValue - aValue; // Positives before negatives
|
|
38
|
-
});
|
|
39
|
-
// Find the transition point between positive and negative values
|
|
40
|
-
const separatorIndex = sortedPayload.findIndex((entry) => entry.value < 0);
|
|
41
|
-
const hasBothPositiveAndNegative = separatorIndex > 0 && separatorIndex < sortedPayload.length;
|
|
42
|
-
return sortedPayload.map((entry, index) => {
|
|
43
|
-
const legendIcon = (_jsx(LegendShape, { color: entry.color, shape: "line", chartColors: { [entry.color]: entry.color } }));
|
|
44
|
-
const isHovered = entry.name === hoveredValue;
|
|
45
|
-
const formattedValue = !Number.isFinite(entry.value)
|
|
46
|
-
? '-'
|
|
47
|
-
: `${entry.value.toFixed(2)}${unitLabel ? ` ${unitLabel}` : ''}`;
|
|
48
|
-
return (_jsxs(React.Fragment, { children: [isSymmetrical &&
|
|
49
|
-
hasBothPositiveAndNegative &&
|
|
50
|
-
index === separatorIndex && _jsx(ChartTooltipSeparator, {}), _jsx(ChartTooltipItem, { label: entry.name, value: formattedValue, legendIcon: legendIcon, isHovered: isHovered })] }, index));
|
|
51
|
-
});
|
|
52
|
-
})() })] }));
|
|
53
|
-
return (_jsx(ChartTooltipPortal, { coordinate: coordinate, chartContainerRef: chartContainerRef, isVisible: active && isChartActive, children: tooltipContent }));
|
|
54
|
-
};
|
|
55
|
-
const isSymmetricalSeries = (series) => {
|
|
56
|
-
return 'above' in series && 'below' in series;
|
|
57
|
-
};
|
|
58
21
|
/**
|
|
59
|
-
*
|
|
60
|
-
*
|
|
22
|
+
* LineTimeSerieChart - A time series line chart component
|
|
23
|
+
*
|
|
24
|
+
* @param series - The data series to display (can be symmetrical with above/below)
|
|
61
25
|
* @param title - The title of the chart
|
|
62
26
|
* @param height - The height of the chart in pixels
|
|
63
27
|
* @param startingTimeStamp - Starting timestamp in seconds
|
|
64
28
|
* @param interval - Interval between data points in seconds
|
|
65
29
|
* @param duration - Total duration of the chart in seconds
|
|
66
|
-
*
|
|
30
|
+
* @param unitRange - Configuration for automatic unit scaling
|
|
31
|
+
* @param syncId - ID to synchronize multiple charts
|
|
32
|
+
* @param isLoading - Whether to show loading state
|
|
33
|
+
* @param yAxisType - Type of Y-axis: 'default', 'percentage', or 'symmetrical'
|
|
34
|
+
* @param yAxisTitle - Label for the Y-axis
|
|
35
|
+
* @param helpText - Help text shown as tooltip
|
|
36
|
+
* @param renderTooltip - Custom tooltip renderer
|
|
67
37
|
*/
|
|
68
|
-
export function LineTimeSerieChart({ series, title, height, startingTimeStamp, interval, duration, unitRange, isLoading = false,
|
|
38
|
+
export function LineTimeSerieChart({ series, title, height, startingTimeStamp, interval, duration, unitRange, isLoading = false, yAxisType = 'default', yAxisTitle, helpText, syncId, renderTooltip, }) {
|
|
69
39
|
const theme = useTheme();
|
|
70
|
-
const { getColor, selectedResources } = useChartLegend();
|
|
71
40
|
const chartRef = useRef(null);
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
// 1. Add missing data points
|
|
87
|
-
const normalizedSeries = yAxisType === 'symmetrical' && isSymmetricalSeries(series)
|
|
88
|
-
? {
|
|
89
|
-
above: series.above
|
|
90
|
-
? series.above.map((line) => ({
|
|
91
|
-
...line,
|
|
92
|
-
data: addMissingDataPoint(line.data, startingTimeStamp, duration, interval),
|
|
93
|
-
}))
|
|
94
|
-
: [],
|
|
95
|
-
// Convert positive values to negative values
|
|
96
|
-
below: series.below
|
|
97
|
-
? series.below.map((line) => ({
|
|
98
|
-
...line,
|
|
99
|
-
data: addMissingDataPoint(line.data, startingTimeStamp, duration, interval).map(([timestamp, value]) => [
|
|
100
|
-
timestamp,
|
|
101
|
-
value === null ? null : `-${Number(value)}`,
|
|
102
|
-
]),
|
|
103
|
-
}))
|
|
104
|
-
: [],
|
|
105
|
-
}
|
|
106
|
-
: series.map((line) => ({
|
|
107
|
-
...line,
|
|
108
|
-
data: addMissingDataPoint(line.data, startingTimeStamp, duration, interval),
|
|
109
|
-
}));
|
|
110
|
-
// 2. Convert directly to Recharts format
|
|
111
|
-
// Initialize an object to hold data points by timestamp
|
|
112
|
-
const dataPointsByTime = {};
|
|
113
|
-
const seriesToProcess = yAxisType === 'symmetrical' && isSymmetricalSeries(normalizedSeries)
|
|
114
|
-
? [...normalizedSeries.above, ...normalizedSeries.below]
|
|
115
|
-
: normalizedSeries;
|
|
116
|
-
seriesToProcess.forEach((serie) => {
|
|
117
|
-
const label = serie.getTooltipLabel(serie.metricPrefix, serie.resource);
|
|
118
|
-
serie.data.forEach((point) => {
|
|
119
|
-
const timestamp = typeof point[0] === 'number' ? point[0] * 1000 : Number(point[0]);
|
|
120
|
-
const value = point[1];
|
|
121
|
-
// Initialize this timestamp if it doesn't exist
|
|
122
|
-
if (!dataPointsByTime[timestamp]) {
|
|
123
|
-
dataPointsByTime[timestamp] = { timestamp };
|
|
124
|
-
}
|
|
125
|
-
// Add this metric's value to the data point, and convert the value to a number if it's a string
|
|
126
|
-
dataPointsByTime[timestamp][label] =
|
|
127
|
-
typeof value === 'string' ? Number(value) : value;
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
// Convert object to array for Recharts
|
|
131
|
-
return Object.values(dataPointsByTime).sort((a, b) => a.timestamp - b.timestamp);
|
|
132
|
-
}, [series, startingTimeStamp, duration, interval, yAxisType]);
|
|
133
|
-
// Calculate evenly spaced ticks that avoid the very beginning and end
|
|
134
|
-
const xAxisTicks = useMemo(() => {
|
|
135
|
-
if (!chartData || chartData.length === 0)
|
|
136
|
-
return [];
|
|
137
|
-
const timestamps = chartData.map((d) => d.timestamp);
|
|
138
|
-
const minTimestamp = Math.min(...timestamps);
|
|
139
|
-
const maxTimestamp = Math.max(...timestamps);
|
|
140
|
-
const timeRange = maxTimestamp - minTimestamp;
|
|
141
|
-
// Add padding to avoid labels at the very edges (10% padding on each side)
|
|
142
|
-
const padding = timeRange * 0.1;
|
|
143
|
-
const paddedStart = minTimestamp + padding;
|
|
144
|
-
const paddedEnd = maxTimestamp - padding;
|
|
145
|
-
const paddedRange = paddedEnd - paddedStart;
|
|
146
|
-
// Create 5 evenly spaced ticks within the padded range
|
|
147
|
-
const numTicks = 5;
|
|
148
|
-
const tickInterval = paddedRange / (numTicks - 1);
|
|
149
|
-
const evenlySpacedTicks = Array.from({ length: numTicks }, (_, index) => paddedStart + index * tickInterval);
|
|
150
|
-
return evenlySpacedTicks;
|
|
151
|
-
}, [chartData]);
|
|
152
|
-
// 3. Transform the data base on the valuebase
|
|
153
|
-
const { topValue, unitLabel, rechartsData, topDomain } = useMemo(() => {
|
|
154
|
-
var _a;
|
|
155
|
-
const values = chartData.flatMap((dataPoint) => Object.entries(dataPoint)
|
|
156
|
-
.filter(([key]) => key !== 'timestamp')
|
|
157
|
-
.map(([_, value]) => {
|
|
158
|
-
if (value === null || value === undefined)
|
|
159
|
-
return null;
|
|
160
|
-
const num = typeof value === 'string' ? Number(value) : value;
|
|
161
|
-
return !isNaN(num) ? num : null;
|
|
162
|
-
})
|
|
163
|
-
.filter((value) => value !== null));
|
|
164
|
-
// Guard against empty values array
|
|
165
|
-
if (values.length === 0) {
|
|
166
|
-
return {
|
|
167
|
-
topValue: 100, // Default value for empty charts
|
|
168
|
-
unitLabel: yAxisType === 'percentage' ? '%' : undefined,
|
|
169
|
-
rechartsData: [],
|
|
170
|
-
topDomain: 100,
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
const top = Math.abs(Math.max(...values));
|
|
174
|
-
const bottom = Math.abs(Math.min(...values));
|
|
175
|
-
const maxValue = Math.max(top, bottom);
|
|
176
|
-
// Use shared normalization function
|
|
177
|
-
const result = normalizeChartDataWithUnits(chartData, maxValue, unitRange, 'timestamp');
|
|
178
|
-
// For percentage charts, ensure Y-axis goes to at least 100%
|
|
179
|
-
const topDomain = yAxisType === 'percentage'
|
|
180
|
-
? Math.max(result.topDomain, 100)
|
|
181
|
-
: result.topDomain;
|
|
182
|
-
return {
|
|
183
|
-
topValue: yAxisType === 'percentage' ? Math.max(result.topValue, 100) : result.topValue,
|
|
184
|
-
unitLabel: (_a = result.unitLabel) !== null && _a !== void 0 ? _a : (yAxisType === 'percentage' ? '%' : undefined),
|
|
185
|
-
rechartsData: result.rechartsData,
|
|
186
|
-
topDomain,
|
|
187
|
-
};
|
|
188
|
-
}, [chartData, yAxisType, unitRange]);
|
|
189
|
-
// Group series by resource and create color mapping
|
|
190
|
-
const { colorMapping, groupedSeries } = useMemo(() => {
|
|
191
|
-
const mapping = {};
|
|
192
|
-
// Guard against empty/undefined series
|
|
193
|
-
if (!series) {
|
|
194
|
-
return { colorMapping: mapping, groupedSeries: {} };
|
|
195
|
-
}
|
|
196
|
-
const allSeries = isSymmetricalSeries(series)
|
|
197
|
-
? [...(series.above || []), ...(series.below || [])]
|
|
198
|
-
: series;
|
|
199
|
-
// Group series by resource
|
|
200
|
-
const groups = allSeries
|
|
201
|
-
.filter((serie) => selectedResources.includes(serie.resource))
|
|
202
|
-
.reduce((acc, serie) => {
|
|
203
|
-
const key = serie.resource;
|
|
204
|
-
if (!acc[key]) {
|
|
205
|
-
acc[key] = [];
|
|
206
|
-
}
|
|
207
|
-
acc[key].push(serie);
|
|
208
|
-
return acc;
|
|
209
|
-
}, {});
|
|
210
|
-
// Get colors from the ChartLegend context
|
|
211
|
-
Object.keys(groups).forEach((resource) => {
|
|
212
|
-
const color = getColor(resource);
|
|
213
|
-
if (color) {
|
|
214
|
-
mapping[resource] = color;
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
console.warn(`Color not defined for resource: ${resource}`);
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
return {
|
|
221
|
-
colorMapping: mapping,
|
|
222
|
-
groupedSeries: groups,
|
|
223
|
-
};
|
|
224
|
-
}, [series, getColor, selectedResources]);
|
|
225
|
-
// Format time for display the tick in the x axis
|
|
41
|
+
// Hover state management for tooltip display
|
|
42
|
+
const { handleMouseEnter, handleMouseLeave, chartId } = useChartHover();
|
|
43
|
+
// Process chart data
|
|
44
|
+
const { rechartsData, topDomain, topValue, unitLabel, xAxisTicks, linesToRender, belowSeriesLabels, } = useChartData({
|
|
45
|
+
series,
|
|
46
|
+
startingTimeStamp,
|
|
47
|
+
duration,
|
|
48
|
+
interval,
|
|
49
|
+
yAxisType,
|
|
50
|
+
unitRange,
|
|
51
|
+
});
|
|
52
|
+
// Format X-axis labels based on duration
|
|
226
53
|
const formatXAxisLabelCallback = useCallback((timestamp) => formatXAxisLabel(timestamp, duration), [duration]);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
},
|
|
238
|
-
}, domain: yAxisType === 'symmetrical'
|
|
239
|
-
? [-topDomain, topDomain]
|
|
240
|
-
: [0, topDomain], axisLine: { stroke: theme.border }, tick: {
|
|
54
|
+
// Format Y-axis tick values
|
|
55
|
+
const tickFormatter = useCallback((value) => formatTickValue(value, topValue), [topValue]);
|
|
56
|
+
return (_jsxs(LineTemporalChartWrapper, { children: [_jsxs(Stack, { gap: "r4", children: [_jsxs(ChartTitleText, { children: [title, " ", unitLabel && `(${unitLabel})`] }), helpText && (_jsx(IconHelp, { tooltipMessage: helpText, overlayStyle: maxWidthTooltip })), isLoading && _jsx(Loader, {})] }), _jsx(StyledResponsiveContainer, { width: "100%", height: height, children: _jsxs(LineChart, { ref: chartRef, data: rechartsData, margin: { top: 0, right: 0, bottom: 0, left: 0 }, "aria-label": `Time series chart for ${title}`, syncId: syncId, accessibilityLayer: true, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, children: [_jsx(CartesianGrid, { vertical: true, horizontal: true, verticalPoints: [0], horizontalPoints: [0], stroke: theme.border, fill: theme.backgroundLevel4, strokeWidth: 1 }), _jsx(XAxis, { dataKey: "timestamp", type: "number", domain: ['dataMin', 'dataMax'], ticks: xAxisTicks, tickFormatter: formatXAxisLabelCallback, tickCount: 5, tick: {
|
|
57
|
+
fill: theme.textSecondary,
|
|
58
|
+
fontSize: fontSize.smaller,
|
|
59
|
+
}, axisLine: { stroke: theme.border } }), _jsx(YAxis, { orientation: "right", label: {
|
|
60
|
+
value: yAxisTitle,
|
|
61
|
+
angle: 90,
|
|
62
|
+
dx: 20,
|
|
63
|
+
style: {
|
|
241
64
|
fill: theme.textSecondary,
|
|
242
65
|
fontSize: fontSize.smaller,
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
66
|
+
},
|
|
67
|
+
}, domain: yAxisType === 'symmetrical'
|
|
68
|
+
? [-topDomain, topDomain]
|
|
69
|
+
: [0, topDomain], allowDataOverflow: true, axisLine: { stroke: theme.border }, tick: {
|
|
70
|
+
fill: theme.textSecondary,
|
|
71
|
+
fontSize: fontSize.smaller,
|
|
72
|
+
}, tickFormatter: tickFormatter, ticks: getTicks(topValue, yAxisType === 'symmetrical'), interval: 0 }), _jsx(Tooltip, { content: (props) => (_jsx(LineTimeSerieChartTooltip, { unitLabel: unitLabel, duration: duration, renderTooltip: renderTooltip, isSymmetrical: yAxisType === 'symmetrical', belowSeriesLabels: belowSeriesLabels, tooltipProps: props, chartContainerRef: chartRef, chartId: chartId })) }), yAxisType === 'symmetrical' && (_jsx(ReferenceLine, { y: 0, stroke: theme.border })), linesToRender.map((line) => (_jsx(Line, { type: "monotone", dataKey: line.dataKey, stroke: line.stroke, dot: false, isAnimationActive: false, strokeDasharray: line.strokeDasharray }, `${title}-${line.key}`)))] }) })] }));
|
|
247
73
|
}
|