fix(echarts): adapt y-axis ticks and padding for compact timeseries charts (#38673)

This commit is contained in:
Enzo Martellucci
2026-03-31 17:44:42 +02:00
committed by GitHub
parent e6f1209318
commit f0b20dc445
3 changed files with 142 additions and 10 deletions

View File

@@ -711,6 +711,10 @@ export default function transformProps(
onLegendScroll,
} = hooks;
const addYAxisLabelOffset =
!!yAxisTitle && convertInteger(yAxisTitleMargin) !== 0;
const addXAxisLabelOffset =
!!xAxisTitle && convertInteger(xAxisTitleMargin) !== 0;
const legendData =
colorByPrimaryAxis && groupBy.length === 0 && series.length > 0
? (() => {
@@ -745,10 +749,6 @@ export default function transformProps(
)
.map(entry => entry.name || '')
.concat(extractAnnotationLabels(annotationLayers));
const addYAxisLabelOffset =
!!yAxisTitle && convertInteger(yAxisTitleMargin) !== 0;
const addXAxisLabelOffset =
!!xAxisTitle && convertInteger(xAxisTitleMargin) !== 0;
const sortedLegendData = [...legendData].sort((a: string, b: string) => {
if (!legendSort) return 0;
@@ -824,12 +824,21 @@ export default function transformProps(
isHorizontal,
);
// Reduce grid padding for small charts to maximize the drawing area.
// Keep enough top padding so the max label doesn't clip against the cell border.
// Preserve bottom padding when zoomable, since getPadding() reserves space for the dataZoom slider.
if (height < TIMESERIES_CONSTANTS.compactChartHeight) {
padding.top = Math.min(padding.top, 12);
if (!zoomable) {
padding.bottom = Math.min(padding.bottom, 5);
}
}
// When showMaxLabel is true, ECharts may render a label at the axis
// boundary that formats identically to the last data-point tick (e.g.
// "2005" appears twice with Year grain). Wrap the formatter to suppress
// consecutive duplicate labels.
const showMaxLabel =
xAxisType === AxisType.Time && xAxisLabelRotation === 0;
const showMaxLabel = xAxisType === AxisType.Time && xAxisLabelRotation === 0;
const deduplicatedFormatter = showMaxLabel
? (() => {
let lastLabel: string | undefined;
@@ -897,14 +906,35 @@ export default function transformProps(
),
};
// Adapt y-axis to chart height: three tiers based on available space.
// >= 100px: full axis with proportional tick count
// 60-99px: show only min/max boundary labels (splitNumber=1), hide lines/ticks
// < 60px: hide all axis decorations, show line only
const isSmallChart = height < TIMESERIES_CONSTANTS.compactChartHeight;
const isMicroChart = height < TIMESERIES_CONSTANTS.microChartHeight;
const yAxisSplitNumber = isMicroChart
? undefined
: isSmallChart
? 1
: Math.max(
3,
Math.floor(height / TIMESERIES_CONSTANTS.yAxisPixelsPerTick),
);
let yAxis: any = {
...defaultYAxis,
type: logAxis ? AxisType.Log : AxisType.Value,
...(yAxisSplitNumber !== undefined && { splitNumber: yAxisSplitNumber }),
min: yAxisMin,
max: yAxisMax,
minorTick: { show: minorTicks },
minorSplitLine: { show: minorSplitLine },
minorTick: { show: isSmallChart ? false : minorTicks },
minorSplitLine: { show: isSmallChart ? false : minorSplitLine },
splitLine: { show: !isSmallChart },
axisLabel: {
show: !isMicroChart,
showMinLabel: !isMicroChart,
showMaxLabel: !isMicroChart,
hideOverlap: true,
formatter: getYAxisFormatter(
metrics,
forcePercentFormatter,
@@ -913,8 +943,9 @@ export default function transformProps(
yAxisFormat,
),
},
axisTick: { show: !isSmallChart },
scale: truncateYAxis,
name: yAxisTitle,
name: isSmallChart ? undefined : yAxisTitle,
nameGap: convertInteger(yAxisTitleMargin),
nameLocation: yAxisTitlePosition === 'Left' ? 'middle' : 'end',
};
@@ -1066,7 +1097,8 @@ export default function transformProps(
...getLegendProps(
effectiveLegendType,
legendOrientation,
showLegend,
// Hide legend on compact charts — not enough vertical space
isSmallChart ? false : showLegend,
theme,
zoomable,
legendState,