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

使用JavaScript为Canvas双层机械轮添加旋转动画

双层Canvas轮盘动画实现

直接基于你现有代码改造即可,全程不需要在body内写额外内容,保持结构简洁,核心是用逐帧渲染逻辑替换原有静态绘制:

  • 将两层轮盘的绘制逻辑封装为接收旋转偏移量的独立函数,每帧渲染前清空画布避免画面叠加
  • 用requestAnimationFrame做动画帧驱动,给内外轮盘设置独立转速,可实现同向/反向差速的机械转动效果
  • 旋转角度累计到360度时自动重置,避免数值溢出

完整代码

HTML部分(完全保留你原有简洁结构)

<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <script src="wheel.js"></script>
  </body>
</html>

JavaScript部分

// 公共配置抽离,方便后续调整参数
const wheelConfig = {
  canvasWidth: 80,
  canvasHeight: 60,
  centerX: 40,
  centerY: 30,
  innerRadius: 15,
  baseLineAngles: [0, 22.5, 45, 67.5, 90, 112.5, 135, 157.5, 180, 202.5, 225, 247.5, 270, 292.5, 315, 337.5],
  themeColor: "#76D7C4"
}

// 初始化外层轮盘Canvas
const outterCanvas = document.createElement('canvas');
outterCanvas.width = wheelConfig.canvasWidth;
outterCanvas.height = wheelConfig.canvasHeight;
document.body.appendChild(outterCanvas);
const outterCtx = outterCanvas.getContext('2d');
outterCtx.lineWidth = 2;

// 初始化内层轮盘Canvas
const innerCanvas = document.createElement('canvas');
innerCanvas.width = wheelConfig.canvasWidth;
innerCanvas.height = wheelConfig.canvasHeight;
document.body.appendChild(innerCanvas);
const innerCtx = innerCanvas.getContext('2d');
innerCtx.lineWidth = 2;

/**
 * 绘制外层轮盘
 * @param {number} rotateDeg 旋转角度偏移量
 */
function renderOutterWheel(rotateDeg = 0) {
  outterCtx.clearRect(0, 0, wheelConfig.canvasWidth, wheelConfig.canvasHeight);
  // 绘制背景
  outterCtx.fillStyle = wheelConfig.themeColor;
  outterCtx.fillRect(0, 0, wheelConfig.canvasWidth, wheelConfig.canvasHeight);
  // 绘制轮盘轮廓和刻度线
  outterCtx.beginPath();
  outterCtx.arc(wheelConfig.centerX, wheelConfig.centerY, wheelConfig.innerRadius, 0, 2 * Math.PI);
  for (const baseAngle of wheelConfig.baseLineAngles) {
    const finalRad = (baseAngle + rotateDeg) * Math.PI / 180;
    outterCtx.moveTo(wheelConfig.centerX, wheelConfig.centerY);
    outterCtx.lineTo(
      wheelConfig.centerX + 17 * Math.cos(finalRad),
      wheelConfig.centerY + 17 * Math.sin(finalRad)
    );
  }
  outterCtx.stroke();
}

/**
 * 绘制内层轮盘
 * @param {number} rotateDeg 旋转角度偏移量
 */
function renderInnerWheel(rotateDeg = 0) {
  innerCtx.clearRect(0, 0, wheelConfig.canvasWidth, wheelConfig.canvasHeight);
  // 绘制内层填充圆,遮挡外层轮盘内部线条
  innerCtx.beginPath();
  innerCtx.arc(wheelConfig.centerX, wheelConfig.centerY, wheelConfig.innerRadius, 0, 2 * Math.PI);
  innerCtx.fillStyle = wheelConfig.themeColor;
  innerCtx.fill();
  // 绘制内层刻度线,保留初始11.25度偏移匹配原有视觉效果
  for (const baseAngle of wheelConfig.baseLineAngles) {
    const finalRad = (baseAngle + 11.25 + rotateDeg) * Math.PI / 180;
    innerCtx.moveTo(wheelConfig.centerX, wheelConfig.centerY);
    innerCtx.lineTo(
      wheelConfig.centerX + 18 * Math.cos(finalRad),
      wheelConfig.centerY + 18 * Math.sin(finalRad)
    );
  }
  innerCtx.stroke();
}

// 动画状态
let outterOffset = 0;
let innerOffset = 0;
// 转速配置:正值顺时针、负值逆时针,数值越大转速越快
const outterSpeed = 1;
const innerSpeed = -1.2;

// 动画主循环
function animationLoop() {
  // 更新旋转角度
  outterOffset += outterSpeed;
  innerOffset += innerSpeed;
  // 角度归位,避免数值无限累加
  outterOffset = outterOffset % 360;
  innerOffset = innerOffset % 360;
  // 重绘两层轮盘
  renderOutterWheel(outterOffset);
  renderInnerWheel(innerOffset);
  // 注册下一帧
  requestAnimationFrame(animationLoop);
}

// 启动动画
animationLoop();

参数调整说明

  • 修改outterSpeed和innerSpeed即可调整转动效果:两个值设为相同则两层同步旋转,设为正负相反则是错位转动的机械轮效果,数值设为0就是静态效果
  • 所有DOM元素均通过JS动态生成,不需要在body标签内添加任何静态内容,完全符合你对body简洁性的要求
  • 原有双层遮挡的视觉逻辑完全保留,只是将固定角度改为随帧变化的动态偏移量,不会破坏你原本的设计效果

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 00:09:13