2013-12-22 26 views
1

我正在試圖製作一棵「正在增長的樹」的動畫。問題是我無法連接下面的這兩個函數使其正常工作。將遞歸與其他函數連接在一起| canvas,JavaScript

到目前爲止,我還繪製從底部直線(主幹)到頂部的功能:
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

**警告**:您的小提琴使用'setInterval',但從未停止它!確保使用'clearInterval',或者更好地使用帶有條件的'setTimeout'。 – Oriol

回答

2

動畫的問題是你必須分步分步算法。

這意味着您必須將遞歸算法轉換爲迭代算法。

要做到這一點,您可以:

  1. 分裂您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(); 
    } 
    
  2. 而不是調用函數,推到一個隊列調用(陣列)並循環:

    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(); 
})(); 
+0

非常感謝!這真的很有幫助。我會玩弄代碼。 – user3127305