javascript D3 区分具有拖动行为的元素的单击和拖动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19931307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
D3 Differentiate between click and drag for an element which has a drag behavior
提问by Rob Schmuecker
I am unable to successfully distinguish between the clickevent and the dragevent on an element that is bound to both using D3.js v3. The circle in the code below is assigned a drag behaviour and also a clicklistener.
Demo here
我无法成功区分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');
});
Whenever I click the circle in the example I get the console logging the dragevent aswell as the clickevent. I also get the same behavior when dragging, first the dragevent is logged and on mouseupthe clickevent gets logged.
每当我单击示例中的圆圈时,控制台都会记录drag事件以及click事件。拖动时,首先我也得到了相同的行为drag记录事件,并且在mouseup该click事件被记录下来。
What is the correct way to handle these events separately?
The use case is an attempt to handle a node-click and a node-drag/drop in a tree layout.
分别处理这些事件的正确方法是什么?
用例是尝试在树布局中处理节点单击和节点拖放。
采纳答案by Lars Kotthoff
The key bit that's missing is the check whether the default behaviour of an event has been prevented. That is, there's a matching sibling to d3.event.preventDefault()-- d3.event.defaultPrevented. You need to check this in your clickhandler to see whether any dragging action is going on.
缺少的关键位是检查是否已阻止事件的默认行为。也就是说,有一个匹配的兄弟d3.event.preventDefault()-- d3.event.defaultPrevented。您需要在click处理程序中检查这一点,以查看是否正在进行任何拖动操作。
See also the answer to this question.
另请参阅此问题的答案。
回答by leMoisela
You can differentiate between a clickand a dragstart, but it is harder to differentiate between a mousdownand a dragstart.
您可以在区分click和dragstart,但它是一个更难区分mousdown和dragstart。
dragstartwill be triggered when you begin your drag action, meaning when you do your mousedown. This is why. whenever you click, dragstartwill be triggered. (a clickis a mousedown+ mouseup).
dragstart将在您开始拖动操作时触发,这意味着当您执行mousedown. 这就是为什么。无论何时你click,dragstart都会triggered。(aclick是mousedown+ mouseup)。
So preventing the click to be triggered should work. In your code, you should add the preventDefault as Lars Kotthoff has hinted. But don't put it in the dragstart function:
所以防止点击被触发应该有效。在您的代码中,您应该像 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');
})
And add it on the right place (in the click function), and write it correctly with d3 (d3.event.defaultPrevented)
并将其添加在正确的地方(在点击功能),并将其与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');
}
See the updated version. Now, when dragging, the clickis not triggered anymore.
请参阅更新版本。现在,拖动时click不再触发 。
Keep in mind that when clicking, the dragstartis still triggered. (but not drag)
请记住,单击时dragstart仍会触发 。(但不是drag)
回答by Vibha Pandey
d3.event.sourceEvent.preventDefault()doesn't work as expected or rather its inconsistent.
d3.event.sourceEvent.preventDefault()不能按预期工作,或者说它不一致。
I faced this issue and to differentiate between the two events, I used a boolean value isDraggedinside the onDragevent. So if this value is set, the dragevent is performed on the object if not then clickevent is performed.
Also a normal click on object triggers its dragstartand dragendevent but not onDragevent.
我遇到了这个问题,为了区分这两个事件,我isDragged在onDrag事件中使用了一个布尔值。因此,如果设置了此值,则drag在对象click上执行事件,否则将执行事件。此外,正常单击对象会触发其dragstart和dragend事件,但不会触发onDrag事件。

