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

Rob*_*ker 32 javascript drag-and-drop d3.js

我无法使用D3.js v3 成功区分绑定到两者的元素上的click事件和drag事件.下面代码中的圆圈被赋予拖动行为和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');
});
Run Code Online (Sandbox Code Playgroud)

每当我点击示例中的圆圈时,我都会让控制台记录drag事件以及click事件.拖动时,首先我也得到了相同的行为drag记录事件,并且在mouseupclick事件被记录下来.

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

Lar*_*off 29

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

另见这个问题的答案.

  • 不幸的是,d3.event.defaultPrevented不能始终如一地工作.至少在Chrome中我发现,尽管进行了此检查,仍然有时会在拖动时执行点击处理程序. (5认同)

leM*_*ela 13

你可以区分a click和a dragstart,但很难区分a mousdown和a dragstart.

dragstart当您开始拖动动作时将触发,这意味着当您执行此操作时mousedown.这就是为什么.每当你click,dragstarttriggered.(a click是a 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');
})
Run Code Online (Sandbox Code Playgroud)

并将其添加在正确的地方(在点击功能),并将其与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');
}
Run Code Online (Sandbox Code Playgroud)

请参阅更新版本.现在,拖动时,click不会再触发.

请记住,点击时dragstart仍会触发.(但不是drag)