javascript平滑动画从X,Y到X1,Y1
javascript smooth animation from X,Y to X1,Y1
我想将图像(或元素)从实际的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
闭包浮动。
不管怎样,在这里拨弄