如何在循环中渲染HTML5画布?

4
我想做以下事情: 我正在通过for循环运行,每次获取新信息并希望在画布上绘制它。 问题是画布在循环结束后才被绘制,我看不到任何动画。如果我使用debug或警告消息进行调试,它会立即绘制到画布上。该怎么办? 这是我的代码,您可以看到我已经尝试了多种方式使用setTimeout,但没有用。
for(var i=0;i<1000; i ++)
    {
        addLines(ga.getBestCreature());   // This method draw on the canvas 

        setTimeout(function() {
        ga.startEvolution(1);       // This method change the best creature
        }, 10);   
    }

绘制方法:
function addLines(best) {

    if(!best) {
        return;
    }
    var global_path = best.data;

    redraw(); // Clear off the canvas

    var cityA;
    var cityB;
    for (var i = 0; i < (global_path.length - 1); i++) {

        cityA = ga.cities[global_path[i]];
        cityB = ga.cities[global_path[i+1]];

        ctx.moveTo(cityA.x,cityA.y);
        ctx.lineTo(cityB.x,cityB.y);
        ctx.stroke();
    }
}

有什么想法吗?

更新:在被建议使用requestAnimationFrame之后,我想出了以下的方法。这是最好的方法吗? 我在点击事件中更新了一个名为“run”的全局变量。

var run = 0;
function animate() {

    if(run > 0) {
        ga.startEvolution(1);
        run--;
    }

addLines(ga.getBestCreature());
    requestAnimationFrame(animate);
}

animate();
2个回答

4
您最好的做法是分离关注点:持续运行一个动画循环,并且“每次获得新信息”时更新您的场景描述,它将在显示准备就绪后立即绘制。
因此,第一个非常简单的演示:这里的“新信息”是用户点击。

var cv = document.getElementById('cv');
var ctx = cv.getContext('2d');
var cvWidth = cv.width;
var cvHeight = cv.height;

// Simple scene description : an array of colored rects
var everyObject = [
  [60, 70, 30, 30, 'yellow']
];

// animation : always running loop.

function animate() {
  // call again next time we can draw
  requestAnimationFrame(animate);
  // clear canvas
  ctx.clearRect(0, 0, cvWidth, cvHeight);
  // draw everything
  everyObject.forEach(function(o) {
    ctx.fillStyle = o[4];
    ctx.fillRect(o[0], o[1], o[2], o[3]);
  });
  // 
  ctx.fillStyle = '#000';
  ctx.fillText('click to add random rects', 10, 10);
}

animate();


// click handler to add random rects
window.addEventListener('click', function() {
  addRandRect();
});

function addRandRect() {
  var randColor = Math.random() > 0.5 ? 'blue' : 'red';
  everyObject.push([Math.random() * cvWidth, Math.random() * cvHeight, 10 + Math.random() * 40, 10 + Math.random() * 40, randColor]);
}
<canvas id='cv' width=400 height=200></canvas>

现在如果您想要一些动画效果,或者使用setTimeOut的简单版本,代码如下:

var cv = document.getElementById('cv');
var ctx = cv.getContext('2d');
var cvWidth = cv.width;
var cvHeight = cv.height;

// Simple scene description : an array of colored rects
var everyObject = [
  [60, 70, 30, 30, 'yellow']
];

// animation : always running loop.

function animate() {
  // call again next time we can draw
  requestAnimationFrame(animate);
  // clear canvas
  ctx.clearRect(0, 0, cvWidth, cvHeight);
  // draw everything
  everyObject.forEach(function(o) {
    ctx.fillStyle = o[4];
    ctx.fillRect(o[0], o[1], o[2], o[3]);
  });
  // 
  ctx.fillStyle = '#000';
  ctx.fillText('click to add 4 random rects with a delay', 10, 10);
}

animate();


// click handler to add random rects
window.addEventListener('click', function() {
  addRandRect();
  setTimeout(addRandRect, 300);
  setTimeout(addRandRect, 600);
  setTimeout(addRandRect, 900);
});

function addRandRect() {
  var randColor = Math.random() > 0.5 ? 'blue' : 'red';
  everyObject.push([Math.random() * cvWidth, Math.random() * cvHeight, 10 + Math.random() * 40, 10 + Math.random() * 40, randColor]);
}
  <canvas id='cv' width=400 height=200></canvas>

(顺便提一下,如果感兴趣的话,我在这里写了关于动画的内容:http://codepen.io/gamealchemist/post/animationcanvas1

好的,这个方法可以工作,但我不得不修改它,现在我认为这不是最佳实践。我注意到在for循环中,requestAnimationFrame不会触发并且会等待循环完成。所以我基本上是将我的逻辑添加到animate()方法中。你可以在我的问题末尾检查一下,我已经在那里添加了它。 - Hasholef

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接