在 Javascript 中使用顺序 Canvas 动画的最佳方式

Best way to have sequential Canvas Animations In Javascript

所以我尝试使用 PaperJs(PaperJs 也是路径和元素的制作方式)为 canvas 元素(在本例中为 PaperJs Path/Text)制作动画。它的工作方式是我有一组用户创建的框架(当我说框架时,我指的是从这里开始的这个用户创建的框架),其中有 0-10 条由用户绘制的路径。从这里开始,我在一个位置创建了一个数字,并将对该 canvas 元素的引用存储在一个名为 text 的数组中,并将相应的路径存储在一个名为 paths 的数组中。对于每一帧,我附加的代码是 运行 及其路径和文本列表。我的代码可以工作,但非常简陋,并且对我要添加的功能有限制。问题是我希望能够调用函数 animate_frame(OBJ_WITH_PATHS[0]) 并让它为帧设置动画,然后一旦它完成第一个帧的动画调用 animate_frame(OBJ_WITH_PATHS[1]) 因此带有路径的整个 OBJ 列表按顺序进行动画处理。目前发生这种情况是因为行

if ((event.time > frame_num*2) && (event.time < ((frame_num*2) + 2))) {.

需要这一行的原因是程序使每个帧的所有文本和路径都带有一个 onFrame 事件,并且没有严格限制对象可见的时间,而是同时对所有帧进行动画处理逐帧(我的帧有路径)。这种行为是我将每帧的总时间严格限制为 2 秒的原因。我还应该注意我将填充颜色更改为黑色然后 t运行sparent 的原因,因此元素仅在动画期间可见,而不是在 2 秒动画周期之前或之后。我目前使用的相关代码如下所示

  var offset = [];

  for(let i = 0; i < paths.length; i ++) {
    offset[i] = 0;
  }
  var time_sec = 2;   
  for(let i = 0; i < paths.length; i ++) {
      text[i].onFrame = function (event) {
          var speed = paths[i].length/time_sec;
          if ((event.time > frame_num*2) && (event.time < ((frame_num*2) + 2))) {
              text[i].fillColor = "black";          
              if (offset[i] < paths[i].length){
                  text[i].position = paths[i].getPointAt(offset[i]);
                  offset[i] += event.delta*speed; // speed - 150px/second
               } else {
                  offset[i] = paths[i].length;
               }
          } else {
              text[i].fillColor = new paper.Color(0.5,0);
          }
      paper.view.draw();
    }
  }

我的代码限制了我想要添加的功能,例如

我还想谈谈我已经尝试在调用 animate_frame 之间实现等待 2 秒,但是在此等待期间,PaperJS 的 onFrame(event) 不会发生,所以它不起作用),我还尝试了标志 var 和 while 循环,但也没有用。

所以我想知道是否有更好的方法来做到这一点。我喜欢创建一个动画对象,其中该对象包含路径和 canvas 元素 moved/animated 并且可以通过 animation.play(); 调用动画;然后它还可以等待上一个动画完成,这样我就可以拥有一系列动画帧。对于整个项目,此时我已与 PaperJs 结婚,但我可以将路径位置数据放入常规 JS 数组并将其传递到新包中,如果有的话,我还可以在 canvas 之上为元素设置动画一个适合我正在尝试做的事情的包。 谢谢你assistance/Ideas!

对于复杂的动画场景,我建议你使用合适的动画库,这将使整个事情变得更容易。
例如,GSAP 可能对所有 play/pause... 处理有很大帮助。
这是一个简单的 fiddle 演示如何使用它来控制基于 Paper.js 的动画。

您应该能够根据您的特定用例对其进行调整。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Debug Paper.js</title>
    <script src="https://unpkg.com/acorn"></script>
    <script src="https://unpkg.com/paper"></script>
    <script src="https://unpkg.com/gsap"></script>
    <style>
        html,
        body {
            margin   : 0;
            overflow : hidden;
            height   : 100%;
        }

        canvas[resize] {
            width  : 100%;
            height : 100%;
        }

        #buttons {
            position : fixed;
            top      : 50px;
            left     : 50px;
            display  : flex;
            gap      : 15px;
        }
    </style>
</head>
<body>
<div id="buttons">
    <button id="play">play</button>
    <button id="pause">pause</button>
    <button id="reverse">reverse</button>
</div>
<canvas id="canvas" resize></canvas>
<script>
    paper.setup('canvas');

    const initialPosition = paper.view.center;

    const circle = new paper.Path.Circle({
        center: initialPosition,
        radius: 50,
        fillColor: 'orange'
    });

    function update(t) {
        circle.position = initialPosition.add([t * 100, 0]);
    }

    const obj = { value: 0 };
    var timeLine = gsap.timeline({
        onUpdate: (event) => {
            update(obj.value);
        }
    });
    timeLine.to(obj, { value: 1, duration: 1 });
    timeLine.pause();

    document.querySelector('#play').addEventListener('click', () => timeLine.play());
    document.querySelector('#pause').addEventListener('click', () => timeLine.pause());
    document.querySelector('#reverse').addEventListener('click', () => timeLine.reverse());
</script>
</body>
</html>