2010-12-14 24 views
5

如何在使用jQuery UI拖動元素拖動元素時啓用緩動或慣性(http://jqueryui.com/demos/draggable/)?我想重新創建類似於maps.google.com的緩動,當您將其拖動/拖動地圖時,它會緩解到位。理想情況下,我想根據您拋出/拖動元素的力量移動元素移動。你如何完成這個功能?也許jquery ui可拖動是沒有必要的,但我希望模擬在Google地圖上找到的拖動和緩動。jquery ui拖動寬鬆/慣性

謝謝!

+0

如果你沒有使用jQuery UI,那麼這是最優雅的香草JS解決方案,我見過的一個:http://jsfiddle.net/soulwire/znj683b9/ – 10basetom 2017-06-22 13:36:04

回答

20

我使用here的一些想法,但將它們與jQuery UI集成。你必須要實現的邏輯來處理勢頭動畫壓出界外(外它的父容器的邊界)的元素

生成的代碼:

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

不錯的工作。很酷。 – tster 2010-12-14 23:00:48

+0

我喜歡這個! :D – jlmakes 2011-02-11 09:41:39

+6

太棒了!我做了一些調整,並把它放在jsFiddle上:http://jsfiddle.net/entropo/gPdzC/ – entropo 2011-04-29 06:14:51

7

工作simshaun做到這一點是太棒了。

我搞砸了他的版本,並與jquery.easing插件有點平滑的動畫。
試試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

我只是在玩這個。有點古怪(至少在Chrome中),但很好。例如,嘗試將easing更改爲easeOutQuad(儘管它可能會爲其他緩動方法執行此操作),並嘗試將該對象從框中移出。有時它會在指定的邊界框外緩和。 – simshaun 2011-05-03 15:53:01

+0

是的,我注意到,它是一個遏制箱挑剔。在「溢出:隱藏」框內,它對現代瀏覽器表現非常好,除了不在iPad上。這很糟糕,因爲這是我嘗試的主要目標。我想我會將我自己的邊界規則放到dragmoMentum.end函數中,並使用它緩和回框內。 – mattsahr 2011-05-09 23:26:12

+1

最後得到了一個與收容箱很好地搭配的解決方案。看到它[這裏(jsfiddle)](http://jsfiddle.net/mattsahr/bKs7w/)。 – mattsahr 2011-07-21 22:48:12