更新D3力图-如何删除圆和文字?

时间:2018-07-03 18:14:06

标签: javascript d3.js angular5

我正在使用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>

我只想删除第一个圆圈和文字...有什么建议吗?

谢谢!

1 个答案:

答案 0 :(得分:0)

发现这是一切的时机……因此简化init的节点/链接: this.link = this.g.append("g").selectAll(".link"); this.node = this.g.append("g").selectAll(".node");

createGraphupdateGraph中,我现在正在调用方法makeNodes()-秘密之处在于 this.svg.selectAll('g .node').remove(); this.svg.selectAll('g text').remove();

然后我可以将节点干净地添加回去...

希望这可以帮助其他尝试此模式的人!