2014-05-23 4 views
0

알고리즘을 더 잘 이해하기 위해 작은 자바 스크립트 애니메이션을 만들려고합니다. 알고리즘은 다음과 같이 2 차원 배열에서 작동 : - 등등캔버스에서 애니메이션의 지연을 추가하는 방법은 무엇입니까?

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); 
      } 
     } 
    } 
} 

그래서 내가 어떻게 randomFill() 함수 후 100 밀리 말을 캔버스에 그리기 위해 호출 할 수 있습니다. 캔버스에 배열의 변화를 보여주고 싶지만 약간의 지연 후에 사람들이 볼 수 있습니다.

+0

setTimeout을 사용하지 않는 이유는 무엇입니까? – swornabsent

답변

1

당신이 예외없이 비동기 타이머를 포함하는 것 지연 등을위한 루프보다 다른 뭔가를 사용해야하는 반복을 지연하고 사용할 수 그 때문에 수 없습니다 다음과 같을 수

for-loop 반복에서 "sleep"합니다.

해결책은 for-loops를 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 

EXAMPLE FIDDLE

next() 메서드는 호출 될 때마다 단순히 내부 루프 (j)를 증가 시켰습니다. 첫 번째 기준이 충족되면 (j = gridSize) j이 재설정되고 바깥 쪽 루프가 증가합니다 (i).

또한 외부 루프가 기준 (i = gridSize)을 충족 시키면 루프가 종료 점을 입력하여 배열을 다시 초기화하고 ij을 재설정하고 루프를 다시 시작하는 등의 작업을 수행 할 수 있습니다.

ij 세계적 함수 내부에서이를 사용할 수 있도록 ij를 선언, 당신은 코드 범위로 글로벌 윈도우 객체로 실행됩니다 setTimeout를 호출 할 때와 같은 전역에 있습니다. 이것 주위에 방법이 있지만 여기서는 간단하게하기 위해이 주제를 남깁니다.

+0

고맙습니다. 나는 그것을 적용하고 그것을 작동합니다. 나는 잘못된 방향을 찾고 있었다. 감사. –

0

setTimeout

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(...) 
+0

setTimeout (randomFill(), 1000)으로 setTimeout을 시도했습니다. 캔버스를 업데이트하고 싶지만 아무런 효과가없는 곳에서. 캔버스의 최종 이미지 만 표시되며 전환은 표시되지 않습니다. –

+0

너무 가까이! setTimeout은 함수를 받아들입니다. 함수 블록을 전달하지 않고'setTimeout (randomFill(), x)'을 호출하면 randomFill()을 실행하고 반환 값을 setTimeout()에 전달합니다. 당신은 대답이나'setTimeout (randFill, x)'(참고 : 괄호 안 함) – swornabsent

+0

의 실마리를 찾지 못했습니다. 그래서 setTimeout (function() {randomFill();}, 1000); 어디서나 캔버스를 업데이트해야합니다. 그러나 캔버스는 1 초 동안 기다렸다가 최종 이미지를 보여줍니다. –

1

window.requestAnimationFrame을 함께

효율적으로 다시 그리기 위해 브라우저 새로 고침 빈도와 루프 실행을 조정하므로이 방법을 사용하는 것이 좋습니다. 또한 브라우저가 다른 브라우저 탭으로 전환하면 (모바일 장치의 배터리 절약) 애니메이션 루프가 일시 중단됩니다.

setTimeout과 마찬가지로 requestAnimationFrame (간단히 RAF라고 부름)에는 실행할 콜백 함수가 제공됩니다. RAF는 브라우저 및 하드웨어와 동기화 된 매너에서 해당 콜백 함수를 실행합니다.

function animate(timestamp){ 

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

} 

RAF가 호출 기능 (즉, 애니메이션의 타임 스탬프의)에 타임 스탬프를 보냅니다

는 다음과 같은 일반적인 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> 
+0

알고리즘 루프가있을 때마다 ARR 요소의 값을 업데이트 할 때마다 randomFill();을 사용하여 캔버스를 업데이트하는 방식으로 사용할 수 있습니까? 100ms 동안 그대로두고 다음 반복을 실행하지 마십시오. 나는 그것을 어떻게 할 것이냐? ??? –

+0

물론, randomFill을 한 후에 다른 루프를 요청하고'lastTime' 변수를 재설정하십시오. 그렇게하면 타이머가 다시 경과하기 전에 100ms가 완전히 걸릴 것입니다. 내 편집 된 답변보기 – markE

+0

오 이런, 나는 총 멍청 아. 나는 아직도 제대로 작동하지 못한다. 좋아, 그래서 당신의 코드를 붙여 넣습니다. 그러나 아무 일도 일어나지 않습니다. 인터넷에서 많은 자료를 읽었지 만 여전히 효과가 없습니다. 내가 원하는 유일한 것은 당신이 arr 요소의 값을 업데이트 할 때마다 randomFill()을 사용하여 캔버스를 다시 칠하기를 원할뿐 아니라 전환이 일어날 수 있도록 잠깐 멈추는 것입니다. 요컨대, 루프의 모든 반복을 느리게하고 싶습니다. –

관련 문제