[根目录](../../CLAUDE.md) > **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 图表组件,负责: 1. **图表渲染**:在微信小程序中渲染 ECharts 图表 2. **Canvas 适配**:适配小程序 Canvas 2D 接口 3. **事件处理**:处理触摸交互事件 4. **响应式布局**:自适应屏幕尺寸 --- ## 入口与启动 ### 组件路径 - **注册路径**:`components/ec-canvas/ec-canvas` - **物理路径**:`components/ec-canvas/ec-canvas.js` ### 使用方式 ```json // 页面 JSON 配置 { "usingComponents": { "ec-canvas": "../../components/ec-canvas/ec-canvas" } } ``` ```xml ``` --- ## 对外接口 ### 组件属性(Properties) | 属性名 | 类型 | 默认值 | 说明 | |--------|------|--------|------| | canvasId | String | 'ec-canvas' | Canvas 组件 ID | | ec | Object | {} | 图表配置对象(必须包含 onInit 方法) | | disableTouch | Boolean | false | 是否禁用触摸交互 | ### ec 对象结构 ```javascript 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 接口 ### 配置项 ```javascript // 组件配置 Component({ properties: { canvasId: { type: String, value: 'ec-canvas' }, ec: { type: Object, value: {} } } }) ``` --- ## 数据模型 ### 组件生命周期 ```javascript 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 初始化 ```javascript 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. 触摸事件处理 ```javascript 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. 基础折线图 ```javascript // 页面 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. 面积图(带渐变) ```javascript 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. 动态更新数据 ```javascript // 更新图表数据 updateChart(newData) { if (this.chart) { this.chart.setOption({ series: [{ data: newData }] }) } } // 清空图表 clearChart() { if (this.chart) { this.chart.clear() } } ``` --- ## WXML 模板结构 ```xml ``` --- ## WXSS 样式 ```css /* components/ec-canvas/ec-canvas.wxss */ .ec-canvas { width: 100%; height: 100%; display: block; } ``` --- ## 测试与质量 ### 测试覆盖 - ✅ 在价格趋势页正常工作 - ✅ 图表渲染正确 - ✅ 触摸交互正常 - ✅ 响应式布局适配 ### 测试要点 1. **图表渲染**:验证不同类型图表正常显示 2. **数据更新**:验证动态更新数据功能 3. **交互功能**:验证触摸、缩放、拖拽等交互 4. **性能测试**:大数据量时的渲染性能 5. **兼容性**:iOS/Android 不同平台兼容性 --- ## 常见问题 (FAQ) ### Q: 图表不显示? **A**: 检查以下几点: 1. 确保 `ec` 对象包含 `onInit` 方法 2. 确保 Canvas 节点已正确渲染 3. 查看控制台是否有错误信息 4. 检查 ECharts 配置是否正确 ### Q: 如何修改图表尺寸? **A**: 在 WXML 中设置容器尺寸: ```xml ``` ### Q: 如何支持手势缩放? **A**: 在 ECharts 配置中启用: ```javascript const option = { dataZoom: [{ type: 'inside', start: 0, end: 100 }], // ... 其他配置 } ``` ### Q: 如何导出图表为图片? **A**: 使用 Canvas 的 `toDataURL` 方法: ```javascript const canvas = this.chart.canvas const url = canvas.toDataURL('image/png') // 预览图片 wx.previewImage({ urls: [url] }) ``` ### Q: 图表性能如何优化? **A**: 优化建议: 1. 减少数据点数量(采样) 2. 关闭动画效果 3. 使用轻量级图表类型 4. 避免频繁更新 ```javascript // 关闭动画 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 # 本文档 ``` --- ## 下一步建议 ### 功能增强 1. **更多图表类型** - 柱状图(Bar) - 饼图(Pie) - 散点图(Scatter) - K 线图(Candlestick) 2. **交互增强** - Tooltip 提示框 - 图例筛选 - 数据区域缩放 - 标记点/标记线 3. **性能优化** - 虚拟滚动(大数据量) - 增量渲染 - Web Worker 计算 ### 最佳实践 1. **数据格式化**:统一数据格式转换逻辑 2. **错误处理**:添加图表渲染失败的降级方案 3. **加载状态**:显示加载动画 4. **空状态**:无数据时友好提示 --- **模块状态**: ✅ 已完成 **优先级**: 高(核心组件) **预估工作量**: 已完成 **使用场景**: [pages/trend](../../pages/trend/CLAUDE.md) - 价格趋势图 **相关资源**: [ECharts 文档](https://echarts.apache.org/zh/index.html)