javascript平滑动画从X,Y到X1,Y1

时间:2011-09-17 13:07:08

标签: javascript image animation smooth

我想将图像(或元素)从实际的X,Y位置倾斜移动到X1,Y1。

当X和X1 之间的距离等于时,Y和Y1之间的距离很容易。 但是,如果X差异是100px而Y diff是273px怎么办?

刚接触Javascript,我不想重新发明轮子! 此外,因为我正在学习,我不想使用jQuery或类似的东西。我想要纯粹的javascript。

请提供简单的脚本: - )

4 个答案:

答案 0 :(得分:7)

一个解决方案:

function translate( elem, x, y ) {
    var left = parseInt( css( elem, 'left' ), 10 ),
        top = parseInt( css( elem, 'top' ), 10 ),
        dx = left - x,
        dy = top - y,
        i = 1,
        count = 20,
        delay = 20;

    function loop() {
        if ( i >= count ) { return; }
        i += 1;
        elem.style.left = ( left - ( dx * i / count ) ).toFixed( 0 ) + 'px';
        elem.style.top = ( top - ( dy * i / count ) ).toFixed( 0 ) + 'px';
        setTimeout( loop, delay );
    }

    loop();
}

function css( element, property ) {
    return window.getComputedStyle( element, null ).getPropertyValue( property );
}

现场演示: http://jsfiddle.net/qEVVT/1/

答案 1 :(得分:3)

在具有各种不同功能(CPU,图形处理能力,计算机上正在发生的其他事情)的系统上进行平滑动画并非易事。正确的实现涉及开发一种有效的“补间”算法,该算法可以自适应地计算(当动画运行时)在动画中使用的增量,以便保持按计划并尽可能平滑。

这样做的最好方法是站在别人的肩膀上,并使用之前发明的东西。在这个时代,我永远不会尝试从头开始写这个。它可以在CSS3过渡/动画中使用,但到处都不支持。它可以在jQuery和YUI3中使用或分析。我的第一选择是使用其中一个具有丰富功能的框架。您不必将框架用于其他任何内容,如果需要,您可以将其用于动画。 YUI3甚至可以让你构建一个代码最少的库,可以满足你的需要。 jQuery起初并不是很大。

如果您仍然没有使用其中一个库,请将源代码下载到每个库的相关模块,并研究它们是如何进行的。在每个应用程序中构建一个示例应用程序并逐步完成它的工作原理,在有趣的位置设置断点这将是最好的老师,并向您展示如何构建一个有效的补间算法,以适应主机的速度功能。

为了让您了解补间算法如何适用于直线动画(使用线性缓动),您可以初步计算您希望动画步长值在您希望动画运行的时间。这可能只是猜测系统可以支持什么。您将创建的步数除以动画运行的时间,并为该时间量设置计时器,以便知道何时运行下一步。然后运行动画的一个或两个步骤,您会看到实际经过了多长时间。如果计算机无法跟上您的步数,您将落后于计划,您将不得不适应并选择更大的步骤。

现在,如果你想做除线性宽松之外的其他事情,那么显然会涉及更多。

Firefox和Chrome还实施了一些新的体验式API来帮助平滑动画。我在查看jQuery源代码时发现了这一点,因为它在可用时使用它。在Chrome中,它被称为webkitRequestAnimationFrame,您可以阅读它here in a Firefox blog post

答案 2 :(得分:1)

如果您的目标是现代浏览器,那么CSS过渡会让生活变得更轻松(firefox示例,对于其他浏览器,更改-moz前缀):

<body>
    <input type="button" onclick="move()" value="press" />
    <div id="sq" style="position:absolute; top:50px; left:50px; height:50px; width:50px; background-color:Black; -moz-transition : all 0.8s ease 0s;" />
</body>

脚本

 function move() {
            var sq = document.getElementById("sq");
            sq.style.left = "300px";
            sq.style.top = "150px";
        }

答案 3 :(得分:0)

如果我要从头开始编写,我会从这样开始:

function linearEase(start, end, percent) {
    return start + ((end - start) * percent);
}

function animateTo(settings) {
    var elem = settings.element;
    var ease = settings.ease;

    var start = { left: elem.offsetLeft, top: elem.offsetTop };

    var lastTime = new Date().getTime();
    var timeLeft = settings.totalTime;

    function update() {
        var currentTime = new Date().getTime();
        var elapsed = currentTime - lastTime;
        timeLeft -= elapsed;
        lastTime = currentTime;

        var percentDone = 1 - timeLeft/settings.totalTime;

        elem.style.top = ease(start.top, settings.top, percentDone) + "px" ;
        elem.style.left = ease(start.left, settings.left, percentDone) + "px" ;

        if(timeLeft > 0) {
            setTimeout(update, 33);
        }   
    }

    update();
}

例如,在接下来的两秒内将div移动到(50,50)。

var elem = document.getElementById("animatable");

setTimeout(function() {
    animateTo({
        element: elem, 
        left: 50, 
        top: 50, 
        totalTime: 2000,
        ease: linearEase
    })
}, 10);

这是一种相当标准的模式来做这种事情。获得元素位置和设置样式的东西可以更好地实现。但是,从长远来看,抽象出ease函数将使您的生活变得更加轻松。我提供了一个简单的线性简易,但其他更复杂的缓动算法将遵循相同的接口。

需要注意的另一件事是超时和间隔是not guaranteed在设定的时间运行,因此通常最好设置您希望转换运行的总时间,然后计算出多少自上次渲染后经过的时间。

另外,如果你一次动画一堆元素,我肯定会将它重构为一个“渲染循环”。对animateTo的调用会将工作者推入工作队列,但只有setTimeout循环计算经过的时间然后调用每个工作者,因此您没有大量的timeout闭包漂浮在周围。

无论如何,摆弄here