Reputation: 29
I have created lines using canvas quadraticCurveTo connecting with each other. My goal is to animate this lines. I have an example with lineTo method, how to change it for quadraticCurveTo method?
(function () {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame) window.requestAnimationFrame = function (callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function () {
callback(currTime + timeToCall);
},
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
Example link: http://jsfiddle.net/m1erickson/7faRQ/
What I expected: example image
Upvotes: 1
Views: 1091
Reputation: 611
I know this question is a little old, but SO is filled with bad answers to variations on this question, and until I found this one I found no good solutions. @Blindman67 pointed me in the right direction with setLineDash, and the following works beautifully for me. rnd2() returns a random integer in the range (but you can always just use a constant or a parameter), and curves() calculates a quick rough approximate length of its curve (the average of chord and total segments length), which I multiply by 1.2 to be sure I don't go over. My setLineDash call works with alpha < 1.0 because it doesn't repeatedly overdraw the curve, and it doesn't spend extra time calculating a long invisible blank. raf() is requestAnimationFrame.
var lineLen = 0, delta = rnd2(20, 80);
var approxCurveLen = curves(c0.width, c0.height, ctx, false) * 1.2;
var step = () =>
{
if (lineLen < approxCurveLen)
{
ctx.setLineDash([0, lineLen, delta, approxCurveLen-lineLen]);
ctx.stroke();
lineLen += delta;
raf(step);
}
else
{
ctx.setLineDash([]);
}
};
raf(step);
Upvotes: 0
Reputation: 54026
To do as the fiddle but with any of the path functions you can use line dash to set the amount of the path that is drawn. This will give you a animation along the path that is at a constant speed.
The only problem with this method is that you do not know how long the path is. To know that involves some rather complicated math (warning some bezier length solutions are approximations).
In this example I used my eye to work out the length.
requestAnimationFrame(loop);
const ctx = canvas.getContext("2d");
ctx.lineCap = "round";
const lines = [[10, 10], [300, 10, 250, 200], [100, 300, 20, 120, 10, 10]];
const render = {
"2"(p) { ctx.lineTo(...p) },
"4"(p) { ctx.quadraticCurveTo(...p) },
"6"(p) { ctx.bezierCurveTo(...p) },
start(width, col) { ctx.lineWidth = width; ctx.strokeStyle = col; ctx.beginPath() }
}
var startTime;
const len = 760;
function loop(time) {
if(startTime === undefined){ startTime = time }
const animTime = time - startTime;
ctx.clearRect(0, 0, 300, 300);
ctx.setLineDash([1, 0]);
render.start(1,"blue")
lines.forEach(l => render[l.length](l));
ctx.stroke();
ctx.setLineDash([(animTime / 10) % len, 10000]);
render.start(8, "red")
lines.forEach(l => render[l.length](l));
ctx.stroke();
requestAnimationFrame(loop);
}
canvas { border : 2px solid black; }
<canvas id="canvas" width = 300 height = 300></canvas>
Upvotes: 4