如何从递归行创建动画以在画布中调用?

此代码在画布中生成希尔伯特曲线,我试图在每次调用ctx.lineTo时从中创建动画。我尝试了使用setIntervalrequestAnimationFrame的许多解决方案,但是它们都不起作用。

这里的代码:

const bw = 904;
const bh = 820;
const pixelX = 10;

const canvas = document.getElementById("board");
canvas.setattribute("width",bw);
canvas.setattribute("height",bh);

const ctx = canvas.getcontext("2d");
const hilbertCurve = (x,y,Xi,Xj,Yi,Yj,n) => {
  if (n < 0) {
    ctx.lineTo(x + (Xi + Yi) / 2,y + (Xj + Yj) / 2);
  } else {
    hilbertCurve(x,Yi / 2,Yj / 2,Xi / 2,Xj / 2,n - 1);
    hilbertCurve(x + Xi / 2,y + Xj / 2,n - 1);
    hilbertCurve(
      x + Xi / 2 + Yi / 2,y + Xj / 2 + Yj / 2,n - 1
    );
    hilbertCurve(
      x + Xi / 2 + Yi,y + Xj / 2 + Yj,-Yi / 2,-Yj / 2,-Xi / 2,-Xj / 2,n - 1
    );
  }
};

function draw() {
  ctx.beginPath();
  hilbertCurve(0,bw,bh,7);
  ctx.strokeStyle = "red";
  ctx.stroke();
}

function init() {
  window.requestAnimationFrame(draw);
}

init();
<canvas id="board"></canvas>

sjh102495 回答:如何从递归行创建动画以在画布中调用?

一个简单的解决方案是使用一种习惯于SVG的人已经知道的stroke-dash-array技巧。
我们只定义路径,将stroke-dash-array设置为路径的长度,然后在每次迭代时增加stroke-dash-offset,以使其看起来像连续绘制。

此解决方案的最大问题是,我们需要能够获取路径的长度...

不幸的是,由于我不知道是什么原因,Path2D界面没有提供任何简便的方法。另一方面,SVGGeometryElement具有非常方便的getTotalLength()方法。 Path2d和svg 元素可以接受相同的字符串路径定义,因此我们只需使您的hilbertCurve函数返回一个字符串定义,然后将此字符串用于svg 和可绘制的Path2D对象根据我们的情况。

const bw = 904;
const bh = 820;
const pixelX = 10;

let path_as_string = "" + hilbertCurve( 0,bw,bh,7).replace('L','M');

const path = new Path2D( path_as_string );
const speed = 5;
const totalLength = getPathLength( path_as_string );

let offset = 0;
const canvas = document.getElementById("board");
canvas.setAttribute("width",bw);
canvas.setAttribute("height",bh);

const ctx = canvas.getContext("2d");
function hilbertCurve( x,y,Xi,Xj,Yi,Yj,n ) {
  if (n < 0) {
    return "L" + (x + (Xi + Yi) / 2) + "," + (y + (Xj + Yj) / 2);
  } else {
    return (
      hilbertCurve(x,Yi / 2,Yj / 2,Xi / 2,Xj / 2,n - 1) +
      hilbertCurve(x + Xi / 2,y + Xj / 2,n - 1) +
      hilbertCurve(
        x + Xi / 2 + Yi / 2,y + Xj / 2 + Yj / 2,n - 1
      ) +
      hilbertCurve(
        x + Xi / 2 + Yi,y + Xj / 2 + Yj,-Yi / 2,-Yj / 2,-Xi / 2,-Xj / 2,n - 1
      )
    );
  }
};

function draw() {
  ctx.clearRect(0,canvas.width,canvas.height)
  ctx.lineDashOffset = offset;
  ctx.stroke(path);

  offset += speed;
  if( offset < totalLength ) {
    requestAnimationFrame(draw);
  }
}

function init() {
  ctx.strokeStyle = "red";
  ctx.setLineDash( [ 0,totalLength,totalLength ] );
  requestAnimationFrame(draw);
}

init();

// returns the length of a path from a string definition
function getPathLength( path ) {
  const elem = document.createElementNS( 'http://www.w3.org/2000/svg','path' );
  elem.setAttribute( 'd',path );
  return elem.getTotalLength();
}
canvas { border: 1px solid; }
The animation starts at the bottom left corner<br>
<canvas id="board"></canvas>

,

这是我刚得到的答案。

const bw = 904;
const bh = 820;
const pixelX = 10;

const canvas = document.getElementById("board");
canvas.setAttribute("width",bh);
const lines = [];

const ctx = canvas.getContext("2d");
const hilbertCurve = (x,n) => {
  if (n < 0) {
    lines.push({ x,Yj });
  } else {
    hilbertCurve(x,n - 1);
    hilbertCurve(x + Xi / 2,n - 1);
    hilbertCurve(
      x + Xi / 2 + Yi / 2,n - 1
    );
    hilbertCurve(
      x + Xi / 2 + Yi,n - 1
    );
  }
};

hilbertCurve(0,7);

let nextLine = 0;
requestAnimationFrame(animate);

function animate() {
  if (nextLine < lines.length) {
    requestAnimationFrame(animate);
  }
  const prevLine = nextLine - 1 > -1 ? lines[nextLine - 1] : lines[nextLine];
  const line = lines[nextLine];
  ctx.beginPath();
  ctx.moveTo(
    prevLine.x + (prevLine.Xi + prevLine.Yi) / 2,prevLine.y + (prevLine.Xj + prevLine.Yj) / 2
  );
  ctx.lineTo(
    line.x + (line.Xi + line.Yi) / 2,line.y + (line.Xj + line.Yj) / 2
  );
  ctx.strokeStyle = "red";
  ctx.stroke();
  nextLine++;
}

animate();
<canvas id="board"></canvas>

本文链接:https://www.f2er.com/3162884.html

大家都在问