使用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
相关产品推荐
相关产品推荐

