最近做的一个需求,场景之一是绘制一个雷达图,找了一圈,似乎 AntV 下的 F2 很适合拿来主义:
但是接着又考虑了一下,我当前所做的项目并不是可视化项目,今后大概率也不会有这种可视化图表的需求,只是为了单个需求一两个图表就引入一个可视化库,性价比有点低,辛辛苦苦优化下来的代码体积,就因为一个冗余的代码库一下子回到解放前,那可真要不得(虽然 F2已经够精简的了)
再加上我刚好对于 canvas
这块有点兴趣,送上门的练手机会更不可能错过了,除此之外,我看了一下 F2的文档 看得有点脑壳疼,有看这文档的时间我还不如直接去看 Canvas
原生 Api
呢,于是决定自己来搞定这个东西
绘制多边形
这个雷达图看起来好像挺简单,实际上还是有点门道的,我考虑了一下,将其分成三部分:
- 正多边形
- 正多边形顶点处文案
- 雷达区域
多边形示意如下(这里以正五边形作为示例):
这个图其实由多个尺寸不同的正五边形嵌套而成,并且通过 5
条线将正五边形的对角顶点连在了一起,关键在于需要知道正五边形的五个顶点坐标,这其实就是求解几何数学题
如图,旋转正五边形,令其中心点位于坐标轴原点,其最左侧的一条边平行于 y
轴,在此状态下的其 x
坐标最大的点(即最右侧的点)位于 x
轴上,然后再画一个此正五边形的外接圆,接下来就可以进行求解了
这里之所以这么旋转正五边形,只是为了更方便的求解坐标,你当然也可以令正五边形的一条边平行于 x
轴或者其他任意的旋转进行求解,只要能取得正多边形各个顶点的相对坐标即可
显而易见神特么显而易见,正五边形的每个顶点的坐标就是:
(radius * cosθ, radius * sinθ)
这里的 radius
就是正五边形外接圆半径,θ
是顶点与原点之间连线和 x
的夹角
其中 radius
是我们自己规定的,只剩下 θ
的求解了,按照上图,如果正多边形最右侧(即 x
坐标最大)的顶点为第一个顶点,逆时针旋转依次为 第二、第三…第 n
显而易见的是,这个 θ
值其实就是正五边形内角角度的一半,正多边形(n
)内角角度(mAngle
)为 Math.PI * 2 / n
, 则第 n
个点的坐标为:
(radius * cos(θ * (n - 1)), radius * sin(θ * (n - 1)))
这里只是拿正五边形举个例子,放宽到正n
边形都是这个道理
顶点拿到了,正多边形就很好画了,不过还有一点需要注意,实际需求中,一般是要求正多边形是正着放置,即底边与 x
平行,而按照本文这里的求解方式得到的顶点坐标画出来的正多边形,是侧边与 y
平行,所以需要将得到的 正多边形的坐标进行一定的映射,将之转换为正着放置的
canvas
也提供了这种操作,即 rotate
,只要先把或者后把 canvas
的坐标系旋转一下,那么画出来的多边形在视觉上看就是 正着放置的了
function drawPolygon () {
// #region 绘制多边形
const r = mRadius / polygonCount
let currentRadius = 0
for (let i = 0; i < polygonCount; i++) {
bgCtx.beginPath()
currentRadius = r * (i + 1)
for (let j = 0