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