Как предотвратить d3 от запуска перетаскивания по правому клику?

Я определил некоторое поведение перетаскивания, которое работает как ожидалось следующим образом (код в 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", вопрос node привязан к указателю мыши и следует за ним, пока я не сделаю другой (слева) щелчок чтобы заставить освобождение (я предполагаю, что e.preventDefault() также вызывает "dragend", чтобы никогда не срабатывать).

Я нашел краткое обсуждение этой проблемы в потоке в группах Google и обсуждение проблем d3 в Github. Тем не менее, я не могу понять из этих комментариев, как предотвратить это поведение.

Как я могу не вызвать перетаскивание по правому клику?

Ответы

Ответ 1

Я нашел возможность ограничить жесты перетаскивания только левой кнопкой мыши.

Он включает дополнительное поле, которое записывает, когда был начат жест:

dragInitiated = false

Остальная часть кода затем модифицируется для регистрации инициирования и завершения желаемых жестов перетаскивания на "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

Я не уверен, что это самое элегантное решение, но оно работает и не является исключительно неуклюжим или большим взломом.

Ответ 2

Немного поздно для вечеринки, у меня была такая же проблема, и я использовал следующий метод, чтобы убедиться, что мой 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]);
            }

        });

Ответ 3

Чтобы обрабатывать всех слушателей события перетаскивания, вы можете использовать следующий код:

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);

Ответ 4

для D3 v4 см. drag.filter([filter])

Если задан фильтр, он устанавливает фильтр в указанную функцию и возвращает поведение перетаскивания. Если фильтр не указан, возвращает текущий фильтр, который по умолчанию.

drag.filter([filter])

для правого клика:

.filter(['touchstart'])

Доступные фильтры

mousedown, mousemove, mouseup, dragstart, selectstart, click, touchstart, touchmove, touchhend, touchcancel

Ответ 5

На самом деле с другой версией d3 вы можете использовать d3.event.which вместо d3.event.sourceEvent.which, чтобы определить, какую кнопку мыши вы нажали.