2013-06-14 10 views
15

Mam zdefiniowane pewne zachowanie przeciągania, który działa zgodnie z oczekiwaniami w następujący sposób (kod w coffeescript):Jak zapobiec przeciągnięciu przez d3 po kliknięciu prawym przyciskiem myszy?

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) 

ja teraz staram się tworzyć niestandardowe zachowanie dla prawych kliknięć na węzłach. Jednak powoduje to "dragstart" i "przeciąganie", tj. Po wywołaniu e.preventDefault() w przypadku zdarzenia "contextmenu", węzeł, o którym mowa, jest przyklejony do wskaźnika myszy i podąża za nim, dopóki nie wykonam kolejnego (lewego) kliknięcia, aby wymusić zwolnienie (Zakładam, że e.preventDefault() powoduje również "dragend", aby nigdy nie strzelać).

Znalazłem krótkie omówienie tego problemu w thread on Google Groups i discussion in d3's issues on Github. Jednak nie mogę zrozumieć tych komentarzy, jak zapobiec temu zjawisku.

Jak nie można uruchomić przeciągania po kliknięciu prawym przyciskiem myszy?

+0

W zdarzeniu 'dragstart' możesz sprawdzić, czy kliknięto prawym przyciskiem myszy (używając d3.zdarzenie), a jeśli tak, nie wywołaj 'force.stop()'. –

+0

Jak mogę sprawdzić, który przycisk myszy został kliknięty w 'd3.event'? Wszystkie sugestie, które mogę znaleźć, takie jak 'which',' button' i 'keyCode', dają mi' undefined'. Poza tym: nazywam 'force.stop()', aby zatrzymać algorytm układu podczas przeciągania użytkownika. Więc nie wywołanie go nie przeszkodzi w tym, że nastąpi gest przeciągania. – notan3xit

+1

Myślę, że 'd3.event' ma element' sourceEvent' lub coś podobnego, co daje dostęp do rzeczywistego zdarzenia. I tak, potrzebujesz czegoś takiego jak 'preventDefault()'. –

Odpowiedz

9

Znalazłem możliwość ograniczenia gestów przeciągania tylko do lewego przycisku myszy.

To pociąga za sobą dodatkowe pole rejestruje gdy gest zainicjowano:

dragInitiated = false 

Reszta kod jest następnie modyfikowany zarejestrować rozpoczęcie i zakończenie pożądanych gestów przeciągania na „dragstart” i „dragend ", odpowiednio. Akcje "przeciągnij" są wtedy wykonywane tylko wtedy, gdy poprawnie zainicjowano gesty przeciągania.

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 

Nie jestem pewien, czy jest to najbardziej eleganckie rozwiązanie, ale to nie działa i nie jest wyjątkowo niezdarny lub duża Hack.

+0

Jeśli chodzi o d3 v3.5.3, aby sprawdzić, który przycisk można użyć "d3.event.button" – herrlich10

+1

dla wersji 3.5.6, prawidłowym sposobem powinno być 'd3.event.sourceEvent.button' zamiast' d3.event .button' – paradite

+0

Powinien równać się 0, nie 1 :) – thatOneGuy

1

Nieco spóźniony na imprezę, miałem ten sam problem i użyłem następującej metody, aby upewnić się, że moja drag działa tylko dla .

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

Aby obsłużyć wszystkich słuchaczy zdarzenie przeciągania, można użyć poniższy kod:

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

dla D3 v4 zobaczyć drag.filter([filter])

Jeśli filtr jest określony, ustawia filtr do określonej funkcji i zwraca zachowanie przeciągania. Jeśli filtr nie jest określony, zwraca bieżący filtr, który jest domyślny.

drag.filter([filter]) 

po prawej kliknij:

.filter(['touchstart'])

Filtry dostępnych

mouseDown, mousemove, mouseUp, dragstart, selectstart, kliknij, touchstart, touchmove, touchend, touchcancel

+0

Witamy w SO. Przeczytaj ten [jak-odpowiedź] (http://stackoverflow.com/help/how-to-answer). Dołącz link nie jest zły, ale może nie być dostępny w miarę upływu czasu. – thewaywewere

0

Właściwie wi w innej wersji d3 możesz użyć d3.event.which zamiast d3.event.sourceEvent.which, aby wykryć, który przycisk myszy kliknąłeś.

Powiązane problemy