36

我无法成功区分click事件和drag使用 D3.js v3 绑定到两者的元素上的事件。下面代码中的圆圈被分配了一个拖动行为和一个click监听器。 演示在这里

var dragGroup = d3.behavior.drag()
    .on('dragstart', function () {
    console.log('Start Dragging Group');
})
    .on('drag', function (d, i) {
    d.x += d3.event.dx;
    d.y += d3.event.dy;
    d3.select(this).attr("transform", "translate(" + d.x + "," + d.y + ")");
});

var dragCircle = d3.behavior.drag()
    .on('dragstart', function () {
    d3.event.sourceEvent.stopPropagation();
    d3.event.sourceEvent.preventDefault();
    console.log('Start Dragging Circle');
})
    .on('drag', function (d, i) {
    d.cx += d3.event.dx;
    d.cy += d3.event.dy;
    d3.select(this).attr('cx', d.cx).attr('cy', d.cy);
});

var svg = d3.select('body').append('svg').attr('viewBox', '-50 -50 300 300');
var g = svg.selectAll('g').data([{
    x: 10,
    y: 10
}])
    .enter().append('g').call(dragGroup);

g.append('rect').attr('width', 100).attr('height', 100);

g.selectAll('circle').data([{
    cx: 90,
    cy: 80
}]).enter()
    .append('circle')
    .attr('cx', function (d) {
    return d.cx;
})
    .attr('cy', function (d) {
    return d.cy;
})
    .attr('r', 30)
    .call(dragCircle)
    .on('click', function () {
    console.log('clicked circle');
});

每当我单击示例中的圆圈时,我都会让控制台记录drag事件以及click事件。拖动时我也得到相同的行为,首先记录drag事件并记录事件。mouseupclick

分别处理这些事件的正确方法是什么?
用例是尝试在树形布局中处理节点单击和节点拖放。

4

3 回答 3

31

缺少的关键位是检查是否已阻止事件的默认行为。也就是说,有一个匹配的兄弟d3.event.preventDefault()-- d3.event.defaultPrevented。您需要在click处理程序中检查这一点,以查看是否正在进行任何拖动操作。

另请参阅此问题的答案。

于 2013-11-13T10:18:53.193 回答
14

您可以区分 aclick和 a dragstart,但很难区分 amousdown和 a dragstart

dragstart将在您开始拖动动作时触发,这意味着当您执行mousedown. 这就是为什么。无论何时clickdragstart都会triggered。(aclick是一个mousedown+ mouseup)。

所以防止点击被触发应该可以工作。在您的代码中,您应该按照 Lars Kotthoff 的提示添加 preventDefault。但不要放在dragstart函数中:

var dragCircle = d3.behavior.drag()
    .on('dragstart', function () {
    d3.event.sourceEvent.stopPropagation();
    d3.event.sourceEvent.preventDefault(); <-- Remove This
    console.log('Start Dragging Circle');
})

并将其添加到正确的位置(在点击功能中),并用d3(d3.event.defaultPrevented )正确写入

g.selectAll('circle').data([{
    cx: 90,
    cy: 80
}]).enter()
    .append('circle')
    .attr('cx', function (d) {
    return d.cx
})
    .attr('cy', function (d) {
    return d.cy
})
    .attr('r', 30)
    .call(dragCircle)
    .on('click', click);

function click(d) {
  if (d3.event.defaultPrevented) return; <-- Add d3.event.defaultPrevented
  console.log('clicked');
}

查看更新版本。现在,拖动时,click不再触发。

请记住,单击时dragstart仍会触发 。(但不是drag

于 2013-11-12T23:19:42.687 回答
0

d3.event.sourceEvent.preventDefault()不能按预期工作,或者说不一致。

我遇到了这个问题,为了区分这两个事件,我在事件中使用了一个布尔isDraggedonDrag。因此,如果设置了此值,则drag在对象上执行事件,否则将click执行事件。同样,对对象的正常单击会触发其dragstartdragend事件,但不会触发onDrag事件。

于 2018-04-08T10:32:25.027 回答