viewof graphViz = {
const width = 900, height = 700;
const svg = d3.select(DOM.svg(width, height)).style("background", "#f0f0f0");
const nodes = data.nodes.map(d => ({...d}));
const links = data.edges.map(d => ({
source: d.source,
target: d.target
}));
const sim = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).distance(50))
.force("charge", d3.forceManyBody().strength(-100))
.force("center", d3.forceCenter(width / 2, height / 2));
svg.append("g")
.selectAll("line")
.data(links)
.join("line")
.attr("stroke", "#aaa")
.attr("stroke-opacity", 0.5);
const node = svg.append("g")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", 4)
.attr("fill", d => {
if (d.type === "Entity") return "#3182bd";
if (d.type === "Event") return "#fd8d3c";
if (d.type === "Relationship") return "#74c476";
return "#ccc";
})
.append("title")
.text(d => d.label || d.name || d.id);
sim.on("tick", () => {
svg.selectAll("line")
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
svg.selectAll("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y);
});
return svg.node();
}