2010-12-14 42 views
5

¿Cómo se habilita la aceleración o la inercia al arrastrar un elemento usando jquery ui draggable (http://jqueryui.com/demos/draggable/)? Me gustaría recrear el easing similar a maps.google.com que al tirar/arrastrar el mapa se acomoda en su lugar. Idealmente, me gustaría mover el movimiento del elemento en función de la fuerza que arroje/arrastre el elemento. ¿Cómo se logra esta funcionalidad? Tal vez jquery ui draggable no es necesario, pero estoy buscando emular el arrastre y la relajación encontrados en Google Maps.jquery ui drag easing/inercia

Gracias!

+0

Si usted no tiene que utilizar jQuery UI, entonces esta es una de las soluciones más elegantes de vainilla JS que he visto: http://jsfiddle.net/soulwire/znj683b9/ – 10basetom

Respuesta

20

Utilicé algunas ideas de here pero las integé con jQuery UI en su lugar. Vas a tener que aplicar la lógica para manejar una animación impulso que empuja el elemento fuera de los límites (fuera de su límites del contenedor primario)

El código resultante:

$(function() { 
    var $d = $("#draggable"); 

    var x1, x2, 
     y1, y2, 
     t1, t2; // Time 

    var minDistance = 40; // Minimum px distance object must be dragged to enable momentum. 

    var onMouseMove = function(e) { 
     var mouseEvents = $d.data("mouseEvents"); 
     if (e.timeStamp - mouseEvents[mouseEvents.length-1].timeStamp > 40) { 
      mouseEvents.push(e); 
      if (mouseEvents.length > 2) { 
       mouseEvents.shift(); 
      } 
     } 
    } 

    var onMouseUp = function() { 
     $(document).unbind("mousemove mouseup"); 
    } 

    $d.draggable({ 
     start: function(e, ui) { 
      $d.data("mouseEvents", [e]); 
      $(document) 
       .mousemove(onMouseMove) 
       .mouseup(onMouseUp); 
     }, 
     stop: function(e, ui) { 
      $d.stop(); 
      $d.css("text-indent", 100); 

      var lastE = $d.data("mouseEvents").shift(); 

      x1 = lastE.pageX; 
      y1 = lastE.pageY; 
      t1 = lastE.timeStamp; 
      x2 = e.pageX; 
      y2 = e.pageY; 
      t2 = e.timeStamp; 

      // Deltas 
      var dX = x2 - x1, 
       dY = y2 - y1, 
       dMs = Math.max(t2 - t1, 1); 

      // Speeds 
      var speedX = Math.max(Math.min(dX/dMs, 1), -1), 
       speedY = Math.max(Math.min(dY/dMs, 1), -1); 

      // Distance moved (Euclidean distance) 
      var distance = Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2)); 

      if (distance > minDistance) { 
       // Momentum 
       var lastStepTime = new Date(); 
       $d.animate({ textIndent: 0 }, { 
        duration: Math.max(Math.abs(speedX), Math.abs(speedY)) * 2000, 
        step: function(currentStep){ 
         speedX *= (currentStep/100); 
         speedY *= (currentStep/100); 

         var now = new Date(); 
         var stepDuration = now.getTime() - lastStepTime.getTime(); 

         lastStepTime = now; 

         var position = $d.position(); 

         var newLeft = (position.left + (speedX * stepDuration/4)), 
          newTop = (position.top + (speedY * stepDuration/4)); 

         $d.css({ 
          left: newLeft+"px", 
          top: newTop+"px" 
         }); 
        } 
       }); 
      } 
     } 
    }); 
});

Try it out

+0

buen trabajo. muy genial. – tster

+0

¡Me gusta esto! : D – jlmakes

+6

¡Fantástico! Hice algunos ajustes y lo puse en jsFiddle: http://jsfiddle.net/entropo/gPdzC/ – entropo

7

El trabajo simshaun hizo en esto es fantástico.

Me equivoqué con su versión y obtuve una animación un poco más suave con el complemento jquery.easing.
Pruébelo en jsfiddle.

$(document).ready(function() { 
    $('#dragme').draggable({ 
     start: function(e, ui) { 
      dragMomentum.start(this.id, e.clientX, e.clientY, e.timeStamp); 
     }, 
     stop: function(e, ui) { 
      dragMomentum.end(this.id, e.clientX, e.clientY, e.timeStamp); 
     } 
    }); 
}); 

var dragMomentum = new function() {  
    var howMuch = 30; // change this for greater or lesser momentum 
    var minDrift = 6; // minimum drift after a drag move 
    var easeType = 'easeOutBack'; 

    // This easing type requires the plugin: 
    // jquery.easing.1.3.js http://gsgd.co.uk/sandbox/jquery/easing/ 

    var dXa =[0]; 
    var dYa =[0]; 
    var dTa =[0]; 

    this.start = function (elemId, Xa, Ya, Ta) { 
      dXa[elemId] = Xa; 
     dYa[elemId] = Ya; 
     dTa[elemId] = Ta; 

     }; // END dragmomentum.start() 

    this.end = function (elemId, Xb, Yb, Tb) {   
     var Xa = dXa[elemId]; 
     var Ya = dYa[elemId]; 
     var Ta = dTa[elemId]; 
     var Xc = 0; 
     var Yc = 0; 

     var dDist = Math.sqrt(Math.pow(Xa-Xb, 2) + Math.pow(Ya-Yb, 2)); 
     var dTime = Tb - Ta; 
     var dSpeed = dDist/dTime; 
     dSpeed=Math.round(dSpeed*100)/100; 

     var distX = Math.abs(Xa - Xb); 
     var distY = Math.abs(Ya - Yb); 

     var dVelX = (minDrift+(Math.round(distX*dSpeed*howMuch/(distX+distY)))); 
     var dVelY = (minDrift+(Math.round(distY*dSpeed*howMuch/(distX+distY)))); 

     var position = $('#'+elemId).position(); 
     var locX = position.left; 
     var locY = position.top; 

     if (Xa > Xb){ // we are moving left 
      Xc = locX - dVelX; 
     } else { // we are moving right 
      Xc = locX + dVelX; 
     } 

     if (Ya > Yb){ // we are moving up 
      Yc = (locY - dVelY); 
     } else { // we are moving down 
      Yc = (locY + dVelY); 
     } 

     var newLocX = Xc + 'px'; 
     var newLocY = Yc + 'px'; 

     $('#'+elemId).animate({ left:newLocX, top:newLocY }, 700, easeType); 

    }; // END dragmomentum.end() 

}; // END dragMomentum() 
+1

Estaba jugando con esto. Un poco peculiar (al menos en Chrome), pero agradable. Por ejemplo, intente cambiar el easing a easeOutQuad (aunque probablemente lo haga para otros métodos de aceleración) e intente lanzar el objeto fuera de la caja. A veces se facilitará fuera del cuadro delimitador especificado. – simshaun

+0

Sí, lo noté, es quisquilloso con una caja de contención. Dentro de un cuadro de "desbordamiento: oculto", funciona muy bien para los navegadores modernos ... excepto en un iPad. Lo cual apesta, ya que ese es un objetivo importante para lo que estoy intentando. Me imagino que voy a rodar mis propias reglas de delimitación en la función dragmoMentum.end, y la usaré para recuperarla dentro de la caja. – mattsahr

+1

Finalmente obtuve una solución que funciona muy bien con cajas de contención. Véalo [aquí (jsfiddle)] (http://jsfiddle.net/mattsahr/bKs7w/). – mattsahr