{
let width = 300
let height = 300
let nodes = [
{ name: 1 },
{ name: 2 },
{ name: 3 },
{ name: 4 },
{ name: 5 }
]
let links = [
{ source: 0, target: 1 },
{ source: 1, target: 4 },
{ source: 1, target: 2 },
{ source: 2, target: 3 },
{ source: 3, target: 1 }, { source: 1, target: 3 }
]
const svg = d3.create("svg")
.attr("viewBox", [-width / 2, -height / 2, width / 2, height])
.style("max-width", `${width}px`)
.style("overflow", "visible");
const simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-1860))
.force("x", d3.forceX())
.force("y", d3.forceY())
.force("link", d3.forceLink().links(links))
const link = svg.append("g")
.attr("stroke", "#000000")
.attr("stroke-opacity", 1)
.attr("stroke-width", 1.5)
.attr("fill", "none")
.attr("marker-end", "url(#end)")
.selectAll("path")
.data(links)
.join("path")
// svg.append('svg:defs').selectAll('svg:marker')
// .data(links)
// .attr('id', (d) => d.id)
// .attr('refX', 14.5)
// .attr('refY', 2.5)
// .attr('markerWidth', 5)
// .attr('markerHeight', 5)
// .attr('orient', 'auto')
// .append('svg:path')
// .attr('d', 'M0,0 L5,2.5 L0,5 Z')
// .attr("class", "arrow")
// Eureka! The data argument is the name of the class to be referenced at the call site
svg.append("defs").selectAll("marker")
.data(["end"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 20)
.attr("refY", -1.5)
.attr("markerWidth", 8)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 0 L 10 0 L 0 5");
const node = svg.append("g")
.attr("fill", "#e66300")
.attr("stroke", "#0f0f0f")
.attr("stroke-width", 2.5)
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", 10)
.text(d => d.name)
const text = svg.append("g")
.attr("text-anchor", "middle")
.attr("font-size", "10")
.selectAll("text")
.data(nodes)
.join("text")
.text(d => d.name)
node.append("title")
.text(d => d.name)
function positionLink(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + d.source.x + " " + d.source.y
+ "A" + dr + " " + dr
+ ", 0, 0, 1," + d.target.x + "," + d.target.y;
}
// function positionLink(d) {
// return "M" + d.source.x + "," + d.source.y
// + "S" + d.source.x + "," + d.source.y
// + " " + d.target.x + "," + d.target.y;
// }
// function positionLink(d) {
// var dx = d.target.x - d.source.x,
// dy = d.target.y - d.source.y,
// dr = Math.sqrt(dx * dx + dy * dy),
// mx = d.source.x + dx,
// my = d.source.y + dy;
// return [
// "M",d.source.x,d.source.y,
// "A",dr,dr,0,0,1,mx,my,
// "A",dr,dr,0,0,1,d.target.x,d.target.y
// ].join(" ");
// }
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)
// .attr('marker-end','url(#arrow)')
link
.attr("d", positionLink)
// .attr('marker-end','url(#arrow)')
node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
text
.attr("x", d => d.x)
.attr("y", d => d.y)
.attr("dy", "3px");
})
return svg.node()
}