2016-08-06 46 views
3

我終於找到了如何動畫繪製貝塞爾曲線。我已經看到其他解決方案使用二次曲線來做到這一點,但我所做的事情需要4分,並且b樣條太難找到隨機地塊,再加上它是我想要做的事情;與貝齊爾Cuves。如何在html5畫布中繪製動畫貝塞爾曲線時保持流暢的線條

我的問題是我找不到一個好的,快速的速度沒有看到點或線。我必須錯過一些東西。有人能指出我的錯誤還是更有效的方法,以便在任何時間/速度下順利進行?我需要的是穩定,比去下面的例子快,但如果我這樣做了差距越來越大......與代碼

小提琴:如果需要更多的信息https://jsfiddle.net/qzsy8aL7/

//B(t) = (1 - t)^3P0 + 3t(1 - t)^2 P1 + 3t^2(1 - t)P2 + t^3P3 
function animatedBSpline(context, points, t) { 
    // Draw curve segment 
    context.beginPath(); 
    context.moveTo(
    Math.pow(1 - t, 3) * points[0].x + 
    3 * t * Math.pow(1 - t, 2) * points[1].x + 
    3 * Math.pow(t, 2) * (1 - t) * points[2].x + 
    Math.pow(t, 3) * points[3].x, 

    Math.pow(1 - t, 3) * points[0].y + 
    3 * t * Math.pow(1 - t, 2) * points[1].y + 
    3 * Math.pow(t, 2) * (1 - t) * points[2].y + 
    Math.pow(t, 3) * points[3].y 
); 

    // Draw spline segemnts 
    context.lineTo(
    Math.pow((1 - t) + 0.001, 3) * points[0].x + 
    3 * (t + 0.001) * Math.pow((1 - t) + 0.001, 2) * points[1].x + 
    3 * Math.pow(t + 0.001, 2) * (1 - (t + 0.001)) * points[2].x + 
    Math.pow(t + 0.001, 3) * points[3].x, 

    Math.pow((1 - t) + 0.001, 3) * points[0].y + 
    3 * (t + 0.001) * Math.pow((1 - t) + 0.001, 2) * points[1].y + 
    3 * Math.pow(t + 0.001, 2) * (1 - (t + 0.001)) * points[2].y + 
    Math.pow(t + 0.001, 3) * points[3].y 
); 

    //33d4ff 
    context.strokeStyle="#35bb23"; 
    context.lineJoin="round"; 
    context.lineWidth=2; 
    context.fillStyle = "black"; 
    context.stroke(); 
    context.fill(); 

    // Keep going until t = 1 
    if (t < 1) requestAnimationFrame(function() { 
    animatedBSpline(context, points, t + 0.01); 
    }); 
    else 
    context.closePath(); 
} 

請告訴我。我一整天都在這。

要添加: 如果我只是徹底繪製它與這些情節,而不是動畫它做的,顯然看起來很好,但只是想指出。它的東西與我的動畫方式我只是不知道。

+0

那麼我注意到,在每個段您調用'context.beginPath()'和'context.moveTo(...)'這將導致段變得不相交。您應該只在曲線的開頭調用這兩種方法,而不是在每一個點上。 –

+0

我可以在哪裏放?如果我把它放在其他任何地方測試它,或者用多條小線條填充黑色(我認爲)或者什麼都不做。 – Grant

+0

https://jsfiddle.net/qzsy8aL7/1/我不知道這是你要做什麼,但我讓這條線連續並刪除了令人討厭的'eval',而不是將'points'變成一個數組。 –

回答

2

這裏的綠色貝塞爾曲線的動畫全部更新代碼:

(function() { 
 
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; 
 

 
    $(function() { 
 
    var canvas = $('#drawings')[0]; 
 
    var context = canvas.getContext('2d'); 
 
    var lineLength = 0; 
 
    var lineLengthMax = 7; 
 
    var timer; 
 

 
    // Define points 
 
    var points = [[{ 
 
     x: 600, 
 
     y: 200 
 
    }, { 
 
     x: 550, 
 
     y: 100 
 
    }, { 
 
     x: 350, 
 
     y: 100 
 
    }, { 
 
     x: 300, 
 
     y: 250 
 
    }], 
 
    [{ 
 
     x: 350, 
 
     y: 250 
 
    }, { 
 
     x: 75, 
 
     y: 225 
 
    }, { 
 
     x: 30, 
 
     y: 400 
 
    }, { 
 
     x: 120, 
 
     y: 450 
 
    }], 
 
    [{ 
 
     x: 200, 
 
     y: 450 
 
    }, { 
 
     x: 5, 
 
     y: 380 
 
    }, { 
 
     x: 25, 
 
     y: 750 
 
    }, { 
 
     x: 175, 
 
     y: 610 
 
    }], 
 
    [{ 
 
     x: 200, 
 
     y: 520 
 
    }, { 
 
     x: 150, 
 
     y: 560 
 
    }, { 
 
     x: 175, 
 
     y: 750 
 
    }, { 
 
     x: 325, 
 
     y: 605 
 
    }], 
 
    [{ 
 
     x: 400, 
 
     y: 395 
 
    }, { 
 
     x: 275, 
 
     y: 450 
 
    }, { 
 
     x: 250, 
 
     y: 750 
 
    }, { 
 
     x: 565, 
 
     y: 655 
 
    }], 
 
    [{ 
 
     x: 515, 
 
     y: 540 
 
    }, { 
 
     x: 500, 
 
     y: 695 
 
    }, { 
 
     x: 660, 
 
     y: 675 
 
    }, { 
 
     x: 675, 
 
     y: 560 
 
    }], 
 
    [{ 
 
     x: 600, 
 
     y: 400 
 
    }, { 
 
     x: 790, 
 
     y: 315 
 
    }, { 
 
     x: 1005, 
 
     y: 500 
 
    }, { 
 
     x: 675, 
 
     y: 585 
 
    }], 
 
    [{ 
 
     x: 500, 
 
     y: 250 
 
    }, { 
 
     x: 700, 
 
     y: 100 
 
    }, { 
 
     x: 775, 
 
     y: 350 
 
    }, { 
 
     x: 700, 
 
     y: 380 
 
    }]]; 
 

 
    //33d4ff 
 
    context.strokeStyle="#35bb23"; 
 
    context.lineJoin="round"; 
 
    context.lineWidth=2; 
 

 
    doLineDraw(); 
 
    //animatedBSpline(context, points, 0); 
 

 
    function doLineDraw() { 
 
     if (lineLength <= lineLengthMax) { 
 
     clearTimeout(timer); 
 

 
     // Kick things off at t = 0 
 
     context.beginPath(); 
 
     animatedBSpline(context, points[lineLength], 0); 
 
     //animatedBSpline(context, eval('points'+(lineLength)), 0); 
 

 
     lineLength++; 
 
     if (lineLength <= lineLengthMax) 
 
      timer = setTimeout(doLineDraw, 2000); 
 
     } 
 
    } 
 

 
    //B(t) = (1 - t)^3P0 + 3t(1 - t)^2 P1 + 3t^2(1 - t)P2 + t^3P3 
 
    function animatedBSpline(context, points, t) { 
 
     // Draw curve segment 
 
     if (t == 0) 
 
     context.moveTo(
 
      Math.pow(1 - t, 3) * points[0].x + 
 
      3 * t * Math.pow(1 - t, 2) * points[1].x + 
 
      3 * Math.pow(t, 2) * (1 - t) * points[2].x + 
 
      Math.pow(t, 3) * points[3].x, 
 

 
      Math.pow(1 - t, 3) * points[0].y + 
 
      3 * t * Math.pow(1 - t, 2) * points[1].y + 
 
      3 * Math.pow(t, 2) * (1 - t) * points[2].y + 
 
      Math.pow(t, 3) * points[3].y 
 
     ); 
 
     
 
     // Draw spline segemnts 
 
     context.lineTo(
 
     Math.pow((1 - t) + 0.001, 3) * points[0].x + 
 
     3 * (t + 0.001) * Math.pow((1 - t) + 0.001, 2) * points[1].x + 
 
     3 * Math.pow(t + 0.001, 2) * (1 - (t + 0.001)) * points[2].x + 
 
     Math.pow(t + 0.001, 3) * points[3].x, 
 

 
     Math.pow((1 - t) + 0.001, 3) * points[0].y + 
 
     3 * (t + 0.001) * Math.pow((1 - t) + 0.001, 2) * points[1].y + 
 
     3 * Math.pow(t + 0.001, 2) * (1 - (t + 0.001)) * points[2].y + 
 
     Math.pow(t + 0.001, 3) * points[3].y 
 
    ); 
 
\t \t \t 
 
     
 
     //context.fillStyle = "black"; 
 
     context.stroke(); 
 
     //context.fill(); 
 
\t \t \t 
 
     // Keep going until t = 1 
 
     if (t < 1) requestAnimationFrame(function() { 
 
     animatedBSpline(context, points, t + 0.01); 
 
     }); 
 
    } 
 
    }); 
 
}());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<section> 
 
    <article> 
 
    <canvas id="drawings" width="1000" height="1000" /> 
 
    </article> 
 
</section>

幾個關鍵點,其中一些是相切的問題。

  • 避免使用eval來引用具有數字後置的變量名稱。只需使用數組。
  • 您之所以繪製點而不是線,是因爲在每個新頂點之前調用context.beginPath()context.moveTo(),這導致context.stroke()context.fill()「忘記」前面的指令。

我感動context.beginPath()animatedBSpline()和指定context.moveTo()t==0該函數內運行,這種方式有沒有脫節點。我希望有所幫助。

+0

非常感謝你,並解釋。貝塞爾曲線上沒有這麼多,只好瘋狂地挖掘。 – Grant

+0

protip:只使用直接乘法而不是'Math.pow',因爲我們處理的是較低的功率。 'let t2 = t * t,mt = 1-t,mt2 = mt * mt,t3 = t2 * t,mt3 = mt * mt2',現在您也不會經常調用函數調用開銷。相同的步長:使其成爲一個變種,所以你可以很容易地改變它,而不是'0.001'硬編碼到處(小曲線,0。001可能比你實際需要的數量級要多) –

+0

@ Mike'Pomax'Kamermans謝謝。我從字面上複製並粘貼了數學,我在這裏談到的只是被問及的問題(和''eval') –