如何防止d3在右键单击时触发拖动?

not*_*xit 16 d3.js

我已经定义了一些按预期工作的拖动行为,如下所示(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的问题.但是,我无法从这些评论中弄清楚如何防止这种行为.

如何在右键单击时不触发拖动?

not*_*xit 9

我发现只能将拖动手势限制为鼠标左键.

它涉及一个记录手势何时启动的附加字段:

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)

我不确定这是否是最优雅的解决方案,但它确实有效,并不是特别笨拙或大黑客.

  • 对于v3.5.6,正确的方法应该是`d3.event.sourceEvent.button`而不是`d3.event.button` (2认同)