代码之家  ›  专栏  ›  技术社区  ›  Grant

在html5画布中绘制动画bezier曲线时如何保持平滑线

  •  3
  • Grant  · 技术社区  · 9 年前

    我的问题是,如果看不到点或线,我就找不到好的、快的速度。我一定错过了什么。有人能指出我的错误吗?或是一种更有效的方法,让这一切在任何时候/任何速度都能顺利进行吗?我需要它稳定并且比下面的例子更快,但是如果我再这样做,差距会越来越大。。。

    玩弄代码: 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();
    }
    

    如果需要更多信息,请告诉我。我已经干了一整天了。

    要添加:

    1 回复  |  直到 9 年前
        1
  •  2
  •   Patrick Roberts Benjamin Gruenbaum    9 年前

    以下是带有绿色贝塞尔曲线动画的完整更新代码:

    (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>

    几个关键点,其中一些与问题无关。

    • 避免使用 eval 用于引用数字后固定的变量名。只需使用数组即可。
    • 您之所以要绘制点而不是线,是因为您调用了 context.beginPath() context.moveTo() 在每个新顶点之前,这会导致 context.stroke() context.fill() “忘记”前面的说明。

    我移动了 context.beginPath() 的外部 animatedBSpline() 和指定的 上下文.moveTo() 以运行 t==0 在这个函数中,这样就没有断开的点。我希望这能有所帮助。