You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FabricJS中为文本对象实现波浪效果?

在FabricJS文本对象实现波浪效果

需求:希望给FabricJS中的文本对象添加如图所示的波浪动画效果,当前已有基础代码,不清楚实现方式。

基础代码:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
  </head>

  <body>
    <canvas id="canvas"></canvas>
    <script>
      var canvas = new fabric.Canvas("canvas");
      canvas.setWidth(900);
      canvas.setHeight(500);
      canvas.set({ backgroundColor: "#FFC0CC" });

      var text = new fabric.Textbox("Hello, Fabric.js!", {
        left: 50,
        top: 50,
        fontSize: 30,
        fill: "black",
      });

      canvas.add(text);

      canvas.renderAll();
    </script>
  </body>
</html>

效果参考:波浪效果


实现方案

核心思路是通过修改文本对象的路径变形,结合requestAnimationFrame实现循环动画,具体实现如下:

1. 自定义波浪文本类(继承fabric.Textbox)

扩展fabric.Textbox类,添加波浪参数和路径变形逻辑:

class WaveText extends fabric.Textbox {
  constructor(text, options) {
    super(text, options);
    // 波浪控制参数
    this.waveOffset = 0; // 动画偏移量
    this.waveAmplitude = options.waveAmplitude || 5; // 波浪幅度
    this.waveFrequency = options.waveFrequency || 0.05; // 波浪密度
  }

  // 重写渲染方法,对文本路径做波浪变形
  _render(ctx) {
    ctx.save();
    const offset = this.waveOffset;
    const amplitude = this.waveAmplitude;
    const frequency = this.waveFrequency;
    
    // 遍历文本的每个路径节点,修改Y轴坐标实现波动
    this._textLines.forEach(line => {
      line.paths.forEach(path => {
        path.path.forEach(command => {
          // 针对路径指令(移动、直线、贝塞尔曲线)修改Y值
          if (['M', 'L', 'Q'].includes(command[0])) {
            command[2] += Math.sin((command[1] * frequency) + offset) * amplitude;
          }
        });
      });
    });
    
    super._render(ctx);
    ctx.restore();
    
    // 更新偏移量驱动动画
    this.waveOffset += 0.1;
    this.dirty = true;
  }
}

2. 替换原文本对象并启动动画

将原本的fabric.Textbox替换为自定义类,同时启动动画循环:

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
  </head>

  <body>
    <canvas id="canvas"></canvas>
    <script>
      class WaveText extends fabric.Textbox {
        constructor(text, options) {
          super(text, options);
          this.waveOffset = 0;
          this.waveAmplitude = options.waveAmplitude || 5;
          this.waveFrequency = options.waveFrequency || 0.05;
        }

        _render(ctx) {
          ctx.save();
          const offset = this.waveOffset;
          const amplitude = this.waveAmplitude;
          const frequency = this.waveFrequency;
          
          this._textLines.forEach(line => {
            line.paths.forEach(path => {
              path.path.forEach(command => {
                if (['M', 'L', 'Q'].includes(command[0])) {
                  command[2] += Math.sin((command[1] * frequency) + offset) * amplitude;
                }
              });
            });
          });
          
          super._render(ctx);
          ctx.restore();
          
          this.waveOffset += 0.1;
          this.dirty = true;
        }
      }

      var canvas = new fabric.Canvas("canvas");
      canvas.setWidth(900);
      canvas.setHeight(500);
      canvas.set({ backgroundColor: "#FFC0CC" });

      // 创建波浪文本实例,可自定义参数
      var text = new WaveText("Hello, Fabric.js!", {
        left: 50,
        top: 50,
        fontSize: 30,
        fill: "black",
        waveAmplitude: 6,
        waveFrequency: 0.04
      });

      canvas.add(text);

      // 启动动画循环
      function animate() {
        canvas.renderAll();
        requestAnimationFrame(animate);
      }
      animate();
    </script>
  </body>
</html>

3. 参数调整说明

  • waveAmplitude:数值越大,波浪上下起伏的幅度越明显
  • waveFrequency:数值越大,波浪的密集程度越高
  • waveOffset的增量(代码中的0.1):数值越大,动画播放速度越快

内容的提问来源于stack exchange,提问作者Vin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 09:30:27