我想按圆的大小在力导向图中居中节点:我们希望最大的圆居中,下一个最大的圆围绕它。
以下是JSFiddle:https://jsfiddle.net/5zrxgteh/1/
以下是模拟和即时报价函数:
var simulation = d3.forceSimulation()
.force("center", d3.forceCenter().x(width / 2).y(height / 2))
.force("charge", d3.forceManyBody().strength(5))
.force("collide", d3.forceCollide().strength(1).radius(function (d) {
return rScale(d.value * 1.2);
}).iterations(3));
simulation
.nodes(data)
.on("tick", function (d) {
elemEnter.selectAll(".pulse")
.attr("cx", function (d) {
return d.x = Math.max(50, Math.min(width - 50, d.x));
})
.attr("cy", function (d) {
return d.y = Math.max(50, Math.min(height - 50, d.y));
});
elemEnter.selectAll(".circle")
.attr("cx", function (d) {
return d.x = Math.max(50, Math.min(width - 50, d.x));
})
.attr("cy", function (d) {
return d.y = Math.max(50, Math.min(height - 50, d.y));
});
elemEnter.selectAll("text")
.attr("x", function (d) {
return d.x = Math.max(50, Math.min(width - 50, d.x));
})
.attr("y", function (d) {
return d.y = Math.max(50, Math.min(height - 50, d.y));
});
});
如果你停下来思考你想要的东西在数学和视觉上都很复杂,因为如果最大的圆紧挨着中心,并且到中心的距离与圆的直径成正比,那么你在中心旁边会有很多空白,模拟不会很好地处理它。
然而,只是为了尝试,这是一个可能的解决方案:放弃d3.forceCenter
,改用forceX
和forceY
,根据圆圈的大小调整它们的强度。
为此,我们首先设置了一个比例:
var strengthScale = d3.scalePow()
.exponent(2)
.range([0, 1])
.domain([0, d3.max(data, function(d) {
return d.value;
})]);
然后,我们更改模拟:
var simulation = d3.forceSimulation()
.force("x", d3.forceX(width / 2).strength(function(d) {
return strengthScale(d.value);
}))
.force("y", d3.forceY(height / 2).strength(function(d) {
return strengthScale(d.value);
}))
.force("charge", d3.forceManyBody().strength(5))
.force("collide", d3.forceCollide().strength(1).radius(function(d) {
return rScale(d.value * 1.2);
}).iterations(30));
下面是生成的 JSFiddle: https://jsfiddle.net/mea9nygb/2/