1

我花了过去 6 个小时试图找到我的问题的答案,但没有任何运气。

我的网站上有一些可拖动的 div。当我拖动它们时,我想要一个逼真的效果,就像有一个气压并且它们被推了一下,所以当它们被拖动时它们会摆动一点。

效果应该如何工作的示例图像,可以在这里看到:惯性加速效果(不知道效果叫什么)

我已经在许多不同的组合中搜索了这些词“Javascript,加速度,惯性,摆动,物理,旋转,移动,气压,摩擦,悬挂”,但没有找到任何可以帮助我的东西。

不过,我在这个 JSFiddle[1](下面的链接)上发现了一种类似的效果。当您拖动元素并将鼠标移到一边时,我还遇到了 Google Gravity[2](下面的链接),它具有我想要实现的效果。

[ 1 ] JSFiddle 我发现:www.jsfiddle.net/gVCWE/150/

[2]谷歌重力:www.mrdoob.com/projects/chromeexperiments/google-gravity/

我试图在这里自己创造效果:

var fn = {
    activeElm : null,
    pos : {},
    transPos : {},
    startPos : null,
    moveSteps : new Array(15),

    init : function(){
        var self = this;
        document.addEventListener('mousedown', function(e){self.handleStart.call(self, e);});
        document.addEventListener('mousemove', function(e){self.handleMove.call(self, e);});
        document.addEventListener('mouseup', function(e){self.handleStop.call(self, e);});
    },
    handleStart : function(e){
        if(fn.hasClass('dragme', e.target)){
            fn.activeElm = e.target;

            e.preventDefault();

            fn.startPos = {x : e.pageX, y : e.pageY};

            var lastPos = {x : fn.activeElm.getAttribute('data-posX'), y : fn.activeElm.getAttribute('data-posY')};
            if(lastPos['x'] && lastPos['y']){
                fn.transPos = {x : parseFloat(lastPos['x']), y : parseFloat(lastPos['y'])};
            }else{
                fn.transPos = {x : 0, y : 0};
            }
            fn.pos = {x : fn.transPos['x'], y : fn.transPos['y']};
            fn.loop();

        }
    },
    handleMove : function(e){
        if(!fn.activeElm)
            return;
        fn.pos = {x : fn.transPos['x'] + e.pageX - fn.startPos['x'], y : fn.transPos['y'] + e.pageY - fn.startPos['y']};
    },
    handleStop : function(e){
        if(!fn.activeElm)
            return;
        fn.activeElm.setAttribute('data-posX', fn.pos['x']);
        fn.activeElm.setAttribute('data-posY', fn.pos['y']);
        fn.activeElm = null;
    },
    addStep : function(move){
        var arr = fn.moveSteps;
        arr = arr.slice(1, arr.length);
        arr.push(move);
        fn.moveSteps = arr;
    },
    loop : function(){
        if(!fn.activeElm)
            return false;
        fn.requestAnimFrame(fn.loop);

        fn.addStep(fn.pos['x']);
        fn.animate();
    },
    animate : function(){
        var arr = fn.moveSteps;
        var rotaSpeed = arr[arr.length-1] - arr[0];
        // The Math.min- and max are there, so we can be sure the angle won't rotate more than 90° and -90°
        var rotation = 'rotate(' + Math.max(Math.min(90, rotaSpeed), -90) + 'deg)';

        if(!fn.activeElm)
            return;
        var obj = fn.activeElm.parentNode.style;
        obj.webkitTransform = obj.MozTransform = obj.msTransform = obj.OTransform = obj.transform = 'translate(' + fn.pos['x'] + 'px, ' + fn.pos['y'] + 'px) ' + rotation;
    },
    requestAnimFrame : function(callback){
        return  window.requestAnimationFrame && window.requestAnimationFrame(callback) || 
        window.webkitRequestAnimationFrame && window.webkitRequestAnimationFrame(callback) || 
        window.mozRequestAnimationFrame && window.mozRequestAnimationFrame(callback) || 
        window.oRequestAnimationFrame && window.mozRequestAnimationFrame(callback) || 
        window.msRequestAnimationFrame && window.msRequestAnimationFrame(callback) || 
        window.setTimeout(callback, 1000 / 60);
    },
    hasClass : function(classname, obj){
        return new RegExp(' ' + classname + ' ').test(' ' + obj.className + ' ');
    }
}
fn.init();

JSFiddle 演示

  • 我做什么:我计算在最后 15 次鼠标移动期间鼠标移动了多少,然后将旋转度设置为该值。所以当鼠标快速移动时,15 次鼠标移动之间的跨度会很大,因此框的旋转也会很大。当鼠标缓慢移动时,跨度会变小,框旋转不会像以前那么大。

但结果看起来并不真实,尤其是当您快速移动鼠标时。我认为随着 div 的移动,需要使用函数 Math.sin 来使旋转更真实地“轻松”。我不知道如何计算这个物理学,所以如果有人有想法、来源、例子、公式,或者只是知道效果的名称,那就太好了。

//此致

4

2 回答 2

1

您正在寻找2D 刚体动力学

考虑使用物理引擎以更少的努力和出色的结果来实现您想要的效果。

请注意,Google Gravity使用Box2Djs,一个物理引擎,将 Box2DFlash 移植到 JavaScript。如果您查看页面的代码,您会发现如何正确设置 Box2djs。

使用 Box2d,您将能够设置世界和对象属性(如重力、摩擦力)和其他物理属性。

以下是 Google Gravity 中用于处理 Box2d 的代码示例:

// init box2d

worldAABB = new b2AABB();
worldAABB.minVertex.Set(-200, -200);
worldAABB.maxVertex.Set(window.innerWidth + 200, window.innerHeight + 200);

world = new b2World(worldAABB, new b2Vec2(0, 0), true);

// Get box2d elements

elements = getElementsByClass("box2d");

for (var i = 0; i < elements.length; i++) {
    properties[i] = getElementProperties(elements[i]);
}

for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    element.style.position = 'absolute';
    element.style.left = properties[i][0] + 'px';
    element.style.top = properties[i][1] + 'px';
    element.style.width = properties[i][2] + 'px';
    element.addEventListener('mousedown', onElementMouseDown, false);
    element.addEventListener('mouseup', onElementMouseUp, false);
    element.addEventListener('click', onElementClick, false);

    bodies[i] = createBox(world, properties[i][0] + (properties[i][2] >> 1), properties[i][1] + (properties[i][3] >> 1), properties[i][2] / 2, properties[i][3] / 2, false);

    // Clean position dependencies
    while (element.offsetParent) {
        element = element.offsetParent;
        element.style.position = 'static';
    }

}

这段代码只是为了帮助您找到重要的代码。仔细研究 Google Gravity 的代码,学习如何使用 Box2djs 来创建你想要的效果。

如果您决定使用物理引擎,您可能更喜欢Box2dWeb而不是 Box2Djs,因为它已更新并存储在单个 js 文件中。

自己实现realist effect是困难的,需要的不仅仅是简单地使用正弦或余弦。也许有某种视觉上相似的效果,但同样,如果不应用良好的物理模拟,就很难实现逼真的效果。

2D 刚体动力学- MIT OpenCourseWare

于 2013-05-24T00:35:14.817 回答
1

没有任何真正的模拟,我做了一些可定制的事情,利用最后 2 次移动的速度来设置你的 div 的角度。

this.drag = function (elem, e)  {
    //
    //ROTATION
    //
    //If there's an end animation I kill it.
    endAnimation.stop();
    //Saving the mouse position
    history.push(e);
    //When we have positions to compare
    if(history.length > 1){
        if (history.length > 2) {
            history.shift();
        }

        var dX = history[0].clientX - history[1].clientX; // Delta
        var tAngle = Math.ceil(angle * -dX);  // Angle to reach       
        var rotation = 'rotate('+ tAngle +'deg)';

        $(elem).css({WebkitTransform: rotation});
        $(elem).css({'-moz-transform': rotation});
        $(elem).css({transform: rotation});
    }
}

这样,您可以更改角度变量以增加或减少角度。

我还在使用另一个主题时添加了一些惯性

你可以在这里看到结果http://jsfiddle.net/Spope/tzqwx/

于 2013-08-09T09:36:08.903 回答