有人知道如何制作螺旋动画吗?

问题描述 投票:0回答:3

我试图制作一个应该旋转的动画螺旋,但是当我尝试它时它没有开始旋转但没有发生错误。如果有人可以帮助我,谢谢

我现在拥有的代码:

CanvasRenderingContext2D.prototype.drawArchimedeanSpiral =
  CanvasRenderingContext2D.prototype.drawArchimedeanSpiral ||
  function(centerX, centerY, stepCount, loopCount,
    innerDistance, loopSpacing, rotation) {
    this.beginPath();

    var stepSize = 2 * Math.PI / stepCount,
      endAngle = 2 * Math.PI * loopCount,
      finished = false;

    for (var angle = 0; !finished; angle += stepSize) {
      // Ensure that the spiral finishes at the correct place,
      // avoiding any drift introduced by cumulative errors from
      // repeatedly adding floating point numbers.
      if (angle > endAngle) {
        angle = endAngle;
        finished = true;
      }

      var scalar = innerDistance + loopSpacing * angle,
        rotatedAngle = angle + rotation,
        x = centerX + scalar * Math.cos(rotatedAngle),
        y = centerY + scalar * Math.sin(rotatedAngle);

      this.lineTo(x, y);
    }

    this.stroke();
  }
  
const canvasEle = document.querySelector("canvas")
const ctx = canvasEle.getContext("2d")

ctx.drawArchimedeanSpiral(200, 200, 100, 10, 1, 1, 2*Math.PI);
<canvas width="400px" height="400px" />

当我尝试它时它根本不起作用,它只是显示一个螺旋,我想要一个动画螺旋,我可以将颜色更改为。

javascript html css codepen
3个回答
1
投票

你的代码已经呈现出一个漂亮的螺旋,所以剩下的就是让动画工作。使用

canvas
元素时,您可以通过在每一帧上重新渲染画布、将内容设置为仅该帧的视觉效果并在下一帧覆盖它来为其设置动画。

要清除帧之间的画布,您可以使用

ctx.clearRect
。要为每一帧安排更新,您可以使用
setInterval
和第二个参数的小值。最后,对于动画本身,我们只需要改变每一帧上的
rotation
参数就可以得到旋转螺旋的图像。

因此,基本步骤是设置一个

setInterval
以每秒执行绘制代码 30 次(或以您想要的任何 FPS),然后,在每个帧上:

  • 清除画布。
  • 计算当前的旋转角度(根据当前时间)。
  • 以该角度产生新的螺旋。
  • 把它画到画布上。

将所有这些放在一起,您的代码片段可能会像这样修改:

CanvasRenderingContext2D.prototype.drawArchimedeanSpiral =
  CanvasRenderingContext2D.prototype.drawArchimedeanSpiral ||
  function(centerX, centerY, stepCount, loopCount,
    innerDistance, loopSpacing, rotation) {
    this.beginPath();

    var stepSize = 2 * Math.PI / stepCount,
      endAngle = 2 * Math.PI * loopCount,
      finished = false;

    for (var angle = 0; !finished; angle += stepSize) {
      // Ensure that the spiral finishes at the correct place,
      // avoiding any drift introduced by cumulative errors from
      // repeatedly adding floating point numbers.
      if (angle > endAngle) {
        angle = endAngle;
        finished = true;
      }

      var scalar = innerDistance + loopSpacing * angle,
        rotatedAngle = angle + rotation,
        x = centerX + scalar * Math.cos(rotatedAngle),
        y = centerY + scalar * Math.sin(rotatedAngle);

      this.lineTo(x, y);
    }

    this.stroke();
  }
  
const canvasEle = document.querySelector("canvas")
const ctx = canvasEle.getContext("2d")

ctx.drawArchimedeanSpiral(200, 200, 100, 10, 1, 1, 0);

const getRotationAngle = (x) => {
  // 0 -> 2pi, every x milliseconds.
  const remainder = Date.now() % x;
  return Math.PI * 2 * (remainder / x);
}

setInterval(() => {
  ctx.clearRect(0, 0, 400, 400);
  ctx.drawArchimedeanSpiral(200, 200, 100, 10, 1, 1, getRotationAngle(1000)) // rotate once per sec.
}, 1000/30) // 30 FPS
<canvas width="400px" height="400px" />

这似乎产生了您正在寻找的动画。您还可以通过在每个循环中修改绘制函数的其他参数来生成不同的动画。


附言要更改颜色,请使用

ctx.strokeStyle
:

CanvasRenderingContext2D.prototype.drawArchimedeanSpiral =
  CanvasRenderingContext2D.prototype.drawArchimedeanSpiral ||
  function(centerX, centerY, stepCount, loopCount,
    innerDistance, loopSpacing, rotation) {
    this.beginPath();

    var stepSize = 2 * Math.PI / stepCount,
      endAngle = 2 * Math.PI * loopCount,
      finished = false;

    for (var angle = 0; !finished; angle += stepSize) {
      // Ensure that the spiral finishes at the correct place,
      // avoiding any drift introduced by cumulative errors from
      // repeatedly adding floating point numbers.
      if (angle > endAngle) {
        angle = endAngle;
        finished = true;
      }

      var scalar = innerDistance + loopSpacing * angle,
        rotatedAngle = angle + rotation,
        x = centerX + scalar * Math.cos(rotatedAngle),
        y = centerY + scalar * Math.sin(rotatedAngle);

      this.lineTo(x, y);
    }

    this.stroke();
  }
  
const canvasEle = document.querySelector("canvas")
const ctx = canvasEle.getContext("2d")

// Change color!!!
ctx.strokeStyle = "green";

ctx.drawArchimedeanSpiral(200, 200, 100, 10, 1, 1, 0);

const getRotationAngle = (x) => {
  // 0 -> 2pi, every x milliseconds.
  const remainder = Date.now() % x;
  return Math.PI * 2 * (remainder / x);
}

setInterval(() => {
  ctx.clearRect(0, 0, 400, 400);
  ctx.drawArchimedeanSpiral(200, 200, 100, 10, 1, 1, getRotationAngle(1000)) // rotate once per sec.
}, 1000/30) // 30 FPS
<canvas width="400px" height="400px" />


0
投票

您需要循环(动画)画布。

我把 FPS 设置为 12 并按 Math.PI / 6 旋转,所以圆每秒旋转 260 度。

CanvasRenderingContext2D.prototype.drawArchimedeanSpiral ??= function(centerX, centerY, stepCount, loopCount, innerDistance, loopSpacing, rotation) {
  this.beginPath();
  const stepSize = 2 * Math.PI / stepCount, endAngle = 2 * Math.PI * loopCount;
  let finished = false;
  for (let angle = 0; !finished; angle += stepSize) {
    if (angle > endAngle) {
      angle = endAngle;
      finished = true;
    }
    const scalar = innerDistance + loopSpacing * angle, rotatedAngle = angle + rotation, x = centerX + scalar * Math.cos(rotatedAngle), y = centerY + scalar * Math.sin(rotatedAngle);
    this.lineTo(x, y);
  }
  this.stroke();
};

const ctx = document.querySelector('canvas').getContext('2d'), FPS = 12;
let rotation = 0;
const update = () => {
  rotation = (rotation + Math.PI / 6) % (Math.PI * 2);
};
const draw = () => {
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.strokeStyle = 'blue';
  ctx.drawArchimedeanSpiral(100, 100, 100, 6, 1, 2, rotation);
};
const loop = (timestamp) => {
  setTimeout(() => {
    update();
    draw();
    requestAnimationFrame(loop);
  }, 1000 / FPS);
};
loop(); // See https://stackoverflow.com/a/39135659/1762224
<canvas width="200px" height="200px" />

如果您想要更快的速度,请调整 FPS。现在圆圈将在 1 秒内旋转 720 度。

CanvasRenderingContext2D.prototype.drawArchimedeanSpiral ??= function(centerX, centerY, stepCount, loopCount, innerDistance, loopSpacing, rotation) {
  this.beginPath();
  const stepSize = 2 * Math.PI / stepCount, endAngle = 2 * Math.PI * loopCount;
  let finished = false;
  for (let angle = 0; !finished; angle += stepSize) {
    if (angle > endAngle) {
      angle = endAngle;
      finished = true;
    }
    const scalar = innerDistance + loopSpacing * angle, rotatedAngle = angle + rotation, x = centerX + scalar * Math.cos(rotatedAngle), y = centerY + scalar * Math.sin(rotatedAngle);
    this.lineTo(x, y);
  }
  this.stroke();
};

const ctx = document.querySelector('canvas').getContext('2d'), FPS = 24;
let rotation = 0;
const update = () => {
  rotation = (rotation + Math.PI / 6) % (Math.PI * 2);
};
const draw = () => {
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.strokeStyle = 'blue';
  ctx.drawArchimedeanSpiral(100, 100, 100, 6, 1, 2, rotation);
};
const loop = (timestamp) => {
  setTimeout(() => {
    update();
    draw();
    requestAnimationFrame(loop);
  }, 1000 / FPS);
};
loop(); // See https://stackoverflow.com/a/39135659/1762224
<canvas width="200px" height="200px" />


0
投票

您的代码正确绘制了螺旋线,但它没有旋转,因为您只调用了 drawArchimedeanSpiral 函数一次,旋转值为 2*Math.PI。要创建旋转效果,您需要重复调用增加或减少旋转值的函数。

CanvasRenderingContext2D.prototype.drawArchimedeanSpiral =
  CanvasRenderingContext2D.prototype.drawArchimedeanSpiral ||
  function(centerX, centerY, stepCount, loopCount,
    innerDistance, loopSpacing, rotation) {
    this.beginPath();

    var stepSize = 2 * Math.PI / stepCount,
      endAngle = 2 * Math.PI * loopCount,
      finished = false;

    for (var angle = 0; !finished; angle += stepSize) {
      // Ensure that the spiral finishes at the correct place,
      // avoiding any drift introduced by cumulative errors from
      // repeatedly adding floating point numbers.
      if (angle > endAngle) {
        angle = endAngle;
        finished = true;
      }

      var scalar = innerDistance + loopSpacing * angle,
        rotatedAngle = angle + rotation,
        x = centerX + scalar * Math.cos(rotatedAngle),
        y = centerY + scalar * Math.sin(rotatedAngle);

      this.lineTo(x, y);
    }

    this.stroke();
  }

const canvasEle = document.querySelector("canvas")
const ctx = canvasEle.getContext("2d")

let rotation = 0

function draw() {
  // Clear the canvas
  ctx.clearRect(0, 0, canvasEle.width, canvasEle.height)

  // Draw the spiral with the current rotation value
  ctx.drawArchimedeanSpiral(200, 200, 100, 10, 1, 1, rotation)

  // Update the rotation value for the next frame
  rotation += 0.01

  // Request the next animation frame
  requestAnimationFrame(draw)
}

// Start the animation loop
draw()
<canvas width="400px" height="400px" />

© www.soinside.com 2019 - 2024. All rights reserved.