动画的问题是你必须分步分步算法。
这意味着您必须将递归算法转换为迭代算法。
要做到这一点,您可以:
分裂您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();
})();
**警告**:您的小提琴使用'setInterval',但从未停止它!确保使用'clearInterval',或者更好地使用带有条件的'setTimeout'。 – Oriol