9.5 KiB
9.5 KiB
根目录 > components/ec-canvas
components/ec-canvas - ECharts 图表组件
模块状态: ✅ 已完成
最后更新: 2026-01-07 09:16:32
变更记录 (Changelog)
2026-01-07 09:16:32
- 生成组件文档
- 补充使用说明与配置项
- 添加常见问题与故障排查
2026-01-06
- 集成 ECharts 图表库
- 实现微信小程序 Canvas 适配
- 封装为通用组件
模块职责
ec-canvas 是 ECharts 图表组件,负责:
- 图表渲染:在微信小程序中渲染 ECharts 图表
- Canvas 适配:适配小程序 Canvas 2D 接口
- 事件处理:处理触摸交互事件
- 响应式布局:自适应屏幕尺寸
入口与启动
组件路径
- 注册路径:
components/ec-canvas/ec-canvas - 物理路径:
components/ec-canvas/ec-canvas.js
使用方式
// 页面 JSON 配置
{
"usingComponents": {
"ec-canvas": "../../components/ec-canvas/ec-canvas"
}
}
<!-- 页面 WXML -->
<ec-canvas id="mychart-dom-line" canvas-id="mychart-line" ec="{{ ec }}"></ec-canvas>
对外接口
组件属性(Properties)
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| canvasId | String | 'ec-canvas' | Canvas 组件 ID |
| ec | Object | {} | 图表配置对象(必须包含 onInit 方法) |
| disableTouch | Boolean | false | 是否禁用触摸交互 |
ec 对象结构
ec: {
onInit: function(canvas, width, height, res) {
// 必须返回图表实例
const chart = echarts.init(canvas)
chart.setOption(option)
return chart
}
}
组件方法(Methods)
| 方法名 | 参数 | 说明 |
|---|---|---|
| touchStart | event | 触摸开始事件 |
| touchMove | event | 触摸移动事件 |
| touchEnd | event | 触摸结束事件 |
关键依赖与配置
依赖文件
| 文件 | 用途 |
|---|---|
ec-canvas.js |
组件逻辑(91 行) |
ec-canvas.wxml |
组件模板 |
ec-canvas.wxss |
组件样式 |
ec-canvas.json |
组件配置 |
echarts.js |
ECharts 库(简化版) |
wx-canvas.js |
Canvas 适配器 |
外部依赖
- ECharts:内置的简化版 ECharts 库
- Canvas 2D:微信小程序 Canvas 2D 接口
配置项
// 组件配置
Component({
properties: {
canvasId: {
type: String,
value: 'ec-canvas'
},
ec: {
type: Object,
value: {}
}
}
})
数据模型
组件生命周期
Component({
ready() {
// 1. 检查 ec 对象
if (!this.data.ec || !this.data.ec.onInit) {
console.warn('组件需绑定 ec 对象,且包含 onInit 方法')
return
}
// 2. 查询 Canvas 节点
const query = this.createSelectorQuery()
query.select(`#${this.data.canvasId}`)
.fields({ node: true, size: true })
.exec((res) => {
// 3. 初始化 Canvas
const canvasNode = res[0].node
const ctx = canvasNode.getContext('2d')
const dpr = wx.getSystemInfoSync().pixelRatio
// 4. 设置 Canvas 尺寸
canvasNode.width = res[0].width * dpr
canvasNode.height = res[0].height * dpr
ctx.scale(dpr, dpr)
// 5. 调用 onInit 初始化图表
const canvas = {
width: res[0].width * dpr,
height: res[0].height * dpr,
getContext: () => ctx,
node: canvasNode
}
this.chart = this.data.ec.onInit(canvas, res[0].width, res[0].height, res)
})
}
})
核心功能实现
1. Canvas 初始化
ready() {
const query = this.createSelectorQuery()
query.select(`#${this.data.canvasId}`)
.fields({ node: true, size: true })
.exec((res) => {
const canvasNode = res[0].node
const ctx = canvasNode.getContext('2d')
const dpr = wx.getSystemInfoSync().pixelRatio
// 缩放以适配高清屏
canvasNode.width = res[0].width * dpr
canvasNode.height = res[0].height * dpr
ctx.scale(dpr, dpr)
// 创建 Canvas 对象
const canvas = {
width: res[0].width * dpr,
height: res[0].height * dpr,
getContext: () => ctx,
node: canvasNode
}
// 调用外部初始化函数
this.chart = this.data.ec.onInit(canvas, res[0].width, res[0].height, res)
})
}
2. 触摸事件处理
methods: {
touchStart(e) {
if (this.chart && this.chart.touchStart) {
this.chart.touchStart(e)
}
},
touchMove(e) {
if (this.chart && this.chart.touchMove) {
this.chart.touchMove(e)
}
},
touchEnd(e) {
if (this.chart && this.chart.touchEnd) {
this.chart.touchEnd(e)
}
}
}
使用示例
1. 基础折线图
// 页面 JS
Page({
data: {
ec: {
onInit: null
}
},
onLoad() {
this.setData({
ec: {
onInit: this.initChart.bind(this)
}
})
},
initChart(canvas, width, height, res) {
const chart = echarts.init(canvas)
const option = {
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri']
},
yAxis: {
type: 'value'
},
series: [{
data: [120, 200, 150, 80, 70],
type: 'line',
smooth: true
}]
}
chart.setOption(option)
return chart
}
})
2. 面积图(带渐变)
initChart(canvas, width, height, res) {
const chart = echarts.init(canvas)
const option = {
xAxis: {
type: 'category',
data: ['1/1', '1/2', '1/3', '1/4', '1/5']
},
yAxis: {
type: 'value'
},
series: [{
data: [3850, 3860, 3840, 3870, 3890],
type: 'line',
smooth: true,
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(24, 144, 255, 0.3)' },
{ offset: 1, color: 'rgba(24, 144, 255, 0.05)' }
]
}
}
}]
}
chart.setOption(option)
return chart
}
3. 动态更新数据
// 更新图表数据
updateChart(newData) {
if (this.chart) {
this.chart.setOption({
series: [{
data: newData
}]
})
}
}
// 清空图表
clearChart() {
if (this.chart) {
this.chart.clear()
}
}
WXML 模板结构
<!-- components/ec-canvas/ec-canvas.wxml -->
<canvas
type="2d"
id="{{canvasId}}"
canvas-id="{{canvasId}}"
class="ec-canvas"
bindtouchstart="touchStart"
bindtouchmove="touchMove"
bindtouchend="touchEnd">
</canvas>
WXSS 样式
/* components/ec-canvas/ec-canvas.wxss */
.ec-canvas {
width: 100%;
height: 100%;
display: block;
}
测试与质量
测试覆盖
- ✅ 在价格趋势页正常工作
- ✅ 图表渲染正确
- ✅ 触摸交互正常
- ✅ 响应式布局适配
测试要点
- 图表渲染:验证不同类型图表正常显示
- 数据更新:验证动态更新数据功能
- 交互功能:验证触摸、缩放、拖拽等交互
- 性能测试:大数据量时的渲染性能
- 兼容性:iOS/Android 不同平台兼容性
常见问题 (FAQ)
Q: 图表不显示?
A: 检查以下几点:
- 确保
ec对象包含onInit方法 - 确保 Canvas 节点已正确渲染
- 查看控制台是否有错误信息
- 检查 ECharts 配置是否正确
Q: 如何修改图表尺寸?
A: 在 WXML 中设置容器尺寸:
<view style="width: 100%; height: 500rpx;">
<ec-canvas ec="{{ ec }}"></ec-canvas>
</view>
Q: 如何支持手势缩放?
A: 在 ECharts 配置中启用:
const option = {
dataZoom: [{
type: 'inside',
start: 0,
end: 100
}],
// ... 其他配置
}
Q: 如何导出图表为图片?
A: 使用 Canvas 的 toDataURL 方法:
const canvas = this.chart.canvas
const url = canvas.toDataURL('image/png')
// 预览图片
wx.previewImage({
urls: [url]
})
Q: 图表性能如何优化?
A: 优化建议:
- 减少数据点数量(采样)
- 关闭动画效果
- 使用轻量级图表类型
- 避免频繁更新
// 关闭动画
const option = {
animation: false,
// ... 其他配置
}
相关文件清单
components/ec-canvas/
├── ec-canvas.js # 组件逻辑(91 行)
├── ec-canvas.json # 组件配置
├── ec-canvas.wxml # 组件模板
├── ec-canvas.wxss # 组件样式
├── echarts.js # ECharts 库(简化版)
├── wx-canvas.js # Canvas 适配器
└── CLAUDE.md # 本文档
下一步建议
功能增强
-
更多图表类型
- 柱状图(Bar)
- 饼图(Pie)
- 散点图(Scatter)
- K 线图(Candlestick)
-
交互增强
- Tooltip 提示框
- 图例筛选
- 数据区域缩放
- 标记点/标记线
-
性能优化
- 虚拟滚动(大数据量)
- 增量渲染
- Web Worker 计算
最佳实践
- 数据格式化:统一数据格式转换逻辑
- 错误处理:添加图表渲染失败的降级方案
- 加载状态:显示加载动画
- 空状态:无数据时友好提示
模块状态: ✅ 已完成 优先级: 高(核心组件) 预估工作量: 已完成 使用场景: pages/trend - 价格趋势图 相关资源: ECharts 文档