javascript - D3 不正确的拖动行为

标签 javascript d3.js drag

这是我上一个问题的后续问题 d3 rect in one group interfering with rect in another group

两个问题:

  1. 拖动行为不正确。当点击第二个矩形进行拖动时,它会跳转到第三个矩形所在的位置。

  2. 我添加了一个匿名函数,该函数在单击任意位置的 svg 时运行。这应该添加一个新的矩形。然而这就是工作原理。

我知道每个问题应该只有一个问题,但这些问题是相关的,我怀疑它们会一起解决。

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  /*.active {
    stroke: #000;
    stroke-width: 2px;
  }*/
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
  var margin = {
      top: 20,
      right: 20,
      bottom: 20,
      left: 20
    },
    width = 600 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

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

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

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

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

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

  // create group
  var group = svg.selectAll(null)
    .data(data)
    .enter().append("g")
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    .on("click", removeElement);

  group.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");

  group.append("text")
    .attr("x", function(d) {
      return d.x
    })
    .attr("y", 100)
    .attr("text-anchor", "start")
    .style("fill", "black")
    .text(function(d) {
      return "x:" + d.x
    });

  // create group
  var group = svg.selectAll("g")
    .data(data)
    .enter().append("g")
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    .on("click", removeElement);

  group.append("rect")
    .attr("x", function(d) {
      return d.x;
    })
    .attr("y", 200)
    .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");

  group.append("text")
    .attr("x", function(d) {
      return d.x
    })
    .attr("y", 200)
    .attr("text-anchor", "start")
    .style("fill", "black")
    .text(function(d) {
      return "x:" + d.x
    });

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

    var newData = {
      x: d3.event.x,
    }
    data.push(newData);

    group.selectAll("rect")
      .data(data)
      .enter()
      .append("rect")
      .attr("x", function(d) {
        return d.x;
      })
      .attr("y", 200)
      .attr("height", 100)
      .attr("width", 15)
      .style("fill", "steelblue")
      .attr('id', function(d, i) {
        return 'rect_' + i;
      })
      .attr("rx", 6)
      .attr("ry", 6)
      .attr("stroke-width", 2)
      .attr("stroke", "black");
  });


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

  function dragged(d) {
    d3.select(this).select("text")
      .attr("x", d.x = d3.event.x);
    d3.select(this).select("rect")
      .attr("x", d.x = d3.event.x);
  }

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

  function removeElement(d) {
    d3.event.stopPropagation();
    data = data.filter(function(e) {
      return e != d;
    });
    d3.select(this)
      .remove();
  }
</script>

最佳答案

以下是对您的问题的解释:

  1. 您正在重新分配var groups ,也就是说,你有两个 var groups在您的代码中,最后一个覆盖第一个。只需删除最后一个变量即可。
  2. 在附加新矩形的函数中,您使用的是选择矩形的更新选择。但是,您的输入选择会附加组 ( <g> ) 元素,而不是矩形。

看看重构的函数,它将数据绑定(bind)到新创建的组并将矩形附加到该组:

var newGroup = svg.selectAll(".group")
    .data(data, function(d) {
        return d.x
    })
    .enter()
    .append("g")
    //etc...

newGroup.append("rect")
    //etc...

此外,在数据绑定(bind)中使用键选择,这样您就可以准确地知道正在拖动哪个矩形:

.data(data, function(d){return d.x})

这是经过这些更改的代码:

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  /*.active {
    stroke: #000;
    stroke-width: 2px;
  }*/
</style>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
  var margin = {
      top: 20,
      right: 20,
      bottom: 20,
      left: 20
    },
    width = 600 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

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

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

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

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

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

  // create group
  var group = svg.selectAll(null)
    .data(data, function(d){return d.x})
    .enter().append("g")
    .attr("class", "group")
    .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    .on("click", removeElement);

  group.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");

  group.append("text")
    .attr("x", function(d) {
      return d.x
    })
    .attr("y", 100)
    .attr("text-anchor", "start")
    .style("fill", "black")
    .text(function(d) {
      return "x:" + d.x
    });

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

    var newData = {
      x: coords[0],
    }
    
    data.push(newData);

    var newGroup = svg.selectAll(".group")
      .data(data, function(d){return d.x})
      .enter()
      .append("g")
      .attr("class", "group")
          .call(d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended))
    .on("click", removeElement);
      
      newGroup.append("rect")
      .attr("x", function(d) {
        return d.x;
      })
      .attr("y", 200)
      .attr("height", 100)
      .attr("width", 15)
      .style("fill", "steelblue")
      .attr('id', function(d, i) {
        return 'rect_' + i;
      })
      .attr("rx", 6)
      .attr("ry", 6)
      .attr("stroke-width", 2)
      .attr("stroke", "black");
  });


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

  function dragged(d) {
    d3.select(this).select("text")
      .attr("x", d.x = d3.event.x);
    d3.select(this).select("rect")
      .attr("x", d.x = d3.event.x);
  }

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

  function removeElement(d) {
    d3.event.stopPropagation();
    data = data.filter(function(e) {
      return e != d;
    });
    d3.select(this)
      .remove();
  }
</script>

关于javascript - D3 不正确的拖动行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46491744/

相关文章:

javascript - hammer.js - 阻止拖动事件直到上一个事件结束

javascript - 使用 D3.js 和 TUIO 的触摸事件

javascript - 即使我引用了 lib,$ 也未定义

javascript - 如何在 D3 中链接函数调用?

python - 127.0.0.1 拒绝连接

java - 通过拖动表格来上下滚动

javascript - 如何根据 JQuery 中的其他选择选项动态更改选择选项?

JavaScript:如何将单个全局对象传递给一组类?

javascript - d3.csv修改输入数据

javascript - jQuery拖动时如何处理停止事件?