Skip to content

Commit

Permalink
Sankey nodes send tooltip events to state (recharts#4817)
Browse files Browse the repository at this point in the history
## Related Issue

recharts#4549
  • Loading branch information
PavelVanecek authored Jul 29, 2024
1 parent 1a90036 commit fcf53a4
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 5 deletions.
38 changes: 35 additions & 3 deletions src/chart/Sankey.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ function NodeElement({
onMouseEnter,
onMouseLeave,
onClick,
dataKey,
}: {
node: SankeyNode;
nodeContent: SankeyNodeOptions;
Expand All @@ -649,7 +650,9 @@ function NodeElement({
onMouseEnter: (nodeProps: NodeProps, e: MouseEvent) => void;
onMouseLeave: (nodeProps: NodeProps, e: MouseEvent) => void;
onClick: (nodeProps: NodeProps, e: MouseEvent) => void;
dataKey: DataKey<any>;
}) {
const dispatch = useAppDispatch();
const { x, y, dx, dy } = node;
const nodeProps: NodeProps = {
...filterProps(nodeContent, false),
Expand All @@ -660,10 +663,35 @@ function NodeElement({
index: i,
payload: node,
};

const activeCoordinate = getCoordinateOfTooltip(nodeProps, 'node');
const activeIndex = `node-${i}`;

const events = {
onMouseEnter: (e: MouseEvent) => onMouseEnter(nodeProps, e),
onMouseLeave: (e: MouseEvent) => onMouseLeave(nodeProps, e),
onClick: (e: MouseEvent) => onClick(nodeProps, e),
onMouseEnter: (e: MouseEvent) => {
dispatch(
setActiveMouseOverItemIndex({
activeIndex,
activeDataKey: dataKey,
activeMouseOverCoordinate: activeCoordinate,
}),
);
onMouseEnter(nodeProps, e);
},
onMouseLeave: (e: MouseEvent) => {
dispatch(mouseLeaveItem());
onMouseLeave(nodeProps, e);
},
onClick: (e: MouseEvent) => {
dispatch(
setActiveClickItemIndex({
activeIndex,
activeDataKey: dataKey,
activeClickCoordinate: activeCoordinate,
}),
);
onClick(nodeProps, e);
},
};

return <Layer {...events}>{renderNodeItem(nodeContent, nodeProps)}</Layer>;
Expand All @@ -676,13 +704,15 @@ function AllNodeElements({
onMouseEnter,
onMouseLeave,
onClick,
dataKey,
}: {
nodes: SankeyNode[];
nodeContent: SankeyNodeOptions;
margin: Margin;
onMouseEnter: (nodeProps: NodeProps, e: MouseEvent) => void;
onMouseLeave: (nodeProps: NodeProps, e: MouseEvent) => void;
onClick: (nodeProps: NodeProps, e: MouseEvent) => void;
dataKey: DataKey<any>;
}) {
const top = get(margin, 'top') || 0;
const left = get(margin, 'left') || 0;
Expand All @@ -698,6 +728,7 @@ function AllNodeElements({
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
onClick={onClick}
dataKey={dataKey}
/>
))}
</Layer>
Expand Down Expand Up @@ -909,6 +940,7 @@ export class Sankey extends PureComponent<Props, State> {
nodes={nodes}
nodeContent={this.props.node}
margin={this.props.margin}
dataKey={this.props.dataKey}
onMouseEnter={(nodeProps: NodeProps, e: MouseEvent) => this.handleMouseEnter(nodeProps, 'node', e)}
onMouseLeave={(nodeProps: NodeProps, e: MouseEvent) => this.handleMouseLeave(nodeProps, 'node', e)}
onClick={(nodeProps: NodeProps, e: MouseEvent) => this.handleClick(nodeProps, 'node', e)}
Expand Down
91 changes: 89 additions & 2 deletions test/chart/Sankey.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import { exampleSankeyData } from '../_data';
import { useChartHeight, useChartWidth, useClipPathId, useViewBox } from '../../src/context/chartLayoutContext';
import { useAppSelector } from '../../src/state/hooks';
import { assertNotNull } from '../helper/assertNotNull';
import { sankeyChartMouseHoverTooltipSelector } from '../component/Tooltip/tooltipMouseHoverSelectors';
import {
sankeyChartMouseHoverTooltipSelector,
sankeyNodeChartMouseHoverTooltipSelector,
} from '../component/Tooltip/tooltipMouseHoverSelectors';

describe('<Sankey />', () => {
it('renders 48 nodes in simple SankeyChart', () => {
Expand Down Expand Up @@ -179,6 +182,90 @@ describe('<Sankey />', () => {
expect(tooltipStateSpy).toHaveBeenCalledTimes(4);
});

it.todo('should start with tooltip inactive, and activate it on hover and click on a node');
it('should start with tooltip inactive, and activate it on hover and click on a node', () => {
const tooltipStateSpy = vi.fn();
const Comp = (): null => {
tooltipStateSpy(useAppSelector(state => state.tooltip.itemInteraction));
return null;
};
const { container } = render(
<Sankey width={1000} height={500} data={exampleSankeyData}>
<XAxis dataKey="number" type="number" />
<YAxis type="category" dataKey="name" />
<Customized component={<Comp />} />
</Sankey>,
);
expect(tooltipStateSpy).toHaveBeenLastCalledWith({
activeClick: false,
activeClickCoordinate: undefined,
activeClickDataKey: undefined,
activeClickIndex: null,
activeHover: false,
activeMouseOverCoordinate: undefined,
activeMouseOverDataKey: undefined,
activeMouseOverIndex: null,
});
expect(tooltipStateSpy).toHaveBeenCalledTimes(1);

const tooltipTriggerElement = container.querySelector(sankeyNodeChartMouseHoverTooltipSelector);
assertNotNull(tooltipTriggerElement);

fireEvent.mouseOver(tooltipTriggerElement, { clientX: 200, clientY: 200 });

expect(tooltipStateSpy).toHaveBeenLastCalledWith({
activeClick: false,
activeClickCoordinate: undefined,
activeClickDataKey: undefined,
activeClickIndex: null,
activeHover: true,
activeMouseOverCoordinate: {
x: 10,
y: 139.51593144373072,
},
activeMouseOverDataKey: 'value',
activeMouseOverIndex: 'node-0',
});
expect(tooltipStateSpy).toHaveBeenCalledTimes(2);

fireEvent.click(tooltipTriggerElement);

expect(tooltipStateSpy).toHaveBeenLastCalledWith({
activeClick: true,
activeClickCoordinate: {
x: 10,
y: 139.51593144373072,
},
activeClickDataKey: 'value',
activeClickIndex: 'node-0',
activeHover: true,
activeMouseOverCoordinate: {
x: 10,
y: 139.51593144373072,
},
activeMouseOverDataKey: 'value',
activeMouseOverIndex: 'node-0',
});
expect(tooltipStateSpy).toHaveBeenCalledTimes(3);

fireEvent.mouseLeave(tooltipTriggerElement);

expect(tooltipStateSpy).toHaveBeenLastCalledWith({
activeClick: true,
activeClickCoordinate: {
x: 10,
y: 139.51593144373072,
},
activeClickDataKey: 'value',
activeClickIndex: 'node-0',
activeHover: false,
activeMouseOverCoordinate: {
x: 10,
y: 139.51593144373072,
},
activeMouseOverDataKey: undefined,
activeMouseOverIndex: null,
});
expect(tooltipStateSpy).toHaveBeenCalledTimes(4);
});
});
});

0 comments on commit fcf53a4

Please sign in to comment.