使用setTimeout从循环内部重新绘制html画布的推荐方法

Recommended way to redraw an html canvas from inside a loop using setTimeout

本文关键字:html 方法 绘制 循环 setTimeout 内部 新绘制 使用      更新时间:2023-09-26

我研究了很多,主要是在SO中,关于setTimeout"不阻塞",因此不适合在for循环中使用,因为循环不断进行,而函数调用不断增加。

我有一个记录图像处理算法的HTML文件,所以我想以"人类可读"的速度显示活动像素"行走"。我尝试过的实现没有工作,如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body onload="run();">
    <canvas id="Canvas" width=501 height=601></canvas>
    <script>
        function run() {
            reevaluate();
        };
        var fixedcenteri;
        var fixedcenterj;

        function reevaluate() {
            var altura_imagem = 50;
            var largura_imagem = 40;
            for (var i = 0; i < altura_imagem; i++) {
                for (var j = 0; j < largura_imagem; j++) {
                    fixedcenteri = i;
                    fixedcenterj = j;
                    setTimeout(draw, 100);

                    // if I uncomment this I can see what I want, but...
                    // alert(i+j);
                };
            };
        };

        function draw () {
            var elem = document.getElementById('Canvas');
            var cx = elem.getContext('2d');
            w = elem.width;
            h = elem.height;
            cx.fillStyle = "white";
            cx.fillRect(0,0,w,h);
            cx.fillStyle = 'blue';
            cx.fillRect(fixedcenteri, fixedcenterj, 10, 10);
        }
    </script>
</body>
</html>

尝试RequestAnimationFrame!

RequestAnimationFrame是异步的,就像setTimeout一样,它比setTimeout更有效。

此外,它还提供动画分组和屏幕外动画的自动停止。

你甚至可以使用以下技术将其限制到你想要的FPS:

var fps = 15;
function draw() {
    setTimeout(function() {
        requestAnimationFrame(draw);
        // your draw() stuff goes here
    }, 1000 / fps);
}

最简单的实现是将所有绘制命令存储在一个数组中,然后使用setTimeout处理该数组,在绘制命令之间等待。

这里有一个简单的例子-> http://jsfiddle.net/K4D84/

//in your initial loop instead of draw
drawCommands.push({i: i, j: j});

然后……

function slowDraw(index) {
    index = index || 0;
    var drawCommand = drawCommands[index];
    if (drawCommand) {
        fixedcenteri = drawCommand.i;
        fixedcenterj = drawCommand.j;
        setTimeout(function () {
            draw();
            slowDraw(++index);
        }, 100);
    }    
}

我想这就是你想要的。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body onload="draw();">
    <canvas id="Canvas" width=501 height=601></canvas>
    <script>
        var fixedcenteri = 0;
        var fixedcenterj = 0;
        function draw () {
            var elem = document.getElementById('Canvas');
            var cx = elem.getContext('2d');
            w = elem.width;
            h = elem.height;
            cx.fillStyle = "white";
            cx.fillRect(0,0,w,h);
            cx.fillStyle = 'blue';
            cx.fillRect(fixedcenteri, fixedcenterj, 10, 10);
            if(fixedcenteri < 50) {
                if(fixedcenterj < 40) {
                    fixedcenterj++;
                } else {
                    fixedcenterj = 0;
                    fixedcenteri++;
                }
                setTimeout(draw, 100);
            }
        }
</script>