【问题标题】:d3 - drag behaviour triggered when clickingd3 - 单击时触发的拖动行为
【发布时间】:2015-02-10 16:12:04
【问题描述】:

在我的 svg 容器中,我有一个带有矩形和文本的 <g>。拖动这个组时,我想让组消失,只需在屏幕上拖动一个小矩形来表示对象。为了做到这一点,我使用了<div>,在拖动开始时我可以看到它。我让被拖动的 svg 组消失了。

你可以看到小提琴here。 代码在这里:

   function dragDiv2End(d) {
    console.log('ending');
    var a = d3.select(this);
    a.attr('x', initial.x).attr('y', initial.y).attr('width', initial.width).attr('height', initial.height);
    a.transition().style("opacity",1);
    d3.select('#dragid').style('visibility', 'hidden');

}

function dragDiv2Start(d) {
    d3.event.sourceEvent.stopPropagation();
    console.log('starting');
    var a = d3.select(this);
    initial = {x: a.attr('x'), y: a.attr('y'), width: a.attr('width'), height: a.attr('height')};
    a.attr('x', d3.mouse(this)[0])
    .attr('y', d3.mouse(this)[1]) .attr('width', 20)
    .attr('height', 20).style("opacity",0);

    var b = d3.select('#dragid');
    b.style({
        left: (parseInt(d3.mouse(this)[0])) + "px",
        top: d3.mouse(this)[1] + "px",
        border: "1px solid black",
        visibility: 'visible'

    });
}

function dragDiv2Move(d) {
    var b = d3.select(this);

    var a = d3.select('#dragid');
    a.transition().delay(50).style('opacity', 1);
    //console.log(d3.event.x, d3.event.y, a.style("right"));
    console.log(d3.mouse(this));
    a.style({
        left: (parseInt(d3.mouse(this)[0])) + "px",
        top: d3.mouse(this)[1] + "px"
    });
}

function doClick(d) {
    if (d3.event.defaultPrevented) return;
    console.log('clicked');
}
var initial = {};
var svg = d3.select('#div2').append('svg').attr('height', 300).attr('width', 300).style('border', 'solid 1px blue');

var g = svg.append('g').on('click', doClick);
g.append('rect').attr('x', 10).attr('y', 10).attr('width', 200).attr('height', 200).style('stroke', 'red').style('fill', 'white');
var text = g.append('text')
text.text('my test').attr('x', 50).attr('y', 50);

var dragDiv = d3.behavior.drag()
        .origin(Object)
        .on("drag", dragDivMove);

var dragDiv2 = d3.behavior.drag()
        .origin(Object)
        .on("dragstart", dragDiv2Start)
        .on("drag", dragDiv2Move)
        .on("dragend", dragDiv2End);
g.call(dragDiv2);

问题始于组也应该监听的点击事件。当一个简单的点击发生时,我得到了我的 svg 对象消失的闪烁效果(拖动事件的行为)。

我明白为什么会发生这种情况,但这是非常不可取的,我正在努力寻找解决这个问题的方法。要查看它的发生,只需单击和/或拖动红色矩形。

我尝试阻止事件传播,从拖动到单击都可以正常工作,但反之则不行。

任何建议将不胜感激。

【问题讨论】:

  • 您必须在 dragDiv2Start 函数中添加一些条件逻辑,以限制视觉变化,直到某种阈值变为真......无论是某种距离还是时间。
  • 这是一个非常简洁的解决方案。效果很好

标签: javascript svg d3.js drag-and-drop


【解决方案1】:

我稍微清理了您的代码,并在此 SO 代码 sn-p 中使用了“整洁”效果。格式化 synatx..

首先,在您的 Start 和 Move 函数中。我正在创建一个变量对象来保存 d3.mouse(this) 数据。 (即var currentPosition = {"x" : d3.mouse(this)[0], "y" : d3.mouse(this)[1]};)。

我正在做的是添加一个阈值并将其与距离相关联。在将 dragStart 方法包装在匿名函数中后,我调用它。这允许我获取this 实例以及thresholdValue,并将其绑定到我正在调用它的dragStart。

var dragDiv2 = d3.behavior.drag()
  .origin(Object)
  .on("dragstart", function(arg) {
    console.log("anonymous function - arg: %o", arg);
    dragDiv2Start.bind(this.children[0], 5)();
  })
  .on("drag", dragDiv2Move)
  .on("dragend", dragDiv2End);

然而this 实际上是元素 g.. 它没有设置任何属性,所以我得到第一个孩子 - 即 rect -,并将其绑定到 dragStart 方法。

我创建了一个名为“threshold”的对象变量,它在 dragStart 函数中分配了 min.xmin.ymax.xmax.y 值。我还设置了一个名为IsNeeded 的标志,指示dragMove 函数是否应检查阈值,并有条件地返回或应用视觉更改。如果IsNeeded 仍然为真,则dragEnd 将简单地返回;

我将您的视觉样式从 dragStart 移到 dragMove,并且我只在 threshold.isNeeded 设置为 false 时运行它。


示例代码片段

function dragDivMove(d) {
  var a = d3.select(this);

  var data = {
    "event": {
      "dx": parseInt(d3.event.dx),
      "dy": parseInt(d3.event.dy)
    },
    select: {
      "right": parseInt(a.style("right").replace("px", "")),
      "top": parseInt(a.style("top").replace("px", ""))
    }
  };


  console.log(data);
  a.style({
    "right": (data.select.right - data.event.dx) + "px",
    "top": (data.event.dy + data.select.top) + "px"
  });
}

function dragDiv2End(d) {
  console.log('ending');
  
  var a = d3.select(this);
  var b = d3.select('#dragid');
    
  a.attr('x', initial.x)
  .attr('y', initial.y)
  .attr('width', initial.width)
  .attr('height', initial.height);
    
  a.transition().style("opacity", 1);
  b.style('visibility', 'hidden');
}

function dragDiv2Start(thresholdValue) {
  d3.event.sourceEvent.stopPropagation();  
  var a = d3.select(this);
  
  console.log('starting - this: %o , d3.select(this): %o, thresholdValue: %o', this, a, thresholdValue);


  initial = {
    "x": parseInt(a.attr('x').replace("px",0)),
    "y": parseInt(a.attr('y').replace("px",0)),
    "width": parseInt(a.attr('width').replace("px","")),
    "height": parseInt(a.attr('height').replace("px",""))
  };

  threshold.min = {
    "x": initial.x - thresholdValue,
    "y": initial.y - thresholdValue
  };
  threshold.max = {
    "x": initial.x + thresholdValue,
    "y": initial.y + thresholdValue
  };
  threshold.isNeeded = true;

  var currentPosition = {
    "x": d3.mouse(this)[0],
    "y": d3.mouse(this)[1]
  };

  console.log("current: %o, initial: %o, threshold: %o", currentPosition, initial, threshold);


}

function dragDiv2Move(d) {
  var a = d3.select('#dragid');
  var b = d3.select(this);

  var currentPosition = {
        "x": d3.mouse(this)[0],
        "y": d3.mouse(this)[1]
      };
    

  if (threshold.isNeeded) {
    if (threshold.min.x < currentPosition.x || threshold.min.y < currentPosition.y || threshold.max.x > currentPosition.x || threshold.max.y > currentPosition.y) {
      threshold.isNeeded = false;

      b.attr('x', currentPosition.x);
      b.attr('y', currentPosition.y);
      b.attr('width', 20);
      b.attr('height', 20);
      b.style("opacity", 0);

      a.style({
        "left" : currentPosition.x + "px",
        "top" : currentPosition.y + "px",
        "border" : "1px solid black",
        "visibility" : 'visible'
      });
    } else {
      return;
    }
  }

    console.log(currentPosition);  
  a.transition().delay(50).style('opacity', 1);
  a.style({
    "left" : currentPosition.x + "px",
    "top" : currentPosition.y + "px"
  });
}

function doClick(d) {
  if (d3.event.defaultPrevented) return;
  console.log('clicked');
}

var initial = {},
  threshold = {
    "min": {
      "x": 0,
      "y": 0
    },
    "max": {
      "x": 0,
      "y": 0
    },
    "isNeeded": true
  };


var svg = d3.select('#div2').append('svg').attr('height', 300).attr('width', 300).style('border', 'solid 1px blue');

var g = svg.append('g').on('click', doClick);
g.append('rect').attr('x', 10).attr('y', 10).attr('width', 200).attr('height', 200).style('stroke', 'red').style('fill', 'white');
var text = g.append('text')
text.text('my test').attr('x', 50).attr('y', 50);

var dragDiv = d3.behavior.drag()
  .origin(Object)
  .on("drag", dragDivMove);

var dragDiv2 = d3.behavior.drag()
  .origin(Object)
  .on("dragstart", function() {
    dragDiv2Start.bind(this.children[0], 5)();
  })
  .on("drag", dragDiv2Move)
  .on("dragend", dragDiv2End);

g.call(dragDiv2);

//d3.select('#dragid').call(dragDiv);
#dragid {
  background-color: lightblue;
  position: absolute;
  top: 0px;
  left: 0px;
  width: 5px;
  height: 5px;
  visibility: hidden
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="dragid">
  <span></span>

</div>
<div id="div2"></div>

注意:存在公式错误。 (g &gt; rect 的)初始值与 dragMove 中鼠标的后续 currentPosition 值进行比较。应该是 dragStart 中鼠标的 currentPosition 将与 dragMove..

中鼠标的后续 currentPosition 值进行比较

无论如何,值得注意的是,dragMove 不会触发,除非您实际使用鼠标键向下拖动。这就是视觉效果不会闪烁的原因;即使在当前实现中,isNeeded 的计算总是在 dragMove 中得到满足..

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-24
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多