|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<head> |
|
<script src="https://fb.me/react-0.14.3.js"></script> |
|
<script src="https://fb.me/react-dom-0.14.3.js"></script> |
|
<script src="https://npmcdn.com/babel-core@5.8.34/browser.min.js"></script> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script src="http://underscorejs.org/underscore-min.js"></script> |
|
<script src="generate_data.js"></script> |
|
|
|
<link rel="stylesheet" href="example.css" type="text/css" /> |
|
</head> |
|
|
|
<body> |
|
|
|
<div id="main" /> |
|
|
|
<script type="text/babel"> |
|
|
|
var width = 960; |
|
var height = 500; |
|
var force = d3.layout.force() |
|
.charge(-300) |
|
.linkDistance(50) |
|
.size([width, height]); |
|
|
|
var Graph = React.createClass({ |
|
componentWillMount() { |
|
force.on('tick', () => { |
|
// after force calculation starts, call |
|
// forceUpdate on the React component on each tick |
|
this.forceUpdate() |
|
}); |
|
}, |
|
|
|
componentWillReceiveProps(nextProps) { |
|
// we should actually clone the nodes and links |
|
// since we're not supposed to directly mutate |
|
// props passed in from parent, and d3's force function |
|
// mutates the nodes and links array directly |
|
// we're bypassing that here for sake of brevity in example |
|
force.nodes(nextProps.nodes).links(nextProps.links); |
|
|
|
force.start(); |
|
}, |
|
|
|
render() { |
|
// use React to draw all the nodes, d3 calculates the x and y |
|
var nodes = _.map(this.props.nodes, (node) => { |
|
var transform = 'translate(' + node.x + ',' + node.y + ')'; |
|
return ( |
|
<g className='node' key={node.key} transform={transform}> |
|
<circle r={node.size} /> |
|
<text x={node.size + 5} dy='.35em'>{node.key}</text> |
|
</g> |
|
); |
|
}); |
|
var links = _.map(this.props.links, (link) => { |
|
return ( |
|
<line className='link' key={link.key} strokeWidth={link.size} |
|
x1={link.source.x} x2={link.target.x} y1={link.source.y} y2={link.target.y} /> |
|
); |
|
}); |
|
|
|
return ( |
|
<svg width={width} height={height}> |
|
<g> |
|
{links} |
|
{nodes} |
|
</g> |
|
</svg> |
|
); |
|
} |
|
}); |
|
|
|
var App = React.createClass({ |
|
getInitialState() { |
|
return { |
|
nodes: [], |
|
links: [], |
|
}; |
|
}, |
|
|
|
componentDidMount() { |
|
this.updateData(); |
|
}, |
|
|
|
updateData() { |
|
// randomData is loaded in from external file generate_data.js |
|
// and returns an object with nodes and links |
|
var newState = randomData(this.state.nodes, width, height); |
|
this.setState(newState); |
|
}, |
|
|
|
render() { |
|
return ( |
|
<div> |
|
<div className="update" onClick={this.updateData}>update</div> |
|
<Graph nodes={this.state.nodes} links={this.state.links} /> |
|
</div> |
|
); |
|
}, |
|
}); |
|
|
|
ReactDOM.render( |
|
<App />, |
|
document.getElementById('main') |
|
); |
|
|
|
</script> |
|
|
|
</body> |
Awesome! Just what I was looking for! Really nice example!