我想用d3做一个图形模拟,我可以拖动节点并移动它们,但链接的长度不能小于300或大于600,我该如何解决这个问题?
这是我的模拟:
const simulation = d3
.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-300))
.force(
"link",
d3
.forceLink(links)
.id((d) => d.id)
.distance(300),
)
.force(
"center",
d3.forceCenter(
container.node().clientWidth / 2 - 75,
container.node().clientHeight / 2 - 75,
),
);
目前我只能设置链接的常量长度。
我尝试在 d3 文档中搜索,但没有找到任何内容,如果所描述的解决方案已经存在这样的问题,我会很高兴看到它。
谢谢!
我相信您必须实施自己的力量,因为没有任何内置力量支持您的用例。例如,forceLink.distance() 仅初始化一次力。
自定义实现看起来像这样(参见现场演示):
function linkForce(links, {
min = 50, max = 200, strength = .5, id = d => d.id
} = {}) {
const clamp = (a, b, v) => v <= a ? a : v >= b ? b : v;
const update = (alpha) => {
const s = .5 * alpha * strength;
for(const {source: a, target: b} of links) {
const dx = a.x + a.vx - b.x - b.vy;
const dy = a.y + a.vy - b.y - b.vy;
const dn = Math.hypot(dx, dy);
const dc = clamp(min, max, dn);
if(dn === dc) continue;
const f = (dc - dn) / dn * .5 * alpha * strength;
a.vx += dx * f;
a.vy += dy * f;
b.vx -= dx * f;
b.vy -= dy * f;
}
};
const initialize = nodes => {
const map = new Map(nodes.map(d => [id(d), d]));
for(const link of links) {
link.source = map.get(link.source);
link.target = map.get(link.target);
}
};
return Object.assign(update, {initialize});
}