使用画布的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();