简体   繁体   中英

html canvas animate curve lines

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

Animation along a path

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> 

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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM