Skip to content

Commit 3e2c58f

Browse files
committed
ARTESCA-14587: Adjust the chart base on the valueBase
1 parent 1e4855b commit 3e2c58f

File tree

2 files changed

+141
-41
lines changed

2 files changed

+141
-41
lines changed

src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,16 @@ import {
1818
fontWeight,
1919
lineTimeSeriesColorRange,
2020
} from '../../style/theme';
21-
import { ChartTitleText } from '../text/Text.component';
21+
import { ChartTitleText, SmallerText } from '../text/Text.component';
2222
import { Loader } from '../loader/Loader.component';
2323
import { spacing } from '../../spacing';
2424
import { getUnitLabel } from '../linetemporalchart/ChartUtil';
25+
import { Icon } from '../icon/Icon.component';
26+
import { Tooltip as TooltipComponent } from '../tooltip/Tooltip.component';
27+
import {
28+
DAY_MONTH_ABBREVIATED_HOUR_MINUTE,
29+
FormattedDateTime,
30+
} from '../date/FormattedDateTime';
2531

2632
const LineTemporalChartWrapper = styled.div`
2733
display: flex;
@@ -168,16 +174,10 @@ const CustomTooltip = ({
168174
return (
169175
<TooltipContainer>
170176
<TooltipTime>
171-
{new Date(label)
172-
.toLocaleString('en-GB', {
173-
day: 'numeric',
174-
month: 'short',
175-
hour: '2-digit',
176-
minute: '2-digit',
177-
second: '2-digit',
178-
hour12: false,
179-
})
180-
.replace(',', '')}
177+
<FormattedDateTime
178+
format="day-month-abbreviated-hour-minute-second"
179+
value={new Date(label)}
180+
/>
181181
</TooltipTime>
182182
{sortedPayload.map((entry, index) => (
183183
<TooltipValue key={index}>
@@ -187,9 +187,7 @@ const CustomTooltip = ({
187187
<TooltipInstanceValue>
188188
{isNaN(Number(entry.value))
189189
? '-'
190-
: typeof entry.value === 'number'
191-
? `${Math.round(entry.value * 100) / 100}${unitLabel}`
192-
: `${Number(entry.value).toFixed(2)}${unitLabel}`}
190+
: `${Number(entry.value).toFixed(2)}${unitLabel}`}
193191
</TooltipInstanceValue>
194192
</TooltipContent>
195193
</TooltipValue>
@@ -262,7 +260,8 @@ export function LineTimeSerieChart({
262260
}));
263261

264262
// 2. Convert directly to Recharts format
265-
const rechartsData: Record<
263+
// Initialize an object to hold data points by timestamp
264+
const dataPointsByTime: Record<
266265
number,
267266
{ timestamp: number } & Record<string, string | number | null>
268267
> = {};
@@ -278,17 +277,17 @@ export function LineTimeSerieChart({
278277
const timestamp =
279278
typeof point[0] === 'number' ? point[0] * 1000 : Number(point[0]);
280279
const value = point[1];
281-
282-
if (!rechartsData[timestamp]) {
283-
rechartsData[timestamp] = { timestamp };
280+
// Initialize this timestamp if it doesn't exist
281+
if (!dataPointsByTime[timestamp]) {
282+
dataPointsByTime[timestamp] = { timestamp };
284283
}
285-
286-
rechartsData[timestamp][label] = value;
284+
// Add this metric's value to the data point, and convert the value to a number if it's a string
285+
dataPointsByTime[timestamp][label] =
286+
typeof value === 'string' ? Number(value) : value;
287287
});
288288
});
289-
290289
// Convert object to array for Recharts
291-
return Object.values(rechartsData).sort(
290+
return Object.values(dataPointsByTime).sort(
292291
(
293292
a: { timestamp: number } & Record<string, string | number | null>,
294293
b: { timestamp: number } & Record<string, string | number | null>,
@@ -320,9 +319,11 @@ export function LineTimeSerieChart({
320319
return exactEvenTicks;
321320
}, [chartData]);
322321

323-
const { topValue, unitLabel } = useMemo(() => {
324-
if (yAxisType === 'percentage') return { topValue: 100, unitLabel: '%' };
325-
if (!unitRange || !chartData.length) return { topValue: 0, unitLabel: '' };
322+
const { topValue, unitLabel, valueBase } = useMemo(() => {
323+
if (yAxisType === 'percentage')
324+
return { topValue: 100, unitLabel: '%', valueBase: 1 };
325+
if (!unitRange || !chartData.length)
326+
return { topValue: 0, unitLabel: '', valueBase: 1 };
326327

327328
const values = chartData.flatMap((dataPoint) =>
328329
Object.entries(dataPoint)
@@ -338,14 +339,34 @@ export function LineTimeSerieChart({
338339
const top = Math.abs(Math.max(...values));
339340
const bottom = Math.abs(Math.min(...values));
340341
const maxValue = Math.max(top, bottom);
341-
const roundedMax = Math.ceil(maxValue / 10) * 10;
342+
343+
const valueBase = getUnitLabel(unitRange, maxValue).valueBase;
344+
const unitLabel = getUnitLabel(unitRange, maxValue).unitLabel;
345+
// Adjust the top value base on the valueBase
346+
const topValue = Math.ceil(maxValue / valueBase / 10) * 10;
342347

343348
return {
344-
topValue: roundedMax,
345-
unitLabel: getUnitLabel(unitRange, maxValue).unitLabel,
349+
topValue,
350+
unitLabel,
351+
valueBase,
346352
};
347353
}, [chartData, yAxisType, unitRange]);
348354

355+
// Convert the chartData base on the valuebase
356+
const rechartsData = useMemo(() => {
357+
if (!chartData || !chartData.length || valueBase === undefined) return [];
358+
359+
return chartData.map((dataPoint) => {
360+
const normalizedDataPoint = { ...dataPoint };
361+
Object.entries(dataPoint).forEach(([key, value]) => {
362+
if (key !== 'timestamp' && typeof value === 'number') {
363+
normalizedDataPoint[key] = value / valueBase;
364+
}
365+
});
366+
return normalizedDataPoint;
367+
});
368+
}, [chartData, valueBase]);
369+
349370
// Group series by resource and create color mapping
350371
const { colorMapping, groupedSeries } = useMemo(() => {
351372
const mapping: Record<string, string> = {};
@@ -383,14 +404,7 @@ export function LineTimeSerieChart({
383404
const formatTime = useMemo(
384405
() => (timestamp: number) => {
385406
const date = new Date(timestamp);
386-
return date
387-
.toLocaleDateString('en-GB', {
388-
day: 'numeric',
389-
month: 'short',
390-
hour: '2-digit',
391-
minute: '2-digit',
392-
})
393-
.replace(',', '');
407+
return DAY_MONTH_ABBREVIATED_HOUR_MINUTE.format(date).replace(',', '');
394408
},
395409
[],
396410
);
@@ -401,11 +415,19 @@ export function LineTimeSerieChart({
401415
<ChartTitleText>
402416
{title} {unitLabel && `(${unitLabel})`}
403417
</ChartTitleText>
418+
{helpText && (
419+
<TooltipComponent
420+
placement={'right'}
421+
overlay={<SmallerText>{helpText}</SmallerText>}
422+
>
423+
<Icon name="Info" color={theme.buttonSecondary} />
424+
</TooltipComponent>
425+
)}
404426
{isLoading && <Loader />}
405427
</ChartHeader>
406428
<ResponsiveContainer width="100%" height={height}>
407429
<LineChart
408-
data={chartData}
430+
data={rechartsData}
409431
ref={chartRef}
410432
margin={{ top: 0, right: 0, bottom: 0, left: 0 }}
411433
aria-label={`Time series chart for ${title}`}

stories/linetimeseriechart.stories.tsx

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ const meta: Meta<typeof LineTimeSerieChart> = {
3232
startingTimeStamp: { control: 'number' },
3333
unitRange: { control: 'object' },
3434
isLoading: { control: 'boolean' },
35-
isLegendHidden: { control: 'boolean' },
3635
yAxisType: {
3736
control: 'select',
3837
options: ['default', 'percentage', 'symmetrical'],
@@ -44,7 +43,6 @@ const meta: Meta<typeof LineTimeSerieChart> = {
4443
export default meta;
4544
type Story = StoryObj<typeof ChartWithProviders>;
4645

47-
// The Prometheus dataset converted for use with LineTemporalChartV2
4846
const prometheusData = [
4947
[1740405600, '47.554166666666674'],
5048
[1740406320, '53.00833333333337'],
@@ -293,6 +291,68 @@ const prometheusData4 = [
293291
[1740492000, '185.90'],
294292
];
295293

294+
const prometheusData5 = [
295+
[1740405600, '12850.45'],
296+
[1740406320, '21780.92'],
297+
[1740407760, '8320.15'],
298+
[1740408480, '16420.78'],
299+
[1740409200, '21950.34'],
300+
[1740409920, '9280.67'],
301+
[1740410640, '18605.89'],
302+
[1740411360, '12450.23'],
303+
[1740412080, '21308.56'],
304+
[1740412800, '18808.90'],
305+
[1740413520, '15305.67'],
306+
[1740414240, '24550.45'],
307+
[1740415680, '10205.89'],
308+
[1740416400, '19208.90'],
309+
[1740417120, '24802.34'],
310+
[1740417840, '13402.56'],
311+
[1740418560, '21450.78'],
312+
[1740419280, '18220.34'],
313+
[1740420000, '26608.90'],
314+
[1740420720, '19380.45'],
315+
[1740421440, '23350.67'],
316+
[1740422160, '19920.45'],
317+
[1740422880, '15480.23'],
318+
[1740423600, '28580.90'],
319+
[1740467520, '17280.45'],
320+
[1740468240, '24750.67'],
321+
[1740468960, '18420.34'],
322+
[1740469680, '23480.90'],
323+
[1740470400, '19850.67'],
324+
[1740471120, '27320.45'],
325+
[1740471840, '19720.34'],
326+
[1740472560, '24405.67'],
327+
[1740473280, '18502.89'],
328+
[1740474000, '27908.45'],
329+
[1740474720, '16205.67'],
330+
[1740475440, '23602.34'],
331+
[1740476160, '19305.89'],
332+
[1740476880, '24450.67'],
333+
[1740477600, '18858.90'],
334+
[1740478320, '26492.34'],
335+
[1740479040, '19588.90'],
336+
[1740479760, '28288.45'],
337+
[1740480480, '19765.67'],
338+
[1740481200, '23398.90'],
339+
[1740481920, '19492.34'],
340+
[1740482640, '25929.45'],
341+
[1740483360, '18329.67'],
342+
[1740484080, '24659.89'],
343+
[1740484800, '19459.23'],
344+
[1740485520, '27559.67'],
345+
[1740486240, '18259.89'],
346+
[1740486960, '25689.90'],
347+
[1740487680, '19959.34'],
348+
[1740488400, '28359.67'],
349+
[1740489120, '19489.90'],
350+
[1740489840, '26429.34'],
351+
[1740490560, '19729.45'],
352+
[1740491280, '28289.67'],
353+
[1740492000, '19859.90'],
354+
];
355+
296356
export const PercentageChartExample: Story = {
297357
args: {
298358
series: [
@@ -307,16 +367,16 @@ export const PercentageChartExample: Story = {
307367
title: 'CPU Usage',
308368
height: 200,
309369
startingTimeStamp: prometheusData[0][0],
310-
unitRange: [{ value: 1, unitLabel: '%' }],
311370
isLoading: false,
312371
isLegendHidden: false,
372+
helpText: 'This is the help text',
313373
yAxisType: 'percentage',
314374
yAxisTitle: '',
315375
},
316376
};
317377
const UNIT_RANGE_BS = [
318378
{
319-
threshold: 0,
379+
threshold: 1,
320380
label: 'B/s',
321381
},
322382
{
@@ -382,3 +442,21 @@ export const SymmetricalAxisExample: Story = {
382442
yAxisTitle: 'in(+)/out(-)',
383443
},
384444
};
445+
export const AutoUnitChartExample: Story = {
446+
args: {
447+
series: [
448+
{
449+
data: prometheusData5,
450+
resource: 'ip-10-160-122-207.eu-north-1.compute.internal',
451+
metricPrefix: 'instance:10.160.122.207:9100',
452+
getTooltipLabel: (prefix, resource) => `${resource}`,
453+
getLegendLabel: (prefix, resource) => `${resource}`,
454+
},
455+
],
456+
title: 'Disk Throughput',
457+
startingTimeStamp: prometheusData5[0][0],
458+
height: 200,
459+
unitRange: UNIT_RANGE_BS,
460+
yAxisType: 'default',
461+
},
462+
};

0 commit comments

Comments
 (0)