chart = {
const links = data.links.map(d => Object.create(d));
const nodes = data.nodes.map(d => Object.create(d));
const simulation = d3
.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collision", d3.forceCollide(d => d.degree + 2));
const svg = d3
.create("svg")
.attr("height", height)
.attr("width", width);
const link = svg
.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width", d => Math.sqrt(d.value));
const node = svg
.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", d => d.degree + 2)
.attr("fill", color)
.call(drag(simulation));
const textElems = svg // add text labels to the nodes on the svg
.append('g')
.selectAll('text') // select all text elements
.data(nodes) // use the nodes information to get the text
.join('text') // adjust the labels when something moves
.text(d => d.id) // use the id attribute of the nodes to write the labels
.attr('font-size', 12) // give each label the css font-size attribute of 12 pixels
.call(drag(simulation)); // use the drag function defined below to move the labels when nodes are dragged. This can be commented out if you don't want to use the drag function below
// this is a standard simulation function that is the same across basically all force directed network visualizations in d3. It keeps the sources and targets of each interacting node pair linked even when the graph is moving around because of collisions or dragging. I honestly just copy/paste the same simulation function across all my network graphs instead of rewriting it every time.
// every time the graph changes due to dragging or movement generated by the layout, update the links, nodes, and text
simulation.on("tick", () => {
link // adjust the position of every 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);
node.attr("cx", d => d.x).attr("cy", d => d.y); // adjust the position of the nodes
textElems // adjust the text labels
.attr("x", d => d.x + 10) // draw the label 10px to the left of the center of the node
.attr("y", d => d.y) // but draw it at the same height as the center of the node
.attr("visibility", function(d) {
// add the css visibility attribute to all text labels
if (d.degree >= 10) {
// if the degree value of the node is greater than or equal to 10
return "visible"; // make its label visible using a css attribute
} else {
// if the degree of the node is smaller than 10
return "hidden"; // make its label hidden using a css attribute
}
});
});
return svg.node(); // draw all the crap above
}