赞
踩
一图胜千言,相信很多开发者都没有绕开过图表制作这个坑,在小程序中也是,当然可以用第三方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) }, })
wxml
<view class="container">
<canvas style="width:100%;height:350px;margin-top:20px;" canvas-id="pieCanvas" id="pieCanvas" bindtouchstart="touchStart"></canvas>
</view>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。