svg = {
const links = data.edges;
const nodes = data.nodes;
const simulation = d3
.forceSimulation(nodes)
.force(
"link",
d3
.forceLink(links)
.id((d) => d.id)
.distance(10)
)
.force("charge", d3.forceManyBody())
.force(
"x",
d3.forceX((d) => x(new Date(d.attributes.order)))
)
.force(
"y",
d3.forceY((d) => 400)
);
const svg = d3.create("svg").attr("width", width).attr("height", 800);
svg
.append("defs")
.append("marker")
.attr("id", "arrow")
.attr("viewBox", [0, 0, markerBoxWidth, markerBoxHeight])
.attr("refX", refX)
.attr("refY", refY)
.attr("markerWidth", markerBoxWidth)
.attr("markerHeight", markerBoxHeight)
.attr("orient", "auto")
.append("path")
.attr("d", d3.line()(arrowPoints))
.attr("stroke", "#989C94");
const link = svg
.append("g")
.selectAll("line")
.data(links)
.join("line")
.attr("stroke", "#989C94")
.attr("stroke-opacity", 0.7)
.attr("stroke-width", 1)
.attr("fill", "none")
.attr("marker-end", "url(#arrow)");
const node = svg
.append("g")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", 4)
.attr("fill-opacity", "0.5")
.attr("stroke", "#555")
.attr("fill", "#555")
.on("click", (event, d) =>
console.log(`Company: ${d.id}, cluster: ${d.attributes.group}`)
);
const labels = svg
.append("g")
.selectAll("text")
.data(nodes)
.join("text")
.text((d) => d.label)
.attr("fill", "#000")
.attr("font-family", "Source Serif Pro")
.attr("font-size", 6)
.attr("text-anchor", "middle");
node.append("title").text((d) => d.id);
simulation.on("tick", () => {
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);
labels.attr("x", (d) => d.x).attr("y", (d) => d.y);
});
svg.append("g").call(xAxis).select(".domain").remove();
invalidation.then(() => simulation.stop());
return svg.node();
}