如何通过递归函数在Fabric.js Canvas上实现同心圆依次动画效果
解决方案
核心实现思路是用递归封装单个圆的动画逻辑,完全避免嵌套回调的冗余代码,适配任意数量的同心圆动画需求。
优化点说明
- 初始绘制圆时默认设置透明度为0,无需每次动画清空画布再重新添加元素
- 递归函数自动控制动画顺序:从最内侧圆开始执行,单个圆动画完成后自动触发下一个外侧圆的动画,直到所有圆全部显现
- 可选增加动画锁,避免重复点击按钮触发多次动画冲突
完整可运行代码
JavaScript代码
const canvas = new fabric.Canvas('gameCanvas', { selection: false }); fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center'; let circles = []; // 动画锁,不需要可直接删除 let isAnimating = false; document.addEventListener('DOMContentLoaded', function() { drawCircles(); }); document.getElementById('animateBtn').addEventListener('click', function() { if (!isAnimating) animateCircles(); }); function makeCircle(r) { return new fabric.Circle({ left: 300, top: 120, strokeWidth: 1.5, radius: r, fill: 'white', stroke: 'black', selectable: false, hoverCursor: 'default', hasControls: false, hasBorders: false, // 初始隐藏所有圆 opacity: 0 }); } function drawCircles() { for(let i = 9; i >= 0; i--) { let circle = makeCircle(10*(i + 1)); circles.push(circle); canvas.add(circle); } canvas.renderAll(); } // 递归动画核心逻辑 function animateSingleCircle(index) { // 递归终止:所有圆动画完成 if (index < 0) { isAnimating = false; return; } circles[index].animate( { opacity: 1 }, { duration: 2000, easing: fabric.util.ease['easeInElastic'], onChange: canvas.renderAll.bind(canvas), onComplete: function () { circles[index].setCoords(); // 触发下一个外侧圆的动画 animateSingleCircle(index - 1); } } ); } function animateCircles() { isAnimating = true; // 从最内侧圆(索引9对应半径10的最小圆)开始动画 animateSingleCircle(9); }
CSS、HTML代码和原有逻辑保持一致即可
内容的提问来源于stack exchange,提问作者Riley Christian
相关产品推荐
相关产品推荐

