I have a react application where I am trying to display a graph with nodes that have specified link distances. I have the following code below where the distance is specified with values for each link. The graph is displayed nicely but the link distances are not correct. For example, the node furthest away could have a distance that is smaller than a node closer to the center. Does anyone know why this would be happening? I'm a newbie to d3 so this is all very confusing.
let FORCE = (function(nsp){
let that = this,
width = 700,
height = 500,
color = d3.scaleOrdinal(d3.schemeCategory10),
PointColors = ['#1769aa', 'magenta'],
div = d3.select("body").append("div")
.style("opacity", 0)
.style("position", "absolute")
.style("text-align", "center")
.style("width", "220px")
.style("height", "40px")
.style("padding", "2px")
.style("font-family", "Roboto")
.style("background", "#f5f5f5")
.style("border", "0px")
.style("border-radius", "8px")
.style("pointer-events", "none"),
initForce = (nodes, links) => {
nsp.force = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-500))
.force("link", d3.forceLink(links).distance(function (d) { return (d.distance)*100;}))
.force("center", d3.forceCenter().x(nsp.width /2).y(nsp.height / 2))
.force("collide", d3.forceCollide([5]).iterations([5]));
},
enterNode = (selection) => {
let circle = selection.select('circle')
.attr("r", 10)
.style("fill", '#1769aa' )
.style("stroke", "#fff")
.style("stroke-width", "2px")
.on("mouseover", function(d){
console.log(d)
let matrix = this.getScreenCTM()
.translate(+ this.getAttribute("cx"), + this.getAttribute("cy"));
PointColors = [PointColors[1], PointColors[0]]
d3.select(this).style("fill", PointColors[0]);
div.transition()
.duration(200)
.style("opacity", .9)
div.html(d.name+'</br>Distance: '+d.distance)
.style("left", (window.pageXOffset + matrix.e + 15) + "px")
.style("top", (window.pageYOffset + matrix.f - 30) + "px")
})
.on("mouseout", function(d) {
PointColors = [PointColors[1], PointColors[0]]
d3.select(this).style("fill", PointColors[0]);
div.transition()
.duration(500)
.style("opacity", 0);
})
.on("click", function(d) {
console.log(d);
window.open(d.url, '_blank');
});
selection.select('text')
.style("fill", "honeydew")
.style("font-weight", "600")
.style("text-anchor", "middle")
.style("alignment-baseline", "middle")
.style("font-size", "12px")
},
updateNode = (selection) => {
selection
.attr("transform", (d) => "translate(" + d.x + "," + d.y + ")")
.attr("cx", function(d) { return d.x = Math.max(30, Math.min(width - 30, d.x)); })
.attr("cy", function(d) { return d.y = Math.max(30, Math.min(height - 30, d.y)); })
},
enterLink = (selection) => {
selection
.attr("stroke-width", 2)
.attr("stroke","#505050")
},
updateLink = (selection) => {
selection
.attr("x1", (d) => d.source.x)
.attr("y1", (d) => d.source.y)
.attr("x2", (d) => d.target.x)
.attr("y2", (d) => d.target.y);
},
updateGraph = (selection) => {
selection.selectAll('.node')
.call(updateNode)
selection.selectAll('.link')
.call(updateLink);
},
dragStarted = (d) => {
if (!d3.event.active) nsp.force.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y
},
dragging = (d) => {
d.fx = d3.event.x;
d.fy = d3.event.y
},
dragEnded = (d) => {
if (!d3.event.active) nsp.force.alphaTarget(0);
d.fx = null;
d.fy = null
},
drag = () => d3.selectAll('g.node')
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragging)
.on("end", dragEnded)
),
tick = (that) => {
that.d3Graph = d3.select(ReactDOM.findDOMNode(that));
nsp.force.on('tick', () => {
that.d3Graph.call(updateGraph)
});
};
nsp.width = width;
nsp.height = height;
nsp.enterNode = enterNode;
nsp.updateNode = updateNode;
nsp.enterLink = enterLink;
nsp.updateLink = updateLink;
nsp.updateGraph = updateGraph;
nsp.initForce = initForce;
nsp.dragStarted = dragStarted;
nsp.dragging = dragging;
nsp.dragEnded = dragEnded;
nsp.drag = drag;
nsp.tick = tick;
return nsp
})(FORCE || {})