我的问题是我的javascript / canvas在低端计算机上运行速度非常慢(即使它们可以顺利运行更具挑战性的canvas scripts。 我正在尝试根据用户选择做一个简单的动画。
当直接在画布上绘图被证明太慢时,我在隐藏的画布上绘制并将所有帧(getImageData
)保存到data
,然后调用animate(1);
来绘制我的画布真实的画布。
function animate(i){
if(i < 12){
ctx2.putImageData(data[i], 0, 0);
setTimeout(function(){animate(i+1)},1);
}
}
但即使这样太慢了。我该怎么办?
答案 0 :(得分:7)
如果可以提供帮助,请不要使用putImageData
。 FF3.6上的表现is abysmal:
Test results showing poor getImageData performance http://phrogz.net/tmp/canvas_copy_benchmark.png
使用drawImage
在屏幕外画布和blit精灵上使用绘图命令代替子区域。
正如@MartinJespersen所提到的,重写你的框架绘图循环:
var animate = function(){
// ...
setTimeout(animate,30); //Max out around 30fps
};
animate();
如果您使用的库强制每帧clearRect
,但您不需要,请停止使用该库。清除并重新绘制您需要的部分。
使用较小的画布尺寸。如果你觉得它足够了,你甚至可以用CSS扩展它。
接受缓慢的计算机是慢的,你站在许多抽象层的肩膀上。如果您想要了解低端计算机的性能,请使用C ++和OpenGL编写。否则,请设置最低系统要求。
答案 1 :(得分:3)
您指定的超时为1毫秒。没有浏览器可以快速更新画布。把它改为1000 - 那将是1秒,即:
setTimeout(function(){animate(i+1)}, 1000)
UPD。要尝试的另一件事是准备尽可能多的画布,因为动画中有帧,将所有帧设置为display:none
,然后在它们上转display:block
顺序。我怀疑它会比putImageData更快,但仍值得尝试。
答案 2 :(得分:2)
如前所述,间隔为1毫秒的超时注定会失败,所以第一步就是停止。
您正在调用setTimeout
recursivly,这对于创建动画并不理想。而是同时启动整个动画所需的所有setTimeout
,同时增加循环中的延迟并让它们运行,或者更好地使用setInterval
这是做动画的更好方法,以及jQuery的动画如何工作。
看起来您正试图在动画的每一步重绘整个canvas
- 这不是最佳选择,只尝试操纵更改的像素。你给“更多challanging canvas脚本”的链接实际上比你想做的更简单,因为它是所有基于矢量的数学 - 这是canvas
元素被优化的 - 它从未被制作过每隔x毫秒进行一次完全重新渲染,很可能永远不会。
如果你真正需要做的是改变动画中每一帧的整个图像 - 不要使用canvas
,而是使用带有预加载图像的普通图像标签,那么它将在ie6上顺利运行单数原子。
答案 3 :(得分:0)
我有一个类似谷歌地图的应用程序 - 它可以让您点击并平移大图像。我重绘了我的画布,从每个重绘的大图像中采样和缩放。
无论如何,我碰巧尝试了双画布方法 - 在需要时绘制到(更大)缓冲区,然后执行canvas_display.drawImage(canvas_buffer)以将区域输出到屏幕。我不仅没有看到性能提升,而且iPhone的速度明显变慢。只是一个数据点...
答案 4 :(得分:0)
好的,首先要做的事情。你正在做这个动画时会发生什么 else ?任何其他JavaScript,任何其他计时器,任何其他处理程序?顺便说一句,答案不能是 nothing 。您的浏览器正在重新绘制窗口 - 至少是您要更改的位。如果其他javascript正在“运行”,请记住,这不是严格正确的。 Javascript是单线程设计。你只能排队执行,所以如果其他一些javascript占用线程,你就不会看到。
其次,了解计时器的工作原理。 http://ejohn.org/blog/how-javascript-timers-work/是我个人最喜欢的帖子。特别是,setTimeout
要求浏览器在至少指定时间之后运行某些内容,但仅在浏览器有开放时才会运行。
第三,知道你在function(){animate(i+1);}
做了些什么。该匿名函数只能 存在于其父级范围内。换句话说,当你排队这样的函数时,父范围仍然存在于callstack上,正如@MartinJespersen指出的那样。而且,由于该功能排队另一个,另一个,另一个......每个都会逐渐变慢。
我把所讨论的所有内容放在一个小小的地方:
(我第一次使用jsfiddle,所以要善待)。这是一个简单的10帧动画(名义上)为100毫秒,每个都使用setTimeout
。 (我已经这样做而不是setInterval
,因为理论上,执行时间较长的应该开始落后于其他人。理论上 - 再次,因为javascript是单一的 - 如果一个人放慢速度,它也会延迟其他人。)
top方法只在重叠的画布上绘制了所有十张图像,一次只显示一张。动画只是隐藏前一帧并显示下一帧。第二个将putImageData
执行到具有顶级功能的画布中。第三个使用您尝试过的匿名函数。观察第0帧的红色闪光,你会看到谁正在执行最快 - 对我来说,它需要一段时间,但它们最终开始漂移(在Chrome中,在一台体面的机器上。在FF中应该更明显在较低规格的东西上。)
在您的低端测试机器上试一试,看看会发生什么。
答案 5 :(得分:0)
我以这种方式完成了setTimeout,希望它可以帮助某人提升应用程序:
var do = true;
var last = false;
window.onmousemove = function(evt){
E.x = evt.pageX - cvs.offsetLeft;
E.y = evt.pageY - cvs.offsetTop;
if(do){
draw();
do = false;
//in 23 ms drawing enabled again
var t = setTimeout(function(){do = true;},23);
}else{
//the last operation must be done to catch the cursor point
clearTimeout(last );
last = setTimeout(function(){draw();},23);
}
};