Creating an Interactive SVG Component Using React
Say I have an SVG element with paths for all US states.
<svg> <g id="nh"> <title>New Hampshire</title> <path d="m 880.79902,142.42476 0.869,-1.0765 1.09022,..." id="NH" class="state nh" /> </g> ... </svg> SVG data is saved in a separate file with the extension .svg . Let's say I want to create a React component of this map with full control over it so that I can modify the style of individual states based on some external input.
Using Webpack, as far as I can tell, I have two options for loading SVG markup: Insert it as raw markup using raw-loader and create the component using dangerouslySetInnerHTML :
var InlineSvg = React.createClass({ render() { var svg = require('./' + this.props.name + '.svg'); return <div dangerouslySetInnerHTML={{__html: svg}}></div>; } }); or manually convert the markup to virtual JSX:
var NewComponent = React.createClass({ render: function() { return ( <svg> <g id="nh"> <title>New Hampshire</title> <path d="m 880.79902,142.42476 0.869,-1.0765 1.09022,..." id="NH" className="state nh" /> </g> ... </svg> ); }); Finally, let's say that in addition to the SVG map, there is a simple list of HTML from all states. Whenever a user hovers over a list item, the corresponding SVG path must shift the fill color.
Now I canโt figure out how to update the React SVG component to reflect the freeze. Of course, I can contact the DOM, select the SVG state by the name of the class and change its color, but this does not seem to โrespondโ to this. The index finger would be greatly appreciated.
PS. I use Redux to handle all communication between components.
You need to do two things:
1) Set an event listener for each item in the list to report the highlighted item about your application.
<li onMouseOver={() => this.handleHover('NH')} onMouseOut={() => this.handleUnhover()} > New Hampshire </li> 2) Capture the data and distribute it to your SVG component.
This is the harder part, and it comes down to how you structured your application.
- If your application is the only React component, then
handleHoversimply update the state of the component - If your application is divided into several components, then
handleHoverwill call the callback passed as a support
Assume the latter. Component methods may look like this:
handleHover(territory) { this.props.onHighlight(territory); } handleUnhover() { this.props.onHighlight(null); } Assuming you have a parent component that contains both an SVG map and a list, it might look something like this:
class MapWrapper extends React.Component { constructor(props) { super(props); this.state = { highlighted: null; }; } setHighlight(territory) { this.setState({ highlighted: territory }); } render() { const highlighted = { this.state }; return ( <div> <MapDiagram highlighted={highlighted} /> <TerritoryList onHighlight={(terr) => this.setHighlight(terr)} /> </div> ); } } The key here is the highlighted state variable. Each time a new hover event occurs, highlighted changes in value. This change causes a re-rendering, and the new value is passed to MapDiagram , which can then determine which part of the SVG to highlight.