I finally found out how to animate drawing a bezier curve. I've seen other solutions that use quadratic curves to do it, but I needed 4 points for what I was doing, and b-spline was too difficult finding random plots, plus it's just how I want to do it; with Bezier Cuves.
My issue is I can't find a good, fast speed without seeing the dots or lines. I've gotta be missing something. Could someone point out my error or a more efficient way to get this going smoothly at any time/speed? I need it to be steady and go faster than the example below, but if I do anymore the gaps get larger and larger...
fiddle with code: 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();
}
If any more information is needed please let me know. I've been at this all day.
To add: If I just outright draw it with these plots, and not animate it being done, it looks fine, obviously, but just wanted to point that out. Its something with the way I'm animating it I just don't know.
Here's the full updated code with animation of green bezier curve:
(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>
A couple key points, some of which were tangential to the question.
eval
for referencing variable names which have numbers post-fixed. Just use an array instead.context.beginPath()
and context.moveTo()
before every new vertex, which causes context.stroke()
and context.fill()
to "forget" the previous instructions.I moved the context.beginPath()
outside of animatedBSpline()
and specified context.moveTo()
to run at t==0
within that function, that way there are no disjointed points. I hope that helps.