一个可直接运行的摩天轮动画页面,使用 Canvas + 原生 JavaScript 实现,无外部依赖。


一、实现方案

  • 技术栈:HTML5 Canvas + 原生 JavaScript

  • 渲染方式:逐帧动画(requestAnimationFrame

  • 自适应:监听 resize 事件,动态调整画布尺寸和元素比例

  • 交互反馈:点击/触摸画面可使摩天轮轻微加速


二、核心代码模块

1. 画布初始化与自适应

javascript

const canvas = document.getElementById('ferrisCanvas');
const ctx = canvas.getContext('2d');

function resize() {
    W = canvas.width = window.innerWidth;
    H = canvas.height = window.innerHeight;
    const base = Math.min(W, H) * 0.42;
    wheelRadius = Math.min(base, 340);
    centerX = W / 2;
    centerY = H / 2 + 20;
    generateStars();
}
  • 画布宽高与视口同步

  • 摩天轮半径取视口最小尺寸的 42%,上限 340px

2. 星空背景(动态闪烁)

javascript

function generateStars() {
    stars = [];
    const count = Math.floor((W * H) / 3600);
    for (let i = 0; i < count; i++) {
        stars.push({
            x: Math.random() * W,
            y: Math.random() * H * 0.75,
            r: Math.random() * 1.6 + 0.6,
            a: Math.random() * 0.7 + 0.3,
            speed: 0.004 + Math.random() * 0.008,
            phase: Math.random() * Math.PI * 2,
        });
    }
}

function drawStars(time) {
    for (const s of stars) {
        const flicker = 0.6 + 0.4 * Math.sin(time * s.speed + s.phase);
        const alpha = s.a * flicker;
        ctx.beginPath();
        ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(255, 245, 230, ${alpha})`;
        ctx.fill();
    }
}
  • 星星数量随视口面积自动调整

  • 每颗星星独立闪烁频率和相位

3. 摩天轮主体结构

3.1 辐条与轿厢位置计算

const count = 12; for (let i = 0; i < count; i++) { const a = (i / count) * Math.PI * 2 + angle; const x = cx + Math.cos(a) * (R - 10); const y = cy + Math.sin(a) * (R - 10); // x, y 即为第 i 个轿厢的位置 }

  • angle 为当前旋转角度,每帧递增 0.0018(约 18 秒转一圈)

  • 辐条从中心连接到轿厢位置

3.2 轿厢绘制(始终保持垂直)

javascript

ctx.save();
ctx.translate(x, y);
ctx.rotate(0); // 关键:不随轮盘旋转,始终保持竖直

// 绘制轿厢主体(圆角矩形)
const w = 22, h = 28, r = 5;
ctx.beginPath();
ctx.moveTo(-w/2 + r, -h/2);
ctx.lineTo(w/2 - r, -h/2);
ctx.quadraticCurveTo(w/2, -h/2, w/2, -h/2 + r);
ctx.lineTo(w/2, h/2 - r);
ctx.quadraticCurveTo(w/2, h/2, w/2 - r, h/2);
ctx.lineTo(-w/2 + r, h/2);
ctx.quadraticCurveTo(-w/2, h/2, -w/2, h/2 - r);
ctx.lineTo(-w/2, -h/2 + r);
ctx.quadraticCurveTo(-w/2, -h/2, -w/2 + r, -h/2);
ctx.closePath();
ctx.fill();

ctx.restore();

4. 轿厢呼吸灯

javascript

const blink = 0.5 + 0.5 * Math.sin(time * 0.006 + i * 0.8);
ctx.beginPath();
ctx.arc(0, h/2 + 2, 3, 0, Math.PI * 2);
ctx.fillStyle = `rgba(255, 200, 150, ${blink * 0.4})`;
ctx.fill();
  • 每个轿厢底部有独立相位差的小灯

  • 亮度随时间正弦变化,形成呼吸效果

5. 交互反馈

javascript

canvas.addEventListener('click', () => { angle += 0.02; });
canvas.addEventListener('touchstart', () => { angle += 0.02; });
  • 点击/触摸屏幕,旋转角度瞬时增加,产生轻微加速感

6. 颜色工具函数

javascript

function lighten(hex, amt) {
    let c = hexToRgb(hex);
    return `rgb(${Math.min(255, c.r + amt)}, ${Math.min(255, c.g + amt)}, ${Math.min(255, c.b + amt)})`;
}
function darken(hex, amt) {
    let c = hexToRgb(hex);
    return `rgb(${Math.max(0, c.r - amt)}, ${Math.max(0, c.g - amt)}, ${Math.max(0, c.b - amt)})`;
}
  • 支持十六进制颜色的明暗调整,用于轿厢渐变


三、参数速查

参数 说明
轿厢数量 12 可调整 CABIN_COUNT
旋转速度 0.0018 rad/frame 约 18 秒/圈
轿厢尺寸 22×28 px 可调整宽高
星星密度 每 3600 px² 一颗 随视口自动缩放
加速增量 0.02 rad/次 点击/触摸触发

更多推荐