我们说我有一条路:
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。
我想用它来实现动画。如果有一种更简单的方法,也欢迎。
答案 0 :(得分:2)
使用D3.js动画制作SVG弧时,我遇到了类似的问题。我的解决方案借鉴了这一点。它不是最直观的,但在D3动画中常用。它需要仔细设置仪表板偏移和线长。 CSS Tricks gives a good explanation of the technique here which I strongly recommend reading before viewing my code
我用这种技术implemented for your line here修改了上面的JSFiddle。请注意,即使线路自行循环,这也会起作用。
有关行长的说明:
此实现要求您知道线的大约长度,以便可以将长度var设置为大于它。对于贝塞尔曲线和二次曲线,这很棘手,但仍可以完成(this SO question looks promising)。对于我的演示,我使用了试验和错误来发现你的大约是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();
}
答案 1 :(得分:2)
使用均匀间隔点绘制复杂路径的演示:
http://jsfiddle.net/m1erickson/2fodu9pa/
统一速度概述
“速度”定义为每单位时间的距离。
“统一速度”因此每单位时间行进一致的指定距离。
因此,以每1/60秒2个像素的路径移动将是以均匀速度移动的示例。
要行进2个像素,您必须计算路径上距离上一个点2个像素的点。
逐步绘制包含线条的路径&amp;均匀速度的曲线需要数百次小计算。
以下是如何确定沿路径均匀间隔的点阵列:
将您的路径划分为其细分:直线,二次曲线,贝塞尔曲线,直线。
使用定义每个段的数学公式计算每个段的许多(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);
祝你的项目好运!
答案 2 :(得分:1)
这是我的解决方案,基本上在你的路径上画一个矩形,然后每一帧更新移动矩形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);
}