web前端之音频可视化、音乐跟随、类型化数组、十六进制随机颜色、devicePixelRatio、createMediaElementSource、requestAnimationFrame

MENU

  • 前言
  • 效果图
  • html
  • JavaScript
  • css


前言

私聊免费获取源码: MJ682517
1、音频一定要正确,网络音频播放无声音,本地音频才可以
2、酷狗下载的kgma格式音频不支持
3、目前试了一下本地的mp3格式可以正常播放
4、代码解析,都在代码中了


效果图

512
web前端之音频可视化、音乐跟随、类型化数组、十六进制随机颜色、devicePixelRatio、createMediaElementSource、requestAnimationFrame_第1张图片


1024
web前端之音频可视化、音乐跟随、类型化数组、十六进制随机颜色、devicePixelRatio、createMediaElementSource、requestAnimationFrame_第2张图片


html

<body class="bc_333">
  <div class="box d_f fd_c jc_c">
      <canvas>canvas>
      <hr class="w_100_ bc_dcdcdc h_1 b_n" />
      <audio class="w_86_ m_a" controls loop src="./1.mp3">audio>
      <div class="m_t_10">
          <div id="idIntervalBtn" class="w_50_ m_lr_a d_f jc_sb">div>
          <div id="idClothCoverBtn" class="w_50_ m_lr_a d_f jc_sb m_t_10">div>
      div>
  div>
body>

JavaScript

// 全局变量
let audioEle = document.querySelector('audio'),
    cvs = document.querySelector('canvas'),
    ctx = cvs.getContext('2d'),
    // 控制初始化
    isInit = false,
    dataArray = undefined,
    analyser = undefined,
    animation = undefined,
    // 按钮操作
    interval = 2,
    // 条形粗细
    clothCover = 1024;

// 初始化页面
initPage();
function initPage() {
    let intervalEl = '',
        clothCoverEl = '';

    for (let i = 2; i < 9; i++) intervalEl += ``;

    for (let i = 9; i < 12; i++) {
        let val = 2 ** i;

        clothCoverEl += ``;
    }

    idIntervalBtn.innerHTML = intervalEl;
    idClothCoverBtn.innerHTML = clothCoverEl;
}

// 初花canvas的尺寸
initCvs();
function initCvs() {
    cvs.width = window.innerWidth * devicePixelRatio;
    cvs.height = (window.innerHeight / 1.5) * devicePixelRatio;
}

// 播放
audioEle.onplay = handlePlay;

function handlePlay() {
    if (isInit) {
        analyser.fftSize = clothCover;

        return draw();
    }

    // 初始化
    // 创建音频上下文
    let audCtx = new AudioContext(),
        // 创建音频源节点
        source = audCtx.createMediaElementSource(audioEle);

    // 分析器节点
    analyser = audCtx.createAnalyser();
    // 设置变换窗口大小
    // 默认值为2048,必须是2的n次幂
    // 数值越大,则得到的值与音频频率更接近
    analyser.fftSize = clothCover;
    // 创建数组,用于接收分析器节点的分析数据
    // 类型化数组
    // 每一项代表一个字节
    // 表示数组里面的每一项是一个无符号的8位整数
    // new Uint8Array(512 / 2);
    // frequencyBinCount属性会自动把值除以2
    dataArray = new Uint8Array(analyser.frequencyBinCount);
    // 音频源与分析器连接
    source.connect(analyser);
    // 分析器连接到输出设备(输出声音)
    analyser.connect(audCtx.destination);
    isInit = true;
    draw();
}

// 暂停
audioEle.onpause = function () {
    cancelAnimationFrame(animation);
}

// 把分析出的波形绘制到canvas
function draw() {
    // 类似递归(循环绘制)
    animation = requestAnimationFrame(draw);
    let { width, height } = cvs,
        len = 0,
        barWidth = 0,
        gradient = undefined;

    // 清空画布
    ctx.clearRect(0, 0, width, height);
    if (!isInit) return console.log('未初始化!');
    // 让分析器节点分析出数据到数组中
    analyser.getByteFrequencyData(dataArray);

    len = dataArray.length / 2.5;
    barWidth = width / len / 2;
    // ctx.fillStyle = '#78c5f7';
    // 创建线性渐变对象(横向渐变)
    gradient = ctx.createLinearGradient(0, 0, width, 0);
    // 添加渐变色段
    gradient.addColorStop(0, hexadecimalColor());
    gradient.addColorStop(0.5, hexadecimalColor());
    gradient.addColorStop(1, hexadecimalColor());

    ctx.fillStyle = gradient;

    for (let i = 0; i < len; i++) {
        let data = dataArray[i],
            barHeight = data / 255 * height,
            // / 2 波形图取一半
            x1 = i * barWidth + width / 2,
            // 波形图另一半
            x2 = width / 2 - (i + 1) * barWidth,
            // x1和x2为对称图形
            // 只是x轴坐标不同
            // y轴一样
            y = height - barHeight;

        // - 2 让每个条之间有缝隙

        // 右半边
        ctx.fillRect(x1, y, barWidth - interval, barHeight);
        //  左半边
        ctx.fillRect(x2, y, barWidth - interval, barHeight);
    }
}

// 随机十六进制颜色
function hexadecimalColor() {
    let str = '0123456789abcdef',
        len = str.length,
        shuffleArray = undefined,
        arr = [],
        color = '#';

    str = str.split('');
    shuffleArray = (arr) => arr.sort(() => Math.random() - 0.5);
    arr = shuffleArray(str);
    str = arr.toString();
    str = str.replace(/,/g, '');

    for (let i = 0; i < 6; i++) {
        let j = Math.floor(Math.random() * len);
        color += str[j];
    }

    return color;
}

// 间隔设置
function handleInterval(event, value) {
    let el = document.querySelector('#idIntervalBtn').childNodes;

    for (let i = 0; i < el.length; i++) {
        const val = el[i].textContent;
        if (value == val) {
            event.target.classList.add('color_blue');
        } else {
            el[i].classList.remove('color_blue');
        }
    }
    interval = value;
}

// 条形粗细
function handleClothCover(value) {
    let el = document.querySelector('#idClothCoverBtn').childNodes;

    for (let i = 0; i < el.length; i++) {
        const val = el[i].textContent;
        if (value == val) {
            event.target.classList.add('color_blue');
        } else {
            el[i].classList.remove('color_blue');
        }
    }

    clothCover = value;

    handlePlay();
}

css

.bc_333 {
    background-color: #333333;
}

.bc_dcdcdc {
    background-color: #dcdcdc;
}

.h_1 {
    height: 1px;
}

.b_n {
    border: none;
}

.c_p {
    cursor: pointer;
}

.w_50_ {
    width: 50%;
}

.w_86_ {
    width: 86%;
}

.w_100_ {
    width: 100%;
}

.d_f {
    display: flex;
}

.fd_c {
    flex-direction: column;
}

.jc_sb {
    justify-content: space-between;
}

.jc_c {
    justify-content: center;
}

.m_a {
    margin: auto;
}

.m_lr_a {
    margin-left: auto;
    margin-right: auto;
}

.m_t_10 {
    margin-top: 10px;
}

.w_68 {
    width: 68px;
}

.radius_4 {
    border-radius: 4;
}

.radius_6 {
    border-radius: 6;
}

.color_blue {
    color: #0000ff;
}

.fw_700 {
    font-weight: 700;
}

你可能感兴趣的:(web前端,JavaScript,功能,前端,音视频,javascript,web,音频可视化)