mirror of
https://github.com/apache/superset.git
synced 2026-04-07 10:31:50 +00:00
fix(Timeseries): dedup x axis labels (#38733)
This commit is contained in:
committed by
GitHub
parent
fc705d94e3
commit
f832f9b0d5
@@ -824,6 +824,33 @@ export default function transformProps(
|
||||
isHorizontal,
|
||||
);
|
||||
|
||||
// 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 deduplicatedFormatter = showMaxLabel
|
||||
? (() => {
|
||||
let lastLabel: string | undefined;
|
||||
const wrapper = (value: number | string) => {
|
||||
const label =
|
||||
typeof xAxisFormatter === 'function'
|
||||
? (xAxisFormatter as Function)(value)
|
||||
: String(value);
|
||||
if (label === lastLabel) {
|
||||
return '';
|
||||
}
|
||||
lastLabel = label;
|
||||
return label;
|
||||
};
|
||||
if (typeof xAxisFormatter === 'function' && 'id' in xAxisFormatter) {
|
||||
(wrapper as any).id = (xAxisFormatter as any).id;
|
||||
}
|
||||
return wrapper;
|
||||
})()
|
||||
: xAxisFormatter;
|
||||
|
||||
let xAxis: any = {
|
||||
type: xAxisType,
|
||||
name: xAxisTitle,
|
||||
@@ -837,17 +864,16 @@ export default function transformProps(
|
||||
// from overlapping each other, with showMaxLabel to ensure
|
||||
// the last data point label stays visible (#37181).
|
||||
hideOverlap: !(xAxisType === AxisType.Time && xAxisLabelRotation !== 0),
|
||||
formatter: xAxisFormatter,
|
||||
formatter: deduplicatedFormatter,
|
||||
rotate: xAxisLabelRotation,
|
||||
interval: xAxisLabelInterval,
|
||||
// Force last label on non-rotated time axes to prevent
|
||||
// hideOverlap from hiding it. Skipped when rotated to
|
||||
// avoid phantom labels at the axis boundary.
|
||||
...(xAxisType === AxisType.Time &&
|
||||
xAxisLabelRotation === 0 && {
|
||||
showMaxLabel: true,
|
||||
alignMaxLabel: 'right',
|
||||
}),
|
||||
...(showMaxLabel && {
|
||||
showMaxLabel: true,
|
||||
alignMaxLabel: 'right',
|
||||
}),
|
||||
},
|
||||
minorTick: { show: minorTicks },
|
||||
minInterval:
|
||||
|
||||
@@ -28,7 +28,9 @@ import {
|
||||
SqlaFormData,
|
||||
TimeseriesAnnotationLayer,
|
||||
ChartDataResponseResult,
|
||||
TimeGranularity,
|
||||
} from '@superset-ui/core';
|
||||
import { GenericDataType } from '@apache-superset/core/common';
|
||||
import { EchartsTimeseriesChartProps } from '../../src/types';
|
||||
import type { SeriesOption } from 'echarts';
|
||||
import transformProps from '../../src/Timeseries/transformProps';
|
||||
@@ -1336,6 +1338,45 @@ test('should not apply axis bounds calculation when seriesType is not Bar for ho
|
||||
expect(xAxisRaw.max).toBeUndefined();
|
||||
});
|
||||
|
||||
test('x-axis formatter deduplicates consecutive identical labels for coarse time grains', () => {
|
||||
const yearData = [
|
||||
{ __timestamp: Date.UTC(2003, 0, 1), sales: 100 },
|
||||
{ __timestamp: Date.UTC(2004, 0, 1), sales: 200 },
|
||||
{ __timestamp: Date.UTC(2005, 0, 1), sales: 300 },
|
||||
];
|
||||
|
||||
const chartProps = createTestChartProps({
|
||||
formData: {
|
||||
granularity_sqla: 'ds',
|
||||
time_grain_sqla: TimeGranularity.YEAR,
|
||||
xAxisTimeFormat: '%Y',
|
||||
},
|
||||
queriesData: [
|
||||
createTestQueryData(yearData, {
|
||||
colnames: ['__timestamp', 'sales'],
|
||||
coltypes: [GenericDataType.Temporal, GenericDataType.Numeric],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
const transformedProps = transformProps(chartProps);
|
||||
const xAxisResult = transformedProps.echartOptions.xAxis as any;
|
||||
const { formatter } = xAxisResult.axisLabel;
|
||||
|
||||
expect(typeof formatter).toBe('function');
|
||||
expect(xAxisResult.axisLabel.showMaxLabel).toBe(true);
|
||||
|
||||
const label1 = formatter(Date.UTC(2003, 0, 1));
|
||||
const label2 = formatter(Date.UTC(2004, 0, 1));
|
||||
const label3 = formatter(Date.UTC(2005, 0, 1));
|
||||
const label4 = formatter(Date.UTC(2005, 6, 1));
|
||||
|
||||
expect(label1).toBe('2003');
|
||||
expect(label2).toBe('2004');
|
||||
expect(label3).toBe('2005');
|
||||
expect(label4).toBe('');
|
||||
});
|
||||
|
||||
test('should assign distinct dash patterns for multiple time offsets consistently', () => {
|
||||
const queriesDataWithMultipleOffsets = [
|
||||
createTestQueryData([
|
||||
|
||||
Reference in New Issue
Block a user