2011-12-23 131 views
0

我想在使用更新渲染動畫循環的畫布上實現氣泡排序動畫。使用畫布的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 
}); 

回答

3

如果你可以重寫使用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/

我猜你是那種在朝着這個方向了,但我發現你的迭代是分佈在幾個功能有點混亂的方式,我更願意把它放在一個函數中。

注:這是怎樣的一個狡猾的實現只是做了我的頭頂部,所以我沒有時間來建立其規模或把它漆成...

1

你可以不喜歡它這

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