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

如何通过递归函数在Fabric.js Canvas上实现同心圆依次动画效果

解决方案

核心实现思路是用递归封装单个圆的动画逻辑,完全避免嵌套回调的冗余代码,适配任意数量的同心圆动画需求。

优化点说明

  1. 初始绘制圆时默认设置透明度为0,无需每次动画清空画布再重新添加元素
  2. 递归函数自动控制动画顺序:从最内侧圆开始执行,单个圆动画完成后自动触发下一个外侧圆的动画,直到所有圆全部显现
  3. 可选增加动画锁,避免重复点击按钮触发多次动画冲突

完整可运行代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 08:24:02