背景
微信小程序项目中需要制作一个 5 维雷达图(如图一),许多人第一时间可能想到的就是去找插件解决问题,其实小程序的数据可视化的插件还真有,但就为了这一个小图非得去把整个笨重的图形库引进来,这就直接拖慢了小程序的加载速度。使用小程序里的 canvas
,结合小学六年级三角函数几何知识,其实我们完全可以很快 DIY 一个 5 维雷达图出来。
实现思路
小程序支持 canvas
作图,只是可能 api
稍有不同,但都是大同小异。我们可以根据输入的 5 个维度的百分比的值,直接在 canvas
描出 5 个点然后连成 5 边形就可以了,如下图。其他维度的雷达图制作方式大同小异。关键是先获取到中心点(Pc)、原点(P0)、第一维的最达值顶点(P1)、第二维的最大值顶点(P2)、第三维的最大值顶点(P3)、第四维的最大值顶点(P4)、第五维的最大值顶点(P5);然后把输入的值影射到 canvas 上的坐标点;最后把所有点连起来就可以了。
完整代码
添加 canvas
标签,背景用底图就可以了
<canvas class="canvas" style="width: 210px; height: 200px;" canvas-id="canvas"></canvas>
使用小程序提供的 js api 在 canvas
上面作图
onLoad () {
this.draw5DChart([0.8, 0.5, 0.7, 0.6, 1]) // 作图
}
draw5DChart (dArr) {
const get5dPoint = function (per, dim, w, h) {
const cos = Math.cos
const sin = Math.sin
const PI = Math.PI
const pc = [w / 2, h / 2]
const angleA = 90 - 360 / 5
const angleB = 90 - 360 / 5 / 2
const r = pc[0] / cos(PI / 180 * angleA)
const p0 = [pc[0], r]
const p1 = [pc[0], 0]
const p2 = [pc[0] * 2, p0[1] - r * sin(PI / 180 * angleA)]
const p3 = [pc[0] + r * cos(PI / 180 * angleB), p0[1] + r * sin(PI / 180 * angleB)]
const p4 = [pc[0] - r * cos(PI / 180 * angleB), p3[1]]
const p5 = [0, p2[1]]
switch (dim) {
case 1:
return [p1[0], p0[1] - p0[1] * per]
break
case 2:
return [p0[0] + (p2[0] - p0[0]) * per, p0[1] - (p0[1] - p2[1]) * per]
break
case 3:
return [p0[0] + (p3[0] - p0[0]) * per, p0[1] + (p3[1] - p0[1]) * per]
break
case 4:
return [p0[0] - (p0[0] - p4[0]) * per, p0[1] + (p3[1] - p0[1]) * per]
break
case 5:
return [p0[0] - p0[0] * per, p0[1] - (p0[1] - p5[1]) * per]
break
default:
return null
}
}
const scale = 750 / wepy.getSystemInfoSync().windowWidth
const pArr = dArr.map((_, index) => {
return get5dPoint(_, index + 1, 210 / scale, 200 / scale)
})
pArr.push(pArr[0])
const context = wepy.createCanvasContext('canvas')
context.setStrokeStyle('#000000')
context.setFillStyle('rgba(255, 235, 59, 0.9)')
context.setLineWidth(1)
pArr.forEach((p, index) => {
if (index > 0) {
context.lineTo(p[0], p[1])
} else {
context.moveTo(p[0], p[1])
}
})
context.fill()
context.stroke()
context.draw()
}