Skip to content

Commit 9e05e58

Browse files
Fix cropped labels in legend + improve spacing
Signed-off-by: AntoineThebaud <antoine.thebaud@yahoo.fr>
1 parent 4730f7e commit 9e05e58

1 file changed

Lines changed: 48 additions & 11 deletions

File tree

components/src/utils/axis.ts

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,57 @@ export interface YAxisConfig {
2323
max?: number;
2424
}
2525

26-
// Average character width in pixels (approximate for typical UI fonts)
27-
const AVG_CHAR_WIDTH = 7;
28-
// Base padding for axis labels (spacing, axis line, etc.)
29-
const AXIS_LABEL_PADDING = 12;
26+
// Character width multipliers (approximate for typical UI fonts)
27+
const CHAR_WIDTH_BASE = 8;
28+
const CHAR_WIDTH_MULTIPLIERS = {
29+
dot: 0.5, // Dots and periods are very narrow
30+
uppercase: 0.9,
31+
lowercase: 0.65, // Lowercase letters slightly narrower
32+
digit: 0.7,
33+
symbol: 0.7, // Symbols like %, $, etc.
34+
space: 0.5, // Spaces
35+
};
36+
const AXIS_LABEL_PADDING = 14;
37+
38+
/**
39+
* Calculate the width of a single character based on its type
40+
*/
41+
function getCharWidth(char?: string): number {
42+
if (!char || char.length === 0) {
43+
return 0;
44+
}
45+
46+
if (char === '.' || char === ',' || char === ':') {
47+
return CHAR_WIDTH_BASE * CHAR_WIDTH_MULTIPLIERS.dot;
48+
}
49+
if (char === ' ') {
50+
return CHAR_WIDTH_BASE * CHAR_WIDTH_MULTIPLIERS.space;
51+
}
52+
if (char >= 'A' && char <= 'Z') {
53+
return CHAR_WIDTH_BASE * CHAR_WIDTH_MULTIPLIERS.uppercase;
54+
}
55+
if (char >= 'a' && char <= 'z') {
56+
return CHAR_WIDTH_BASE * CHAR_WIDTH_MULTIPLIERS.lowercase;
57+
}
58+
if (char >= '0' && char <= '9') {
59+
return CHAR_WIDTH_BASE * CHAR_WIDTH_MULTIPLIERS.digit;
60+
}
61+
// Symbols like %, $, -, +, etc.
62+
return CHAR_WIDTH_BASE * CHAR_WIDTH_MULTIPLIERS.symbol;
63+
}
3064

3165
/**
3266
* Estimate the pixel width needed for an axis label based on the formatted max value.
3367
* This provides dynamic spacing that adapts to the actual data scale.
3468
*/
3569
function estimateLabelWidth(format: FormatOptions | undefined, maxValue: number): number {
3670
const formattedLabel = formatValue(maxValue, format);
37-
return formattedLabel.length * AVG_CHAR_WIDTH + AXIS_LABEL_PADDING;
71+
// Calculate width based on individual character types
72+
let totalWidth = 0;
73+
for (let i = 0; i < formattedLabel.length; i++) {
74+
totalWidth += getCharWidth(formattedLabel[i]);
75+
}
76+
return totalWidth;
3877
}
3978

4079
/*
@@ -92,12 +131,6 @@ export function getFormattedMultipleYAxes(
92131

93132
// Additional Y axes (right side) for each unique format
94133
additionalFormats.forEach((format, index) => {
95-
// For subsequent axes, add the width of the previous axis's labels
96-
if (index > 0 && maxValues) {
97-
const prevMaxValue = maxValues[index - 1] ?? 1000;
98-
cumulativeOffset += estimateLabelWidth(additionalFormats[index - 1], prevMaxValue);
99-
}
100-
101134
const rightAxisConfig: YAXisComponentOption = {
102135
type: 'value',
103136
position: 'right',
@@ -115,6 +148,10 @@ export function getFormattedMultipleYAxes(
115148
show: baseAxis?.show,
116149
};
117150
axes.push(rightAxisConfig);
151+
// For subsequent axes, add the width of the previous axis's labels
152+
if (maxValues) {
153+
cumulativeOffset += estimateLabelWidth(format, maxValues[index] ?? 1000) + AXIS_LABEL_PADDING;
154+
}
118155
});
119156

120157
return axes;

0 commit comments

Comments
 (0)