diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx index aab4af54585b..c195c5e2214d 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/controlPanel.tsx @@ -183,6 +183,18 @@ const config: ControlPanelConfig = { }, }, ], + [ + { + name: 'show_total', + config: { + type: 'CheckboxControl', + label: t('Show Total'), + default: false, + renderTrigger: true, + description: t('Whether to display the aggregate count'), + }, + }, + ], // eslint-disable-next-line react/jsx-key [

{t('Pie shape')}

], [ diff --git a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts index 237f4ae001f7..aeeec088b05c 100644 --- a/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts +++ b/superset-frontend/plugins/plugin-chart-echarts/src/Pie/transformProps.ts @@ -25,6 +25,7 @@ import { getTimeFormatter, NumberFormats, NumberFormatter, + t, } from '@superset-ui/core'; import { CallbackDataParams } from 'echarts/types/src/util/types'; import { EChartsCoreOption, PieSeriesOption } from 'echarts'; @@ -45,6 +46,7 @@ import { } from '../utils/series'; import { defaultGrid, defaultTooltip } from '../defaults'; import { OpacityEnum } from '../constants'; +import { convertInteger } from '../utils/convertInteger'; const percentFormatter = getNumberFormatter(NumberFormats.PERCENT_2_POINT); @@ -82,6 +84,54 @@ export function formatPieLabel({ } } +function getTotalValuePadding({ + chartPadding, + donut, + width, + height, +}: { + chartPadding: { + bottom: number; + left: number; + right: number; + top: number; + }; + donut: boolean; + width: number; + height: number; +}) { + const padding: { + left?: string; + top?: string; + } = { + top: donut ? 'middle' : '0', + left: 'center', + }; + const LEGEND_HEIGHT = 15; + const LEGEND_WIDTH = 215; + if (chartPadding.top) { + padding.top = donut + ? `${50 + ((chartPadding.top - LEGEND_HEIGHT) / height / 2) * 100}%` + : `${((chartPadding.top + LEGEND_HEIGHT) / height) * 100}%`; + } + if (chartPadding.bottom) { + padding.top = donut + ? `${50 - ((chartPadding.bottom + LEGEND_HEIGHT) / height / 2) * 100}%` + : '0'; + } + if (chartPadding.left) { + padding.left = `${ + 50 + ((chartPadding.left - LEGEND_WIDTH) / width / 2) * 100 + }%`; + } + if (chartPadding.right) { + padding.left = `${ + 50 - ((chartPadding.right + LEGEND_WIDTH) / width / 2) * 100 + }%`; + } + return padding; +} + export default function transformProps( chartProps: EchartsPieChartProps, ): PieChartTransformedProps { @@ -110,6 +160,7 @@ export default function transformProps( showLabelsThreshold, emitFilter, sliceId, + showTotal, }: EchartsPieFormData = { ...DEFAULT_LEGEND_FORM_DATA, ...DEFAULT_PIE_FORM_DATA, @@ -147,6 +198,7 @@ export default function transformProps( const colorFn = CategoricalColorNamespace.getScale(colorScheme as string); const numberFormatter = getNumberFormatter(numberFormat); + let totalValue = 0; const transformedData: PieSeriesOption[] = data.map(datum => { const name = extractGroupbyLabel({ @@ -158,9 +210,14 @@ export default function transformProps( const isFiltered = filterState.selectedValues && !filterState.selectedValues.includes(name); + const value = datum[metricLabel]; + + if (typeof value === 'number' || typeof value === 'string') { + totalValue += convertInteger(value); + } return { - value: datum[metricLabel], + value, name, itemStyle: { color: colorFn(name, sliceId), @@ -197,10 +254,16 @@ export default function transformProps( color: '#000000', }; + const chartPadding = getChartPadding( + showLegend, + legendOrientation, + legendMargin, + ); + const series: PieSeriesOption[] = [ { type: 'pie', - ...getChartPadding(showLegend, legendOrientation, legendMargin), + ...chartPadding, animation: false, radius: [`${donut ? innerRadius : 0}%`, `${outerRadius}%`], center: ['50%', '50%'], @@ -248,6 +311,18 @@ export default function transformProps( ...getLegendProps(legendType, legendOrientation, showLegend), data: keys, }, + graphic: showTotal + ? { + type: 'text', + ...getTotalValuePadding({ chartPadding, donut, width, height }), + style: { + text: t(`Total: ${numberFormatter(totalValue)}`), + fontSize: 16, + fontWeight: 'bold', + }, + z: 10, + } + : null, series, };