d3没有正确更新绑定到数据的矩形

时间:2017-10-05 10:28:08

标签: d3.js updates

我有一个矩形绑定到一个称为数据的数据数组。当我单击svg时,将调用函数removeElement。此函数从数据中删除与该矩形相关的元素。然后调用函数render()。

问题是以前的矩形没有被删除。所以render()函数没有正确更新。

点击一个矩形并将其移除后,如果我拖动另一个矩形,可以看到下面还有一个矩形。

类似的相关问题是我必须双击rects才能删除它们。不知道为什么会这样。

以下是代码段(所谓的代码段,实际上是完整代码)

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  /*.active {
    stroke: #000;
    stroke-width: 2px;
  }*/

  svg {
    border: 1px solid black;
  }
</style>
<svg width="800" height="300"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
  var margin = {
      top: 20,
      right: 20,
      bottom: 20,
      left: 20
    },
    width = 840 - margin.left - margin.right,
    height = 640 - margin.top - margin.bottom;

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

  var data = [{
    x: 100
  }, {
    x: 300
  }, {
    x: 400
  }, {
    x: 600
  }];

  var ind = 0;
  var groove = svg.append("g")
    .attr("class", "groove_group");

  groove.append("rect")
    .attr("x", 0)
    .attr("y", 150)
    .attr("rx", 2)
    .attr("ry", 2)
    .attr("height", 6)
    .attr("width", width)
    .style("fill", "grey");

  groove.append("rect")
    .attr("x", 2)
    .attr("y", 152)
    .attr("rx", 2)
    .attr("ry", 2)
    .attr("height", 2)
    .attr("width", 796)
    .style("fill", "black");

  render();

  function render() {
    // create group
    var group = svg.selectAll(null)
      .data(data, function(d) {
        return d.x
      });

    group.exit().remove();

    var groupEnter = group.enter().append("g")
      .attr("class", "group");

    groupEnter.call(d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended))
      .on("click", removeElement);

    groupEnter.append("rect")
      .attr("x", function(d) {
        return d.x;
      })
      .attr("y", 100)
      .attr("height", 100)
      .attr("width", 15)
      .style("fill", "lightblue")
      .attr('id', function(d, i) {
        return 'handle_' + i;
      })
      .attr("rx", 6)
      .attr("ry", 6)
      .attr("stroke-width", 2)
      .attr("stroke", "black");

    groupEnter.append("text")
      .attr("x", function(d, i) {
        if (i == 0) { // first element
          return ((data[i].x / 2));
        } else {
          return (data[i].x - (data[i].x - data[i - 1].x) / 2);
        }
      })
      .attr("y", 100)
      .attr("text-anchor", "middle")
      .style("fill", "black")
      .attr('id', function(d, i) {
        return 'text_' + i;
      })
      .text(function(d, i) {
        if (i == 0) { // first set
          return i + ": " + (data[i].x) + "m";
        } else {
          return i + ": " + ((data[i].x - data[i - 1].x)) + "m";
        }
      });

  }
  svg.on("click", function() {
    var coords = d3.mouse(this);

    getPosition(ind, coords[0]);

    render();

  });

  function dragstarted(d) {
    d3.select(this).raise().classed("active", true);
  }

  function dragged(d, i) {
    if (i == 0) {
      d3.select("#text_" + i)
        .attr("x", d.x = (d3.event.x / 2))
        .text(function(d) {
          return i + " " + d3.event.x
        });
      d3.select("#text_" + (i + 1))
        .attr("x", d.x = d3.event.x + ((data[i + 1].x - d3.event.x) / 2))
        .text(function(d) {
          return (i + 1) + " " + (data[i + 1].x - d3.event.x) + "m"
        });
      d3.select(this).select("rect")
        .attr("x", d.x = d3.event.x);
    } else if (i == data.length - 1) {
      d3.select("#text_" + i)
        .attr("x", d.x = (d3.event.x - data[i - 1].x) / 2 + data[i - 1].x)
        .text(function(d) {
          return i + ": " + (d3.event.x - data[i - 1].x) + "m"
        });
      d3.select("#text_" + (i + 1))
        .attr("x", d.x = d3.event.x + (width - d3.event.x) / 2)
        .text(function(d) {
          return (i + 1) + ": " + (width - d3.event.x) + "m"
        });
      d3.select(this).select("rect")
        .attr("x", d.x = d3.event.x);
    } else {
      d3.select("#text_" + i)
        .attr("x", d.x = d3.event.x - ((d3.event.x - data[i - 1].x) / 2))
        .text(function(d) {
          return i + ": " + (d3.event.x - data[i - 1].x) + "m"
        });
      d3.select("#text_" + (i + 1))
        .attr("x", d.x = d3.event.x + ((data[i + 1].x - d3.event.x) / 2))
        .text(function(d) {
          return (i + 1) + ": " + (data[i + 1].x - d3.event.x) + "m"
        });
      d3.select(this).select("rect")
        .attr("x", d.x = d3.event.x);
    }
  }

  function dragended(d) {
    d3.select(this)
      .classed("active", false);
  }

  function removeElement(d, i) {
    d3.event.stopPropagation();

    data = data.filter(function(e) {
      return e != d;
    });
    d3.select(this)
      .remove();

    render();

  }

  function getPosition(ind, coords) {
    if (coords[0] > data[ind].x) {
      getPosition(++ind);
    } else {
      data.splice(1, 0, {
        x: coords
      });
    }
  }
</script>

这个问题来自here

1 个答案:

答案 0 :(得分:1)

.exit()无法正常工作的原因,因此您的旧元素在更新后仍然可见,因为您正在进行数据加入.data() .selectAll(null)

在进行数据连接时,d3会根据您的选择器查看所有现有元素,然后在已经存在的内容之外附加所需的任何元素,或者反过来删除任何不再需要的元素。 根据您的代码选择null,d3无法找到任何现有元素。通过将其更改为.selectAll('.group')

,它应该可以正常工作