2013-06-14 5 views
15

я определил некоторое поведение сопротивления, которое работает, как ожидается, следующим образом (код в CoffeeScript):Как предотвратить d3 от запуска перетаскивания по правому клику?

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», чтобы никогда не срабатывать).

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

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

+0

В событии 'dragstart' вы можете проверить, была ли нажата правая кнопка мыши (с помощью d3.событие), и если да, не вызывайте 'force.stop()'. –

+0

Как проверить, какая кнопка мыши была нажата в 'd3.event'? Все предложения, которые я могу найти как 'which',' button' и 'keyCode', дают мне' undefined'. Кроме того: я вызываю 'force.stop()', чтобы остановить алгоритм компоновки во время перетаскивания пользователем. Поэтому, не вызывая этого, это не будет препятствовать тому, чтобы перетащить жест. – notan3xit

+1

Я думаю, что 'd3.event' имеет член' sourceEvent' или что-то вроде того, что дает вам доступ к реальному событию. И да, вам понадобится нечто вроде 'preventDefault()'. –

ответ

9

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

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

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 

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

+0

Что касается d3 v3.5.3, чтобы проверить, какая кнопка, вы можете использовать 'd3.event.button' – herrlich10

+1

для v3.5.6, правильный путь должен быть' d3.event.sourceEvent.button' вместо 'd3.event .button' – paradite

+0

Также он должен быть равен 0 не 1 :) – thatOneGuy

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

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

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

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

drag.filter([filter]) 

для правой кнопки мыши:

.filter(['touchstart'])

Фильтров доступных

MouseDown, MouseMove, MouseUp, dragstart, selectstart, нажмите, touchstart, TouchMove, touchend, touchcancel

+0

Добро пожаловать в SO. Пожалуйста, прочтите это [как-ответ] (http://stackoverflow.com/help/how-to-answer). Включить ссылку неплохо, но она может быть недоступна с течением времени. – thewaywewere

0

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

Смежные вопросы