2013-06-13 12 views
9

EDIT: Ho risolto. Ma StackOverflow non mi ha lasciato la risposta come soluzione, quindi semplicemente non lo farò.jQuery UI Draggable + CSS Transform Cause "Jumping"

Sto riscontrando un problema relativo all'utilizzo di Draggable con un genitore trasformato CSS. Fondamentalmente, ho bisogno di usare il posizionamento assoluto per generare un div Draggable direttamente sotto il cursore. Quando il posizionamento assoluto viene utilizzato con le trasformazioni CSS, l'elemento trascinabile fa un po 'di salto mentre avviene il trascinamento. Dopo il salto, il comportamento procede come previsto. Il salto non si verifica se non vengono applicate trasformazioni al trascinabile o al div principale.

Ecco un violino che mostra esattamente qual è il problema: 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> 

già provato l'applicazione di questa patch, senza alcun risultato. C'è una (buona) possibilità che questa soluzione sia troppo vecchia per funzionare. C'è anche una possibilità che sto applicando la patch in modo errato. Webkit and jQuery draggable jumping

+0

Per chiarezza, io sono su Firefox 21.0 –

risposta

10

Ho trovato la soluzione.

La soluzione è completamente evitare position:absolute; quando si utilizzano le trasformazioni Draggable e CSS. Puoi facilmente manipolare qualsiasi cosa da assoluta/finestra/qualsiasi coordinate in relativo, quindi è proprio quello che ho fatto.

Nel mio caso, stavo generando un elemento trascinabile sotto il mouse. Ho calcolato la posizione relativa in base alla posizione del mouse con l'offset() dell'elemento (entrambe nelle coordinate della finestra) e quindi diviso per la scala del div principale.

Ecco un frammento:

// 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

Quando il 'containment' è ridimensionato, questo non funziona bene. Ecco una soluzione: 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

Una soluzione molto più semplice è quello di avvolgere il contenuto in scala con un altro div e impostare che, per essere trascinabile invece.

0

position:absolute; è davvero problematico. Ho però trovato una soluzione alternativa che impedisce il salto, mantenendo una base absolute per le coordinate e mantenere la posizione, spostando la posizione css per relative su mousedown, e riportarla al absolute su mouseup, come il seguente:

$('#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'; 
    } 
}); 

Funziona bene per gli eventi del mouse. E per risolvere il problema degli eventi touch, insieme al plugin "touchpunch", ho dovuto anche annullare gli eventi "click" (solo per le modalità mobile e touch abilitata).

0

Ampliando "raghugolconda" risposta superiore:

che ho avuto trascinando velocità e saltare problemi con jQueryUI trascinabili e CSS trasformare: scala()

immagine Il contenitore è scalabile con zoom cursore, il quadrato rosso è trascinabile.

enter image description here

Che cosa è successo quando ho provato a trascinare l'elemento rosso:

  • Elemento saltato quando si è tentato di trascinarla
  • velocità Trascinare era troppo bassa quando Zoom è stato superiore al 100%
  • La velocità di trascinamento era troppo veloce quando Zoom era inferiore al 100%

Correzione:

  1. Calcolare la frazione (valore di scala) dal cursore jQuery. Ecco il mio dispositivo di scorrimento che trasforma contenitore immagine:

    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. sovrascrittura jQuery UI trascinabili trascinare e inizio funzioni.

In trascinare si modifica la velocità di trascinamento (scala 0,9 mezzi drag_speed = 1/0,9 = 1,11)

Ecco il mio esempio:

$("#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; 
    }, 
});