2013-06-13 8 views
9

EDYCJA: Rozwiązałem to. Ale StackOverflow nie pozwala mi zaznaczyć mojej odpowiedzi jako rozwiązanie, więc po prostu nie zamierzam.jQuery UI przeciąganie + transformacja CSS Powoduje "przeskakiwanie"

Mam problem z używaniem przeciągania z przekształconym rodzicem CSS. Zasadniczo, potrzebuję użyć pozycjonowania bezwzględnego, aby odradzić Przeciągalny element div bezpośrednio pod kursorem. Gdy do transformacji CSS używane jest pozycjonowanie bezwzględne, element przeciągalny przeskakuje w prawo podczas przeciągania. Po zakończeniu skoku zachowanie przebiega zgodnie z oczekiwaniami. Skok nie występuje, jeśli transformacje nie są stosowane do elementu przeciągalnego lub elementu nadrzędnego.

Oto skrzypce, który pokazuje dokładnie, na czym polega problem: http://jsfiddle.net/qBubN/7/

body { 
    background-color: blue; 
} 

#draggable { 
    position: absolute; 
    left: 50px; 
    top: 50px; 
    background-color: rgba(0,0,0,0.5); 
    border: 1px solid black; 
    width: 350px; 
    height: 350px; 
    color: white; 
    -moz-transform: scale(0.5); 
    -webkit-transform: scale(0.5); 
    transform: scale(0.5);} 

    $("#draggable").draggable({ 
      scroll: true, 
      distance: 5, 
      grid : [ 10, 10 ], 
      start: function (event, ui) { 
      } 
     }); 

<html> 
    <body> 
     <div id="draggable"> 
      Hello! 
     </div> 
    </body> 
</html> 

już próbował zastosowaniu tej poprawki, bezskutecznie. Jest (dobra) szansa, że ​​ta poprawka jest zbyt stara, by działać. Jest też szansa, że ​​błędnie stosuję tę poprawkę. Webkit and jQuery draggable jumping

+0

Dla jasności, jestem na Firefox 21.0 –

Odpowiedz

10

Znalazłem rozwiązanie.

Rozwiązaniem jest całkowite uniknięcie position:absolute; podczas korzystania z transformacji przeciągnij i CSS. Możesz łatwo manipulować czymkolwiek od absolutnych/okien/dowolnych współrzędnych do względnych, więc to jest właśnie to, co zrobiłem.

W moim przypadku element spawający znajdował się pod spodem myszy. Obliczyłem względną pozycję w oparciu o pozycję myszy z przesunięciem() elementu (zarówno we współrzędnych okna), a następnie podzielone przez skalę div jednostki.

Oto fragment:

// ops.[x|y] is the mouse position in window coords 
// parentDiv.offset().[left|right] is the div position in window coords 

// get the scale transform matrix from our poorly written panzooming lib 
var mtx = graph.parentDiv.panzoom('getMatrix'); 
var zx = mtx[0]; 
var zy = mtx[3]; 

// calculate the relative position 
var x = (ops.x - parentDiv.offset().left)/zx; 
var y = (ops.y - parentDiv.offset().top)/zy; 

// set some initial css 
parentDiv.css('position', 'relative') 
     .css('left', x + 'px') 
     .css('top', y + 'px'); 

// initialize the draggable 
parentDiv.draggable({ 
    stack: $(graph.parentDiv).children(), 
    drag: function(e, ui){ 
     var mtx = graph.parentDiv.panzoom('getMatrix'); 
     var zoomScaleX = mtx[0]; 
     var zoomScaleY = mtx[3]; 

     // scale the delta by the zoom factor 
     var dx = ui.position.left - ui.originalPosition.left; 
     var dy = ui.position.top - ui.originalPosition.top; 

     ui.position.left = ui.originalPosition.left + (dx/zoomScaleX); 
     ui.position.top = ui.originalPosition.top + (dy/zoomScaleY); 
    } 
}); 
+0

Kiedy "powstrzymywanie" jest skalowane, to nie działa dobrze. Oto jedno rozwiązanie: http://cerdiogenes.blogspot.com.br/2015/01/jquery-ui-draggable-reseizable-with.html –

13
//css3 transform bug with jquery ui drag - fixed(works fine whether position, absolute or relative) 
var __dx; 
var __dy; 
var __scale=0.5; 
var __recoupLeft, __recoupTop; 

$("#draggable").draggable({ 
    //revert: true, 
    zIndex: 100, 
    drag: function (event, ui) { 
     //resize bug fix ui drag `enter code here` 
     __dx = ui.position.left - ui.originalPosition.left; 
     __dy = ui.position.top - ui.originalPosition.top; 
     //ui.position.left = ui.originalPosition.left + (__dx/__scale); 
     //ui.position.top = ui.originalPosition.top + (__dy/__scale); 
     ui.position.left = ui.originalPosition.left + (__dx); 
     ui.position.top = ui.originalPosition.top + (__dy); 
     // 
     ui.position.left += __recoupLeft; 
     ui.position.top += __recoupTop; 
    }, 
    start: function (event, ui) { 
     $(this).css('cursor', 'pointer'); 
     //resize bug fix ui drag 
     var left = parseInt($(this).css('left'), 10); 
     left = isNaN(left) ? 0 : left; 
     var top = parseInt($(this).css('top'), 10); 
     top = isNaN(top) ? 0 : top; 
     __recoupLeft = left - ui.position.left; 
     __recoupTop = top - ui.position.top; 
    }, 
    stop: function (event, ui) { 
     $(this).css('cursor', 'default'); 
     //alternate to revert (don't use revert) 
     $(this).animate({ 
      left: $(this).attr('oriLeft'), 
      top: $(this).attr('oriTop') 
     }, 1000) 
    }, 
    create: function (event, ui) { 
     $(this).attr('oriLeft', $(this).css('left')); 
     $(this).attr('oriTop', $(this).css('top')); 
    } 
}); 
2

Znacznie prostsze rozwiązanie jest owinąć skalowany treści z innego div i ustawić, że zamiast być przeciągany.

0

position:absolute; jest rzeczywiście problematyczna. Ja jednak znaleźć alternatywne rozwiązanie, które zapobiega skok, jednocześnie utrzymując absolute podstawę współrzędnych i utrzymać pozycję, przez odwracanie pozycji CSS relative na mousedown i przywrócić go do absolute na mouseup, takie jak:

$('#container').on('mousedown', 'canvas', function (e) { 
    e.currentTarget.style.position = 'relative'; 
}).on('mouseup', 'canvas', function (e) { 
    if (e.currentTarget.style.position !== 'absolute'){ 
     e.currentTarget.style.position = 'absolute'; 
    } 
}); 

Działa dobrze w przypadku zdarzeń myszy. Aby rozwiązać problem związany z wydarzeniami dotykowymi wraz z wtyczką "touchpunch", musiałem również anulować zdarzenia "kliknięcia" (tylko w przypadku urządzeń mobilnych i obsługiwanych dotykowo).

0

Rozszerzając "raghugolconda" top odpowiedź:

miałem przeciągając prędkość i skoki problemy z jQueryUI Draggable i CSS transform: skala()

Pojemnik obrazu jest skalowalny z zoomem suwak, czerwony kwadrat jest przeciągalny.

enter image description here

Co się stało, kiedy próbował przeciągnąć czerwony element:

  • Element wyskoczyła kiedy próbowała przeciągnąć go
  • Drag prędkość była zbyt niska, gdy zoom był ponad 100%
  • Prędkość przeciągania była zbyt duża, gdy powiększenie było mniejsze niż 100%

Poprawka:

  1. Oblicz część (wartość skali) z suwaka jQuery. Oto mój suwak niż przekształca pojemnik obrazu:

    var fraction = 1; 
    
    $("#slider").slider({ 
        value: 0, 
        min: -70, 
        max: 70, 
        step: 10, 
        slide: function (event, ui) { 
         fraction = (1 + ui.value/100); 
    
         $("#infoSlider").text('Zoom: ' + Math.floor(fraction * 100) + '%'); 
    
         $('.image_scalable_container').css({ 
          '-webkit-transform': 'scale(' + fraction + ')', 
          '-moz-transform': 'scale(' + fraction + ')', 
          '-ms-transform': 'scale(' + fraction + ')', 
          '-o-transform': 'scale(' + fraction + ')', 
          'transform': 'scale(' + fraction + ')' 
         }); 
    
        } 
    }); 
    
  2. nadpisywania jQuery UI przeciągalne przeciągnij i początek funkcje.

W przeciągnij zmodyfikować szybkość przeciągania (skala 0,9 środki drag_speed = 1/0,9 = 1,11)

Oto mój przykład:

$("#marker").draggable({ 
    //revert: true, 
    zIndex: 100, 
    drag: function (event, ui) { 
     var drag_speed = 1/fraction; 

     __dx = (ui.position.left - ui.originalPosition.left) * drag_speed; 
     __dy = (ui.position.top - ui.originalPosition.top) * drag_speed; 
     ui.position.left = ui.originalPosition.left + (__dx); 
     ui.position.top = ui.originalPosition.top + (__dy);    
     ui.position.left += __recoupLeft; 
     ui.position.top += __recoupTop; 
    },   
    start: function (event, ui) {    
     //resize bug fix ui drag 
     var left = parseInt($(this).css('left'), 10); 
     left = isNaN(left) ? 0 : left; 
     var top = parseInt($(this).css('top'), 10); 
     top = isNaN(top) ? 0 : top; 
     __recoupLeft = left - ui.position.left; 
     __recoupTop = top - ui.position.top; 
    }, 
}); 
Powiązane problemy