我正在尝试制作“成长树”的动画。问题是我无法连接下面这两个函数以使其正常工作。
到目前为止,我有一个从底部到顶部绘制直线(树干)的功能:
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);
我尝试了几个选项,但没有一个能给出正确的结果,所以我决定寻求帮助。
答案 0 :(得分:2)
动画的问题在于你必须分步算法。
这意味着您必须将递归算法转换为迭代算法。
为此,你可以:
在子功能[Demo]中拆分stick
功能:
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();
})();