gpt4 book ai didi

javascript - 如何使用函数动态分配 d3.forceRadial 的中心?

转载 作者:行者123 更新时间:2023-11-29 15:11:34 25 4
gpt4 key购买 nike

我有一个包含父节点和子节点的数据集。父节点可以与其他父节点链接,子节点可以与它们的父节点链接。我想要做的是将子节点径向放置在父节点周围。节点看起来像这样

parent: [{
id: 1,
type: 'parent',
x: ,
y: ,
vx: ,
vy: ,
}, {
id: 2
x: ,
y: ,
vx: ,
vy: ,
}]

child: [{
id: 1,
type: 'child',
parent_node: {
id: 1,
x: ,
y: ,
vx: ,
vy: ,
},
x: ,
y: ,
vx: ,
vy: ,
}]

所以我有父节点的详细信息,例如子节点内的 x 和 y。

我尝试动态分配 xy(如中间所示),但找不到方法:

force('radial', d3.forceRadial()
.radius(node => {
if (node.type === 'child') {
return 10
}
return 0
})
.x(node => {
if (node.type === 'child') {
return node.parent_node.x
}
return 0
})
.y(node => {
if (node.type === 'child') {
return node.parent_node.y
}
return 0
})
)

这样的事情能做吗?以便可以根据父节点的位置动态提供每个子节点的中心?

最佳答案

前段时间我创建了一个 d3.forceRadial 版本,它接受一个用于设置 xy 位置的函数。你可以看到 pull request here , 和 code is here

这个 pull request 还没有被接受,考虑到它是一个很老的请求并且没有来自 Mike Bostock(D3 的创建者)的评论,我认为它永远不会被接受。因此,如果需要,您可以通过复制链接中的函数来使用此自定义 d3.forceRadial:https://pastebin.com/75j8vj3C

然后,只需使用带有自定义力的定位函数,如下所示:

simulation.force("radial", customRadial(radius, foo, bar))
//positioning functions--------------------------^----^

或者:

simulation.force("radial", customRadial()
.radius(radius)
.x(foo)
.y(bar))

foobar 是您在 xy 位置的函数。

这是一个演示:

var svg = d3.select("body")
.append("svg")
.attr("width", 600)
.attr("height", 200);

var data = d3.range(500).map(function(d) {
return {
node: "foo" + d,
centerX: 100 + ~~((d / 100) % 20) * 100
}
});

var simulation = d3.forceSimulation(data)
.force("radius", customRadial().radius(40)
.x(function(d) {
return d.centerX
})
.y(100)
.strength(1))
.force("collide", d3.forceCollide().radius(3).strength(.8));

var nodes = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", 2.5)
.style("fill", "teal")

simulation.on("tick", tick);

function tick() {
nodes.attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
});
}


function customRadial(radius, x, y) {

var constant = function(x) {
return function() {
return x;
};
};

var nodes,
strength = constant(0.1),
strengths,
radiuses,
xs,
ys;

if (typeof radius !== "function") radius = constant(+radius);
if (typeof x !== "function") x = constant(x == null ? 0 : +x);
if (typeof y !== "function") y = constant(y == null ? 0 : +y);

function force(alpha) {
for (var i = 0, n = nodes.length; i < n; ++i) {
var node = nodes[i],
dx = node.x - xs[i] || 1e-6,
dy = node.y - ys[i] || 1e-6,
r = Math.sqrt(dx * dx + dy * dy),
k = (radiuses[i] - r) * strengths[i] * alpha / r;
node.vx += dx * k;
node.vy += dy * k;
}
}

function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
radiuses = new Array(n);
xs = new Array(n);
ys = new Array(n);
for (i = 0; i < n; ++i) {
radiuses[i] = +radius(nodes[i], i, nodes);
xs[i] = +x(nodes[i], i, nodes);
ys[i] = +y(nodes[i], i, nodes);
strengths[i] = isNaN(radiuses[i]) ? 0 : +strength(nodes[i], i, nodes);
}
}

force.initialize = function(_) {
nodes = _, initialize();
};

force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
};

force.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius;
};

force.x = function(_) {
return arguments.length ? (x = typeof _ === "function" ? _ : constant(+_), initialize(), force) : x;
};

force.y = function(_) {
return arguments.length ? (y = typeof _ === "function" ? _ : constant(+_), initialize(), force) : y;
};

return force;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

如果您不想(或者出于任何原因不能)使用此自定义代码,一个简单的解决方法是创建多个模拟,每组元素一个,就像我在 this data visualization 做过.

关于javascript - 如何使用函数动态分配 d3.forceRadial 的中心?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54035048/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com