你有没有在小程序里见过这样的场景:一个健康类小程序展示近一周的步数变化曲线,或者一个记账小程序用饼图展示支出分类。这些图表在小程序里怎么画出来的?

不同于网页端可以轻松使用ECharts、Highcharts等成熟的图表库,小程序环境有自己的限制——没有DOM,不支持SVG,Canvas的能力也有所不同。但这并不意味着在小程序里做图表很困难。今天就聊聊几种可行的方案。

方案一:微信官方扩展组件库中的echarts-for-weixin

百度、阿里、腾讯的小程序生态中都有图表方案。微信这边最常用的是echarts-for-weixin,这是ECharts团队官方维护的小程序版本。

使用方法:

第一步,从GitHub下载ec-canvas组件,放到项目的components目录下。

第二步,在页面的JSON配置文件中声明使用该组件:

json
{
  "usingComponents": {
    "ec-canvas": "/components/ec-canvas/ec-canvas"
  }
}

第三步,在页面的WXML中添加组件标签:

html
 
<ec-canvas id="mychart" canvas-id="mychart" ec="{{ ec }}"></ec-canvas>

第四步,在JS中配置图表选项:

javascript
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绘制是更轻量的选择。小程序提供的Canvas 2D API已经相当完善。

以一个简单的柱状图为例:

javascript
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的步骤:

首先安装或下载f2-mp组件,然后在页面中使用:

html
 
<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是完全值得的。

电话咨询
QQ咨询
在线咨询
服务投诉