跳到主要内容

音频播放器可视化

示例加载中…

源码
import { Chart } from '@antv/g2';

// 音乐播放器音频可视化
// 1. 预生成所有帧的 options 配置
// 2. 使用 setInterval 切换 options 实现动画
// 3. encode('key') 确保元素平滑过渡

const BANDS = 32; // 频段数量
const FRAMES = 60; // 动画帧数
const FPS = 30; // 每秒帧数

// 生成单帧音频频谱数据
function generateFrameData(time) {
  const data = [];

  for (let i = 0; i < BANDS; i++) {
    // 模拟不同频段的能量变化
    const frequency = (i / BANDS) * 10;
    const bassWave = Math.sin(time * 2 + i * 0.2) * 0.3; // 低频节奏
    const midWave = Math.sin(time * 4 + i * 0.4) * 0.4; // 中频旋律
    const highWave = Math.sin(time * 8 + i * 0.6) * 0.3; // 高频细节

    // 随机脉冲模拟鼓点
    const pulse = Math.random() > 0.85 ? Math.random() * 0.5 : 0;

    // 综合计算振幅(0-100)
    const amplitude = Math.max(
      0,
      (bassWave + midWave + highWave + pulse) * 50 + 30 + Math.random() * 10,
    );

    // 根据振幅分配能量等级
    let energy = 'low';
    if (amplitude > 70) energy = 'high';
    else if (amplitude > 45) energy = 'medium';

    data.push({
      band: i,
      frequency: `${(frequency * 1000).toFixed(0)}Hz`,
      amplitude: amplitude,
      energy: energy,
    });
  }

  return data;
}

// 预生成所有帧的 options
const allOptions = [];
for (let frame = 0; frame < FRAMES; frame++) {
  const time = frame * 0.1;
  const data = generateFrameData(time);

  // 每一帧都是一个完整的图表配置
  const option = {
    type: 'interval',
    data: data,
    encode: {
      x: 'band',
      y: 'amplitude',
      color: 'energy',
      key: 'band', // 关键:追踪每个频段实现平滑过渡
    },
    scale: {
      color: {
        domain: ['low', 'medium', 'high'],
        range: ['#1890ff', '#52c41a', '#ff4d4f'], // 蓝→绿→红 能量渐变
      },
      y: { domain: [0, 100] },
    },
    axis: {
      x: {
        title: '频段',
        labelFormatter: (d) => (d % 4 === 0 ? d : ''),
      },
      y: { title: '振幅 (dB)' },
    },
    legend: {
      color: {
        itemLabelText: (d) => {
          if (d.label === 'high') return '高';
          else if (d.label === 'medium') return '中';
          else return '低';
        },
      },
    },
    style: {
      radius: 4,
    },
    tooltip: {
      title: (d) => `频段 ${d.band}`,
      items: [
        { field: 'frequency', name: '频率' },
        {
          field: 'amplitude',
          name: '振幅',
          valueFormatter: (v) => `${v.toFixed(1)} dB`,
        },
        {
          field: 'energy',
          name: '能量',
          valueFormatter: (v) => {
            const map = { low: '低', medium: '中', high: '高' };
            return map[v];
          },
        },
      ],
    },
  };

  allOptions.push(option);
}

// 创建图表并渲染初始帧
const chart = new Chart({
  container: 'container',
  autoFit: true,
});

chart.options(allOptions[0]);
chart.render();

// 使用 setInterval 切换 options
let currentFrame = 0;

const timer = setInterval(() => {
  currentFrame = (currentFrame + 1) % FRAMES;
  chart.options(allOptions[currentFrame]);
  chart.render();
}, 1000 / FPS);
全站搜索
文档与示例输入关键词开始搜索

输入关键词,查找文档、API 与示例

↑↓选择↵打开Esc关闭