由于微信小程序本身框架的限制,很难整合现有的图表工具。目前有两种显示图表的方案:
服务器渲染图表,输出图片,直接在微信小程序中显示渲染后的图片。例如,高图表提供了服务器端呈现功能。这种方法需要一套后台的渲染服务,有一定的网络开销。微信小程序API提供了画布的支持,可以自行绘制图表。我们来看看如何在微信小程序中绘制图表。
查看微信小程序的详细Canvas API文档。
使用画布/画布在模板文件中声明画布组件。
使用wx.createContext获取绘图上下文上下文。
调用wx.drawCanvas进行绘制。
wx . draw canvas({ canvas id : ' first canvas ',actions 3360 context . geta actions()//get draw action array });绘制折线图
//获取绘图上下文contextvarcontext=wx . create context();//设置笔画颜色上下文. setstrokestyle(# 7cb 5ec ');//设置线宽上下文. setlinewidth(4);context.moveTo(50,70);context.lineTo(150,150);context.lineTo(250,30);context.lineTo(350,120);context.lineTo(450,150);context.lineTo(550,95);//描边当前路径上下文. Stroke();wx . draw canvasid({ canvasid : ' testCanvas ',actions 3360 context . GetActions()});描述:路径中没有记录moveTo方法。
渲染:
看起来没有预期的那么难,但似乎效果不错。
画出每个数据点的识别图案。
.context . BeginPath();//设置笔画颜色上下文. setstrokestyle(' # ffffff ');//设置填充颜色上下文. setfillstyle(' # 7cb 5ec ');context.moveTo(50 7,70);//绘制圆形区域context.arc (50,70,8,0,2 * math.pi,false);context.moveTo(150 7,150);context.arc(150,150,8,0,2 *数学。PI,假);context . closepath();//填充路径上下文. Fillcontext . stroke();渲染:
说明:为避免影响logo图案路径之前画的折线路径,用beginPath和closePath包裹。
画横坐标
规定的参数格式如下。
Opts={width: 640,//画布区域宽度高度3360 400,//画布区域高度类别: ['2016-08 ',' 2016-09 ',' 2016-10 ',' 2016-11 ',' 2016-16 '
稍微整理一下你的想法:
根据类别号均匀划分画布宽度;计算横坐标中每个分类的起点;画一个副本(这里会有更多的代码,后面会详细提到)。每个间距=数学楼层(o
pts.width / opts.categories.length);var points = [];// 起始点x坐标var startX = 0;// 起始点y坐标var startY = opts.height - 30;// 终点x坐标var endX = opts.width;// 终点y坐标var endY = opts.height;// 计算每个分类的起始点x坐标opts.categories.forEach(function(item, index) { points.push(startX + index * eachSpacing);});points.push(endX);// 绘制横坐标context.beginPath();context.setStrokeStyle("#cccccc");context.setLineWidth(1);// 绘制坐标轴横线context.moveTo(startX, startY);context.lineTo(endX, startY);// 绘制坐标轴各区块竖线points.forEach(function(item, index) { context.moveTo(item, startY); context.lineTo(item, endY);});context.closePath();context.stroke();context.beginPath();// 设置字体大小context.setFontSize(20);// 设置字体填充颜色context.setFillStyle('#666666');opts.categories.forEach(function(item, index) { context.fillText(item, points[index], startY + 28);});context.closePath();context.stroke();效果图:
效果不错,除了文字没有居中……
查看微信小程序官方提供的文档并没有提供HTML5 Canvas中的mesureText(获取文案宽度)方法,下面我们自己简单的实现,并不是绝对精确,但是误差基本可以忽略。
function mesureText (text) { var text = text.split(''); var width = 0; text.forEach(function(item) { if (/[a-zA-Z]/.test(item)) { width += 14; } else if (/[0-9]/.test(item)) { width += 11; } else if (/./.test(item)) { width += 5.4; } else if (/-/.test(item)) { width += 6.5; } else if (/[u4e00-u9fa5]/.test(item)) { width += 20; } }); return width;}
这里分别处理了字母、数字、.、-、汉字这几个常用字符。
上面的代码稍微修改下:
opts.categories.forEach(function(item, index) { var offset = eachSpacing / 2 - mesureText(item) / 2; context.fillText(item, points[index] + offset, startY + 28);});
大功告成!
如何在折线上绘制出每个数据点的数值文案大家可以动手自己实现下。
为了避免纵坐标的刻度出现小数的情况,我们把纵坐标分为5个区块,我们取最小单位刻度为例如10(能够被5整除),当然真实情况会比这复杂,待会儿我们再讨论。
所以我们的处理输入输出应该是下面的结果。
(5, 34.1) => (10, 40)(10, 34) => (10, 40)(-5.1, 40) => (-10, 40)
// 确定Y轴取值范围function findRange (num, type, limit) { limit = limit || 10; // upper向上查找,lower向下查找 type = type ? type : 'upper'; // 进行取整操作,避免while时进入死循环 if (type === 'upper') { num = Math.ceil(num); } else { num = Math.floor(num); } while (num % limit !== 0) { if (type === 'upper') { num++; } else { num--; } } return num;}
好了,初步的确定范围已经完成了,但是细想一下这个范围还是不是很理想,比如用户传入的数据都是小数级别的,比如 (0.2, 0.8),我们输出的范围是(0, 5)这个范围偏大,图表展现的效果则会是上面有大部分的留白,同样用户输入的数据很大,比如(10000, 18000),我们得到的范围是(10000, 18010),这个范围则没什么意义,所以我们需要根据传入的数据的范围来分别确定我们的最小单位刻度。
规定我们的参数格式是这样的:
opts = { ... series: [{ ... data: [15, 20, 45, 37, 4, 80] }, {