jquery ui拖动缓动/惯性

Posted

技术标签:

【中文标题】jquery ui拖动缓动/惯性【英文标题】:jquery ui drag easing/inertia 【发布时间】:2011-05-25 12:26:30 【问题描述】:

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

谢谢!

【问题讨论】:

如果您不必使用 jQuery UI,那么这是我见过的最优雅的 vanilla JS 解决方案之一:jsfiddle.net/soulwire/znj683b9 【参考方案1】:

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

【讨论】:

太棒了!我做了一些调整并将其放在 jsFiddle 上:jsfiddle.net/entropo/gPdzC 我只是再次查看这段代码,想知道为什么需要$d.css("text-indent", 100); 行?我尝试删除它,这导致动量部分永远不会触发。我还尝试在 div 中添加文本,这表明在动量部分触发后,文本缩进值缓慢下降到 0……这很奇怪。 该行设置它,以便每次放开鼠标时脚本都会从 100% 动画到 0%(属性无关紧要)。我们在 animate 方法的 step 属性中利用这一点来手动移动对象“一次一步”,产生漂移效果。不过,我不能完全相信这一点。我从链接的文章中吸取了很多逻辑。 不适用于 FF 17.0.1(使用 Jquery 1.9 + JQuery UI 1.9.2)。盒子几乎直接变成负数。在 Chrome 中 - 成功移动几次后,框停止响应鼠标移动。 需要这个,谢谢!似乎我们将使用 javascript 去一个关于重力和物理的非常好的地方。也刚刚证实了这一点,它正在使用最新的 Firefox Quantum 版本 65.0.1。好东西!【参考方案2】:

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

【讨论】:

我只是在玩这个。有点古怪(至少在 Chrome 中),但很好。例如,尝试将缓动更改为 easeOutQuad(尽管它可能对其他缓动方法这样做)并尝试将对象扔出盒子。有时它会在指定的边界框之外缓和。 是的,我注意到了,收容箱很挑剔。在“溢出:隐藏”框中,它在现代浏览器中表现得非常好......除了在 iPad 上。这很糟糕,因为这是我正在尝试的主要目标。我想我会将我自己的边界规则滚动到 dragmoMentum.end 函数中,并使用它来缓和回到框内。 终于找到了一个与收容箱配合得很好的解决方案。看到它here (jsfiddle)。

以上是关于jquery ui拖动缓动/惯性的主要内容,如果未能解决你的问题,请参考以下文章

requestAnimationFrame之缓动的应用

用AS3中的惯性拖动假人

模拟物体的惯性滚动

android ScrollView 滑动特效 怎么做成iphone那样有惯性弹性!

IOS 拖动、轻弹或轻弹 UIView

为啥我不能引用将惯性js添加到我的项目的应用程序布局文件?