I am using the d3 drawing library with React.js, and have run into a problem with firing onClick events from SVG elements.
What I want to do is call a function (passed from parent in props) when I click on an element in the SVG. The problem is that the elements of the SVG are produced by d3, and are not react components. Is there any way that I can make this work?
For those not familiar with d3, it provides a very nice fluent syntax for generating and updating svg from a set of data. The code looks something like this:
const existingNodes = d3Select('.nodes')
.selectAll('g.node')
.data(root.descendants());
const newNodes = existingNodes.enter().append('g');
newNodes
.append('circle')
.attr('onclick', (node) => 'onNodeSelected("Test")')
.attr('r', (node) => nodeRadius(node.data));
The problem with this code is the line that says .attr('onclick', (node) => 'onNodeSelected("Test")') which correctly adds an onclick attribute to the circles, but of course onNodeSelected is a prop of the react component and can't be accessed like this.
To provide some context, the abbreviated code for the React component is like this:
export const HierarchyDiagram = ({ onNodeSelected, hierarchyData }) => {
useEffect(() => {
function buildSvg(root) {
...abbreviated
const existingNodes = d3Select('.nodes')
.selectAll('g.node')
.data(root.descendants());
const newNodes = existingNodes.enter().append('g');
newNodes
.append('circle')
.attr('onclick', (node) => 'onNodeSelected({node})')
.attr('r', (node) => nodeRadius(node.data));
....abbreviated
}
if (hierarchyData) {
buildSvg(hierarchyData);
}
}, [hierarchyData]);
return (
<svg width="100%" height="100%">
<g className="wrapper">
<g className="links"></g>
<g className="nodes"></g>
</g>
</svg>
);
};