<div id="root"></div>
body {
margin: 0;
}
.d3-component svg {
background: #ddd;
height: 300px;
max-height: 300px;
}
const size = 600
const defaultRadius = 20
const level2Colors = level => {
const colors = {
1: "#A01928",
2: "#9F62A4",
3: "#0B7A7A",
4: "#3F3F38",
}
return colors[level]
}
const level2Rad = level => {
return (2.5 * defaultRadius) / level
}
const loadData = () => {
const nodes = [
{ id: 1, level: 1, r: 8 },
{ id: 2, level: 2, r: 8 },
{ id: 3, level: 2, r: 8 },
{ id: 4, level: 2, r: 8 },
{ id: 5, level: 3, r: 8 },
{ id: 6, level: 3, r: 8 },
{ id: 7, level: 3, r: 8 },
{ id: 8, level: 3, r: 8 },
{ id: 9, level: 3, r: 8 },
{ id: 10, level: 3, r: 8 },
{ id: 11, level: 4, r: 8 },
{ id: 12, level: 4, r: 8 },
{ id: 13, level: 4, r: 8 },
{ id: 14, level: 4, r: 8 },
{ id: 15, level: 4, r: 8 },
{ id: 16, level: 4, r: 8 },
]
const links = [
{ source: 1, target: 2 },
{ source: 1, target: 3 },
{ source: 1, target: 4 },
{ source: 2, target: 5 },
{ source: 2, target: 6 },
{ source: 3, target: 7 },
{ source: 3, target: 8 },
{ source: 3, target: 9 },
{ source: 4, target: 5 },
{ source: 4, target: 9 },
{ source: 4, target: 10 },
{ source: 5, target: 11 },
{ source: 5, target: 12 },
{ source: 7, target: 13 },
{ source: 8, target: 14 },
{ source: 10, target: 15 },
{ source: 10, target: 16 },
{ source: 9, target: 16 },
]
return { nodes, links }
}
class CustomD3Component extends React.Component {
componentDidMount() {
const node = document.querySelector("#d3Node")
console.log(node)
this.initialize(node, {})
}
initialize = (node, props) => {
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
}
const svg = (this.svg = d3.select(node).append("svg"))
svg
.attr("viewBox", `0 0 ${size} ${size}`)
.style("width", "100%")
.style("height", "auto")
const simulation = d3
.forceSimulation()
.force(
"link",
d3
.forceLink()
.id(function(d) {
return d.id;
})
.distance(100)
)
.force(
"collide",
d3
.forceCollide(function(d) {
return level2Rad(d.level) + 3
})
.iterations(16)
)
.force("charge", d3.forceManyBody().strength(-800))
.force("center", d3.forceCenter(size / 2, size / 2))
.force("y", d3.forceY(-100))
.force("x", d3.forceX(-100))
const data = loadData()
var link = svg
.append("g")
.attr("class", "links")
.selectAll("line")
.data(data.links)
.enter()
.append("line")
.attr("stroke", "grey")
var node = svg
.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(data.nodes)
.enter()
.append("circle")
.attr("fill", d => level2Colors(d.level))
.attr("r", function(d) {
return level2Rad(d.level)
})
.call(
d3
.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
)
var ticked = function() {
link
.attr("x1", function(d) {
return d.source.x
})
.attr("y1", function(d) {
return d.source.y
})
.attr("x2", function(d) {
return d.target.x
})
.attr("y2", function(d) {
return d.target.y
})
node
.attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
})
}
simulation.nodes(data.nodes).on("tick", ticked)
simulation.force("link").links(data.links);
}
render() {
return <div id="d3Node" className="d3-component"></div>;
}
}
ReactDOM.render(<CustomD3Component />, document.getElementById("root"))
View Compiled
This Pen doesn't use any external CSS resources.