Анимация в Javascript с использованием холста - PullRequest
0 голосов
/ 23 декабря 2011

Я пытаюсь реализовать анимацию пузырьковой сортировки на холсте, используя цикл обновления анимации рендеринга.

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

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

Ответы [ 2 ]

3 голосов
/ 23 декабря 2011

Если вы можете переписать цикл, используя 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 голос
/ 23 декабря 2011

Вы можете сделать это так

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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...