chart = {
const links = data3.edges.map(d => Object.create(d));
const nodes = data3.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));
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
const xScale = d3
.scaleLinear()
.domain([1890, 2020])
.range([0, width]);
const link = svg
.append("g")
.selectAll("line")
.data(links)
.join("path")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.attr("stroke-width", d => Math.sqrt(d.value));
const nodeGroups = svg
.append('g')
.selectAll("circle")
.data(nodes)
.join("g")
.attr('class', 'node-group');
const nodeCircles = nodeGroups
.append('circle')
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.attr("r", ({ size }) => size / 2)
.attr("fill", color)
.call(drag(simulation));
const nodeText = nodeGroups
.append("text")
.attr('class', 'node-text')
.style('opacity', ({ size }) => size / 100)
.text(d => d.id);
simulation.on("tick", () => {
const sourceX = d => (d.source.year ? xScale(d.source.year) : d.source.x);
const targetX = d => (d.target.year ? xScale(d.target.year) : d.source.x);
link.attr("d", d => {
var dx = targetX(d) - sourceX(d),
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return (
"M" +
sourceX(d) +
"," +
d.source.y +
"A" +
dr +
"," +
dr +
" 0 0,1 " +
targetX(d) +
"," +
d.target.y
);
});
nodeCircles
.attr("cx", d => (d.year ? xScale(d.year) : d.x))
.attr("cy", d => d.y);
nodeText
.attr("x", d => (d.year ? xScale(d.year) : d.x))
.attr("y", d => d.y);
});
invalidation.then(() => simulation.stop());
return svg.node();
}