JavaScript 动画的持续时间并不精确
JavaScript Duration of animation isn't exact
首先我想提两件事,一:我的代码并不完美(特别是评估部分) - 但我想为自己尝试一些东西,看看我是否可以复制jQuery动画功能,所以请原谅我的"坏"做法,请不要建议我会使用jQuery,我想尝试一下。
二:这段代码还没有完成,我只是想弄清楚是什么让它工作不好。
所以动画运行了大约 12 秒,而我输入的持续时间参数是 15 秒,我做错了什么?
function animate(elem, attr, duration){
if(attr.constructor === Object){//check for object literal
var i = 0;
var cssProp = [];
var cssValue = [];
for(key in attr) {
cssProp[i] = key;
cssValue[i] = attr[key];
}
var fps = (1000 / 60);
var t = setInterval(function(){
for(var j=0;j<cssProp.length;j++){
if(document.getElementById(elem).style[cssProp[j]].length == 0){
//asign basic value in css if the object dosn't have one.
document.getElementById(elem).style[cssProp[j]]= 0;
}
var c = document.getElementById(elem).style[cssProp[j]];
//console.log(str +" | "+c+"|"+cssValue[j]);
if(c > cssValue[j]){
document.getElementById(elem).style[cssProp[j]] -= 1/((duration/fps)*(c-cssValue[j]));
}else if(c < cssValue[j]){
document.getElementById(elem).style[cssProp[j]] += 1/((duration/fps)*(c-cssValue[j]));
}else if(c == cssValue[j]){
window.clearInterval(t);
}
}
},fps);
}
}
animate('hello',{opacity:0},15000);
.html:
<p id="hello" style="opacity:1;">Hello World</p>
注意:我想有问题
(duration/fps)*(c-cssValue[j])
部分或/和 setInterval 的间隔(fps 变量)。
提前谢谢。
我不会尝试重构并弄清楚它,因为它很不稳定。 可是。。。几件事。
不要依赖要制作动画的值来告知动画进度
总的来说,你的方法是不合理的。你最好自己跟踪进度。 此外,由于你的方法,你的数学似乎太努力了,应该简单得多。
可以这样想:当时间过去时,您的动画就完成了,而不是当动画值似乎指示它位于最终位置时。
不递增,设置
浮点数学是不精确的,像这样的重复加法累积也会累积浮点误差。 制作一些变量来跟踪进度的可读性要高得多,您可以在计算中使用。
animatedValue += changeOnThisFrame // BAD!
animatedValue = valueOnThisFrame // GOOD!
不要做积极/消极的条件舞
事实证明,10 + 10
和10 - (-10)
真的是一回事。 这意味着您始终可以添加值,但变化率可以是负数或正数,并且值将沿适当的方向进行动画处理。
超时和间隔不精确
事实证明setTimeout(fn, 50)
实际上意味着将 fn 安排在至少 50 毫秒后调用。 在这 50 毫秒之后执行的下一个 JS 运行循环将运行该函数,因此您不能依赖它完全准确。
也就是说,它通常在几毫秒内。 但是 60fps 对于帧来说大约是 16 毫秒,并且该计时器实际上可能会在 16-22 毫秒的可变时间内触发。 因此,当您根据帧速率进行计算时,它与实际经过的时间根本不匹配。
重构复杂数学
在这里解构这条线将是困难的。
document.getElementById(elem).style[cssProp[j]] -= 1/((duration/fps)*(c-cssValue[j]));
为什么要更复杂的分解它,以便您可以轻松了解这里发生的事情。 单独重构这一行,我可能会这样做:
var style = document.getElementById(elem).style;
var changeThisFrame = duration/fps;
var someOddCalculatedValue = c-cssValue[j];
style[cssProp[j]] -= 1 / (changeThisFrame * someOddCalculatedValue);
这样做可以更清楚地了解数学中的每个表达式的含义及其用途。 因为你没有在这里做,我很难想知道为什么c-cssValue[j]
在那里以及它代表什么。
简单示例
这比你所拥有的能力差,但它显示了你应该采取的方法。 它使用动画开始时间来创建完美的值,具体取决于动画的完成程度、开始的位置以及要去的地方。 它不使用当前动画值来确定任何内容,并保证运行动画的整个长度。
var anim = function(elem, duration) {
// save when we started for calculating progress
var startedAt = Date.now();
// set animation bounds
var startValue = 10;
var endValue = 200;
// figure out how much change we have over the whole animation
var delta = endValue - startValue;
// Animation function, to run at 60 fps.
var t = setInterval(function(){
// How far are we into the animation, on a scale of 0 to 1.
var progress = (Date.now() - startedAt) / duration;
// If we passed 1, the animation is over so clean up.
if (progress > 1) {
alert('DONE! Elapsed: ' + (Date.now() - startedAt) + 'ms');
clearInterval(t);
}
// Set the real value.
elem.style.top = startValue + (progress * delta) + "px";
}, 1000 / 60);
};
anim(document.getElementById('foo'), 5000);
JSFiddle: http://jsfiddle.net/DSRst/
不能使用setInterval
来准确执行总计时。 由于 JS 是单线程的,并且多个事物在一个线程上竞争周期,因此无法保证下一个间隔调用将完全准时或 N 个间隔将消耗确切的持续时间。
相反,几乎所有动画例程都获取当前时间,并使用系统时钟来测量总持续时间的时间。 一般的算法是获取开始时间,计算出期望的完成时间(开始时间+持续时间)。 然后,如前所述,计算预期的步长值和迭代次数。 然后,在每个步骤中,重新计算剩余时间和剩余步骤值。 通过这种方式,您可以确保动画始终准确(或几乎完全)准时完成,并且始终准确到达最终位置。 如果动画落后于理想轨迹,则它将自行更正并在剩余步骤中稍微移动更多。 如果它因任何原因(舍入误差等)领先,它将回拨步长,同样准时到达最终位置。
您可能还需要知道浏览器并不总是支持非常小的计时量。 每个浏览器都有某种允许计时器操作的最短时间。 这是一篇关于最低计时器水平的文章。
这是一篇关于补间(不断重新计算步骤以完全适合持续时间的过程)的文章。
我还建议您查看某些库中制作动画的代码(jQuery,YUI或您找到的任何其他库),因为它们都可以向您展示如何以非常通用的方式完成此操作,包括补间,缓动函数等...
- 提交按钮通过JQuery和JavaScript函数所做的更改不会持续
- 在jQuery中,短距离长持续时间的精细字体大小动画
- 创建一个倒计时计时器脚本,该脚本计算声音文件的持续时间,而不是特定的日期
- 文本正在立即消失,而不是随着时间的推移而消失
- 输入视频文件时获取视频持续时间
- 无填充的滚动魔术持续时间
- 我需要在每5秒内调用一个函数,并重置持续时间
- jQuery动画的持续时间就像一个延迟
- 如何在特定时间重新加载page.php,例如:07:45.非持续时间,例如:每5秒
- 如何在dhtmlxgantt中显示灯箱中的开始日期、结束日期和持续时间
- YouTube V3 API——按持续时间过滤相关视频信息,不;似乎不起作用
- SoundManager2 - 使用 RTMP 不显示持续时间
- JavaScript 动画的持续时间并不精确
- 当添加新行时,总持续时间值应该会更改,但不会更改;t
- Chrome扩展-变量值不分配取决于间隔持续时间
- Javascript转换持续时间不工作
- 改变动画持续时间CSS3不工作在Chrome
- for循环中的视频持续时间不工作
- 如何不断更新此mp3文件的持续时间I'我在玩JS?进度条不起作用
- GSAP 补间无法正常工作.设置持续时间不起作用