gpt4 book ai didi

javascript - 现有节点在输入新数据时卡住

转载 作者:行者123 更新时间:2023-11-30 16:50:55 27 4
gpt4 key购买 nike

将新的链接和节点数据绑定到强制布局和svg元素后,旧的节点和链接将冻结。新节点和enter()选择的链接也不会连接到现有节点。

jsFiddle

为什么会发生此问题?

我浏览了各种类似的问题,但是没有一个给出令人满意的为什么答案。请注意,我还仔细阅读了经常引用的“使用联接的思想”,输入/更新/退出选择文章。不过,有些东西没有点击这里。

start(graph);

force.on("tick", function() {
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("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});

window.setTimeout(function(){
graph.nodes.push({"name":"Westby","group":2})
graph.links.push({"source":5,"target":2,"value":1})
start(graph);
}, 2000);


function start(graph){
force
.nodes(graph.nodes)
.links(graph.links)
.start();

link = svg.selectAll(".link")
.data(graph.links)
.enter().append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });

node = svg.selectAll(".node")
.data(graph.nodes)
.call(force.drag)
.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.style("fill", function(d) { return color(d.group); })
.call(force.drag);

node.append("title")
.text(function(d) { return d.name; });
}

最佳答案

代码修订

修改布局后,需要运行force.start()。布局的所有配置都在force.start()中完成。

每次更改数据时,不必重新绑定nodeslinks

我还将结构更改为一种模式,该模式可以为您提供最大的控制和灵活性。
使用此模式,您可以分别管理更新,输入和退出组件。

最后一个星期是

link.enter().insert("line", "circle.node")


代替

link.enter().append("line")


这是为了确保链接显示在圆的后面。

修改后的代码

force
//you only need to do this once///////////
.nodes(graph.nodes)
.links(graph.links)
//////////////////////////////////////////
.on("tick", function () {
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("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
});

start(graph);

window.setTimeout(function () {
graph.nodes.push({ "name": "Westby", "group": 2 })
graph.links.push({ "source": 5, "target": 2, "value": 1 })
start(graph);
}, 2000);

function start(graph) {
//UPDATE pre-existing nodes to be re-cycled
link = svg.selectAll(".link")
.data(graph.links);
//ENTER new nodes to be created
link.enter().insert("line", "circle.node") //insert before node!
.attr("class", "link")
//UPDATE+ENTER .enter also merges update and enter, link is now both
link.style("stroke-width", function (d) { return Math.sqrt(d.value); });
//EXIT
link.exit().remove()
//UPDATE
node = svg.selectAll(".node")
.data(graph.nodes)
//ENTER
node.enter().append("circle")
.attr("class", "node")
.attr("r", 5)
.call(force.drag);
//UPDATE+ENTER .enter also merges update and enter, link is now both
node.style("fill", function (d) { return color(d.group); })
//EXIT
node.exit().remove();

node.append("title")
.text(function (d) { return d.name; });

force.start();
}


背景

资料绑定

d3.layout.force维护对 nodeslinks数组的引用的关闭,因此您只需将布局绑定到数组引用一次。
如您所见,当您阅读代码时...

d3.layout.force = function () {
var force = {},
//...
nodes = [], links = [], distances, strengths, charges;
//...
force.nodes = function (x) {
if (!arguments.length) return nodes;
nodes = x;
return force;
};
force.links = function (x) {
if (!arguments.length) return links;
links = x;
return force;
};
//...
};


所以我们有

force().nodes(nodesData);
force().links(linksData);

force().nodes() === nodesData // true
force().links() === linksData // true


此外,由于数据绑定在d3中起作用的方式,选择结构中的每个DOM节点都引用了其相应数据数组的一个元素。这存储在d3添加到DOM节点的 __data__成员上。

由于数组元素通常是复杂的对象,

__data__ === nodesData[i] // true


对于绑定数据的选择的第i个成员。

selection.datum()方法返回所选节点(或所选内容中的第一个非空节点)的 __data__成员的值,该值是对数据数组元素的引用。当然,这意味着对数据数组元素成员的任何修改都会自动反映在所选内容的数据绑定以及引用节点的 __data__成员的任何内容中。

但是,值得注意的是,

update = selection.data(values)


是一个新数组,所以我们有

update.data() === values  // false
update.data()[i] === values[i] // true


角色和参考(摘要)

节点和链接数据存储为对象数组。数组元素的成员是通知可视化所需的信息-节点或链接的类型,它们的标签,分组信息等。

通过引用数据数组将强制布局绑定到数据:

force().nodes(nodesData);
force().links(linksData);

force().nodes() === nodesData // true
force().links() === linksData // true


通过引用数据数组元素将选择绑定到数据:

nodes = selection.data(nodesData); links.enter().append(nodeSelector)
links = selection.data(linksData); links.enter().append(linkSelector)

nodes === nodesData //false - nodes is a selection, nodesData is an array
nodes.data() === nodesData //false - nodes.data() returns a new array
nodes.data()[i] === nodesData[i] //true! - the elements of the data array are coppied to the new array that is returned by the selection

//similar for links


力的布局和选择引用相同的数据(以不同的方式!),但彼此不引用。

力布局的作用是通过使用其内部动力学设置来计算每个 tick的节点位置,从而管理动画事件(帧)。每当发生数据结构事件时,都需要通过调用 force.start()来通知部队布局(如果您想知道原因,请获取d3源和RTFC)。

选择的作用是通过将DOM元素绑定到DOM元素并提供一个用于根据数据管理它们的API来管理DOM元素。每当发生数据结构事件时,都需要通过更新/输入/追加周期来告知选择。

在强制布局API提供的滴答事件中,这些选择用于根据强制布局计算的新数据来驱动可视化(DOM元素)。

动态变化的力布局结构

如果使用浏览器开发人员工具查看force.nodes()返回的数组元素,则将看到在原始成员之上添加了许多状态,并且d3中也封闭了状态。强制物体,例如距离,力量和电荷。所有这些都必须在某个地方设置,并且毫不奇怪,它是在 force.start()中完成的。因此,这就是每次更改数据结构时都必须调用 force.start()的原因。

一般模式

一般来说,这是最防御的模式。

//UPDATE
var update = baseSelection.selectAll(elementSelector)
.data(values, key),
//ENTER
enter = update.enter().append(appendElement)
.call(initStuff),
//enter() has side effect of adding enter nodes to the update selection
//so anything you do to update now will include the enter nodes

//UPDATE+ENTER
updateEnter = update
.call(stuffToDoEveryTimeTheDataChanges);
//EXIT
exit = update.exit().remove()


第一次通过 update将是具有与数据相同结构的null数组。
在这种情况下, .selectAll()返回零长度选择,没有任何用处。

在后续更新中, .selectAll将不为空,并且将使用 valueskeys进行比较,以确定要更新的节点,进入和退出节点。这就是为什么在数据联接之前需要选择。

要了解的重要一点是它必须为 .enter().append(...),因此您要在enter选择上附加元素。如果将它们附加到更新选择(数据联接返回的选择)上,那么您将重新输入相同的元素,并看到与所得到的行为相似的行为。

回车选择是一个简单对象的数组,格式为 { __data__: data }
更新和退出选择是对DOM元素的引用数组。

d3中的data方法使输入和退出选择保持关闭状态,这些选择可通过 .enter()上的 .exit()update方法访问。两者都返回对象,这些对象除其他外是二维数组(d3中的所有选择都是组的数组,其中组是节点的数组。)。
还为 enter成员提供了对 update的引用,以便可以将两者合并。这样做是因为在大多数情况下,两个小组的工作相同。

关于javascript - 现有节点在输入新数据时卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30542069/

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