在 html5 canvas 中绘制动画贝塞尔曲线时如何保持流畅的线条
How to keep smooth lines when drawing out animated bezier curves in html5 canvas
我终于找到了如何动画绘制贝塞尔曲线。我见过其他使用二次曲线来做到这一点的解决方案,但我所做的需要 4 个点,而且 b 样条很难找到随机图,而且这正是我想要做的;使用贝塞尔曲线。
我的问题是我无法在没有看到点或线的情况下找到良好、快速的速度。我一定是错过了什么。有人可以指出我的错误或更有效的方法来让这一切顺利进行 time/speed 吗?我需要它比下面的例子更稳定和更快,但如果我再这样做,差距会越来越大...
fiddle 代码: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();
}
如果需要更多信息,请告诉我。我整天都在做这个。
添加:
如果我只是直接用这些图画出来,而不是动画它正在完成,它看起来很好,显然,但只是想指出这一点。这与我制作动画的方式有关,我只是不知道。
这是带有绿色贝塞尔曲线动画的完整更新代码:
(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
);
//context.fillStyle = "black";
context.stroke();
//context.fill();
// 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
来引用编号为 post 的变量名。只需使用数组即可。
- 你绘制点而不是线的原因是因为你在每个新顶点之前调用了
context.beginPath()
和 context.moveTo()
,这导致 context.stroke()
和 context.fill()
到 "forget" 前面的说明。
我将 context.beginPath()
移到 animatedBSpline()
之外,并在该函数内的 t==0
处将 context.moveTo()
指定为 运行,这样就没有脱节点了.希望对您有所帮助。
我终于找到了如何动画绘制贝塞尔曲线。我见过其他使用二次曲线来做到这一点的解决方案,但我所做的需要 4 个点,而且 b 样条很难找到随机图,而且这正是我想要做的;使用贝塞尔曲线。
我的问题是我无法在没有看到点或线的情况下找到良好、快速的速度。我一定是错过了什么。有人可以指出我的错误或更有效的方法来让这一切顺利进行 time/speed 吗?我需要它比下面的例子更稳定和更快,但如果我再这样做,差距会越来越大...
fiddle 代码: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();
}
如果需要更多信息,请告诉我。我整天都在做这个。
添加: 如果我只是直接用这些图画出来,而不是动画它正在完成,它看起来很好,显然,但只是想指出这一点。这与我制作动画的方式有关,我只是不知道。
这是带有绿色贝塞尔曲线动画的完整更新代码:
(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
);
//context.fillStyle = "black";
context.stroke();
//context.fill();
// 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
来引用编号为 post 的变量名。只需使用数组即可。 - 你绘制点而不是线的原因是因为你在每个新顶点之前调用了
context.beginPath()
和context.moveTo()
,这导致context.stroke()
和context.fill()
到 "forget" 前面的说明。
我将 context.beginPath()
移到 animatedBSpline()
之外,并在该函数内的 t==0
处将 context.moveTo()
指定为 运行,这样就没有脱节点了.希望对您有所帮助。