This is an automated email from the ASF dual-hosted git repository.
villebro pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new b02d18a39e fix(plugin-chart-echarts): sort tooltip correctly (#30819)
b02d18a39e is described below
commit b02d18a39e3ffb7cee2a6abd97a44393e33dc129
Author: Ville Brofeldt <[email protected]>
AuthorDate: Fri Nov 1 15:24:51 2024 -0700
fix(plugin-chart-echarts): sort tooltip correctly (#30819)
---
.../src/MixedTimeseries/transformProps.ts | 87 ++++++++++++----------
.../src/Timeseries/transformProps.ts | 52 +++++++------
.../plugin-chart-echarts/src/utils/series.ts | 19 +++++
.../plugin-chart-echarts/test/utils/series.test.ts | 27 +++++++
4 files changed, 122 insertions(+), 63 deletions(-)
diff --git
a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts
b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts
index e12cdfe6f8..d4d19f9c2f 100644
---
a/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts
+++
b/superset-frontend/plugins/plugin-chart-echarts/src/MixedTimeseries/transformProps.ts
@@ -62,6 +62,7 @@ import {
extractDataTotalValues,
extractSeries,
extractShowValueIndexes,
+ extractTooltipKeys,
getAxisType,
getColtypesMapping,
getLegendProps,
@@ -584,9 +585,13 @@ export default function transformProps(
: params.value[0];
const forecastValue: any[] = richTooltip ? params : [params];
- if (richTooltip && tooltipSortByMetric) {
- forecastValue.sort((a, b) => b.data[1] - a.data[1]);
- }
+ const sortedKeys = extractTooltipKeys(
+ forecastValue,
+ // horizontal mode is not supported in mixed series chart
+ 1,
+ richTooltip,
+ tooltipSortByMetric,
+ );
const rows: string[][] = [];
const forecastValues =
@@ -594,44 +599,46 @@ export default function transformProps(
const keys = Object.keys(forecastValues);
let focusedRow;
- keys.forEach(key => {
- const value = forecastValues[key];
- // if there are no dimensions, key is a verbose name of a metric,
- // otherwise it is a comma separated string where the first part is
metric name
- let formatterKey;
- if (primarySeries.has(key)) {
- formatterKey =
- groupby.length === 0 ? inverted[key] : labelMap[key]?.[0];
- } else {
- formatterKey =
- groupbyB.length === 0 ? inverted[key] : labelMapB[key]?.[0];
- }
- const tooltipFormatter = getFormatter(
- customFormatters,
- formatter,
- metrics,
- formatterKey,
- !!contributionMode,
- );
- const tooltipFormatterSecondary = getFormatter(
- customFormattersSecondary,
- formatterSecondary,
- metricsB,
- formatterKey,
- !!contributionMode,
- );
- const row = formatForecastTooltipSeries({
- ...value,
- seriesName: key,
- formatter: primarySeries.has(key)
- ? tooltipFormatter
- : tooltipFormatterSecondary,
+ sortedKeys
+ .filter(key => keys.includes(key))
+ .forEach(key => {
+ const value = forecastValues[key];
+ // if there are no dimensions, key is a verbose name of a metric,
+ // otherwise it is a comma separated string where the first part
is metric name
+ let formatterKey;
+ if (primarySeries.has(key)) {
+ formatterKey =
+ groupby.length === 0 ? inverted[key] : labelMap[key]?.[0];
+ } else {
+ formatterKey =
+ groupbyB.length === 0 ? inverted[key] : labelMapB[key]?.[0];
+ }
+ const tooltipFormatter = getFormatter(
+ customFormatters,
+ formatter,
+ metrics,
+ formatterKey,
+ !!contributionMode,
+ );
+ const tooltipFormatterSecondary = getFormatter(
+ customFormattersSecondary,
+ formatterSecondary,
+ metricsB,
+ formatterKey,
+ !!contributionMode,
+ );
+ const row = formatForecastTooltipSeries({
+ ...value,
+ seriesName: key,
+ formatter: primarySeries.has(key)
+ ? tooltipFormatter
+ : tooltipFormatterSecondary,
+ });
+ rows.push(row);
+ if (key === focusedSeries) {
+ focusedRow = rows.length - 1;
+ }
});
- rows.push(row);
- if (key === focusedSeries) {
- focusedRow = rows.length - 1;
- }
- });
return tooltipHtml(rows, tooltipFormatter(xValue), focusedRow);
},
},
diff --git
a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts
b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts
index c0da444bfe..b552ceba5c 100644
---
a/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts
+++
b/superset-frontend/plugins/plugin-chart-echarts/src/Timeseries/transformProps.ts
@@ -65,6 +65,7 @@ import {
extractDataTotalValues,
extractSeries,
extractShowValueIndexes,
+ extractTooltipKeys,
getAxisType,
getColtypesMapping,
getLegendProps,
@@ -251,7 +252,7 @@ export default function transformProps(
legendState,
});
const seriesContexts = extractForecastSeriesContexts(
- Object.values(rawSeries).map(series => series.name as string),
+ rawSeries.map(series => series.name as string),
);
const isAreaExpand = stack === StackControlsValue.Expand;
const xAxisDataType = dataTypes?.[xAxisLabel] ?? dataTypes?.[xAxisOrig];
@@ -543,11 +544,12 @@ export default function transformProps(
? params[0].value[xIndex]
: params.value[xIndex];
const forecastValue: any[] = richTooltip ? params : [params];
-
- if (richTooltip && tooltipSortByMetric) {
- forecastValue.sort((a, b) => b.data[yIndex] - a.data[yIndex]);
- }
-
+ const sortedKeys = extractTooltipKeys(
+ forecastValue,
+ yIndex,
+ richTooltip,
+ tooltipSortByMetric,
+ );
const forecastValues: Record<string, ForecastValue> =
extractForecastValuesFromTooltipParams(forecastValue, isHorizontal);
@@ -570,24 +572,28 @@ export default function transformProps(
const showPercentage = showTotal && !forcePercentFormatter;
const keys = Object.keys(forecastValues);
let focusedRow;
- keys.forEach(key => {
- const value = forecastValues[key];
- if (value.observation === 0 && stack) {
- return;
- }
- const row = formatForecastTooltipSeries({
- ...value,
- seriesName: key,
- formatter,
+ sortedKeys
+ .filter(key => keys.includes(key))
+ .forEach(key => {
+ const value = forecastValues[key];
+ if (value.observation === 0 && stack) {
+ return;
+ }
+ const row = formatForecastTooltipSeries({
+ ...value,
+ seriesName: key,
+ formatter,
+ });
+ if (showPercentage && value.observation !== undefined) {
+ row.push(
+ percentFormatter.format(value.observation / (total || 1)),
+ );
+ }
+ rows.push(row);
+ if (key === focusedSeries) {
+ focusedRow = rows.length - 1;
+ }
});
- if (showPercentage && value.observation !== undefined) {
- row.push(percentFormatter.format(value.observation / (total ||
1)));
- }
- rows.push(row);
- if (key === focusedSeries) {
- focusedRow = rows.length - 1;
- }
- });
if (stack) {
rows.reverse();
if (focusedRow !== undefined) {
diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts
b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts
index 13d36b7141..0aa0ae988e 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/utils/series.ts
@@ -642,3 +642,22 @@ export function getTimeCompareStackId(
}) || defaultId
);
}
+
+const TOOLTIP_SERIES_KEY = 'seriesId';
+export function extractTooltipKeys(
+ forecastValue: any[],
+ yIndex: number,
+ richTooltip?: boolean,
+ tooltipSortByMetric?: boolean,
+): string[] {
+ if (richTooltip && tooltipSortByMetric) {
+ return forecastValue
+ .slice()
+ .sort((a, b) => b.data[yIndex] - a.data[yIndex])
+ .map(value => value[TOOLTIP_SERIES_KEY]);
+ }
+ if (richTooltip) {
+ return forecastValue.map(s => s[TOOLTIP_SERIES_KEY]);
+ }
+ return [forecastValue[0][TOOLTIP_SERIES_KEY]];
+}
diff --git
a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts
b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts
index efc0ac745a..7054f6019a 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts
+++ b/superset-frontend/plugins/plugin-chart-echarts/test/utils/series.test.ts
@@ -31,6 +31,7 @@ import {
extractGroupbyLabel,
extractSeries,
extractShowValueIndexes,
+ extractTooltipKeys,
formatSeriesName,
getAxisType,
getChartPadding,
@@ -1072,3 +1073,29 @@ describe('getTimeCompareStackId', () => {
expect(result).toEqual('123');
});
});
+
+const forecastValue = [
+ {
+ data: [0, 1],
+ seriesId: 'foo',
+ },
+ {
+ data: [0, 2],
+ seriesId: 'bar',
+ },
+];
+
+test('extractTooltipKeys with rich tooltip', () => {
+ const result = extractTooltipKeys(forecastValue, 1, true, false);
+ expect(result).toEqual(['foo', 'bar']);
+});
+
+test('extractTooltipKeys with rich tooltip and sorting by metrics', () => {
+ const result = extractTooltipKeys(forecastValue, 1, true, true);
+ expect(result).toEqual(['bar', 'foo']);
+});
+
+test('extractTooltipKeys with non-rich tooltip', () => {
+ const result = extractTooltipKeys(forecastValue, 1, false, false);
+ expect(result).toEqual(['foo']);
+});