简体   繁体   中英

How to keep smooth lines when drawing out animated bezier curves in html5 canvas

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.

  • Avoid using eval for referencing variable names which have numbers post-fixed. Just use an array instead.
  • The reason you were drawing points instead of lines was because you called 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.

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