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

javascript smooth animation from X,Y to X1,Y1

本文关键字:X1 Y1 平滑 动画 javascript      更新时间:2023-09-26

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

当X与X1 之间的距离等于Y与Y1之间的距离时,这很容易。但是如果X差值是100px Y差值是273px呢?

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

请提供简单的脚本:-)

一个解决方案:

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/

在具有各种不同功能(CPU、图形处理能力、计算机上的其他功能)的系统上制作流畅的动画并不是一项简单的任务。适当的实现包括开发一种有效的"渐变"算法,该算法可以自适应地(在动画运行时)计算出在动画中使用的增量,以保持进度并尽可能平滑。

要做到这一点,最好的方法是站在别人的肩膀上,使用以前发明的东西。在这个时代,我永远不会尝试自己从零开始写这个。它可以在CSS3的过渡/动画中使用,但这些还不是无处不在的支持。它可以在jQuery和YUI3中使用或分析。我的第一选择是使用其中一个具有丰富功能的框架。你不需要用这个框架做任何事情,如果你想的话,你可以把它用在动画上。YUI3甚至允许您构建一个库,其中的代码尽可能少,以满足您的需求。jQuery一开始不是很大。

如果您仍然坚决反对使用其中一个库,那么请下载每个库的相关模块的源代码,并研究它们是如何实现的。在每个应用程序中构建一个示例应用程序,并逐步了解它是如何工作的,在有趣的地方设置断点。这将是最好的老师,告诉你如何建立一个有效的补间算法,可以适应主机的速度能力。

为了让你了解渐变算法是如何为一个直接动画(线性缓动)工作的,你需要对你想要的动画步长值做一个初始计算,在你想要动画运行的时候。这可能只是对系统所能支持的内容的猜测。你将创建的步数除以动画运行的时间,并为这段时间设置一个计时器,这样你就知道什么时候运行下一步。然后运行动画的一个或两个步骤,您可以看到实际经过了多少时间。如果计算机跟不上你的步长值,你就会落后于计划,你将不得不适应并选择一个更大的步长。

现在,如果你想做线性缓动以外的事情,显然还有更多的事情要做

Firefox和Chrome也实现了一些新的实验性api来帮助实现流畅的动画。我在查看jQuery源代码时发现了这一点,因为它在可用时使用了它。在Chrome中,它被称为webkitRequestAnimationFrame,你可以在Firefox的博客文章中读到它。

如果您的目标是现代浏览器,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";
        }

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

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函数会让你的工作变得容易得多。我提供了一个简单的线性缓解,但其他更复杂的缓解算法将遵循相同的接口。

另一件要注意的事情是,超时和间隔不能保证在设定的时间内运行,所以通常最好设置您希望转换运行的总时间,然后计算出自上次呈现以来已经过了多少时间。

同样,如果你是一次动画一堆元素,我肯定会重构它到一个单一的"渲染循环"。对animateTo的调用将工人推入工人队列,但只有setTimeout循环计算经过的时间,然后调用每个工人,所以你没有无数的timeout闭包浮动。

不管怎样,在这里拨弄