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

(cherry picked from commit f0b20dc445)
This commit is contained in:
Enzo Martellucci
2026-03-31 17:44:42 +02:00
committed by Michael S. Molina
parent 6cff944b7f
commit 2ca54b418f
3 changed files with 141 additions and 8 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,6 +824,16 @@ 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
@@ -896,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,
@@ -912,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',
};
@@ -1065,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,

View File

@@ -47,6 +47,11 @@ export const TIMESERIES_CONSTANTS = {
extraControlsOffset: 22,
// Min right padding (px) for horizontal bar charts to ensure value labels are fully visible
horizontalBarLabelRightPadding: 70,
// Height thresholds (px) for responsive y-axis behavior
compactChartHeight: 100,
microChartHeight: 60,
// One y-axis tick per this many pixels of chart height
yAxisPixelsPerTick: 80,
};
export enum OpacityEnum {