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 click
event and the drag
event 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 click
listener.
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 drag
event aswell as the click
event. I also get the same behavior when dragging, first the drag
event is logged and on mouseup
the click
event 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 click
handler 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 click
and a dragstart
, but it is harder to differentiate between a mousdown
and a dragstart
.
您可以在区分click
和dragstart
,但它是一个更难区分mousdown
和dragstart
。
dragstart
will be triggered when you begin your drag action, meaning when you do your mousedown
. This is why. whenever you click
, dragstart
will be triggered
. (a click
is 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 click
is not triggered anymore.
请参阅更新版本。现在,拖动时click
不再触发 。
Keep in mind that when clicking, the dragstart
is 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 isDragged
inside the onDrag
event. So if this value is set, the drag
event is performed on the object if not then click
event is performed.
Also a normal click on object triggers its dragstart
and dragend
event but not onDrag
event.
我遇到了这个问题,为了区分这两个事件,我isDragged
在onDrag
事件中使用了一个布尔值。因此,如果设置了此值,则drag
在对象click
上执行事件,否则将执行事件。此外,正常单击对象会触发其dragstart
和dragend
事件,但不会触发onDrag
事件。