[英]Draw HTML5/Javascript Canvas Path in Time
假設我有一條路:
var context = canvas.getContext('2d');
context.beginPath();
context.moveTo(100, 20);
context.lineTo(200, 160);
context.quadraticCurveTo(230, 200, 250, 120);
context.bezierCurveTo(290, -40, 300, 200, 400, 150);
context.lineTo(500, 90);
context.lineWidth = 5;
context.strokeStyle = 'blue';
context.stroke();
這會一次打印所有路徑:
如何將路徑拆分為給定長度的子路徑? 例如: context.splitCurrentPathIntoSubPath(0, 0.75)
應僅返回路徑的前3/4。
我想用它來實現一個動畫。 如果有一種更簡單的方法,也歡迎。
使用D3.js動畫SVG弧時,我遇到了類似的問題。 我的解決方案借鑒了這一點。 它不是最直觀的,但在D3動畫中常用。 它需要仔細設置儀表板偏移和線長。 CSS Tricks在這里給出了很好的解釋,我強烈建議在查看代碼之前閱讀 。
我已經使用為您的線路實現的這種技術修改了上面的JSFiddle。 請注意,即使線路自行循環,這也會起作用。
關於線長的說明:
此實現要求您知道線的大約長度,以便您可以將長度var設置為大於它。 對於貝塞爾曲線和二次曲線,這很棘手,但仍然可以完成( 這個問題看起來很有希望 )。 對於我的演示,我使用了試驗和錯誤來發現你的大約是608px。 將長度設置為10000可能會確保您的線條始終正確繪制,但代價是每毫秒都會調用大量不必要的間隔回調。 底線是:如果你關心性能,找出更好的公式; 如果不這樣做,請將該變量設置為高。
碼:
HTML
<body>
<canvas id="canvas" width="500" height="500">
webgl couldn't be started
</canvas>
</body>
JavaScript的
canvasHolder = document.getElementById( 'canvas' );
context = canvasHolder.getContext('2d');
context.fillStyle = 'white';
var w = canvasHolder.width, h = canvasHolder.height;
context.fillRect( 0, 0, w, h);
//set the direction the line draws in
//1->ltr | -1->rtl
var dir = -1;
//IMPORTANT: this must be set to greater than the length
//of the line
var length = 608;
//the speed of the line draw
var speed = 1;
var progress = 0;
var lineInterval;
//Go!
context.globalCompositeOperation='copy';
drawLine();
function drawLine() {
//this clears itself once the line is drawn
lineInterval = setInterval(updateLine, 1);
}
function updateLine() {
//define the line
defineLine();
if(progress<length)
{
progress+=speed;
moveDash(progress, dir);
} else {
clearInterval(lineInterval);
}
}
function defineLine() {
context.beginPath();
context.moveTo(100, 20);
context.lineTo(200, 160);
context.quadraticCurveTo(230, 200, 250, 120);
context.bezierCurveTo(290, -40, 300, 200, 400, 150);
context.lineTo(500, 90);
context.lineWidth = 5;
context.strokeStyle = 'blue';
}
function moveDash(frac, dir) {
//default direction right->left
var dir = dir || -1
context.setLineDash([length]);
context.lineDashOffset = dir*(frac+length);
context.stroke();
}
使用均勻間隔點繪制復雜路徑的演示:
http://jsfiddle.net/m1erickson/2fodu9pa/
統一速度概述
“速度”定義為每單位時間的距離。
因此, “均勻速度”每單位時間行進一致的指定距離。
因此,以每1/60秒2個像素的路徑移動將是以均勻速度移動的示例。
要行進2個像素,您必須計算沿您的路徑距離上一個點2個像素的點。
以統一的速度逐步繪制包含直線和曲線的路徑需要數百次小的計算。
以下是如何確定沿路徑均勻間隔的點陣列:
將您的路徑划分為它們的線段:直線,二次曲線,貝塞爾曲線,直線。
使用定義每個段的數學公式計算每個段的許多(300+)個點(請參閱下面的公式)並將這些點放在數組中。
沿着每個點順序行走並計算點之間的距離(參見下面的公式)。
保持沿點的總累積距離。
當前行進的點達到指定長度時,將該點保存在第二個數組中。
然后,為了逐步為路徑設置動畫,您可以創建一個動畫循環,該循環將線條繪制到第二個數組中的每個下一個點。
注意:如果保持指定距離足夠小(例如1-2像素),則繪制的線條在必要時顯示為彎曲。
以下是支持此方法的公式:
沿線計算點數:
// T is an interval between 0.00 and 1.00
// To divide a Line into 300 parts you would call the function 300 times
// with T increasing 1.00/300 each time
function getLineXYatPercent(startPt,endPt,T) {
var dx = endPt.x-startPt.x;
var dy = endPt.y-startPt.y;
var X = startPt.x + dx*T;
var Y = startPt.y + dy*T;
return( {x:X,y:Y} );
}
沿二次曲線計算點:
// T is an interval between 0.00 and 1.00
// To divide a Quadratic Curve into 300 parts you would call the function 300 times
// with T increasing 1.00/300 each time
function getQuadraticBezierXYatT(startPt,controlPt,endPt,T) {
var x = Math.pow(1-T,2) * startPt.x + 2 * (1-T) * T * controlPt.x + Math.pow(T,2) * endPt.x;
var y = Math.pow(1-T,2) * startPt.y + 2 * (1-T) * T * controlPt.y + Math.pow(T,2) * endPt.y;
return( {x:x,y:y} );
}
沿貝塞爾曲線計算點:
// T is an interval between 0.00 and 1.00
// To divide a BezierCurve into 300 parts you would call the function 300 times
// with T increasing 1.00/300 each time
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T
+ (3 * b + T * (-6 * b + b * 3 * T)) * T
+ (c * 3 - c * 3 * T) * t2
+ d * t3;
}
2點之間的距離:
var dx=point2.x-point1.x;
var dy=point2.y-point1.y;
var distance=Math.sqrt(dx*dx+dy*dy);
祝你的項目好運!
這是我的解決方案,基本上在您的路徑上方繪制一個矩形,然后每個幀更新移動矩形1 X位置,所以慢慢地將框移動並遠離路徑,它看起來像是在繪制動畫路徑,
我已經把它保存在jsfiddle上了:)這里是獨立代碼
window.addEventListener( "load", firstLoaded, false);
then = Date.now();
setInterval(main, 1); // Execute as fast as possible
var cube_x_position = 0;
function main()
{
context.beginPath();
context.moveTo(100, 20);
context.lineTo(200, 160);
context.quadraticCurveTo(230, 200, 250, 120);
context.bezierCurveTo(290, -40, 300, 200, 400, 150);
context.lineTo(500, 90);
context.lineWidth = 5;
context.strokeStyle = 'blue';
context.stroke();
context.fillRect(cube_x_position, 0, canvasHolder.width, canvasHolder.height);
if(cube_x_position < canvasHolder.width)
{
cube_x_position += 1;
}
}
function firstLoaded()
{
canvasHolder = document.getElementById( 'canvas' );
context = canvasHolder.getContext('2d');
context.fillStyle = "#AAAAAA";
context.fillRect( 0, 0, 500, 500);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.