我正在尝试制作“正在生长的树”的动画。问题是我无法连接下面这两个函数以使其正常工作。
到目前为止,我有一个从底部到顶部绘制直线(树干)的函数:
http://jsfiddle.net/FTCcW/1/
下面是绘制整棵树的函数代码:
function stick(d) {
if (d==0)
return;
context.beginPath();
context.moveTo(0,70);
context.lineTo(0,0);
context.lineWidth = 3;
context.strokeStyle = 'gray';
context.stroke();
if (d==1) {
context.strokeStyle = 'green';
context.stroke(); }
context.save();
context.scale(0.75,0.75);
context.translate(-35,-60);
context.rotate(-30 * Math.PI/180);
stick(d-1);
context.restore();
context.save();
context.scale(0.75,0.75);
context.translate(35,-60);
context.rotate(30 * Math.PI/180);
stick(d-1);
context.restore();
}
stick(17);
我尝试了几个选项,但没有一个给出正确的结果,所以我决定寻求帮助。
最佳答案
动画的问题在于您必须逐步拆分算法。
这意味着您必须将递归算法转换为迭代算法。
为此,您可以:
将您的
stick
函数拆分为子函数[ Demo ]:function pre(i) { context.save(); context.scale(0.75,0.75); context.translate(i * 35,-60); context.rotate(i * 30 * Math.PI/180); } function post() { context.restore(); } function middle(d) { context.beginPath(); context.moveTo(0,70); context.lineTo(0,0); context.lineWidth = 3; context.strokeStyle = 'gray'; context.stroke(); if (d==1) { context.strokeStyle = 'green'; context.stroke(); } } function stick(d, i) { if(i) pre(i); if(d > 0) { middle(d); stick(d-1, -1); stick(d-1, 1); } if(i) post(); }
不是调用函数,而是将调用推送到队列(数组)并循环它:
function stick(n, i) { function main(d, i) { // Note the order of pushing is the inverse! // You must push first the last function if(i) queue.push([], post); if(d > 0) { queue.push([d-1,-1], main); queue.push([d-1,1], main); queue.push([d], middle); } if(i) queue.push([i], pre); } queue.push([n, 0], main); while(queue.length) { (queue.pop()).apply(null, queue.pop()); } }
完整代码[ Demo ]:
function stick(n, i) {
var queue = [];
function pre(i) {
context.save();
context.scale(0.75,0.75);
context.translate(i * 35,-60);
context.rotate(i * 30 * Math.PI/180);
}
function post() {
context.restore();
}
function middle(d) {
context.beginPath();
context.moveTo(0,70);
context.lineTo(0,0);
context.lineWidth = 3;
context.strokeStyle = 'gray';
context.stroke();
if (d==1) {
context.strokeStyle = 'green';
context.stroke();
}
}
function main(d, i) {
if(i) queue.push([], post);
if(d > 0) {
queue.push([d-1,-1], main);
queue.push([d-1,1], main);
queue.push([d], middle);
}
if(i) queue.push([i], pre);
}
queue.push([n, 0], main);
while(queue.length) {
(queue.pop()).apply(null, queue.pop());
}
}
现在,将它转换为动画是微不足道的。只需将 while 循环替换为以下内容:
(function step() {
if (queue.length) {
(queue.pop()).apply(null, queue.pop());
setTimeout(step, 100);
}
})();
但是,由于只有 main
函数会进行视觉更改,所以最好使用 [ Demo ]
(function step() {
if (queue.length) {
var f = queue.pop(),
args = queue.pop();
f.apply(null, args);
if(f === main) setTimeout(step, 100);
else step();
}
})();
或者您可能希望在每个步骤中执行更多操作,[ Demo ]:
var iter = 1000;
(function step() {
var i = iter,
d = new Date();
while (queue.length && --i>=0) {
var f = queue.pop(),
args = queue.pop();
f.apply(null, args);
}
iter = Math.max(50, iter*60/(new Date()-d)|0);
if (queue.length) f === main ? setTimeout(step, 100) : step();
})();
关于javascript - 将递归与其他函数连接在一起 | Canvas ,JavaScript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20731024/