带动画的子选择删除

Sub selection deletion with animations

我有一组节点数据

var dataNodes = [ 
  { id: 1, x: 10, y:30, text: "node 1", muteText: false }, 
  { id: 2, x: 30, y:50, text: "node 2", muteText: false }, 
  { id: 3, x: 50, y:70, text: "node 3", muteText: false } 
];

我使用这种函数在 DOM 中添加元素(由于很多业务复杂性,这不是我的真实代码):

function redraw(newData) {
    var node = d3
      .select("body")
      .selectAll("g.node")
      .data(dataNodes)
      .transition().duration(500)
      .attr("transform", d => "translate(" + d.x + "," + d.y + ")");

    node.enter()
      .append("g")
      .attr("class", "node")
      .attr("transform", d => "translate(" + d.x + "," + d.y + ")")
      .append("text")
      .text(d => d.text)
      .style("opacity", "0")
      .transition().duration(500)
      .style("opacity", "1");

    node.exit()
      .style("opacity", "0");
}

我希望在数据更新时能够执行以下所有操作:

我对前 3 个要求很满意,但我真的不知道如何做最后一个:如何根据过滤后的数据集删除(甚至更改)子元素?我可以使用 d3.data 函数中的过滤器来实现吗?

如果我的问题不清楚,请告诉我。

如果要过滤,请在更新选择时执行:

  var node = svg
    .selectAll("g.node")
    .data(someData);

  var nodeE = node.enter()
    .append("g")
    .attr("class", "node");

  nodeE.append("text")
    .text(d => d.text);

  // node is now UPDATE + ENTER
  node = nodeE.merge(node);

  // filter the text and set how you care
  node.filter(function(d) {
      return d.muteText
    })
    .select("text")
    .style("opacity", 1)
    .transition()
    .style("opacity", 0);

  node.filter(function(d) {
      return !d.muteText
    })
    .select("text")
    .style("opacity", 0)
    .transition()
    .style("opacity", 1);

这是一个 运行 示例:

<!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>
  <style>
    text {
      fill: black;
      font-family: arial;
    }
  </style>
</head>

<body>
  <script>
    var dataNodes = [{
      id: 1,
      x: 10,
      y: 30,
      text: "node 1",
      muteText: false
    }, {
      id: 2,
      x: 30,
      y: 50,
      text: "node 2",
      muteText: false
    }, {
      id: 3,
      x: 50,
      y: 70,
      text: "node 3",
      muteText: false
    }];

    var svg = d3.select('body')
      .append('svg')
      .attr('width', 500)
      .attr('height', 500);

    redraw([{
        id: 1,
        x: 10,
        y: 30,
        text: "node 1",
        muteText: false
      }, {
        id: 2,
        x: 30,
        y: 50,
        text: "node 2",
        muteText: false
      }, {
        id: 3,
        x: 50,
        y: 70,
        text: "node 3",
        muteText: false
      }]);
    
    setTimeout(function() {
      redraw([{
        id: 1,
        x: 10,
        y: 30,
        text: "node 1",
        muteText: true
      }, {
        id: 2,
        x: 100,
        y: 50,
        text: "node 2",
        muteText: false
      }, {
        id: 3,
        x: 50,
        y: 70,
        text: "node 3",
        muteText: true
      }])
    }, 2000)
    
    setTimeout(function() {
      redraw([{
        id: 1,
        x: 10,
        y: 30,
        text: "node 1",
        muteText: true
      }, {
        id: 2,
        x: 100,
        y: 50,
        text: "node 2",
        muteText: false
      }, {
        id: 3,
        x: 50,
        y: 70,
        text: "node 3",
        muteText: false
      },{
        id: 4,
        x: 60,
        y: 90,
        text: "node 4",
        muteText: false
      }])
    }, 4000)

    function redraw(someData) {

      var node = svg
        .selectAll("g.node")
        .data(someData);

      var nodeE = node.enter()
        .append("g")
        .attr("class", "node")
        .attr("transform", d => "translate(" + d.x + "," + d.y + ")");

      nodeE.append("text")
        .text(d => d.text)
        .style("opacity", 0)
        .transition()
        .style("opacity", 1);

      node = nodeE.merge(node);

      node.exit()
        .style("opacity", "0");

      node.transition().duration(500)
        .attr("transform", d => "translate(" + d.x + "," + d.y + ")");

      node.filter(function(d) {
          return d.muteText
        })
        .select("text")
        .transition()
        .style("opacity", 0);    

    }
  </script>
</body>

</html>