在html5 canvas

时间:2016-08-06 21:52:22

标签: javascript html5 canvas curve bezier

我终于找到了如何绘制bezier曲线的动画。我已经看到其他解决方案使用二次曲线来做到这一点,但我需要4点才能完成我的工作,并且b-spline太难找到随机图,而且它只是我想要的方式;与Bezier Cuves合作。

我的问题是,如果没有看到点或线,我找不到好的,快速的速度。我一定会错过一些东西。有人可以指出我的错误或更有效的方式在任何时间/速度顺利进行吗?我需要它稳定并且比下面的例子更快,但如果我再做的话,差距越来越大......

摆弄代码: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 个答案:

答案 0 :(得分:2)

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

(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()之外,并指定context.moveTo()在该函数内的t==0处运行,这样就没有脱节点了。我希望有所帮助。