更新对象的D3选择

时间:2017-05-06 11:32:27

标签: javascript d3.js

我正在构建一个交互式散点图,我无法更新圆圈的选择(数据点SEEM工作正常,但我不能确定,因为行为有些不稳定)。当我创建初始绘图时,点和线显示正常,但在单击节点并将其删除后,我无法重置选择。更具体地说,变量“i”(在我的理解中给出了选择中对象的索引)仍然与初始选择绑定。代码如下:

        function mousedownCircle(d, i) {
            console.log(i);
            circles[0][i].remove();
            dataset.splice(i, 1);
            circles = svg.selectAll("circle").data(dataset);
            line_obj.attr("d", valueline(dataset));
            d3.event.stopPropagation();
        }

        // Create Circles
        var circles = svg.selectAll("circle")
            .data(dataset)
            .enter()
            .append("circle")  // Add circle svg
            .attr("cx", function(d) {
                return xScale(d[0]);  // Circle's X
            })
            .attr("cy", function(d) {  // Circle's Y
                return yScale(d[1]);
            })
            .attr("r", radius)  // radius
            .on("click", mousedownCircle); // click callback

主要思想是能够删除圆圈和数据点。我做错了什么?

谢谢你的时间!

1 个答案:

答案 0 :(得分:0)

d3的关键是遵循正确的enterupdateexit模式。我通常将它包装成一个我可以调用的函数,而不管“重绘”我的可视化的动作。从查看代码片段开始,正确的函数将如下所示:

function update() {

  // Create Circles
  var circles = svg.selectAll("circle")
    .data(dataset);

  circles.exit().remove(); // remove the ones exiting

  circles = circles
    .enter() // Add circle to svg
    .append("circle")
    .merge(circles); // this is the update + enter selection

  circles // update circles
    .attr("cx", function(d) {
      return xScale(d[0]); // Circle's X
    })
    .attr("cy", function(d) { // Circle's Y
      return yScale(d[1]);
    })
    .attr("r", 40) // radius
    .style("fill", "steelblue")
    .on("click", mousedownCircle); // click callback
}

您的mousedownCircle功能变得如此简单:

function mousedownCircle(d, i) {
    dataset.splice(i, 1);
    update();
}

运行示例:

<!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>
    function mousedownCircle(d, i) {
      dataset.splice(i, 1);
      update();
    }

    var w = 400,
      h = 400;

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

    var dataset = [
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h]
    ];

    update();

    function update() {

      // Create Circles
      var circles = svg.selectAll("circle")
        .data(dataset);

      circles.exit().remove();

      circles = circles
        .enter()
        .append("circle")
        .merge(circles); // Add circle svg
        
      circles
        .attr("cx", function(d) {
          return d[0]; // Circle's X
        })
        .attr("cy", function(d) { // Circle's Y
          return d[1];
        })
        .attr("r", 40) // radius
        .style("fill", "steelblue")
        .on("click", mousedownCircle); // click callback

    }
  </script>
</body>

</html>

对评论的回应

最直接的做法是:

<!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>
    function mousedownCircle(d, i) {
      d3.select(this).remove();
    }

    var w = 400,
      h = 400;

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

    var dataset = [
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h],
      [Math.random() * w, Math.random() * h]
    ];


    // Create Circles
    var circles = svg.selectAll("circle")
      .data(dataset)
      .enter()
      .append("circle")
      .attr("cx", function(d) {
        return d[0]; // Circle's X
      })
      .attr("cy", function(d) { // Circle's Y
        return d[1];
      })
      .attr("r", 40) // radius
      .style("fill", "steelblue")
      .on("click", mousedownCircle); // click callback
  </script>
</body>

</html>