你有没有在小程序里见过这样的场景:一个健康类小程序展示近一周的步数变化曲线,或者一个记账小程序用饼图展示支出分类。这些图表在小程序里怎么画出来的?
不同于网页端可以轻松使用ECharts、Highcharts等成熟的图表库,小程序环境有自己的限制——没有DOM,不支持SVG,Canvas的能力也有所不同。但这并不意味着在小程序里做图表很困难。今天就聊聊几种可行的方案。
百度、阿里、腾讯的小程序生态中都有图表方案。微信这边最常用的是echarts-for-weixin,这是ECharts团队官方维护的小程序版本。
使用方法:
第一步,从GitHub下载ec-canvas组件,放到项目的components目录下。
第二步,在页面的JSON配置文件中声明使用该组件:
{ "usingComponents": { "ec-canvas": "/components/ec-canvas/ec-canvas" } }
第三步,在页面的WXML中添加组件标签:
<ec-canvas id="mychart" canvas-id="mychart" ec="{{ ec }}"></ec-canvas>
第四步,在JS中配置图表选项:
Page({ data: { ec: { onInit: function(canvas, width, height, dpr) { const chart = echarts.init(canvas, null, { width: width, height: height, devicePixelRatio: dpr }) canvas.setChart(chart) const option = { xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五'] }, yAxis: { type: 'value' }, series: [{ data: [120, 200, 150, 80, 70], type: 'line' }] } chart.setOption(option) return chart } } } })
这个方案的优势是ECharts生态完整,各种图表类型都能支持。缺点是组件包体积较大(压缩后约200多KB),对小程序代码包有压力。此外,在低端手机上频繁更新数据时会有一定的性能开销。
如果只需要一种或两种简单的图表类型,自己用Canvas绘制是更轻量的选择。小程序提供的Canvas 2D API已经相当完善。
以一个简单的柱状图为例:
drawBarChart(canvasId, data, labels) { const query = wx.createSelectorQuery() query.select(`#${canvasId}`) .fields({ node: true, size: true }) .exec((res) => { const canvas = res[0].node const ctx = canvas.getContext('2d') const width = res[0].width const height = res[0].height canvas.width = width canvas.height = height const barWidth = (width - 80) / data.length const maxValue = Math.max(...data) for (let i = 0; i < data.length; i++) { const barHeight = (data[i] / maxValue) * (height - 100) const x = 40 + i * barWidth const y = height - 30 - barHeight ctx.fillStyle = '#07c160' ctx.fillRect(x, y, barWidth - 5, barHeight) // 绘制标签 ctx.fillStyle = '#666666' ctx.font = '12px sans-serif' ctx.fillText(labels[i], x, height - 10) } }) }
这种方式的好处是完全可控,不引入额外的依赖库,代码包体积几乎不增加。缺点是实现复杂图表(如带交互的折线图、区域缩放等)工作量较大。
F2是蚂蚁集团出品的移动端图表库,也提供了小程序版本。它在设计上更注重移动端的性能和手势交互。
使用F2的步骤:
首先安装或下载f2-mp组件,然后在页面中使用:
<f2-chart id="myChart" onInit="handleChartInit"></f2-chart>
F2对触摸交互的支持更好,比如在折线图上双指缩放、单指滑动查看数据点等。如果图表需要较强的用户交互,F2是比ECharts更合适的选项。
对于极简场景——比如只需要在分享卡片或报告页面中展示一张静态图表——可以考虑服务端渲染。
流程是:小程序端将数据传给云函数,云函数在Node.js环境中使用Canvas库(如node-canvas)绘制图表,生成图片上传到云存储,返回图片URL给小程序端展示。
这种方案的优点是前端完全不承担绘制压力,图表风格完全可控,甚至可以用HTML+CSS的方式渲染得更精美。缺点是增加了云函数的调用成本和延迟,不适合需要实时刷新的动态图表。
明确你的需求再做选择,这比纠结哪个库“更好”更重要。
如果你需要多种图表类型(折线、柱状、饼图、雷达图等),且用户设备性能普遍不错,直接用echarts-for-weixin是最省事的。
如果你只需要一两种简单的图表,且对代码包大小敏感,手写Canvas绘制足够。
如果你追求流畅的交互体验(如金融类K线图、可缩放的数据仪表板),F2值得尝试。
如果你做的是企业内部的管理后台类小程序,数据展示频率不高,服务端渲染图片可能更省事,还能规避小程序Canvas的各种兼容问题。
画出来的图表模糊怎么办?这是经典问题。小程序的Canvas画布尺寸和显示尺寸需要对应。用SelectorQuery获取节点实际尺寸后,设置canvas.width和canvas.height为该尺寸乘以设备像素比。然后用ctx.scale(dpr, dpr)进行缩放。
图表更新时闪一下或者重绘不干净?每次重新绘制前,先用ctx.clearRect(0, 0, width, height)清空整个画布。
图表内的文字在某些安卓机型上显示位置偏移?不同手机的字体度量存在差异。建议使用sans-serif系统字体,并且避免依赖精确的文字宽度计算做布局。对于需要精密对齐的场景,用Canvas的measureText方法实测宽度再做偏移。
性能问题:频繁更新图表时(比如每秒刷新一次的数据监控),不要每次都重新创建Canvas上下文。保留上下文对象,只更新数据对应的部分区域。
小程序的图表可视化并没有想象中复杂。对于大部分小程序来说,echarts-for-weixin或手写Canvas绘制足以覆盖90%的需求。关键在于根据你实际需要的图表类型、交互程度、包体积限制来选择方案。
如果你只是想在一个页面里展示一两条简单的趋势线,手写Canvas百来行代码就能搞定,没必要引入一个完整的图表库。反过来,如果你的小程序有十几个页面都需要各种复杂的统计图表,那花点包体积的代价引入echarts是完全值得的。