d3合并嵌套选择

时间:2017-03-11 03:05:22

标签: javascript d3.js

给定以下代码调用update函数创建4个节点,其中圆圈和文本元素嵌套在g元素中,等待500ms,然后使用更新的数据再次调用该函数:

var data1 = [
  { x: 10, y: 10, text: "A" },
  { x: 30, y: 30, text: "B" },
  { x: 50, y: 50, text: "C" },
  { x: 70, y: 70, text: "D" }
];

var data2 = [
  { x: 30, y: 10, text: "X" },
  { x: 50, y: 30, text: "Y" },
  { x: 70, y: 50, text: "Z" },
  { x: 90, y: 70, text: "W" }
];


var svg = d3.select("body").append("svg");

update(data1);
setTimeout(function() { update(data2); }, 500);

function update(data) {

  var nodes = svg.selectAll(".node")
      .data(data);

  var nodesUpdate = nodes
      .attr("class", "node update")

  var nodesEnter = nodes.enter();

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

  node
      .attr("transform", function(d) { return  "translate("+d.x+","+d.y+")"; });

  node.append("circle")
      .attr("r", 10)
      .style("opacity", 0.2);

  node.append("text")
      .text(function(d) { return  d.text; });
}

使用代码,因为它是第二个调用无效,因为所有内容都在输入选择中设置。我正在尝试这样做,以便我可以使用新数据调用update,并更改输入和更新选项的属性,而无需复制代码。通过进行此更改,我可以使用g为顶级元素(即merge元素)实现此目的:

node
  .merge(nodesUpdate)
    .attr("transform", function(d) { return  "translate("+d.x+","+d.y+")"; });

现在节点在500ms后更新它们的位置。但是,我还没弄清楚如何更新文本元素。如果我nodes.selectAll("text")我最终会使用嵌套数据,但这不起作用。

我已经搜索了以下文档,试图弄清楚这一点:

https://bl.ocks.org/mbostock/3808218

https://github.com/d3/d3-selection

https://bost.ocks.org/mike/nest/

2 个答案:

答案 0 :(得分:3)

处理子选择时应该只有nodes.select

这是一个快速重构,带有注释和更清晰的变量名称:



<!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 data1 = [{
      x: 10,
      y: 10,
      text: "A"
    }, {
      x: 30,
      y: 30,
      text: "B"
    }, {
      x: 50,
      y: 50,
      text: "C"
    }, {
      x: 70,
      y: 70,
      text: "D"
    }];

    var data2 = [{
      x: 30,
      y: 10,
      text: "X"
    }, {
      x: 50,
      y: 30,
      text: "Y"
    }, {
      x: 70,
      y: 50,
      text: "Z"
    }, {
      x: 90,
      y: 70,
      text: "W"
    }];

    var svg = d3.select("body").append("svg");

    update(data1);
    setTimeout(function() {
      update(data2);
    }, 500);

    function update(data) {

      var nodesUpdate = svg.selectAll(".node")
        .data(data); // UPDATE SELECTION

      var nodesEnter = nodesUpdate.enter()
        .append("g")
        .attr("class", "node"); // ENTER THE Gs
         
      nodesEnter.append("text"); // APPEND THE TEXT
      
      nodesEnter.append("circle") // APPEND THE CIRCLE
        .attr("r", 10)
        .style("opacity", 0.2);
      
      var nodesEnterUpdate = nodesEnter.merge(nodesUpdate); // UPDATE + ENTER

      nodesEnterUpdate // MOVE POSITION
        .attr("transform", function(d) {
          return "translate(" + d.x + "," + d.y + ")";
        });

      nodesEnterUpdate.select("text") // SUB-SELECT THE TEXT
        .text(function(d) {
          return d.text;
        });
    }
  </script>
</body>

</html>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

如果不重构大量代码,最简单的解决方案是在数据函数中使用键,然后选择“退出”:

var nodes = svg.selectAll(".node")
    .data(data, d=> d.text);

nodes.exit().remove();

以下是演示:

var data1 = [{
  x: 10,
  y: 10,
  text: "A"
}, {
  x: 30,
  y: 30,
  text: "B"
}, {
  x: 50,
  y: 50,
  text: "C"
}, {
  x: 70,
  y: 70,
  text: "D"
}];

var data2 = [{
  x: 30,
  y: 10,
  text: "X"
}, {
  x: 50,
  y: 30,
  text: "Y"
}, {
  x: 70,
  y: 50,
  text: "Z"
}, {
  x: 90,
  y: 70,
  text: "W"
}];


var svg = d3.select("body").append("svg");

update(data1);
setTimeout(function() {
  update(data2);
}, 500);

function update(data) {

  var nodes = svg.selectAll(".node")
    .data(data, d => d.text);

  nodes.exit().remove();

  var nodesUpdate = nodes
    .attr("class", "node update")

  var nodesEnter = nodes.enter();

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

  node
    .merge(nodesUpdate)
    .attr("transform", function(d) {
      return "translate(" + d.x + "," + d.y + ")";
    });

  node.append("circle")
    .attr("r", 10)
    .style("opacity", 0.2);

  node.append("text")
    .text(function(d) {
      return d.text;
    });
}
<script src="https://d3js.org/d3.v4.min.js"></script>

这将创建一个不同的“enter”选项。另一方面,如果您希望将数据绑定到“更新”选项,则必须重构代码。