gpt4 book ai didi

d3.js - d3 v4 强制作用于动态添加的节点

转载 作者:行者123 更新时间:2023-12-01 12:25:50 28 4
gpt4 key购买 nike

我正在尝试将节点一个一个地添加到 d3 力模拟(在版本 4 中!),但有些节点在创建后似乎并没有被模拟演化。


目前模拟分配一个节点,然后调用一个函数 addNode 两次添加两个节点。每一个都被添加到模拟中,呈现一个圆圈和一条线,并添加一个光标事件,一个接一个。

(从技术上讲,第一个和第二个节点是同时完成的,因为第一个节点仅在第二个调用 addNode 时设置)

然后,当单击一个节点时,应创建一个连接到光标下的节点的新节点。然后,该节点应该像任何其他节点一样在模拟的力量下进化。


但是,虽然一两个节点似乎创建得很好,但后来的节点似乎并没有在模拟下进化。特别是应该在节点之间保持一定空间的多体力似乎不起作用。


我的直觉是,对于模拟的 ticked 函数,节点是在不合时宜的时间添加的(早期的问题是通过添加一些 simulation.stop 和 simulation.restart 命令来解决的,只要新节点被添加)但理论上模拟每当添加新主体时都应暂停。

这是在 d3 v4 中动态添加节点的正确实现,还是力的问题只是突出了一个损坏的方法? This之前的回答帮助我意识到我需要合并新条目,但力似乎在那里工作正常。

var w = 250;
var h = 250;

var svg = d3.select("body").append("svg");

svg.attr('width', w)
.attr('height', h);

// ensures links sit beneath nodes
svg.append("g").attr("id", "lnks")
svg.append("g").attr("id", "nds")

function new_node(id) {
this.id = id;
this.x = w / 2;
this.y = h / 2;
}

function new_link(source, target) {
this.source = source;
this.target = target;
}

var nodes = [];
var links = [];

var node;

var circles;

var link;

var simulation = d3.forceSimulation()
.force("link", d3.forceLink().distance(80).id(function(d) {
return d.id;
}))
.force("charge", d3.forceManyBody().strength(-1000))
.force("xPos", d3.forceX(w / 2))
.force("yPos", d3.forceY(h / 2))
.on('tick', ticked);

simulation.stop();

var newNode = new new_node(0);
nodes.push(newNode);

for (var i = 1; i < 3; i++) {
if (i == 3) continue;
addNode(0, i)
}

function addNode(rootId, newId) {

var newNode = new new_node(newId);
nodes.push(newNode);
var newLink = new new_link(rootId, newId);
links.push(newLink);

//adds newest link and draws it
link = svg.select("#lnks").selectAll(".link")
.data(links)
var linkEnter = link
.enter().append("line")
.attr("class", "link");
link = linkEnter.merge(link);

//adds newest node
node = svg.select("#nds").selectAll(".node")
.data(nodes)
var nodeEnter = node
.enter().append("g")
.attr("class", "node");

//draws circle on newest node
var circlesEnter = nodeEnter.append('circle')

node = nodeEnter.merge(node);
circles = d3.selectAll('circle');

simulation.stop();

simulation.nodes(nodes);

simulation.force("link")
.links(links);

restartSim();
}

//starts up the simulation and sets up the way the leaves react to interaction
function restartSim() {
simulation.restart();

circles.on('click', function(d, i) {
addNode(i, nodes.length)
})
}

function ticked() {
link
.attr("x1", function(d) {
return d.source.x;
})
.attr("y1", function(d) {
return d.source.y;
})
.attr("x2", function(d) {
return d.target.x;
})
.attr("y2", function(d) {
return d.target.y;
});

node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
.link {
stroke: #bbb;
}
.node circle {
pointer-events: all;
fill: black;
stroke-width: 0px;
r: 20px
}
h1 {
color: white;
}
<script src="https://d3js.org/d3.v4.min.js"></script>

代码也在 codepen 上: http://codepen.io/zpenoyre/pen/kkxBRW?editors=0010

最佳答案

力模拟顾名思义就是对粒子相互作用的模拟。 Alpha 用于通过在每次迭代时衰减来帮助收敛系统。力乘以 alpha,因此在每次迭代中力都会变弱,直到 alpha 在模拟停止时达到非常低的值。来自 d3 文档:

simulation.restart() <>

Restarts the simulation’s internal timer and returns the simulation. In conjunction with simulation.alphaTarget or simulation.alpha, this method can be used to “reheat” the simulation during interaction, such as when dragging a node, or to resume the simulation after temporarily pausing it with simulation.stop.

当你添加一个节点时,模拟已经停止,所以,你需要用 alpha 1“重新加热”模拟。

  simulation.force("link")
.links(links);

simulation.alpha(1); // <---- reheat;

restartSim();

这是更新后的代码笔: http://codepen.io/anon/pen/amqrWq?editors=0010

关于d3.js - d3 v4 强制作用于动态添加的节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39843310/

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