简体   繁体   English

在html5画布中绘制动画贝塞尔曲线时如何保持平滑线条

[英]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. 我终于找到了如何绘制bezier曲线的动画。 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; 我已经看到其他解决方案使用二次曲线来做到这一点,但我需要4点才能完成我的工作,并且b-spline太难找到随机图,而且它只是我想要的方式; with Bezier Cuves. 与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/ 小提琴代码: 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. 避免使用eval来引用具有后固定数字的变量名称。 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. 您绘制点而不是线的原因是因为您在每个新顶点之前调用了context.beginPath()context.moveTo() ,这导致context.stroke()context.fill() “忘记”前面的指令。

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. 我将context.beginPath()移动到animatedBSpline() context.beginPath()之外,并指定context.moveTo()在该函数中的t==0运行,这样就没有脱节点。 I hope that helps. 我希望有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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