我正在尝试创建一个小的javascript动画来更好地理解算法。 该算法适用于像这样的二维数组: -
function algorithm(){
for(var i=0;i<gridSize;i++){
for(var j=0;j<gridSize;j++){
if(arr[i][j]=="D"){
// fill every nearby emty place with 1
if(i-1>=0 && j-1>=0 && arr[i-1][j-1]=="-"){
arr[i-1][j-1]=1;
// change the canvas here.
queue.enqueue(new Point(i-1,j-1));
}
}
}
}
}
等等。 我基于数组填充画布的功能如下:
function execute(){
for(var i=0;i<gridSize;i++){
for(var j=0;j<gridSize;j++){
drawRect(i,j);
}
}
}
function randomFill(){
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
execute();
for(var i=0;i<gridSize;i++){
for(var j=0;j<gridSize;j++){
if(arr[i][j]=="W")
ctx.fillStyle = "red";
else if(arr[i][j]=="D")
ctx.fillStyle = "blue";
else if(arr[i][j] == "-")
ctx.fillStyle = "green";
else
ctx.fillStyle = "purple";
ctx.font='30px Calibri';
ctx.fillText(arr[i][j],i*40 + 40,(j+1)*40 + 40);
}
}
}
}
那么如何在100毫秒之后调用randomFill()函数在画布上重绘。 我想在画布上显示数组中的变化,但是稍微延迟之后,人们就可以看到了。
答案 0 :(得分:1)
创建动画循环的新方法和首选方法是使用window.requestAnimationFrame
这是首选,因为它使用浏览器刷新率协调循环执行,以生成有效的重绘。如果浏览器切换到不同的浏览器选项卡(在移动设备上节省电池电量),它还会暂停动画循环。
与setTimeout类似,requestAnimationFrame(我将其简称为RAF)被赋予一个回调函数来执行。 RAF将在与浏览器和硬件同步的庄园中执行该回调函数。
以下是典型的RAF动画循环:
function animate(timestamp){
// execute RAF again to request the next loop
requestAnimationFrame(animate);
}
RAF向其调用的函数发送时间戳(这是动画中的时间戳)。您可以使用此时间戳在100ms后执行randomFill()。
可能如下所示:http://jsfiddle.net/m1erickson/2afLc/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
ctx.fillStyle="skyblue";
ctx.strokeStyle="lightgray";
ctx.lineWidth=4;
// testing: rotate a rectangle every 100ms
var r=0;
var interval=100;
$("#interval").text("Call randomFill to rotate every "+interval+"ms");
// a variable to hold when the animation loop last fired
var lastTime;
// start the animation loop
requestAnimationFrame(animate);
function animate(timestamp) {
// initialize lastTime during the first run of the animate() loop
if(!lastTime){lastTime=timestamp;}
// calculate the elapsed time
var elapsed=timestamp-lastTime;
if(elapsed>interval){
// let randomFill complete before
// resetting the timer and requesting another loop
r+=Math.PI/120;
randomFill(r);
// reset the timer
lastTime=performance.now();
}
// request another animation loop
requestAnimationFrame(animate);
}
function randomFill(r){
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
ctx.save();
ctx.translate(100,100);
ctx.rotate(r);
ctx.fillRect(-25,-25,50,50);
ctx.strokeRect(-25,-25,50,50);
ctx.restore();
}
}); // end $(function(){});
</script>
</head>
<body>
<p id="interval">Call randomFill</p>
<canvas id="canvas" width=350 height=350></canvas>
</body>
</html>
答案 1 :(得分:1)
要延迟迭代,你需要使用除了for-loop以外的其他东西,因为延迟会涉及异步的异常,而且不能用于&#34; sleep&#34;在for循环迭代中。
解决方案是将for循环分解为计数器,每100ms递增一次。它变得有点不同,但是你可以为每个&#34;迭代引入一个延迟&#34; (或增加)。
这是一个基本的示例设置循环使用计数器和每次迭代的延迟 - 该示例仅作为您可以用于您的场景的骨架:
/* global variables */
var i = 0; // outer loop
var j = 0; // inner loop
function next() {
if (j === gridSize) {
i++; // increase outer loop counter
j = 0; // reset inner loop counter
if (i === gridSize) {
/* ...loop has finished, re-initialize etc. here ... */
return;
}
}
/* ... use i, j here and update canvas - see example link below ... */
j++; // iterate inner counter
setTimeout(next, 100); // delayed calling of next() again
}
next(); // start loop
<强> EXAMPLE FIDDLE 强>
next()方法每次调用时都会增加内循环(j
)。当满足第一个条件时(j = gridSize),重置j
并增加外循环(i
)。
当外循环满足条件(i = gridSize)时,循环进入退出点,可用于重新初始化数组,重置i
和j
,重启循环等等。
i
和j
位于全局范围内,因为当您调用setTimeout
时,代码将以全局窗口对象作为范围执行,因此声明i
和{ {1}}全局使它们在函数内部可用。有很多方法,但为了简单起见,我将这个主题留在这里。
答案 2 :(得分:0)
function randomFill(){
setTimeout(function() {
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
execute();
for(var i=0;i<gridSize;i++){
for(var j=0;j<gridSize;j++){
if(arr[i][j]=="W")
ctx.fillStyle = "red";
else if(arr[i][j]=="D")
ctx.fillStyle = "blue";
else if(arr[i][j] == "-")
ctx.fillStyle = "green";
else
ctx.fillStyle = "purple";
ctx.font='30px Calibri';
ctx.fillText(arr[i][j],i*40 + 40,(j+1)*40 + 40);
}
}
}
}, 100); // or however long the delay should be, in ms
}
建议您确保不要使用clearTimeout重叠超时请求,例如:
tid && clearTimeout(tid);
tid = setTimeout(...)