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
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.
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.
Right click is to click the right mouse button. To drag is to point to an object on the screen, hold down the left mouse button while moving the mouse (and the object) to a new location on the screen then release the mouse button. The object is moved to the new location on the screen.
On the “mouse up” event, the value of drag variable is checked. If the value is true, a “drag” event has occurred and the output is displayed in the console. If the value is 'false' which means there has been no “mouse move” event which also implies that a “click” event had occurred.
You can differentiate between a click
and a dragstart
, but it is harder to differentiate between a mousdown
and a 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
).
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:
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)
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.
Keep in mind that when clicking, the dragstart
is still triggered. (but not drag
)
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.
See also the answer to this question.
d3.event.sourceEvent.preventDefault()
doesn't work as expected or rather its inconsistent.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With