【问题标题】:Animating drawing arcTo lines on canvas在画布上动画绘制 arcTo 线
【发布时间】:2020-05-25 00:51:27
【问题描述】:

我正在尝试实现在 Canvas 上绘制 arcTo 线的动画。以直线为例,动画如下

c = canvas.getContext("2d");

width = window.innerWidth;
height = window.innerHeight;
complete = false
var percent = 1

function drawEdge(x1, y1, x2, y2, color){
 c.beginPath();
 c.lineWidth = 10;
 c.strokeStyle = color;
 c.moveTo(x1, y1);
 c.lineTo(x2, y2);
 c.stroke();
 c.closePath();
}

function getPosition(x1, y1, x2, y2, percentageBetweenPoints){
 let xPosition = x1 + (x2 - x1) * (percentageBetweenPoints / 100);
 let yPosition = y1 + (y2 - y1) * (percentageBetweenPoints / 100);

 const position = {
     x: xPosition,
     y: yPosition,
 }
 return position
}

function drawLine(){
 if (!complete){
     requestAnimationFrame(drawLine);
 }

 if (percent >= 100){
     complete = true;
     percent = 100;
 } else{
     percent = percent + 1;
 }

 position = getPosition(300,300,1000,300,percent);
 c.clearRect(0, 0 , width, height);
 drawEdge(300,300,position.x,position.y, "black");

}

drawLine()

这会创建一条在屏幕上绘制的动画。但是,我在为 arcTo 线做同样的事情时遇到了麻烦。有什么方法可以实现吗?

【问题讨论】:

    标签: html canvas html5-canvas


    【解决方案1】:

    您正在寻找这样的东西吗?

    let ctx = canvas.getContext('2d');
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.font = 'bold 18px Arial';
    
    requestAnimationFrame(draw);
    
    function draw(t) {
      t = t % 5e3 / 5e3;
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.beginPath();
      ctx.arc(canvas.width/2, canvas.height/2, 50, 0, t * 2 * Math.PI);
      ctx.stroke();
      ctx.fillText((t*100).toFixed(0), canvas.width/2, canvas.height/2);
      requestAnimationFrame(draw);
    }
    <canvas id=canvas></canvas>

    【讨论】:

      【解决方案2】:

      黑客还是不黑客?

      有两种方法可以做到这一点

      1. 计算每条线段的起点、终点和长度,每条弧线段的起点、终点角度、方向(CW 或 CCW)和中心。基本上重复所有使arcTo 成为如此有用的渲染函数的数学和逻辑(大约 50 行代码)。

        您可以从html5 canvas triangle with rounded corners 获取有关如何获取完整解决方案的详细信息

      2. ctx.lineDash 与一个长破折号和一个长空格一起使用。使用ctx.lineDashOffset 随时间移动破折号,使线条看起来越来越长(参见演示)。虚线偏移值是相反的,从最大长度开始,到零结束。

        注意此方法存在一个问题。您不知道线路的长度,因此您不知道完成线路需要多长时间。你可以做一个估计。要知道线的长度,您必须进行所有计算(差不多)

      黑客

      由于第二种方法最容易实现并且可以满足大多数需求,因此我将演示该方法。

      不多说,它为ctx.arcTo创建的路径设置动画 附带的好处是它将为使用ctx.stroke渲染的任何路径设置动画

      requestAnimationFrame(mainLoop);
      // Line is defined in unit space. 
      // Origin is at center of canvas, -1,-1 top left, 1, 1 bottom right
      // Unit box is square and will be scaled to fit the canvas size.
      // Note I did not use ctx.setTransform to better highlight what is scaled and what is not.
      const ctx = canvas.getContext("2d");
      var w, h, w2, h2;          // canvas size and half size
      var linePos;               // current dash offset
      var scale;                 // canvas scale
      const LINE_WIDTH = 0.05;      // in units
      const LINE_STYLE = "#000"; // black
      const LINE_SPEED = 1;      // in units per second
      const MAX_LINE_LENGTH = 9; // in units approx
      const RADIUS = 0.08;       //Arc radius in units
      const SHAPE = [[0.4, 0.2], [0.8, 0.2], [0.5, 0.5], [0.95, 0.95], [0.0, 0.5], [-0.95, 0.95], [-0.5, 0.5], [-0.8, 0.2], [-0.2, 0.2],  [-0.2, -0.2], [-0.8, -0.2], [-0.5, -0.5], [-0.95, -0.95], [0.0, -0.5], [0.95,-0.95], [0.5, -0.5], [0.8, -0.2], [0.2, -0.2], [0.2, 0.2], [0.6, 0.2], [0.8, 0.2]];
      
      function sizeCanvas() {
          w2 = (w = canvas.width = innerWidth) / 2;
          h2 = (h = canvas.height = innerHeight) / 2;
          scale = Math.min(w2, h2);
          resetLine();
      }
      
      function addToPath(shape) {
         var p1, p2;
         for (p2 of shape) {
             !p2.length ? 
                 ctx.closePath() :
                 (p1 ? ctx.arcTo(p1[0] * scale + w2, p1[1] * scale + h2, p2[0] * scale + w2, p2[1] * scale + h2, RADIUS * scale) : 
                      ctx.lineTo(p2[0] * scale + w2, p2[1] * scale + h2)
                  );
             p1 = p2;
         }
      }
      
      function resetLine() {
          ctx.setLineDash([MAX_LINE_LENGTH * scale, MAX_LINE_LENGTH * scale]);
          linePos = MAX_LINE_LENGTH * scale;
          ctx.lineWidth = LINE_WIDTH  * scale;
          ctx.lineJoin = ctx.lineCap = "round";
      }
      
      function mainLoop() {
          if (w !== innerWidth || h !== innerHeight) { sizeCanvas() }
          else { ctx.clearRect(0, 0, w, h) }
          ctx.beginPath();
          addToPath(SHAPE);  
          ctx.lineDashOffset = (linePos -= LINE_SPEED * scale * (1 / 60));
          ctx.stroke();
          if (linePos <= 0) { resetLine() }
          requestAnimationFrame(mainLoop);
      }
          
          
      body {
         padding: 0px,
         margin: 0px;
      }
      canvas {
         position: absolute;
         top: 0px;
         left: 0px;
      }
      &lt;canvas id="canvas"&gt;&lt;/canvas&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-19
        • 1970-01-01
        • 1970-01-01
        • 2014-06-29
        • 2019-11-11
        • 1970-01-01
        • 2018-05-31
        • 2019-04-12
        相关资源
        最近更新 更多