javascript canvas 围绕一个面向中心的圆绘制多个矩形

javascript canvas draw multiple rectangles around a circle facing the centre

我正在寻找一种方法,以面向中心的角度围绕一个圆绘制多个矩形。到目前为止我所拥有的,目前只是围绕一个面向一个方向的圆圈绘制矩形,缺少朝向中心的倾斜角 -

https://thysultan.com/projects/thyplayer/

我想要的是让矩形倾斜一个角度,使每个矩形在指定位置面向圆心。 怎么做到的?

三角法

要使线条向中心移动,您可以使用变换或三角数学。就个人而言,我发现在这种情况下使用数学更容易,所以这里有这样一个例子。

有关如何使用转换的示例,请参见@markE 的回答(转换通常在视觉上和代码中更容易)。

一些先决条件:

  • 我们知道 canvas 的方向是 0° 角指向右边。如果您想以某种方式标记频率范围,这是必不可少的。
  • 我们需要计算从外半径到中心(内半径)的线的长度
  • 我们需要根据角度计算直线的端点。

一个简单的解决方案可以是创建一个函数,该函数在某个 angle(以弧度为单位)的中心 (cx, cy) 处计算一条单线,长度为 t,t在 [0, 1] 范围内(作为 FFT 浮点缓冲区)。我们还提供了一个外半径和内半径来限制线:

function getLine(cx, cy, angle, t, oRadius, iRadius) {

    var radiusDiff = oRadius - iRadius,            // calc radius diff to get max length
        length = radiusDiff * t;                   // now we have the line length

    return {
        x1: oRadius * Math.cos(angle),             // x1 point (outer)
        y1: oRadius * Math.sin(angle),             // y1 point (outer)
        x2: (oRadius - length) * Math.cos(angle),  // x2 point (inner)
        y2: (oRadius - length) * Math.sin(angle)   // y2 point (inner)
    }
}

我们现在需要做的就是从 FFT 分析器向它提供数据。

注意:由于所有线都指向中心,因此中心区域会很拥挤。确定线宽和内半径以及要使用的 bin 数量时需要注意的事项。

示例演示

例如,我将为 "FFT" 使用一些随机数据并绘制 64 个 bin。

// angle - in radians
function getLine(cx, cy, angle, t, oRadius, iRadius) {

  var radiusDiff = oRadius - iRadius,            // calc radius diff to get max length
      length = radiusDiff * t;                   // now we have the line length

  return {
    x1: cx + oRadius * Math.cos(angle),             // x1 point (outer)
    y1: cy + oRadius * Math.sin(angle),             // y1 point (outer)
    x2: cx + (oRadius - length) * Math.cos(angle),  // x2 point (inner)
    y2: cy + (oRadius - length) * Math.sin(angle)   // y2 point (inner)
  }
}

// calculate number of steps based on bins
var ctx = document.querySelector("canvas").getContext("2d"),
    fftLength = 64,
    angleStep = Math.PI * 2 / fftLength,
    angle = 0,
    line;

ctx.beginPath();                                    // not needed in demo, but when animated

while(angle < Math.PI*2) {
  // our line function in action:
  line = getLine(250, 250, angle, getFFT(), 240, 50);
  
  ctx.moveTo(line.x1, line.y1);                    // add line to path
  ctx.lineTo(line.x2, line.y2);
  angle += angleStep                               // get next angle
}

ctx.lineWidth = 5;                                 // beware of center area
ctx.stroke();                                      // stroke all lines at once

// to smooth the "FFT" random data
function getFFT() {return Math.random() * 0.16 + 0.4}
<canvas width=500 height=500></canvas>