Skip to content

Commit bf199aa

Browse files
Improve Y axis computation
1 parent 6e49a39 commit bf199aa

File tree

4 files changed

+41
-67
lines changed

4 files changed

+41
-67
lines changed

package-lock.json

Lines changed: 0 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/components/barchartv2/Barchart.component.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
297297
{} as Record<string, ChartColors | string>,
298298
);
299299

300-
const { rechartsBars, unitLabel, roundReferenceValue, rechartsData } =
300+
const { rechartsBars, unitLabel, roundReferenceValue, rechartsData, topDomain } =
301301
useChartData(
302302
bars || [],
303303
type,
@@ -363,7 +363,7 @@ export const Barchart = <T extends BarchartBars>(props: BarchartProps<T>) => {
363363

364364
<YAxis
365365
interval={0}
366-
domain={[0, roundReferenceValue]}
366+
domain={[0, topDomain]}
367367
ticks={getTicks(roundReferenceValue, false)}
368368
tickFormatter={
369369
(value) => new Intl.NumberFormat('fr-FR').format(value) // Add a space as thousand separator

src/lib/components/barchartv2/utils.ts

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,39 @@ import { useChartLegend } from '../chartlegend/ChartLegendWrapper';
55

66
export const getRoundReferenceValue = (value: number): number => {
77
if (value <= 0) return 1; // Default for zero or negative values
8+
9+
// Buffer the value by 10% to avoid being too close to the edge of the chart
10+
const bufferedValue = value * 1.1;
11+
12+
if (value >= 10) {
13+
const remainder = value % 10;
14+
const incremented = value + (10 - remainder);
15+
16+
// If the remainder is less than 5, round down to the nearest 10
17+
if (remainder < 5) {
18+
return value - remainder;
19+
}
20+
21+
// If incrementing would exceed the buffered max, also round down
22+
if (incremented > bufferedValue) {
23+
return value - remainder;
24+
}
25+
26+
// Otherwise, round up to the next 10
27+
return incremented;
28+
}
829

9-
// Get the magnitude (10^n where n is the number of digits - 1)
1030
const magnitude = Math.pow(10, Math.floor(Math.log10(value)));
1131

12-
// Buffer the value by 10% to avoid being too close to the edge of the chart
13-
const bufferedValue = value * 1.1;
32+
const remainder = bufferedValue % magnitude;
1433

15-
// Normalized value between 1 and 10
16-
const normalized = bufferedValue / magnitude;
17-
18-
// Round to nice numbers based on normalized value
19-
// skip 1.5, 3, 4, 7.5 as top value for better chart
20-
// appearance for small values
21-
let result: number;
22-
23-
if (normalized <= 1) result = magnitude;
24-
else if (value > 10 && normalized <= 1.5) result = 1.5 * magnitude;
25-
else if (normalized <= 2) result = 2 * magnitude;
26-
else if (value > 10 && normalized <= 2.5) result = 2.5 * magnitude;
27-
else if (value > 10 && normalized <= 3) result = 3 * magnitude;
28-
else if (value > 10 && normalized <= 4) result = 4 * magnitude;
29-
else if (normalized <= 5) result = 5 * magnitude;
30-
else if (value > 10 && normalized <= 6) result = 6 * magnitude;
31-
else if (value > 10 && normalized <= 8) result = 8 * magnitude;
32-
else if (normalized <= 10) result = 10 * magnitude;
33-
else result = 10 * magnitude;
34-
35-
return result;
34+
return remainder === 0 ? bufferedValue : bufferedValue - remainder;
3635
};
3736

3837
export const getTicks = (topValue: number, isSymmetrical: boolean) => {
39-
if (topValue < 10) {
40-
if (isSymmetrical) {
41-
return [-topValue, 0, topValue];
42-
} else {
43-
return [0, topValue];
44-
}
45-
}
4638
const possibleTickNumbers = [4, 3];
4739
const numberOfTicks =
48-
possibleTickNumbers.find((number) => topValue % (number - 1) === 0) || 2; // Default to 2 ticks if no match
40+
possibleTickNumbers.find((number) => topValue % (number - 1) === 0) || 3; // Default to 2 ticks if no match
4941
const tickInterval = topValue / (numberOfTicks - 1);
5042
const ticks = Array.from(
5143
{ length: numberOfTicks },
@@ -339,7 +331,7 @@ export const computeUnitLabelAndRoundReferenceValue = (
339331
) => {
340332
if (!unitRange) {
341333
const roundReferenceValue = getRoundReferenceValue(maxValue);
342-
return { unitLabel: undefined, roundReferenceValue, rechartsData: data };
334+
return { unitLabel: undefined, roundReferenceValue, rechartsData: data, topDomain: maxValue * 1.1 };
343335
}
344336

345337
const { valueBase, unitLabel } = getUnitLabel(unitRange, maxValue);
@@ -354,7 +346,7 @@ export const computeUnitLabelAndRoundReferenceValue = (
354346
});
355347
return normalizedDataPoint;
356348
});
357-
return { unitLabel, roundReferenceValue, rechartsData };
349+
return { unitLabel, roundReferenceValue, rechartsData, topDomain: topValue * 1.1 };
358350
};
359351

360352
/**
@@ -534,12 +526,13 @@ export const useChartData = <T extends BarchartBars>(
534526

535527
const maxValue = getMaxBarValue(filteredData, stacked);
536528

537-
const { unitLabel, roundReferenceValue, rechartsData } =
529+
const { unitLabel, roundReferenceValue, rechartsData, topDomain } =
538530
computeUnitLabelAndRoundReferenceValue(filteredData, maxValue, unitRange);
539531

540532
return {
541533
rechartsBars: filteredRechartsBars,
542534
unitLabel,
535+
topDomain,
543536
roundReferenceValue,
544537
rechartsData,
545538
};

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

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -360,13 +360,7 @@ export function LineTimeSerieChart({
360360
}, [chartData]);
361361

362362
// 3. Transform the data base on the valuebase
363-
const { topValue, unitLabel, rechartsData } = useMemo(() => {
364-
if (yAxisType === 'percentage')
365-
return {
366-
topValue: 100,
367-
unitLabel: '%',
368-
rechartsData: chartData,
369-
};
363+
const { topValue, unitLabel, rechartsData, topDomain } = useMemo(() => {
370364

371365
const values = chartData.flatMap((dataPoint) =>
372366
Object.entries(dataPoint)
@@ -383,19 +377,20 @@ export function LineTimeSerieChart({
383377
if (values.length === 0) {
384378
return {
385379
topValue: 100, // Default value for empty charts
386-
unitLabel: '',
380+
unitLabel: yAxisType === 'percentage' ? '%' : '',
387381
rechartsData: [],
382+
topDomain: 100,
388383
};
389384
}
390385

391386
const top = Math.abs(Math.max(...values));
392387
const bottom = Math.abs(Math.min(...values));
393388
const maxValue = Math.max(top, bottom);
394-
395-
const { valueBase, unitLabel } = getUnitLabel(unitRange ?? [], maxValue);
389+
const { valueBase, unitLabel } = yAxisType === 'percentage' ? { valueBase: 1, unitLabel: '%' } : getUnitLabel(unitRange ?? [], maxValue);
396390
// Use round reference value to add extra padding to the top value
397-
const topValue = getRoundReferenceValue(maxValue / valueBase);
398-
391+
const basedValue = maxValue / valueBase
392+
const topDomain = basedValue * 1.1;
393+
const topValue = getRoundReferenceValue(basedValue);
399394
const rechartsData = chartData.map((dataPoint) => {
400395
const normalizedDataPoint = { ...dataPoint };
401396
Object.entries(dataPoint).forEach(([key, value]) => {
@@ -406,7 +401,7 @@ export function LineTimeSerieChart({
406401
return normalizedDataPoint;
407402
});
408403

409-
return { topValue, unitLabel, rechartsData };
404+
return { topValue, unitLabel, rechartsData, topDomain };
410405
}, [chartData, yAxisType, unitRange]);
411406

412407
// Group series by resource and create color mapping
@@ -522,10 +517,10 @@ export function LineTimeSerieChart({
522517
}}
523518
domain={
524519
yAxisType === 'percentage'
525-
? [0, 100]
520+
? [0, topDomain]
526521
: yAxisType === 'symmetrical'
527-
? [-topValue, topValue]
528-
: [0, topValue]
522+
? [-topDomain, topDomain]
523+
: [0, topDomain]
529524
}
530525
axisLine={{ stroke: theme.border }}
531526
tick={{

0 commit comments

Comments
 (0)