18

我已经定义了一些按预期工作的拖动行为(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)

我现在尝试为节点上的右键单击创建自定义行为。但是,这会触发“dragstart”和“drag”,即在我调用e.preventDefault()“contextmenu”事件后,有问题的节点会粘在我的鼠标指针上并跟随它,直到我再次(左)单击以强制释放(我假设e.preventDefault()也会导致“dragend”永远不会触发)。

我在 Google Groups 上的一个线程Github 上的 d3 问题中的讨论中找到了对这个问题的简短讨论。但是,我无法从这些评论中弄清楚如何防止这种行为。

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

4

5 回答 5

10

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.

于 2013-06-14T14:48:34.230 回答
3

对于 D3 v4,请参阅drag.filter([filter])

如果指定了过滤器,则将过滤器设置为指定的函数并返回拖动行为。如果未指定过滤器,则返回当前过滤器,默认为。

drag.filter([filter])

右键单击:

.filter(['touchstart'])

可用的过滤器

mousedown, mousemove, mouseup, dragstart, selectstart, 点击, touchstart, touchmove, touchend, touchcancel

于 2017-05-22T03:17:34.087 回答
1

派对迟到了,我遇到了同样的问题,我使用以下方法来确保我drag只适用于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]);
            }

        });
于 2015-07-04T01:00:28.037 回答
1

要处理拖动事件的所有侦听器,可以使用以下代码:

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);
于 2015-09-16T06:35:23.980 回答
0

实际上,使用不同版本的d3您可能想要使用d3.event.which而不是d3.event.sourceEvent.which检测您单击了哪个鼠标按钮。

于 2017-09-28T17:50:57.387 回答