[英]D3 v4 Update-Pattern for Groups
给定以下布局:
<g>
... // many nodes
<g>
<circle></circle>
<text></text>
</g>
...
</g>
如何在d3 v4中找到正确的更新模式? 我必须使用什么作为合并(?)中的参数,我多久需要调用一次合并(仅在节点上?节点+圆+文本?)
我在小提琴上创建了一个工作示例: https : //jsfiddle.net/cvvfsg97/6/
码:
function update(items) {
node = nodeLayer.selectAll(".node")
.data(items, function(d) { return d.id; })
node = node.enter() // insert
.append("g")
.attr("class", "node");
node.append("circle") // insert
.attr("r", 2.5)
.attr('class', 'circle')
.merge(nodeLayer.selectAll('.node > circle')) // is this correct?! // merge
.attr('fill', 'red') // just for testing purposes
.exit().remove(); // exit
node.append("text") // insert
.attr("dy", 3)
.text(function(d) { return d.name; })
.merge(nodeLayer.selectAll('.node > text')) // is this correct?! // merge
.attr('fill', 'green') // just for testing purposes
.exit().remove();
node.merge(nodeLayer.selectAll('.node')) // is this correct?! // merge
.attr('class', 'anotherClass')
.exit().remove(); // does not work // exit
}
有人可以在组中使用enter(),merge(),exit()方面有所清晰吗?
我可能希望在每个阶段对每个元素进行更改。
更新 :我简化了示例,我不需要链接或强制布局。 我的问题只是关于更新模式,而不是关于力量。 更新的jsfiddle没有强制布局。
你的模式过于复杂。 这是您正确编写的更新函数:
function update(items) {
var node = nodeLayer.selectAll(".node") // bind the data, this is update
.data(items, function(d) {
return d.id;
});
node.exit().remove(); // exit, remove the g
nodeEnter = node.enter() // enter, append the g
.append("g")
.attr("class", "node");
nodeEnter.append("circle") // enter, append the circle on the g
.attr("r", 2.5)
.attr('class', 'circle')
.attr('fill', 'red');
nodeEnter.append("text") // enter, append the text on the g
.attr("dy", 3)
.text(function(d) {
return d.name;
})
.attr('fill', 'green');
node = nodeEnter.merge(node); // enter + update on the g
node.attr('transform', function(d){ // enter + update, position the g
return 'translate(' + d.x + ',' + d.y + ')';
});
node.select("text") // enter + update on subselection
.text(function(d) {
return d.name;
});
}
这里它运行多个调用:
<!DOCTYPE html> <html> <head> <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script> </head> <body> <script> var nodeLayer = d3.select('body') .append('svg') .attr('width',500) .attr('height',500); update([ { id: 1, name: 'A', x: Math.random() * 500, y: Math.random() * 500 },{ id: 2, name: 'B', x: Math.random() * 500, y: Math.random() * 500 },{ id: 3, name: 'C', x: Math.random() * 500, y: Math.random() * 500 } ]); setTimeout(function(){ update([ { id: 1, name: 'A', x: Math.random() * 500, y: Math.random() * 500 },{ id: 4, name: 'This is a new name...', x: Math.random() * 500, y: Math.random() * 500 },{ id: 3, name: 'C', x: Math.random() * 500, y: Math.random() * 500 } ]); }, 3000); function update(items) { var node = nodeLayer.selectAll(".node") .data(items, function(d) { return d.id; }); node.exit().remove(); // exit, remove the g nodeEnter = node.enter() // enter the g .append("g") .attr("class", "node"); nodeEnter.append("circle") // enter the circle on the g .attr("r", 2.5) .attr('class', 'circle') .attr('fill', 'red'); nodeEnter.append("text") // enter the text on the g .attr("dy", 3) .attr('fill', 'green'); node = nodeEnter.merge(node); // enter + update node.attr('transform', function(d){ return 'translate(' + dx + ',' + dy + ')'; }); node.select("text") .text(function(d) { return d.name; }); } </script> </body> </html>
我最近在我的代码中完成了这个 - 我在包含元素的当前选择上使用select(subSelector)。 在您的示例中,我将更改如下:
function update(items) {
var node = nodeLayer.selectAll(".node")
.data(items, function(d) { return d.id; })
var nodeEnter = node.enter()
.append("g")
.attr("class", "node");
nodeEnter.append("circle")
.attr("r", 2.5)
.attr('class', 'circle')
.merge(node.select('circle'))
.attr('fill', 'red');
nodeEnter.append("text") // insert
.attr("dy", 3)
.text(function(d) { return d.name; })
.merge(node.select('text'))
.attr('fill', 'green');
// You only need to call remove on the group, all the other exit().remove() calls are superfluous
node.exit().remove();
simulation
.nodes(items);
}
var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height"), nodeLayer = svg.append('g'), node; var list = []; var links = []; var simulation = d3.forceSimulation(list) .force("charge", d3.forceManyBody().strength(-1000)) .force("link", d3.forceLink(links).distance(200)) .force("center", d3.forceCenter(width / 2, height / 2)) .on("tick", ticked); function createNodes(index) { links.push({ 'source': 0, 'target': index }) list.push({ "id": index, "name": "server " + index }); return list; } var iteration = 0; update(createNodes(iteration)); // just simulating updates d3.interval(function(timer) { iteration++; update(createNodes(iteration)); }, 1000); //<-- this was commented out incorrectly just now function update(items) { var dataJoin = nodeLayer.selectAll(".node") .data(items, function(d) { return d.id; }); node = dataJoin.enter() // insert .append("g") .attr("class", "node"); node.append("circle") // insert .attr("r", 2.5) .attr('class', 'circle') .merge(dataJoin) // not the class, the actual selected group you called enter() on .select('.circle') .style('fill', 'red') // just for testing purposes .exit().remove(); // exit node.append("text") // insert .attr("dy", 3) .attr('class', 'text') .text(function(d) { return d.name; }) .merge(dataJoin) .select('.text') .style('fill', 'green') // fill is a style dataJoin.exit().remove(); simulation.nodes(list); simulation.force("link").links(links); simulation.alpha(1).restart(); } function ticked() { node.attr("transform", function(d) { var a = dx || 0; var b = dy || 0; return "translate(" + a + ", " + b + ")"; }); }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.4.1/d3.min.js"></script> <svg height="300" width="300"></svg>
有一堆错误,
首先应该使用所有数据节点的列表来调用“更新”(misnomer),而不仅仅是更改。
您可能想要浏览https://bl.ocks.org/并复制人们如何使用力导向图。 你需要有力量的链接。
合并背后的想法是将新列表与旧列表进行比较,这意味着您需要使用dataJoin或附加了数据/ ID的组。
我不是专家,请查看力导向图的所有示例,并了解它们如何更新/合并。 (更新/重启图表的方法不止一种)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.