小程序中使用 canvas 制作 5 维雷达图(结合小学六年级三角函数知识)

背景

微信小程序项目中需要制作一个 5 维雷达图(如图一),许多人第一时间可能想到的就是去找插件解决问题,其实小程序的数据可视化的插件还真有,但就为了这一个小图非得去把整个笨重的图形库引进来,这就直接拖慢了小程序的加载速度。使用小程序里的 canvas,结合小学六年级三角函数几何知识,其实我们完全可以很快 DIY 一个 5 维雷达图出来

图一-5维雷达图
图一-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()
  }

 

作者: 博主

Talk is cheap, show me the code!

发表评论

电子邮件地址不会被公开。

Captcha Code