Skip to content

Commit 9292307

Browse files
committed
support onClick for Donut/PieChart
1 parent cbf488b commit 9292307

File tree

4 files changed

+42
-20
lines changed

4 files changed

+42
-20
lines changed

packages/charts/src/components/PieChart/PieChart.tsx

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { enrichEventWithDetails, useStylesheet, useSyncRef } from '@ui5/webcomponents-react-base';
44
import { clsx } from 'clsx';
55
import type { CSSProperties } from 'react';
6-
import { cloneElement, forwardRef, isValidElement, useCallback, useMemo } from 'react';
6+
import { useRef, cloneElement, forwardRef, isValidElement, useCallback, useMemo } from 'react';
77
import {
88
Cell,
99
Curve,
@@ -18,7 +18,7 @@ import {
1818
import { getValueByDataKey } from 'recharts/lib/util/ChartUtils.js';
1919
import { useLegendItemClick } from '../../hooks/useLegendItemClick.js';
2020
import { useOnClickInternal } from '../../hooks/useOnClickInternal.js';
21-
import type { IChartBaseProps } from '../../interfaces/IChartBaseProps.js';
21+
import type { ActivePayload, IChartBaseProps } from '../../interfaces/IChartBaseProps.js';
2222
import type { IChartDimension } from '../../interfaces/IChartDimension.js';
2323
import type { IChartMeasure } from '../../interfaces/IChartMeasure.js';
2424
import type { IPolarChartConfig } from '../../interfaces/IPolarChartConfig.js';
@@ -141,6 +141,16 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
141141
}),
142142
[props.measure],
143143
);
144+
const activePayloadsRef = useRef<ActivePayload>({
145+
...measure,
146+
// these properties must be either set in the component, or in the `useOnClickInternal` hook
147+
dataKey: measure.accessor,
148+
name: measure.accessor,
149+
color: '',
150+
stroke: '',
151+
payload: {},
152+
value: '',
153+
});
144154

145155
const dataLabel = (props) => {
146156
const hideDataLabel =
@@ -164,11 +174,12 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
164174
);
165175

166176
const onItemLegendClick = useLegendItemClick(onLegendClick, () => measure.accessor);
167-
const onClickInternal = useOnClickInternal(onClick);
177+
const onClickInternal = useOnClickInternal(onClick, dataset, activePayloadsRef);
168178

169179
const onDataPointClickInternal = useCallback(
170180
(payload, dataIndex, event) => {
171181
if (payload && payload && typeof onDataPointClick === 'function') {
182+
//todo check values
172183
onDataPointClick(
173184
enrichEventWithDetails(event, {
174185
value: payload.value,
@@ -302,6 +313,10 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
302313
classNames.piechart,
303314
)}
304315
>
316+
{/*todo: accessibility layer needs active shape?*/}
317+
{/*todo: keyboard nav with active shape doesn't hide the default label of the Cell when active*/}
318+
{/*todo: when clicked while activeShape is set, it takes a lot of time to rerender the component, leading to
319+
strange behavior*/}
305320
<Pie
306321
onClick={onDataPointClickInternal}
307322
innerRadius={chartConfig.innerRadius}
@@ -315,17 +330,23 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
315330
labelLine={renderLabelLine}
316331
label={dataLabel}
317332
activeShape={chartConfig.activeSegment != null && renderActiveShape}
318-
rootTabIndex={-1}
333+
//todo: why do we need this?
334+
// rootTabIndex={-1}
319335
>
320336
{centerLabel && <RechartsLabel position="center">{centerLabel}</RechartsLabel>}
321337
{dataset &&
322-
dataset.map((data, index) => (
323-
<Cell
324-
key={index}
325-
name={`${dimension.formatter(getValueByDataKey(data, dimension.accessor, ''))}`}
326-
fill={measure.colors?.[index] ?? `var(--sapChart_OrderedColor_${(index % 12) + 1})`}
327-
/>
328-
))}
338+
dataset.map((data, index) => {
339+
const color = measure.colors?.[index] ?? `var(--sapChart_OrderedColor_${(index % 12) + 1})`;
340+
activePayloadsRef.current.color = color;
341+
activePayloadsRef.current.stroke = color;
342+
return (
343+
<Cell
344+
key={index}
345+
name={`${dimension.formatter(getValueByDataKey(data, dimension.accessor, ''))}`}
346+
fill={color}
347+
/>
348+
);
349+
})}
329350
</Pie>
330351
{tooltipConfig?.active !== false && (
331352
<Tooltip

packages/charts/src/hooks/useLabelFormatter.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
import { useCallback } from 'react';
2-
import type { TooltipProps } from 'recharts';
3-
import type { NameType, TooltipLabelFormatter, ValueType } from '../interfaces/index.js';
2+
import type { TooltipLabelFormatter } from '../interfaces/index.js';
43

54
export const useLabelFormatter = (formatter: TooltipLabelFormatter) => {
65
return useCallback<TooltipLabelFormatter>(
7-
(label: TooltipProps<ValueType, NameType>['label'], payload) => {
6+
(label: string | number, payload) => {
87
if (typeof formatter === 'function') {
98
return formatter(label, payload);
109
}

packages/charts/src/hooks/useOnClickInternal.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,20 @@ import type { ActivePayload, IChartBaseProps } from '../interfaces/IChartBasePro
66
export const useOnClickInternal = (
77
onClick: IChartBaseProps['onClick'],
88
dataset: IChartBaseProps['dataset'],
9-
activePayloadsRef: MutableRefObject<ActivePayload[]>,
9+
activePayloadsRef: MutableRefObject<ActivePayload[]> | MutableRefObject<ActivePayload>,
1010
): CategoricalChartFunc => {
1111
//todo: deprecate payload & activePayloads?
1212
return useCallback(
1313
(nextState, event) => {
1414
if (typeof onClick === 'function') {
1515
const payload = nextState.activeIndex != null ? dataset?.[nextState.activeIndex] : undefined;
16-
const activePayloads = activePayloadsRef.current.map((item) => ({
16+
const activePayloads = (
17+
Array.isArray(activePayloadsRef.current) ? activePayloadsRef.current : [activePayloadsRef.current]
18+
).map((item) => ({
1719
...item,
1820
payload,
1921
value: item.dataKey ? payload?.[item.dataKey] : undefined,
2022
}));
21-
console.log('click enriched');
2223
onClick(
2324
//todo: check ts-error
2425
// @ts-expect-error: check

packages/charts/src/interfaces/IChartBaseProps.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ export interface ActivePayload {
1313
color: string;
1414
stroke: string;
1515
dataKey: string;
16-
hide: boolean;
16+
hide?: boolean;
1717
name: string;
18-
fillOpacity: string | number;
19-
strokeOpacity: string | number;
18+
fillOpacity?: string | number;
19+
strokeOpacity?: string | number;
2020
payload: Record<string, unknown>;
2121
value: number | string;
22+
colors?: string[];
2223
}
2324

2425
export interface IChartBaseProps<T = ICartesianChartConfig> extends Omit<CommonProps, 'onClick'> {

0 commit comments

Comments
 (0)