2010-12-14 3 views
5

Comment activer l'accélération ou l'inertie lorsque vous faites glisser un élément à l'aide de jquery ui draggable (http://jqueryui.com/demos/draggable/)? Je souhaite recréer l'accélération similaire à maps.google.com: lorsque vous lancez/faites glisser la carte, elle se met en place. Idéalement, je voudrais déplacer le déplacement de l'élément en fonction de la force que vous lancez/faites glisser l'élément. Comment accomplissez-vous cette fonctionnalité? Peut-être que jquery ui draggable n'est pas nécessaire, mais je cherche à imiter le glisser et l'assouplissement trouvés sur Google Maps.jquery ui drag easing/inertie

Merci!

+0

Si vous ne devez pas utiliser jQuery UI, alors c'est l'une des plus élégantes solutions de JS vanille Je l'ai vu: http://jsfiddle.net/soulwire/znj683b9/ – 10basetom

Répondre

20

J'ai utilisé quelques idées de here mais les ai intégrées avec l'interface utilisateur jQuery à la place. Vous devrez mettre en œuvre la logique pour gérer une animation dynamique qui pousse l'élément hors des limites du terrain (en dehors d'elle est les limites du conteneur parent)

Le code résultant:

$(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

beau travail. très sympa. – tster

+0

J'aime ça! : D – jlmakes

+6

Fantastique! J'ai fait quelques réglages et je l'ai mis sur jsFiddle: http://jsfiddle.net/entropo/gPdzC/ – entropo

7

Le travail simshaun fait sur ce sujet est fantastique. J'ai joué avec sa version et ai obtenu une animation un peu plus lisse avec le plugin jquery.easing. Essayez-le sur 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

Je jouais juste avec ça. Un peu excentrique (au moins en Chrome), mais sympa. Par exemple, essayez de remplacer easing par easeOutQuad (même si c'est probablement le cas pour d'autres méthodes d'accélération) et essayez de lancer l'objet hors de la boîte. Parfois, il sera facilité en dehors de la zone de délimitation spécifiée. – simshaun

+0

Ouais j'ai remarqué ça, c'est finicky avec une boîte de confinement. A l'intérieur d'une boîte "overflow: hidden", elle fonctionne plutôt bien pour les navigateurs modernes ... sauf sur un iPad. Ce qui est nul, car c'est une cible majeure pour ce que j'essaie. J'imagine que je vais rouler mes propres règles de délimitation dans la fonction dragmoMentum.end, et l'utiliser pour revenir à l'intérieur de la boîte. – mattsahr

+1

Enfin obtenu une solution qui joue bien avec les boîtes de confinement. Voyez-le [ici (jsfiddle)] (http://jsfiddle.net/mattsahr/bKs7w/). – mattsahr