d3.behavior.zoom()跳了起来

时间:2016-10-15 05:31:51

标签: javascript d3.js svg

我有以下d3图表。它只是一些节点和它们之间的链接。该图表做了两件事:

  1. 您可以点击并拖动图表周围的各个节点。
  2. 您可以点击并拖动svg以使用d3.behavior.zoom平移(并使用鼠标滚轮缩放)。
  3. 我遇到的问题是,如果我拖动一个节点(例如,将节点向右移动20px),然后尝试平移图表,整个图形会立即向右跳20px(每个例)。 d3.behavior.zoom似乎最初使用拖动节点的d3.event或类似的东西。不确定。这是代码:

    var data = {
      nodes: [{
        name: "A",
        x: 200,
        y: 150,
        size: 30
      }, {
        name: "B",
        x: 140,
        y: 300,
        size: 15
      }, {
        name: "C",
        x: 300,
        y: 300,
        size: 15
      }, {
        name: "D",
        x: 300,
        y: 180,
        size: 45
      }],
      links: [{
        source: 0,
        target: 1
      }, {
        source: 1,
        target: 2
      }, {
        source: 2,
        target: 3
      }, ]
    };
    
    var dragging = false;
    
    var svg = d3.select("body")
      .append("svg")
      .attr("width", "100%")
      .attr("height", "100%")
      .call(d3.behavior.zoom().on("zoom", function() {
        if (dragging === false) {
          svg.attr("transform", "translate(" + d3.event.translate + ") scale(" + d3.event.scale + ")")
        }
      })).append("g");
    
    var links = svg.selectAll("link")
      .data(data.links)
      .enter()
      .append("line")
      .attr("class", "link")
      .attr("x1", function(l) {
        var sourceNode = data.nodes.filter(function(d, i) {
          return i == l.source
        })[0];
        d3.select(this).attr("y1", sourceNode.y);
        return sourceNode.x
      })
      .attr("x2", function(l) {
        var targetNode = data.nodes.filter(function(d, i) {
          return i == l.target
        })[0];
        d3.select(this).attr("y2", targetNode.y);
        return targetNode.x
      })
      .attr("fill", "none")
      .attr("stroke", "white");
    
    var nodes = svg.selectAll("node")
      .data(data.nodes)
      .enter()
      .append("circle")
      .each(function(d, i) {
        d.object = d3.select(this);
        console.log(d);
      })
      .attr("class", "node")
      .attr("cx", function(d) {
        return d.x
      })
      .attr("cy", function(d) {
        return d.y
      })
      .attr("r", function(d) {
        return d.size;
      })
      .on('click', function(d) {
    
      })
      .call(d3.behavior.drag()
        .on('dragstart', function() {
          dragging = true;
        })
        .on('dragend', function() {
          dragging = false;
        })
        .on("drag", function(d, i) {
          d.x += d3.event.dx
          d.y += d3.event.dy
          d3.select(this).attr("cx", d.x).attr("cy", d.y);
          links.each(function(l, li) {
            if (l.source == i) {
              d3.select(this).attr("x1", d.x).attr("y1", d.y);
            } else if (l.target == i) {
              d3.select(this).attr("x2", d.x).attr("y2", d.y);
            }
          });
        })
      );
    

    这是一个演示:

    https://jsfiddle.net/25q1Lu3x/2/

    如何在尝试平移时防止最初的跳跃?我已经阅读了一些建议制作一个额外的嵌套svg g元素并移动它的东西,但这似乎没有什么区别。

1 个答案:

答案 0 :(得分:2)

根据D3 v3 API:

  

将拖动行为与其他事件侦听器组合以进行交互事件(例如将拖动优先于缩放)时,您还可以考虑停止对源事件的传播以防止多个操作

因此,在dragstart中,只需添加d3.event.sourceEvent.stopPropagation();

.on('dragstart', function() {
    d3.event.sourceEvent.stopPropagation();
    dragging = true;
});

这是你的小提琴:https://jsfiddle.net/hj7krohd/