当前位置:   article > 正文

微信小程序之图表系列——canvas绘制饼状图,带点击效果_微信小程序,扇形控件

微信小程序,扇形控件

一图胜千言,相信很多开发者都没有绕开过图表制作这个坑,在小程序中也是,当然可以用第三方echart等制图插件来做,但小程序要求代码量最大12M,还得分好几个包,一个echart插件就将近1M,要是只做一张表或几张表实在浪费,况且小程序的加载速度与程序包大小也是息息相关的。因此写这系列文章,目的是降低程序包大小,又能实现需要的图表。
上篇文章微信小程序之图表系列——一步步用canvas实现柱状图制作了柱状图,做完之后不管对制作图表还是canvas都会有一个新的认识,这篇文章做个练习,制作一下饼状图,同时还要再增加一个点击效果,因为毕竟很多图表是需要与用户交互的。
上效果:
在这里插入图片描述
体验路径:
在这里插入图片描述
实现思路:
1、与柱状图一样,本质上还是通过计算参数用canvas画,只不过这次需要用到canvas的arc方法,画圆弧,再构成扇形
2、点击效果就需要监听touch方法,也是通过计算判断点击在哪个扇形区域,从而重新绘制

代码:
js

Page({

  /**
   * 页面的初始数据
   */
  data: {
    canvasInfo: {},
    dataList: [{
      title: "男",
      value: 3,
      background: "#b8f2e6"
    }, {
      title: "女",
      value: 8,
      background: "#ffa69e"
    }, {
      title: "未知",
      value: 9,
      background: "#f7db70"
    }],
    pieInfo: {}
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    this.messureCanvas()
  },
  messureCanvas() {
    let query = wx.createSelectorQuery().in(this);
    // 然后逐个取出navbar和header的节点信息
    // 选择器的语法与jQuery语法相同
    query.select('#pieCanvas').boundingClientRect();
    // 执行上面所指定的请求,结果会按照顺序存放于一个数组中,在callback的第一个参数中返回
    var that = this
    query.exec((res) => {
      // 分别取出navbar和header的高度 
      console.log(res)
      var canvasInfo = {}
      canvasInfo.width = res[0].width
      canvasInfo.height = res[0].height
      that.setData({
        canvasInfo: canvasInfo
      })
      console.log(canvasInfo)
      that.drawPie(-1)
    })
  },
  drawPie(index) {
    const ctxPie = wx.createCanvasContext("pieCanvas")
    var canvasInfo = this.data.canvasInfo
    var dataList = this.data.dataList
    var pieInfo = this.data.pieInfo
    var pieRadius = (canvasInfo.width - 90) / 4
    pieInfo.pieRadius = pieRadius
    var pieX = 30 + pieRadius
    pieInfo.centerX = pieX
    var pieY = 30 + pieRadius
    pieInfo.centerY = pieY
    var totalValue = 0
    for (var i = 0; i < dataList.length; i++) {
      totalValue = totalValue + dataList[i].value
    }
    var area = []
    for (var i = 0; i < dataList.length; i++) {
      var areaItem = {}
      ctxPie.beginPath()
      var start = 0
      for (var j = 0; j < i; j++) {
        start = start + dataList[j].value
      }
      if (i < dataList.length - 1) {
        if(index==i){
          ctxPie.arc(pieX, pieY, pieRadius+5, start / totalValue * 2 * Math.PI, (start + dataList[i].value) / totalValue * 2 * Math.PI)
        }else{
          ctxPie.arc(pieX, pieY, pieRadius, start / totalValue * 2 * Math.PI, (start + dataList[i].value) / totalValue * 2 * Math.PI)
        }
        areaItem.start = start / totalValue * 2 * Math.PI
        areaItem.end = (start + dataList[i].value) / totalValue * 2 * Math.PI
      } else {
        if(index == i){
          ctxPie.arc(pieX, pieY, pieRadius+5, start / totalValue * 2 * Math.PI, 2 * Math.PI)
        }else{
          ctxPie.arc(pieX, pieY, pieRadius, start / totalValue * 2 * Math.PI, 2 * Math.PI)
        }
        areaItem.start = start / totalValue * 2 * Math.PI
        areaItem.end = 2 * Math.PI
      }
      area.push(areaItem)
      ctxPie.lineTo(pieX, pieY);
      ctxPie.setFillStyle(dataList[i].background);
      ctxPie.fill();
      ctxPie.closePath();


      //绘制标注
      var startX = 2 * pieRadius + 60
      var startY = (30 + pieRadius) - 30 * dataList.length / 2 + i * 30
      ctxPie.setFillStyle(dataList[i].background)
      ctxPie.fillRect(startX, startY, 20, 20)


      ctxPie.setFillStyle('#8a8a8a')
      ctxPie.setFontSize(12)
      ctxPie.fillText(dataList[i].title, startX + 30, startY + 15)
      ctxPie.fillText(dataList[i].value + "", startX + 70, startY + 15)
      ctxPie.fillText(parseInt(dataList[i].value * 100 / totalValue) + "%" + "", startX + 100, startY + 15)

    }
    pieInfo.area = area
    this.data.pieInfo = pieInfo
    console.log(this.data.pieInfo)
    ctxPie.draw()
  },
  touchStart(e) {
    var pieInfo = this.data.pieInfo
    var x = e.touches[0].x
    var y = e.touches[0].y
    if ((Math.pow(x - pieInfo.centerX, 2) + Math.pow(y - pieInfo.centerY, 2)) > Math.pow(pieInfo.pieRadius, 2)) {
      console.log("在圆外,不执行")
      return
    }
    var pointPos = 0
    console.log("在圆内,继续执行")
    var angle = Math.atan((y - pieInfo.centerY) / (x - pieInfo.centerX)) / (Math.PI / 180)
    //判断角度值
    if (x > pieInfo.centerX) {
      if (angle > 0) {
        pointPos = angle / 180 * Math.PI
      } else {
        pointPos = angle / 180 * Math.PI + 2 * Math.PI
      }
    } else {
      if (angle > 0) {
        pointPos = angle / 180 * Math.PI + Math.PI
      } else {
        pointPos = angle / 180 * Math.PI + Math.PI
      }
    }
    var index = 0
    for(var i = 0;i<pieInfo.area.length;i++){
      if(pointPos>pieInfo.area[i].start&&pointPos<pieInfo.area[i].end){
        index = i
      }
    }
    console.log("在第"+index+"个区域")
    this.drawPie(index)
  },
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150

wxml

<view class="container">
  <canvas style="width:100%;height:350px;margin-top:20px;" canvas-id="pieCanvas" id="pieCanvas" bindtouchstart="touchStart"></canvas>
</view>
  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/549692
推荐阅读
相关标签
  

闽ICP备14008679号