[DASHBOARD] Allow hovering small pie slices that are smaller than the gap (#17330)
Fixes https://github.com/twentyhq/core-team-issues/issues/2059 ## Video QA ### Example with normal padding https://github.com/user-attachments/assets/aa0c610a-cdac-472e-afe7-b995ef3f32cd ### Example with bigger padding to better see the behavior https://github.com/user-attachments/assets/ff15b1f1-d18a-4fae-858a-2388f2cd9fa2
This commit is contained in:
+36
-22
@@ -11,9 +11,10 @@ type CustomArcsLayerProps = Pick<
|
||||
PieCustomLayerProps<PieChartDataItemWithColor>,
|
||||
'dataWithArc' | 'arcGenerator' | 'centerX' | 'centerY'
|
||||
> & {
|
||||
onMouseMove?: MouseEventHandler<PieChartDataItemWithColor, SVGPathElement>;
|
||||
onMouseLeave?: MouseEventHandler<PieChartDataItemWithColor, SVGPathElement>;
|
||||
onClick?: MouseEventHandler<PieChartDataItemWithColor, SVGPathElement>;
|
||||
padAngle: number;
|
||||
onMouseMove?: MouseEventHandler<PieChartDataItemWithColor, SVGElement>;
|
||||
onMouseLeave?: MouseEventHandler<PieChartDataItemWithColor, SVGElement>;
|
||||
onClick?: MouseEventHandler<PieChartDataItemWithColor, SVGElement>;
|
||||
};
|
||||
|
||||
export const CustomArcsLayer = ({
|
||||
@@ -21,6 +22,7 @@ export const CustomArcsLayer = ({
|
||||
arcGenerator,
|
||||
centerX,
|
||||
centerY,
|
||||
padAngle,
|
||||
onMouseMove,
|
||||
onMouseLeave,
|
||||
onClick,
|
||||
@@ -29,33 +31,35 @@ export const CustomArcsLayer = ({
|
||||
graphWidgetHighlightedLegendIdComponentState,
|
||||
);
|
||||
|
||||
const { transition, interpolate } = useArcsTransition(
|
||||
[...dataWithArc],
|
||||
'innerRadius',
|
||||
);
|
||||
const { transition } = useArcsTransition([...dataWithArc], 'innerRadius');
|
||||
|
||||
return (
|
||||
<g transform={`translate(${centerX},${centerY})`}>
|
||||
{transition((style, datum) => {
|
||||
{transition((_, datum) => {
|
||||
const isDimmed =
|
||||
isDefined(highlightedLegendId) &&
|
||||
String(highlightedLegendId) !== String(datum.id);
|
||||
const arcLength = datum.arc.endAngle - datum.arc.startAngle;
|
||||
const padAngleRadians = (padAngle * Math.PI) / 180;
|
||||
const clampedPadAngle = Math.min(
|
||||
padAngleRadians,
|
||||
Math.max(0, arcLength - 0.0001),
|
||||
);
|
||||
const halfPadAngle = clampedPadAngle / 2;
|
||||
const hitAreaPath = arcGenerator(datum.arc);
|
||||
const paddedArc = clampedPadAngle
|
||||
? {
|
||||
...datum.arc,
|
||||
startAngle: datum.arc.startAngle + halfPadAngle,
|
||||
endAngle: datum.arc.endAngle - halfPadAngle,
|
||||
}
|
||||
: datum.arc;
|
||||
const visiblePath = arcGenerator(paddedArc);
|
||||
|
||||
return (
|
||||
<animated.path
|
||||
<g
|
||||
key={datum.id}
|
||||
d={interpolate(
|
||||
style.startAngle,
|
||||
style.endAngle,
|
||||
style.innerRadius,
|
||||
style.outerRadius,
|
||||
arcGenerator,
|
||||
)}
|
||||
fill={datum.color}
|
||||
opacity={isDimmed ? LEGEND_HIGHLIGHT_DIMMED_OPACITY : 1}
|
||||
style={{
|
||||
transition: 'opacity 0.15s ease-in-out',
|
||||
}}
|
||||
pointerEvents="all"
|
||||
onMouseMove={
|
||||
onMouseMove ? (event) => onMouseMove(datum, event) : undefined
|
||||
}
|
||||
@@ -63,7 +67,17 @@ export const CustomArcsLayer = ({
|
||||
onMouseLeave ? (event) => onMouseLeave(datum, event) : undefined
|
||||
}
|
||||
onClick={onClick ? (event) => onClick(datum, event) : undefined}
|
||||
/>
|
||||
>
|
||||
<animated.path d={hitAreaPath ?? undefined} fill="transparent" />
|
||||
<animated.path
|
||||
d={visiblePath ?? undefined}
|
||||
fill={datum.color}
|
||||
opacity={isDimmed ? LEGEND_HIGHLIGHT_DIMMED_OPACITY : 1}
|
||||
style={{
|
||||
transition: 'opacity 0.15s ease-in-out',
|
||||
}}
|
||||
/>
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
</g>
|
||||
|
||||
+11
-4
@@ -111,7 +111,7 @@ export const GraphWidgetPieChart = ({
|
||||
const handleSliceMove = useCallback(
|
||||
(
|
||||
datum: ComputedDatum<PieChartDataItemWithColor>,
|
||||
event: ReactMouseEvent<SVGPathElement>,
|
||||
event: ReactMouseEvent<SVGElement>,
|
||||
) => {
|
||||
if (!isDefined(containerRef.current)) return;
|
||||
|
||||
@@ -140,14 +140,16 @@ export const GraphWidgetPieChart = ({
|
||||
const chartColors = hasNoData
|
||||
? [theme.background.tertiary]
|
||||
: enrichedData.map((item) => item.colorScheme.solid);
|
||||
const pieChartPadAngle = hasNoData ? 0 : 0.4;
|
||||
|
||||
const ArcsLayer = useCallback(
|
||||
(props: PieCustomLayerProps<PieChartDataItem>) => (
|
||||
(props: PieCustomLayerProps<PieChartDataItemWithColor>) => (
|
||||
<CustomArcsLayer
|
||||
dataWithArc={props.dataWithArc}
|
||||
arcGenerator={props.arcGenerator}
|
||||
centerX={props.centerX}
|
||||
centerY={props.centerY}
|
||||
padAngle={pieChartPadAngle}
|
||||
onMouseMove={hasNoData ? undefined : handleSliceMove}
|
||||
onMouseLeave={hasNoData ? undefined : handleSliceLeave}
|
||||
onClick={
|
||||
@@ -161,7 +163,13 @@ export const GraphWidgetPieChart = ({
|
||||
}
|
||||
/>
|
||||
),
|
||||
[hasNoData, handleSliceMove, handleSliceLeave, onSliceClick],
|
||||
[
|
||||
hasNoData,
|
||||
handleSliceMove,
|
||||
handleSliceLeave,
|
||||
onSliceClick,
|
||||
pieChartPadAngle,
|
||||
],
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -177,7 +185,6 @@ export const GraphWidgetPieChart = ({
|
||||
data={chartData}
|
||||
margin={showDataLabels && !hasNoData ? PIE_CHART_MARGINS : {}}
|
||||
innerRadius={0.8}
|
||||
padAngle={hasNoData ? 0 : 0.4}
|
||||
colors={chartColors}
|
||||
enableArcLinkLabels={showDataLabels && !hasNoData}
|
||||
enableArcLabels={false}
|
||||
|
||||
Reference in New Issue
Block a user