使用画布的Javascript中的动画

问题描述:

我想在使用更新渲染动画循环的画布上实现气泡排序动画。使用画布的Javascript中的动画

因此,如果下面是泡沫的实际非动画版的排序

for(var i = 0 ;i < arr.length - 1; i++) 
    for(var j = 0 ;j < arr.length - 1; j++) 
     if(arr[j] > arr[j+1]) { swap arr[j], arr[j+1]} 

我的要求现在的问题是,在每一个交换或比较指令,所有的酒吧(数组元素)应该被重新绘制。但由于多年平均值的JavaScript支持任何睡眠功能,我不能简单地转换上面的代码动画版如下图所示

for(var i = 0 ;i < arr.length - 1; i++) 
    for(var j = 0 ;j < arr.length - 1; j++){ 
     if(arr[j] > arr[j+1]) { after swap..... } 
     call to draw method // draw all bars 
     sleep(); // doesnot work in javascript 
    } 

天色我能够使用setTimeout函数来实现它。但我无法弄清楚,我们怎样才能将嵌套循环内部的代码(比较和交换)完全折叠成单独的函数(更新函数),而不会丢失索引变量的状态。

所以,请让我知道是否有任何优雅的解决方案的问题 下面是我的实现通过展开循环到单独的函数。当然,如果算法包含更紧密的环路,我的实现不会扩展。

$(function(){ 
    var canvas = $("#mycan"); 
    var ctx = canvas.get(0).getContext("2d"); 
    (function Graph(nBars,ctx){ 
     this.nBars = nBars; 
     this.Bars = []; 
     var MaxBarLen = 250; 
     function Bar(color,height,x,y){ 
      this.color = color; 
      this.height = height; 
      this.width = 10; 
      this.x = x; 
      this.y = y; 

     }; 
     Bar.prototype.toString = function(){ 
      return "height: "+height+" x: "+x+" y: "+y; 
     }; 
     function init(){ 
      //create bars randomly of size 10 - 250 
      for(var i = 0;i < nBars; i++){ 
       Bars.push(new Bar("rgb(0,0,0)", Math.floor(Math.random()*MaxBarLen+10),15*i+1,MaxBarLen)) 
      } 
      algo(); 
      //draw(); 
     }; 
     //method to draw the bars collection to the given context 
     this.draw = function(){ 
      ctx.clearRect(0,0,500,500); 
      for(var i = 0; i < nBars; i++){ 
       if(Bars[i].color == "rgb(0,0,0)") 
        ctx.fillRect(Bars[i].x,Bars[i].y,Bars[i].width,-Bars[i].height); 
       else{ 
        ctx.fillStyle = Bars[i].color; 
        ctx.fillRect(Bars[i].x,Bars[i].y,Bars[i].width,-Bars[i].height); 
        ctx.fillStyle = "rgb(0,0,0)"; 
       } 
      } 
     }; 
     // BUBBLE SORT ALGORITHM 
     var I = -1, J = -1; 
     this.algo = function(){ 
      updateI(); // invocate outer loop 
     }; 
     //outer loop 
     var updateI = function(){ 
      console.log("updateI", I, J); 
      if(I < Bars.length - 1){ 
       J = -1; 
       I++; 
       updateJ(); 

      } 
     }; 
     //inner loop 
     var updateJ = function(){ 
      console.log("updateJ", I, J); 
      if(J < Bars.length - 2){ 
       J++; 
       setTimeout(compare,100); // trigger the compare and swap after very 100 ms 
      }else{ 
       updateI(); 
      } 
     }; 
     //actual compare function 
     var compare = function(){ 
      console.log("compare ", I, J); 
      Bars[J].color = "rgb(0,255,0)"; 
      Bars[J+1].color = "rgb(0,0,255)"; 
      draw(); //draw the frame. 
      if(Bars[J].height > Bars[J+1].height){ 
        //update  
       temp = Bars[J].height; 
       Bars[J].height = Bars[J+1].height; 
       Bars[J+1].height = temp; 
      } 

      Bars[J].color = Bars[J+1].color = "rgb(0,0,0)"; 
      updateJ(); //render next iteration 
     }; 

     //invoke bar creation and bubble sort algorithm 
     init(); 
    })(10,ctx); // 10 bars and context 
}); 

如果你可以重写使用setTimeout触发每次迭代,然后,让浏览了一下,每次迭代之间重绘循环。因此,也许是这样的:

function doIteration(i,j,max,callback) { 
    callback(i,j); 
    if (++j >= max){ 
    j = 0; 
    i++; 
    } 
    if (i < max) 
     setTimeout(function() { doIteration(i,j,max,callback); }, 100); 
} 

var arr = [12, 3, 4, 1, 20, 2, 5, 7, 9, 13, 19, 6, 8, 14, 18, 10, 15, 11, 16, 17]; 

function drawFunction() { 
    document.getElementById("output").innerHTML = arr.join(",") + "<br>"; 
} 

doIteration(0,0,arr.length-1,function(i,j){ 
    var t; 
    if(arr[j] > arr[j+1]) { 
     t = arr[j]; 
     arr[j] = arr[j+1]; 
     arr[j+1] = t; 
    } 
    drawFunction(); 
}); 

呼叫doIteration与初始值i和j和最大值(在这种情况下,它们都具有相同的最大值,所以我离开它作为一个参数),和回调函数将在每次迭代中调用并传递当前的i和j。真的应该在第一次调用回调函数之前测试i和j的值,但我会把它作为读者的练习。

这里有很多简单的拉伸工艺演示:http://jsfiddle.net/Kpkxw/2/

我猜你是那种在朝着这个方向了,但我发现你的迭代是分布在几个功能有点混乱的方式,我更愿意把它放在一个函数中。

注:这是怎样的一个狡猾的实现只是做了我的头顶部,所以我没有时间来建立其规模或把它漆成...

你可以不喜欢它这

var iMax = 10, jMax = 10; 
var i = 0, j=0; 

function firstloop(){ 

    if(i < iMax){ 

    secondloop(); 

    }else{ 

    //final statements 

    } 
} 

function secondloop(){ 

    if(j < jMax){ 

     //statements 

     j++; 
     setTimeout(secondloop, 100)  

    }else{ 

     j = 0;i++; 
     firstloop(); // You can add a time out here if needed 
    } 

} 

firstloop();