動畫的問題是你必須分步分步算法。
這意味着您必須將遞歸算法轉換爲迭代算法。
要做到這一點,您可以:
分裂您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