feat(plugin-chart-echarts): add aggregate total for the Pie/Donuct chart (#19622)

This commit is contained in:
Stephen Liu 2022-04-11 13:56:45 +08:00 committed by GitHub
parent b45f89b954
commit a6bf041edd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 2 deletions

View File

@ -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
[<h1 className="section-header">{t('Pie shape')}</h1>],
[

View File

@ -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,
};