Javascript 如何在画布中添加动画延迟?

Javascript 如何在画布中添加动画延迟?,javascript,canvas,Javascript,Canvas,我正在尝试创建一个小的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

我正在尝试创建一个小的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));
                }
            }
        }
    }
}
函数算法(){
对于(变量i=0;i=0&&arr[i-1][j-1]==“-”){
arr[i-1][j-1]=1;
//在这里更改画布。
排队(新点(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);
            }
        }
    }
}
函数执行(){
对于(var i=0;i


创建动画循环的新的首选方法是使用
window.requestAnimationFrame

这是首选,因为它将循环执行与浏览器刷新率相协调,以生成高效的重画。如果浏览器切换到其他浏览器选项卡(节省移动设备上的电池),它还将暂停动画循环

和setTimeout一样,requestAnimationFrame(我简称为RAF)也有一个回调函数要执行。RAF将在与浏览器和硬件同步的manor中执行该回调函数

以下是典型的英国皇家空军动画循环:

function animate(timestamp){

    // execute RAF again to request the next loop
    requestAnimationFrame(animate);

}
RAF向它调用的函数发送一个时间戳(这是animate中的时间戳)。您可以使用此时间戳在100毫秒后执行randomFill()

可能是这样的:


正文{背景色:象牙;}
画布{边框:1px纯红;}
$(函数(){
var canvas=document.getElementById(“canvas”);
var ctx=canvas.getContext(“2d”);
ctx.fillStyle=“天蓝色”;
ctx.strokeStyle=“浅灰色”;
ctx.线宽=4;
//测试:每100ms旋转一个矩形
var r=0;
var区间=100;
$(“#间隔”).text(“调用randomFill以每”+间隔+毫秒旋转一次”);
//上次触发动画循环时要保留的变量
var上次;
//启动动画循环
请求动画帧(动画);
函数动画(时间戳){
//在第一次运行animate()循环期间初始化lastTime
如果(!lastTime){lastTime=timestamp;}
//计算经过的时间
var Appead=时间戳lastTime;
如果(经过>间隔){
//让随机填充在之前完成
//重置计时器并请求另一个循环
r+=Math.PI/120;
随机填充(r);
//重置计时器
lastTime=性能。现在();
}
//请求另一个动画循环
请求动画帧(动画);
}        
函数随机填充(r){
clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
ctx.save();
ctx.translate(100100);
ctx.旋转(r);
ctx.fillRect(-25,-25,50,50);
ctx.strokeRect(-25,-25,50,50);
ctx.restore();
}
});//end$(函数(){});

调用随机填充


要延迟迭代,您需要使用for循环以外的东西,因为延迟将涉及异步计时器,毫无例外,因此不能用于在for循环迭代中“休眠”

解决方案是将for循环分解成每100ms递增一次的计数器。这会成为一种稍微不同的模式,但可以为每个“迭代”(或递增)引入延迟

下面是一个基本示例设置循环,使用计数器和每次迭代的延迟-该示例仅表示您可用于场景的框架:

/* 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

next()方法每次调用时只增加内循环(
j
),当满足第一个条件(j=gridSize)时,重置
j
,增加外循环(
i

当外部循环也满足条件(i=gridSize)时,循环进入一个出口点,该出口点可用于重新初始化数组、重置
i
j
、重新启动循环等


i
j
在全局范围内,当您调用
setTimeout
时,代码将以全局窗口对象作为范围来执行,因此声明
i
j
全局使它们可以从函数内部使用。有一些方法可以解决此问题,但为了安全起见,我将此主题留在这里plicity.

为什么不直接使用setTimeout?我确实尝试过setTimeout作为setTimeout(randomFill(),1000);在我想更新画布的地方,但没有任何效果。只显示画布中的最终图像,而不显示转换。如此接近!setTimeout接受一个函数。当调用
setTimeout(randomFill(),x)时
您没有向它传递函数块,而是执行randomFill()并将返回值传递给setTimeout()。您想要的是我在答案中列出的方式,或者
setTimeout(randFill,x)
(注意:没有括号)仍然没有线索。因此,我将setTimeout(function(){randomFill();},1000);无论何时需要更新画布。但画布仍会等待1秒并显示最终图像。我是否可以这样使用它:每当算法循环时,它都会更新ARR元素的值,并使用randomFill()更新画布;让它在那里停留100毫秒,而不执行下一次迭代。我该怎么做呢???当然,要做到这一点,你需要另一个循环,并在你进行随机填充后重置
lastTime
变量。这样,在计时器再次消失之前,你将得到整整100毫秒的时间。请看我编辑的答案。哦,天哪,我是一个彻头彻尾的傻瓜。我仍然无法得到它为了正常运行。好吧,我复制粘贴了你的代码。但是什么也没发生。我从互联网上的许多资源中阅读,但仍然无法让它工作。我唯一想要的是,如果你看看我的算法循环,那就是每当我更新arr元素的值时,我只想重新绘制can
function animate(timestamp){

    // execute RAF again to request the next loop
    requestAnimationFrame(animate);

}
<!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>
/* 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