像大多数人一样,我在D3的数据连接机制中苦苦挣扎。我读过有关该主题的每篇文章,无论是好是坏。克里斯蒂安·贝伦斯(Christian Behrens)的guest-and-chair party analogy可能是最好的,尽管我警告读者,他忽略了我们大约2/3,从“现在我们的update()函数执行两组不同的动作”开始–他在这里没有澄清显然,更新选择专门忽略DOM构造(附加/删除)调用,而属性调用则由所有三种选择类型处理,尽管它们都无缝出现在一个方法链中。 (就他本人而言,Mike Bostock在解释数据联接和方法链接方面所做的数项努力从轻描淡写到完全复杂化。)
我仍然在理解data()和enter()之间的隔膜时仍然遇到问题,特别是何时保存变量以及给定链中的调用如何对哪些对象进行操作,以及变量保存的链返回值以及如何知道那(显然,attr不会影响变量,而是在包括一系列选择,数据和输入的链中返回)?因此,我对本来很好的Behrens论文提出了温和的批评,因为它在那里有很大的希望。
下面,我有一个强制布局(可以是任何布局),该布局在启动时显示两个节点,如果单击任何一个节点,则应添加第三个节点。
var graph = {
"nodes":[ {"name":"1" }, {"name":"2" } ],
"links":[ {"source":0,"target":1} ]
}
var width = 500, height = 400;
var force = d3.layout.force()
.size([width, height]);
var svg = d3.select("#map").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
var rect = svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all");
var container = svg.append("g");
force
.nodes(graph.nodes)
.links(graph.links)
.start();
var link = container.append("g")
.attr("class", "links")
.selectAll(".link")
.data(graph.links)
.enter()
.append("line")
.attr("class", "link")
.style("stroke-width", function(d) { return Math.sqrt(d.value); });
var nodes = container.append("g")
.attr("class", "nodes");
function update() {
var n = nodes.selectAll(".node").data(graph.nodes);
ne = n.enter()
.append("g")
.attr("class", "node")
.attr("cx", function(d) { return d.x; }) // sets on initial enter() but not on click
.attr("cy", function(d) { return d.y; }); // sets on initial enter() but not on click
ne.append("rect")
.attr("width", "20")
.attr("height", "20")
.attr("fill", "red");
return n;
} // end update()
var node = update();
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("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
});
node.on("click", function(d) {
graph.nodes.push({ "name":"3" });
update();
}); // end .on("click")
在Behrens之后,我制作了一个update()函数以节省资源。最初设置cx和cy可以正常工作,但单击节点时不可行。新节点位于[0,0]。我认为我在管理参数和在update()上返回的方式一定存在问题。一种更好的方法,实际上可行吗?
最佳答案
您只是缺少了两个小东西。首先,您需要重新启动力布局,以便更新节点位置,并且需要更新在node
处理函数中使用的tick
:
node.on("click", function(d) {
graph.nodes.push({ "name":"3" });
node = update();
force.start();
});
完成演示here。