[D3] Creating a D3 Force Layout in React
Learn how to leverage d3's layout module to create a Force Layout inside of React. We'll take a look at React's lifecycle methods, using them to bootstrap d3's force layout in order to render our visualization.
import React, { Component } from 'react'; import * as d3 from 'd3'; const data = { "nodes": [ {"id": "Myriel", "group": 1}, ... {"id": "Mme.Hucheloup", "group": 8} ], "links": [ {"source": "Napoleon", "target": "Myriel", "value": 1}, ... {"source": "Mme.Hucheloup", "target": "Enjolras", "value": 1} ] } export default class ForceLayoutIntro extends Component { componentDidMount() { const { width, height } = this.props; const color = d3.scaleOrdinal(d3.schemeCategory20); const linkColor = d3.rgb('#c3c3c3'); function ticked (d) { link .attr("x1", (d) => d.source.x) .attr("y1", (d) => d.source.y) .attr("x2", (d) => d.target.x) .attr("y2", (d) => d.target.y); nodes .attr('cx', d => d.x) .attr('cy', d => d.y) } const simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function (d) { return d.id; })) .force("charge", d3.forceManyBody()) .force("center", d3.forceCenter(width / 2, height / 2)); const svg = d3.select(this.refs.mountPoint) .append('svg') .attr('height', height) .attr('width', width); const link = svg .append('g') .attr('class', 'links') .selectAll('links') .data(data.links) .enter().append('line') .attr('stroke', linkColor.brighter(0.5)) .attr('stroke-width', d => Math.sqrt(d.value)) const nodes = svg .append('g') .attr('class', 'nodes') .selectAll('circle') .data(data.nodes) .enter().append('circle') .attr('r', 5) .attr('fill', (d) => color(d.group)) .call(d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); simulation .nodes(data.nodes) .on('tick', ticked); simulation.force("link") .links(data.links); function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.3).restart(); d.fx = d.x; d.fy = d.y; } function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; } } // In render, we just need to create the container graph // The only important thing is we need to set ref // So that we can access the container in componentDidMount lifeCycle render() { const { width, height } = this.props; const style = { width, height, margin: '10px auto', border: '1px solid #323232', }; return ( <div style = {style} ref = "mountPoint"></div> ); } }