Search code examples
javascriptreactjssvgstate-machinecreateelement

How to dynamically modify an existing SVG in react?


I'm currently using state-machine-cat to generate dynamic state machine diagrams as SVG images for a reactJS application. This library generates the SVGs as strings, so I am able to integrate them into the react application using <div dangerouslySetInnerHTML={{__html: svg}} />.

I'm trying to do some "post-processing" of these images in order to add some additional SVG elements and attach onClick event handlers to specific nodes in the SVG.

If this was in plain HTML, I'd do something like the following:

div.querySelectorAll("g.node").forEach((node) => 
{       
    const icon = document.createElementNS("http://www.w3.org/2000/svg", "image"); 
    icon.setAttribute("x", calcX(node));
    icon.setAttribute("y", calcY(node));
    icon.setAttribute("height", "16");
    icon.setAttribute("width", "16");
    icon.setAttribute("src", "/badge.png");
    icon.addEventListener('click', clickHandler(node));
    node.appendChild(icon);
});    

However, ReactElements are in the virtual DOM, so they don't support querySelectorAll, etc. All of the examples I can find on manipulating an SVG in React involve creating it in React, while this is created externally and I need to manipulate it after-the-fact.

What is the best way to accomplish this?


Solution

  • I ended up replacing the <div dangerouslySetInnerHTML={{__html: svg}} /> line with html-react-parser and then using the options.replace callback to do processing as it walks down the DOM. It's reasonably fast and lets me do what I need to do.