jquery ui拖动缓动/惯性

时间:2010-12-14 19:51:40

标签: javascript jquery jquery-ui google-maps draggable

使用jquery ui draggable(http://jqueryui.com/demos/draggable/)拖动元素时如何启用缓动或惯性?我想重新创建类似于maps.google.com的缓动,当您抛出/拖动地图时,它会轻松到位。理想情况下,我想根据您投掷/拖动元素的力移动元素移动。你是如何完成这项功能的?也许jquery ui draggable不是必需的,但我希望模仿谷歌地图上的拖动和缓和。

谢谢!

2 个答案:

答案 0 :(得分:21)

我使用了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

答案 1 :(得分:9)

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