如何在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
相关产品推荐
相关产品推荐

