我已经定义了一些按预期工作的拖动行为,如下所示(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)
Run Code Online (Sandbox Code Playgroud)
我现在尝试为节点上的右键单击创建自定义行为.然而,这会触发"dragstart"和"drag",即在我调用e.preventDefault()"contextmenu"事件之后,有问题的节点会粘在我的鼠标指针上并跟随它,直到我再做一次(左)单击以强制释放(我认为e.preventDefault()也会导致"dragend"从不开火.
我在Google网上论坛的一个主题中找到了对此问题的简短讨论,并在Github上讨论了d3的问题.但是,我无法从这些评论中弄清楚如何防止这种行为.
如何在右键单击时不触发拖动?
我发现只能将拖动手势限制为鼠标左键.
它涉及一个记录手势何时启动的附加字段:
dragInitiated = false
Run Code Online (Sandbox Code Playgroud)
然后修改代码的其余部分以分别在"dragstart"和"dragend"上注册所需拖动手势的启动和终止.然后,只有在正确启动拖动手势的情况下才执行"拖动"操作.
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
Run Code Online (Sandbox Code Playgroud)
我不确定这是否是最优雅的解决方案,但它确实有效,并不是特别笨拙或大黑客.