我找到了一个很好的递归函数示例,它生成一个简单的分形树here(如下所示)。
var canvas = document.getElementById('canvas_main');
canvas.width = 600;
canvas.height = 600;
var ctx = canvas.getContext('2d');
function draw(x, y, len, ang){
ctx.save();
ctx.beginPath();
ctx.translate(x, y);
ctx.rotate(ang * Math.PI/180);
ctx.moveTo(0, 0);
ctx.lineTo(0, -len);
ctx.stroke();
if (len < 10) {
ctx.restore();
return;
}
draw(0, -len, len*0.8, -15);
draw(0, -len, len*0.8, 15);
ctx.restore();
}
draw(300, 600, 120, 0);
&#13;
<canvas id="canvas_main"></canvas>
&#13;
我想延迟迭代的绘制。我认为setTimeout()函数可以帮助我,但我似乎无法做到正确。
最让我困惑的是为什么简单地包装draw()函数不会起作用:
setTimeout(function(){
draw(0, -len, len*0.8, 15);
draw(0, -len, len*0.8, -15);
ctx.restore();
},500)
上下文转换给我带来了麻烦。如果第二个绘图功能和恢复功能被禁用,我可以让一方工作:
setTimeout(function(){
draw(0, -len, len*0.8, 15);
//draw(0, -len, len*0.8, -15);
//ctx.restore();
},500)
但我没有比这更进一步。如何逐步绘制整棵树? 有人可以解释为什么包装不起作用?谢谢!
编辑: 作为一个额外的问题,是否可以使用requestAnimationFrame()方法执行此操作?
答案 0 :(得分:1)
用于每次迭代移动线的方法不会跟踪分支的位置,而是依赖于ctx.save()
和ctx.restore()
状态堆栈函数来返回正确的位置以移动到下一个分支。
使用set timeout意味着在递归到达最后一个分支之前调用恢复。
setTimeout(function(){
draw(0, -len, len*0.8, 15); // this function draws and exits
draw(0, -len, len*0.8, -15); // this function draws and exits
ctx.restore(); // the restore is called before the above two functions
// have completed their next iterations as that is waiting
// for the timeouts.
},500)
只有在绘制了上面的所有分支后才能调用恢复。
简单的方法是删除保存和恢复并手动执行转换。这样,每个分支的状态都存储在函数中,而不是单独的堆栈。
以下是使用超时的修改。 x和y位置现在包含分支开始位置,下一个分支位置在代码中计算。
超时对每个分支都有一个,并且时间稍微随机化,这使渲染流程保持平滑。
还添加了线宽以获得乐趣。 :)
var canvas = document.getElementById('canvas_main');
canvas.width = 600;
canvas.height = 600;
var ctx = canvas.getContext('2d');
function draw(x, y, len, ang, width){
ctx.lineWidth = width;
// draw the branch
ctx.beginPath();
ctx.lineTo(x, y);
// get the end position
x += Math.cos(ang) * len;
y += Math.sin(ang) * len;
ctx.lineTo(x, y);
ctx.stroke();
if (len > 10) {
setTimeout(()=>{
draw(x , y , len * 0.8, ang - 0.2, width * 0.8);
}, 300 + Math.random() * 100);
setTimeout(()=>{
draw(x , y , len * 0.8, ang + 0.2, width * 0.8);
}, 300 + Math.random() * 100);
}
}
draw(300, 600, 120, -Math.PI /2,4);
&#13;
<canvas id="canvas_main"></canvas>
&#13;