Skip to content

Commit d5b612d

Browse files
authored
fix(Pie- & DonutChart): improve activeSegment handling & fix focus behavior (#6686)
Fixes #6683
1 parent 2d9dbe4 commit d5b612d

File tree

6 files changed

+92
-19
lines changed

6 files changed

+92
-19
lines changed

packages/charts/src/components/DonutChart/DonutChart.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import LegendStory from '../../resources/LegendConfig.mdx';
4343

4444
### With highlighted active segment
4545

46-
<Canvas of={ComponentStories.WithHighlightedActiveSegment} />
46+
<Canvas of={ComponentStories.WithActiveShape} />
4747

4848
### Hide labels
4949

packages/charts/src/components/DonutChart/DonutChart.stories.tsx

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Meta, StoryObj } from '@storybook/react';
2+
import { useEffect, useState } from 'react';
23
import { legendConfig, simpleDataSet, simpleDataSetWithSmallValues, tooltipConfig } from '../../resources/DemoProps.js';
34
import { DonutChart } from './DonutChart.js';
45

@@ -73,15 +74,6 @@ export const WithFormatter: Story = {
7374
}
7475
};
7576

76-
export const WithHighlightedActiveSegment: Story = {
77-
args: {
78-
chartConfig: {
79-
activeSegment: 9,
80-
showActiveSegmentDataLabel: true
81-
}
82-
}
83-
};
84-
8577
export const HideLabels: Story = {
8678
args: {
8779
measure: {
@@ -103,3 +95,27 @@ export const WithCustomTooltipConfig: Story = {
10395
export const WithCustomLegendConfig: Story = {
10496
args: legendConfig
10597
};
98+
99+
export const WithActiveShape: Story = {
100+
args: {
101+
chartConfig: {
102+
activeSegment: 1,
103+
showActiveSegmentDataLabel: true
104+
}
105+
},
106+
render(args) {
107+
const [activeSegment, setActiveSegment] = useState(args.chartConfig.activeSegment);
108+
const handleChartClick = (e) => {
109+
const { dataIndex } = e.detail;
110+
if (dataIndex != null) {
111+
setActiveSegment(dataIndex);
112+
}
113+
};
114+
115+
useEffect(() => {
116+
setActiveSegment(args.chartConfig.activeSegment);
117+
}, [args.chartConfig.activeSegment]);
118+
119+
return <DonutChart {...args} chartConfig={{ ...args.chartConfig, activeSegment }} onClick={handleChartClick} />;
120+
}
121+
};

packages/charts/src/components/DonutChart/DonutChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const DonutChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
1717
...props.chartConfig
1818
};
1919

20-
return <PieChart {...props} ref={ref} chartConfig={chartConfig} />;
20+
return <PieChart {...props} ref={ref} chartConfig={chartConfig} data-component-name="DonutChart" />;
2121
});
2222

2323
DonutChart.displayName = 'DonutChart';

packages/charts/src/components/PieChart/PieChart.module.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,11 @@
33
path:focus {
44
outline: none;
55
}
6+
7+
[data-active-legend] {
8+
background: color-mix(in srgb, var(--sapSelectedColor), transparent 87%);
9+
:global(.recharts-legend-item-text) {
10+
color: var(--sapTextColor) !important;
11+
}
12+
}
613
}

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Meta, StoryObj } from '@storybook/react';
2+
import { useEffect, useState } from 'react';
23
import { legendConfig, simpleDataSet, simpleDataSetWithSmallValues, tooltipConfig } from '../../resources/DemoProps.js';
34
import { PieChart } from './PieChart.js';
45

@@ -51,6 +52,41 @@ export const WithFormatter: Story = {
5152
activeSegment: 1,
5253
showActiveSegmentDataLabel: true
5354
}
55+
},
56+
render(args) {
57+
const [activeSegment, setActiveSegment] = useState(1);
58+
const handleChartClick = (e) => {
59+
const { dataIndex } = e.detail;
60+
if (dataIndex != null) {
61+
setActiveSegment(dataIndex);
62+
}
63+
};
64+
65+
return <PieChart {...args} chartConfig={{ ...args.chartConfig, activeSegment }} onClick={handleChartClick} />;
66+
}
67+
};
68+
69+
export const WithActiveShape: Story = {
70+
args: {
71+
chartConfig: {
72+
activeSegment: 1,
73+
showActiveSegmentDataLabel: true
74+
}
75+
},
76+
render(args) {
77+
const [activeSegment, setActiveSegment] = useState(args.chartConfig.activeSegment);
78+
const handleChartClick = (e) => {
79+
const { dataIndex } = e.detail;
80+
if (dataIndex != null) {
81+
setActiveSegment(dataIndex);
82+
}
83+
};
84+
85+
useEffect(() => {
86+
setActiveSegment(args.chartConfig.activeSegment);
87+
}, [args.chartConfig.activeSegment]);
88+
89+
return <PieChart {...args} chartConfig={{ ...args.chartConfig, activeSegment }} onClick={handleChartClick} />;
5490
}
5591
};
5692

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

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { enrichEventWithDetails, useStylesheet } from '@ui5/webcomponents-react-base';
3+
import { enrichEventWithDetails, useStylesheet, useSyncRef } from '@ui5/webcomponents-react-base';
44
import { clsx } from 'clsx';
55
import type { CSSProperties } from 'react';
66
import { cloneElement, forwardRef, isValidElement, useCallback, useMemo } from 'react';
@@ -109,6 +109,8 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
109109
} = props;
110110

111111
useStylesheet(styleData, PieChart.displayName);
112+
const [componentRef, chartRef] = useSyncRef(ref);
113+
const isDonutChart = props['data-component-name'] === 'DonutChart';
112114

113115
const chartConfig: PieChartProps['chartConfig'] = {
114116
margin: { right: 30, left: 30, bottom: 30, top: 30, ...(props.chartConfig?.margin ?? {}) },
@@ -193,12 +195,23 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
193195
const ex = mx + (cos >= 0 ? 1 : -1) * 22;
194196
const ey = my;
195197
const textAnchor = cos >= 0 ? 'start' : 'end';
198+
const activeLegendItem = chartRef.current?.querySelector<HTMLLIElement>(
199+
`.legend-item-${chartConfig.activeSegment}`
200+
);
201+
if (!activeLegendItem?.dataset.activeLegend) {
202+
const allLegendItems = chartRef.current?.querySelectorAll('.recharts-legend-item');
203+
204+
allLegendItems.forEach((item) => item.removeAttribute('data-active-legend'));
205+
activeLegendItem.setAttribute('data-active-legend', 'true');
206+
}
196207

197208
return (
198209
<g>
199-
<text x={cx} y={cy} dy={8} textAnchor="middle" fill={fill}>
200-
{payload.name}
201-
</text>
210+
{isDonutChart && (
211+
<text x={cx} y={cy} dy={8} textAnchor="middle" fill={fill}>
212+
{payload.name}
213+
</text>
214+
)}
202215
<Sector
203216
cx={cx}
204217
cy={cy}
@@ -232,7 +245,7 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
232245
</g>
233246
);
234247
},
235-
[showActiveSegmentDataLabel]
248+
[showActiveSegmentDataLabel, chartConfig.activeSegment, isDonutChart]
236249
);
237250

238251
const renderLabelLine = useCallback(
@@ -249,11 +262,11 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
249262
if (chartConfig.activeSegment != null && showActiveSegmentDataLabel) {
250263
if (chartConfig.legendPosition === 'bottom') {
251264
return {
252-
paddingTop: '30px'
265+
paddingBlockStart: '30px'
253266
};
254267
} else if (chartConfig.legendPosition === 'top') {
255268
return {
256-
paddingBottom: '30px'
269+
paddingBlockEnd: '30px'
257270
};
258271
}
259272
}
@@ -266,7 +279,7 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
266279
return (
267280
<ChartContainer
268281
dataset={dataset}
269-
ref={ref}
282+
ref={componentRef}
270283
loading={loading}
271284
loadingDelay={loadingDelay}
272285
Placeholder={ChartPlaceholder ?? PieChartPlaceholder}
@@ -301,6 +314,7 @@ const PieChart = forwardRef<HTMLDivElement, PieChartProps>((props, ref) => {
301314
label={dataLabel}
302315
activeIndex={chartConfig.activeSegment}
303316
activeShape={chartConfig.activeSegment != null && renderActiveShape}
317+
rootTabIndex={-1}
304318
>
305319
{centerLabel && <RechartsLabel position="center">{centerLabel}</RechartsLabel>}
306320
{dataset &&

0 commit comments

Comments
 (0)