2011-12-23 2 views
0

Я пытаюсь реализовать анимацию анимации пузыря на холсте с помощью цикла анимации рендеринга рендеринга.Анимация в Javascript с помощью canvas

так, если следующая фактическая не анимационная версия пузырьковой сортировки

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(); 
Смежные вопросы