我正在使用Angular 6和D3v4创建一个力模拟图,并且第一次加载就很好,并且我向圆圈和文本添加了一个click事件来更新数据,但是过渡效果很奇怪-删除了一些节点,但是其余的节点仅添加了一个新的圆圈和文本...我尝试了Mike Bostock的general update pattern,但是在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);
}
}
所以...更新之后,我最终得到
<g transform="translate(..., ...)>
<circle class="node" ...></circle>
<text ...>First call's text</text>
<circle class="node" ...></circle>
<text ...>Second call's text</text>
</g>
我只想删除第一个圆圈和文字...有什么建议吗?
谢谢!
答案 0 :(得分:0)
发现这是一切的时机……因此简化init的节点/链接:
this.link = this.g.append("g").selectAll(".link");
this.node = this.g.append("g").selectAll(".node");
在createGraph
和updateGraph
中,我现在正在调用方法makeNodes()
-秘密之处在于
this.svg.selectAll('g .node').remove();
this.svg.selectAll('g text').remove();
然后我可以将节点干净地添加回去...
希望这可以帮助其他尝试此模式的人!