2010-12-14 15 views
5

Wie können Sie beim Ziehen eines Elements mit jquery ui draggable (http://jqueryui.com/demos/draggable/) die Beschleunigung oder Trägheit aktivieren? Ich möchte die Beschleunigung ähnlich wie maps.google.com neu erstellen, die beim Verschieben/Ziehen der Karte erleichtert wird. Idealerweise würde ich die Elementbewegung basierend auf der Kraft, die Sie werfen/ziehen, verschieben. Wie erreichen Sie diese Funktionalität? Vielleicht ist das Ziehen nicht möglich, aber ich möchte das Ziehen und Beschleunigen in Google Maps nachahmen.jquery ui drag easing/trägheit

Danke!

+0

Wenn Sie jQuery UI nicht verwenden müssen, dann ist dies eine der eleganteste Vanille JS Lösungen, die ich gesehen habe: http://jsfiddle.net/soulwire/znj683b9/ – 10basetom

Antwort

20

Ich habe einige Ideen aus here verwendet, aber sie stattdessen mit jQuery UI integriert. Sie müssen Logik implementieren einen Impuls Animation zu handhaben, die das Element außerhalb der Grenzen stößt (außerhalb geordneten Containers der Grenzen ist)

Der resultierende Code:

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

schöne Arbeit. sehr cool. – tster

+0

Ich mag das! : D – jlmakes

+6

Fantastisch! Ich habe einige Verbesserungen vorgenommen und es auf jsFiddle gesetzt: http://jsfiddle.net/entropo/gPdzC/ – entropo

7

Die Arbeit simshaun tat dies ist fantastisch.

Ich vermasselte seine Version und bekam eine etwas sanftere Animation mit dem jquery.easing Plugin.
Probieren Sie es aus 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

Ich spielte gerade damit herum. Ein wenig skurril (zumindest in Chrome), aber nett. Versuchen Sie beispielsweise, das Beschleunigen auf easeOutQuad zu ändern (obwohl dies wahrscheinlich für andere Beschleunigungsmethoden der Fall ist), und versuchen Sie, das Objekt aus der Box zu werfen. Manchmal wird es außerhalb der angegebenen Begrenzungsbox gelockert. – simshaun

+0

Ja, ich habe es bemerkt, es ist knifflig mit einer Containment-Box. In einem "overflow: hidden" Feld, funktioniert es ziemlich gut für moderne Browser ... außer nicht auf einem iPad. Was ist scheiße, denn das ist ein Hauptziel für das, was ich versuche. Ich stelle mir vor, dass ich meine eigenen Begrenzungsregeln in die dragmoMentum.end-Funktion einbringe, und benutze das, um die Box wieder zu verlassen. – mattsahr

+1

Endlich eine Lösung, die gut mit Containment-Boxen funktioniert. Sehen Sie es [hier (jsfiddle)] (http://jsfiddle.net/mattsahr/bKs7w/). – mattsahr