I have defined some drag behaviour that works as expected as follows (code in CoffeeScript):
nodeDrag = d3.behavior.drag()
.on("dragstart", (d, i) ->
force.stop())
.on("drag", (d, i) ->
d.px += d3.event.dx
d.py += d3.event.dy
d.x += d3.event.dx
d.y += d3.event.dy
tick())
.on("dragend", (d, i) ->
force.resume()
d.fixed = true
tick())
// ...
nodes = vis.selectAll(".node")
.data(graph.nodes)
.enter()
.append("g")
// ...
.call(nodeDrag)
I now try to create custom behaviour for right clicks on nodes. However, this triggers "dragstart" and "drag", i.e. after I call e.preventDefault()
on the "contextmenu" event, the node in question is stuck to my mouse pointer and follows it around until I do another (left) click to force a release (I assume e.preventDefault()
also causes "dragend" to never fire).
I found a brief discussion of this issue in a thread on Google Groups and a discussion in d3's issues on Github. However, I cannot figure out from those comments how to prevent this behaviour.
How can I not trigger dragging on right click?
I found a possibility to limit the drag gestures to left mouse button only.
It involves an additional field that records when a gesture has been initiated:
dragInitiated = false
The rest of the code is then modified to register initiation and termination of a desired drag gestures on "dragstart" and "dragend", respectively. Actions for "drag" are then only performed if a drag gestures was properly initiated.
nodeDrag = d3.behavior.drag()
.on "dragstart", (d, i) ->
if (d3.event.sourceEvent.which == 1) # initiate on left mouse button only
dragInitiated = true # -> set dragInitiated to true
force.stop()
.on "drag", (d, i) ->
if (dragInitiated) # perform only if a drag was initiated
d.px += d3.event.dx
d.py += d3.event.dy
d.x += d3.event.dx
d.y += d3.event.dy
tick()
.on "dragend", (d, i) ->
if (d3.event.sourceEvent.which == 1) # only take gestures into account that
force.resume() # were valid in "dragstart"
d.fixed = true
tick()
dragInitiated = false # terminate drag gesture
I am not sure whether this is the most elegant solution, but it does work and is not exceptionally clumsy or a big hack.
for D3 v4 see drag.filter([filter])
If filter is specified, sets the filter to the specified function and returns the drag behavior. If filter is not specified, returns the current filter, which defaults.
drag.filter([filter])
for the right click:
.filter(['touchstart'])
Filters available
mousedown, mousemove, mouseup, dragstart, selectstart, click, touchstart, touchmove, touchend, touchcancel
Little late to the party, I had the same problem and I used the following method to make sure my drag
only works for left click
.
var drag = d3.behavior.drag()
.on('drag', function () {
console.log(d3.event.sourceEvent.button);
if(d3.event.sourceEvent.button == 0){
var mouse = d3.mouse(this);
d3.select(this)
.attr('x', mouse[0])
.attr('y', mouse[1]);
}
});
To handle all listeners of drag event, you can use the code below:
function dragChartStart() {
if(d3.event.sourceEvent.button !== 0) {
console.log("not left click");
return;
}
console.log("dragStart");
}
function dragChartEnd() {
if(d3.event.sourceEvent.button !== 0) {
console.log("not left click");
return;
}
console.log("dragEnd");
}
function dragChartMove() {
if(d3.event.sourceEvent.button !== 0) {
console.log("not left click");
return;
}
console.log("dragMove");
}
var dragBehavior = d3.behavior.drag()
.on("drag", dragChartMove)
.on("dragstart", dragChartStart)
.on("dragend", dragChartEnd);
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