D3 区分具有拖动行为的元素的单击和拖动

D3 Differentiate between click and drag for an element which has a drag behavior

本文关键字:拖动 元素 单击 D3      更新时间:2023-09-26

我无法使用 D3 v3 成功区分绑定到两者的元素上的click事件和drag事件.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事件,mouseup记录click事件。

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

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

另请参阅此问题的答案。

你可以区分clickdragstart,但很难区分mousdowndragstart

dragstart将在您开始拖动操作时触发,这意味着当您执行mousedown时。这就是原因。每当你clickdragstart都会triggered。(clickmousedown + mouseup)。

因此,防止触发点击应该有效。在你的代码中,你应该添加 preventDefault,正如 Lars Kotthoff 所暗示的那样。但不要把它放在 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)正确编写。默认已阻止

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

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

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