围绕 canvas 圈绘制条形音箱

Drawing sound bars around a canvas circle

我有以下将音频剪辑的频率绘制为条形音箱的方法:

const drawSinewave = function() {
    requestAnimationFrame(drawSinewave);

    analyser.getByteFrequencyData(sinewaveDataArray);

    canvasCtx.fillStyle = 'white';
    canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
    canvasCtx.lineWidth = 2;
    canvasCtx.strokeStyle = "#40a9ff";
    canvasCtx.beginPath();

    const sliceWidth = canvas.width * 1.0 / analyser.fftSize;
    let x = 0;

    var barWidth = (canvas.width  / analyser.fftSize) * 2.5;
    var barHeight;

    for(let i = 0; i < analyser.fftSize; i++) {
        barHeight = sinewaveDataArray[i];

        canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
        canvasCtx.fillRect(x,canvas.height-barHeight/2,barWidth,barHeight);

        x += barWidth + 1;
    }

    canvasCtx.lineTo(canvas.width, canvas.height / 2);
    canvasCtx.stroke();
};

看起来像这样:

不过我想把它画成一个圆圈,所以就像从圆圈边界发出的光线一样。我没能弄清楚这一点。有人可以帮助我吗?

一个简单的方法是在其侧面绘制一个条形图,偏离圆心。在绘制条形图之前,将当前变换旋转到条形图的正确位置。

该示例使用了一些随机测试数据,因为我懒得设置分析器

const steps = 100;
const testData = [];

const ctx = canvas.getContext("2d");
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
const innerRadius = Math.min(canvas.width, canvas.height) / 2 * (3/4);
const outerRadius = Math.min(canvas.width, canvas.height) / 2 - 20;
const barHeight = outerRadius - innerRadius;
const angStep = (Math.PI * 2) / steps;
const barWidth = (innerRadius * Math.PI * 2 / steps) * 0.9;
const barWidthHalf= barWidth * 0.5;
const startAngle = -Math.PI / 2; // 12 oclock
requestAnimationFrame(drawBars)

function drawBars() {
    const color = h => 'rgb(' + (100+h*150) + ',' + (50+h*100) + ',' + (100+h*40) + ')';

    //analyser.getByteFrequencyData(sinewaveDataArray);
    //const steps = analyser.fftSize;
    animateTestData();
    
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    ctx.lineWidth = 2;
    ctx.strokeStyle = "#40a9ff";
    ctx.beginPath();
    ctx.arc(centerX, centerY, innerRadius - 4, 0, Math.PI * 2);
    ctx.stroke();

    for(let i = 0; i < steps; i++) {
        const h = testData[i];
        const ang = i * angStep + startAngle;
        const xAx = Math.cos(ang);  // direction of x axis
        const xAy = Math.sin(ang);
        ctx.setTransform(xAx, xAy, -xAy, xAx, centerX, centerY);

        ctx.fillStyle = color(h);
        ctx.fillRect(innerRadius, -barWidthHalf, h * barHeight, barWidth);
    }

    ctx.setTransform(1,0,0,1,0,0);  // reset the transform;
    requestAnimationFrame(drawBars);
};


for(let i = 0; i < steps; i ++) { testData.push(Math.random()) }
var sOffset = 0;
function animateTestData() {
    var i = 0, t, phase = Math.sin(sOffset/ 10) * 100;
    while(i < steps) {
        var t = testData[i];
        t += (Math.random() - 0.5) * 0.01;
        t += Math.sin(i * 0.6 + phase + sOffset) * 0.03
        t += Math.sin(i * 0.1 + sOffset * 2) * 0.07
        testData[i++] = t <= 0 ? 0 : t >= 1 ? 1 : t;
    }
    sOffset += 0.1;
}
<canvas id = "canvas" width = "600" height = "600"></canvas>