[英]Update D3 Force chart - how to remove Circles & Text?
I'm using Angular 6 & D3v4 to create a force simulation chart, and it loads just fine the first time, and i added a click event to the circles & text which updates the data, however the transitions are working strangely - some nodes are removed, but the remaining nodes just have a new circle & text added... I tried the general update pattern from Mike Bostock, but that doesn't seem to work for me in Angular (or maybe it's this newer version of D3?)... here's what i'm doing: 我使用Angular 6和D3v4创建了一个力模拟图,并且第一次加载就很好,并且我向圆圈和文本添加了一个click事件来更新数据,但是过渡效果很奇怪-有些节点在已删除,但其余节点仅添加了一个新的圆圈和文本...我尝试了Mike Bostock的常规更新模式 ,但在Angular中似乎不适用于我(或者这可能是D3的较新版本?) ...这是我在做什么:
ngOnInit() {
// get data from service
this.service.getGraphData(this.id).subscribe(results => {
this.graphData = results;
this.forceSimulation = d3.forceSimulation(this.graphData)
// push nodes apart to space them out
.force("charge", d3.forceManyBody().strength(-100))
// add some collision detection so they don't overlap
.force("collide", d3.forceCollide().radius(55))
// and draw them around the centre of the space
.force("center", d3.forceCenter(this.width / 2, this.height / 2));
this.link = this.svg.selectAll(".link").data(this.graphData.links)
.enter()
.append("path")
.attr("class", "link")
.attr('stroke', "#FFF");
this.node = this.svg.selectAll(".node")
.data(this.graphData.nodes)
.enter()
.append('g');
this.updateGraph();
});
}
updateGraph() {
let graphComponent = this;
//start building/rebuilding the graph
let t = d3.transition().duration(750);
this.link = this.link.data(this.graphData.links);
this.link.exit().remove();
this.forceSimulation
// pull nodes together based on the links between them
.force("link", d3.forceLink().id(function (d) {
return d.id;
}).strength(0.025));
// add the nodes to the graphic
this.node = this.node.data(this.graphData.nodes);
this.node.exit().remove();
this.node.transition(t).style('fill', 'blue').attr('35');
this.node.append("circle")
.attr("class", "node")
.attr("r", function (d) {
// center node = larger & blue
return d.id == graphComponent.programNode.id ? 65 : 40;
})
.attr('stroke', function (d) {
// apply red border to nodes
return 'red';
})
.attr('stroke-width', function (d) {
return d.id == graphComponent.programNode.id ? 0 : 3;
})
.attr("fill", function (d) {
return d.id == graphComponent.programNode.id ? 'blue' : '#FFF';
})
.on('click', function (d) {
if (d.id !== graphComponent.programNode.id) {
graphComponent.currentLevel++;
graphComponent.componentClicked(d.programId);
}
});
// add a label to each node
this.node.append("text")
.attr('x', 0)
.attr('y', function (d) {
return d.name.length > 10 ? -20 : 0;
})
.attr('text-anchor', 'middle')
.attr("dy", "0").merge(this.node)
.text(function (d) {
return d.name.replace(/\w\S*/g, function (txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
})
.style("stroke", function (d) {
return d.id == graphComponent.programNode.id ? 'white' : 'black'
})
.style("stroke-width", .70)
.style("fill", function (d) {
return d.id == graphComponent.programNode.id ? '#FFF' : '#000';
})
.call(graphComponent.wrap, 35) // fit text inside of node circle
.on('click', function (d) {
if (d.programId !== graphComponent.programNode.id) {
graphComponent.currentLevel++;
graphComponent.componentClicked(d.programId);
}
});
// Update and restart the simulation.
this.forceSimulation.nodes(this.graphData.nodes)
.force("collide", d3.forceCollide().strength(1).radius(55).iterations(1))
.on("tick", ticked);
this.forceSimulation
.force("link")
.links(this.graphData.links);
// on each tick, update node and link positions
// draws links and moves nodes' x & y positions inside the svg
function ticked() {
graphComponent.link.attr('d', graphComponent.positionLink);
graphComponent.node.attr("transform", graphComponent.positionNode);
}
}
So... after the update, i end up with 所以...更新之后,我最终得到
<g transform="translate(..., ...)>
<circle class="node" ...></circle>
<text ...>First call's text</text>
<circle class="node" ...></circle>
<text ...>Second call's text</text>
</g>
I just want to remove the first circle & text... any suggestions? 我只想删除第一个圆圈和文字...有什么建议吗?
Thanks in advance! 提前致谢!
Found out it was the timing of everything... so simplifying the node/link to this in init: this.link = this.g.append("g").selectAll(".link"); this.node = this.g.append("g").selectAll(".node");
发现这是一切的时机……因此在init中简化为此的节点/链接: this.link = this.g.append("g").selectAll(".link"); this.node = this.g.append("g").selectAll(".node");
this.link = this.g.append("g").selectAll(".link"); this.node = this.g.append("g").selectAll(".node");
and in createGraph
and updateGraph
i'm now calling a method makeNodes()
- the secret sauce was this.svg.selectAll('g .node').remove(); this.svg.selectAll('g text').remove();
在createGraph
和updateGraph
现在我调用一个方法makeNodes()
-的秘密武器是this.svg.selectAll('g .node').remove(); this.svg.selectAll('g text').remove();
this.svg.selectAll('g .node').remove(); this.svg.selectAll('g text').remove();
then i could add my nodes back cleanly... 然后我可以干净地添加我的节点...
Hope this helps anyone else trying this pattern! 希望这对其他尝试此模式的人有所帮助!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.