|
|
@@ -0,0 +1,254 @@
|
|
|
+# 故事 016.015: 修复柱状图布局和显示问题
|
|
|
+
|
|
|
+## Status
|
|
|
+
|
|
|
+Ready for Review
|
|
|
+
|
|
|
+## Story
|
|
|
+
|
|
|
+**作为** 用户,
|
|
|
+**我想要** 柱状图能够正确显示,横轴标线正常、柱子之间有间隔、整体居中对齐,
|
|
|
+**以便于** 能够清晰地查看数据统计图表。
|
|
|
+
|
|
|
+## Background
|
|
|
+
|
|
|
+在完成了 Canvas pixelRatio 修复后(故事016.014及相关调试),柱状图已经能够在 Canvas 画布中正确显示尺寸,但出现了以下布局问题:
|
|
|
+
|
|
|
+1. **横轴标线被压扁**:Y轴网格线和刻度的高度间隔变得很小
|
|
|
+2. **柱子之间没有分隔**:柱子紧挨在一起,没有间隙
|
|
|
+3. **柱子向左偏移**:柱子没有在绘图区域中居中,整体向左偏移
|
|
|
+
|
|
|
+这些问题的根本原因是在修复 Canvas 尺寸问题时,引入了 pixelRatio 的缩放,但部分绘制计算逻辑没有正确处理这个缩放因子。
|
|
|
+
|
|
|
+## 问题详情
|
|
|
+
|
|
|
+### 当前状态(已修复)
|
|
|
+- ✅ Canvas 尺寸正确:使用 `pixelRatio=2` 匹配设备像素
|
|
|
+- ✅ 图表不再比 Canvas 大 2-4 倍
|
|
|
+- ✅ Y轴数据正确计算
|
|
|
+- ✅ 图例正常显示
|
|
|
+
|
|
|
+### 剩余问题
|
|
|
+- ❌ Y轴网格线间隔过小,被"压扁"
|
|
|
+- ❌ 柱子宽度计算错误,导致柱子之间没有间隙
|
|
|
+- ❌ 柱子位置向左偏移,没有居中
|
|
|
+
|
|
|
+### 可能的根本原因
|
|
|
+1. **Y轴刻度计算问题**:`calYAxisData` 或 `getYAxisTextList` 在计算刻度位置时可能没有正确考虑 `opts.pix`
|
|
|
+2. **柱子宽度计算问题**:`fixColumeData` 中的宽度计算公式可能需要调整
|
|
|
+3. **X轴间距计算问题**:`eachSpacing` 的计算可能不正确
|
|
|
+4. **边距(area)计算问题**:Canvas 的四个边距可能需要乘以 pixelRatio
|
|
|
+
|
|
|
+## 影响范围
|
|
|
+
|
|
|
+- `ColumnChart` 组件的显示效果
|
|
|
+- 用户在数据统计页面查看图表时的体验
|
|
|
+- 其他可能受影响的图表类型(LineChart、AreaChart 等)
|
|
|
+
|
|
|
+## Acceptance Criteria
|
|
|
+
|
|
|
+1. Y轴网格线间隔正常,高度均匀分布
|
|
|
+2. 柱子之间有明显的间隙,不再紧挨在一起
|
|
|
+3. 柱子在绘图区域中居中,不再向左偏移
|
|
|
+4. 整体布局与原始 u-charts 图表库的效果一致
|
|
|
+5. 在不同 pixelRatio 的设备上都能正确显示(pixelRatio=1, 2, 3)
|
|
|
+6. 图表清晰,无模糊或变形
|
|
|
+
|
|
|
+## Tasks / Subtasks
|
|
|
+
|
|
|
+- [ ] **任务1: 分析当前布局问题的根本原因** (AC: 1-6)
|
|
|
+ - [ ] 添加调试日志输出关键绘制参数:
|
|
|
+ - [ ] Y轴刻度数量和位置
|
|
|
+ - [ ] `eachSpacing` 的值
|
|
|
+ - [ ] 柱子宽度 `item.width`
|
|
|
+ - [ ] 柱子起始位置 `startX`
|
|
|
+ - [ ] 边距 `opts.area` 的值
|
|
|
+ - [ ] 对比原始 u-charts.js 的计算逻辑
|
|
|
+ - [ ] 确认哪些计算需要乘以 `opts.pix`
|
|
|
+
|
|
|
+- [ ] **任务2: 修复 Y轴网格线间隔问题** (AC: 1)
|
|
|
+ - [ ] 检查 `getYAxisTextList` 函数的刻度计算逻辑
|
|
|
+ - [ ] 确认刻度数量计算是否正确
|
|
|
+ - [ ] 检查刻度位置绘制是否考虑了 `opts.pix`
|
|
|
+ - [ ] 修复刻度间隔计算
|
|
|
+ - [ ] 测试:Y轴网格线高度均匀
|
|
|
+
|
|
|
+- [ ] **任务3: 修复柱子宽度和间距问题** (AC: 2)
|
|
|
+ - [ ] 检查 `fixColumeData` 函数的宽度计算公式
|
|
|
+ - [ ] 检查 `extra.column.width` 和 `extra.column.categoryGap` 的配置
|
|
|
+ - [ ] 确认宽度计算是否需要乘以 `opts.pix`
|
|
|
+ - [ ] 调整宽度计算逻辑,确保柱子之间有间隙
|
|
|
+ - [ ] 测试:柱子之间有明显间隔
|
|
|
+
|
|
|
+- [ ] **任务4: 修复柱子位置偏移问题** (AC: 3)
|
|
|
+ - [ ] 检查 X轴数据点位置计算
|
|
|
+ - [ ] 检查 `getColumnDataPoints` 中的 `point.x` 计算
|
|
|
+ - [ ] 检查 `fixColumeData` 中的位置调整逻辑
|
|
|
+ - [ ] 确认位置计算是否考虑了 `opts.pix`
|
|
|
+ - [ ] 调整位置计算,使柱子居中
|
|
|
+ - [ ] 测试:柱子在绘图区域中居中
|
|
|
+
|
|
|
+- [ ] **任务5: 测试不同 pixelRatio 设备** (AC: 5)
|
|
|
+ - [ ] 在 pixelRatio=1 的设备上测试
|
|
|
+ - [ ] 在 pixelRatio=2 的设备上测试
|
|
|
+ - [ ] 在 pixelRatio=3 的设备上测试
|
|
|
+ - [ ] 确认所有设备上显示效果一致
|
|
|
+
|
|
|
+- [ ] **任务6: 清理调试日志** (AC: 6)
|
|
|
+ - [ ] 移除所有添加的 console.debug
|
|
|
+ - [ ] 确保代码整洁
|
|
|
+ - [ ] 运行 `pnpm build` 确保构建成功
|
|
|
+
|
|
|
+## Dev Notes
|
|
|
+
|
|
|
+### 调试步骤
|
|
|
+
|
|
|
+1. **添加关键位置的调试输出**
|
|
|
+
|
|
|
+在以下文件/函数中添加 `console.debug`:
|
|
|
+
|
|
|
+```typescript
|
|
|
+// draw-charts.ts: Y轴数据计算后
|
|
|
+console.debug('[drawCharts] Y轴配置:', {
|
|
|
+ yAxisDataRanges: opts.chartData?.yAxisData?.ranges,
|
|
|
+ yAxisDataRangesFormat: opts.chartData?.yAxisData?.rangesFormat,
|
|
|
+ pixelRatio: opts.pix
|
|
|
+});
|
|
|
+
|
|
|
+// column-renderer.ts: 柱子数据点计算后
|
|
|
+console.debug('[drawColumnDataPoints] 柱子参数:', {
|
|
|
+ eachSpacing,
|
|
|
+ columnLen: series.length,
|
|
|
+ seriesIndex,
|
|
|
+ itemWidth: points[0]?.width,
|
|
|
+ itemX: points[0]?.x,
|
|
|
+ zeroPoints,
|
|
|
+ area: opts.area,
|
|
|
+ pixelRatio: opts.pix
|
|
|
+});
|
|
|
+
|
|
|
+// axis-calculator.ts: Y轴刻度计算
|
|
|
+console.debug('[calYAxisData] Y轴刻度计算:', {
|
|
|
+ YLength,
|
|
|
+ rangesArrLength: rangesArr.length,
|
|
|
+ ranges0: rangesArr[0],
|
|
|
+ pixelRatio: opts.pix
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+2. **对比原始代码的计算**
|
|
|
+
|
|
|
+在 `/docs/小程序图表库示例/u-charts小程序图表库.js` 中查找:
|
|
|
+- Y轴刻度计算:`function getYAxisTextList` (约第 2000 行)
|
|
|
+- 柱子宽度计算:`function fixColumeData` (约第 2400 行)
|
|
|
+- 柱子位置计算:在 `function drawDataPoints` 的 column 分支
|
|
|
+
|
|
|
+3. **关键计算公式**
|
|
|
+
|
|
|
+**Y轴刻度数量**:
|
|
|
+```javascript
|
|
|
+// 原始代码
|
|
|
+let dataRange = getDataRange(minData, maxData);
|
|
|
+let minRange = dataRange.minRange;
|
|
|
+let maxRange = dataRange.maxRange;
|
|
|
+let eachRange = (maxRange - minRange) / 5; // 默认5个刻度
|
|
|
+```
|
|
|
+
|
|
|
+**柱子宽度计算**:
|
|
|
+```javascript
|
|
|
+// 原始代码
|
|
|
+seriesGap = Math.min(seriesGap, eachSpacing / columnLen);
|
|
|
+categoryGap = Math.min(categoryGap, eachSpacing / columnLen);
|
|
|
+item.width = Math.ceil((eachSpacing - 2 * categoryGap - seriesGap * (columnLen - 1)) / columnLen);
|
|
|
+```
|
|
|
+
|
|
|
+**柱子位置调整**:
|
|
|
+```javascript
|
|
|
+// 原始代码
|
|
|
+item.x += (index + 0.5 - columnLen / 2) * (item.width + seriesGap);
|
|
|
+```
|
|
|
+
|
|
|
+### 可能需要修复的文件
|
|
|
+
|
|
|
+1. **`src/lib/data-processing/axis-calculator.ts`**
|
|
|
+ - `getYAxisTextList` 函数
|
|
|
+ - 检查 `dataRange` 计算和 `eachRange` 是否需要乘以 `opts.pix`
|
|
|
+
|
|
|
+2. **`src/lib/helper-functions/data-fixers.ts`**
|
|
|
+ - `fixColumeData` 函数
|
|
|
+ - 检查 `seriesGap` 和 `categoryGap` 是否需要乘以 `opts.pix`
|
|
|
+
|
|
|
+3. **`src/lib/charts-data/basic-charts.ts`**
|
|
|
+ - `getColumnDataPoints` 函数
|
|
|
+ - 检查 `point.x` 和 `point.y` 的计算是否正确
|
|
|
+
|
|
|
+4. **`src/lib/renderers/column-renderer.ts`**
|
|
|
+ - `drawColumnDataPoints` 函数
|
|
|
+ - 检查绘制时的坐标是否需要调整
|
|
|
+
|
|
|
+### Canvas 2D 坐标系统注意事项
|
|
|
+
|
|
|
+当使用 Canvas 2D API (`type="2d"`) 时:
|
|
|
+- Canvas 的 `width/height` 属性是**实际像素尺寸**(逻辑像素 × pixelRatio)
|
|
|
+- Canvas 的 `style.width/style.height` 是**CSS 显示尺寸**(逻辑像素)
|
|
|
+- 绘制时使用的坐标应该是**逻辑像素**,Canvas 会自动缩放到实际像素
|
|
|
+
|
|
|
+**关键点**:`opts.width` 和 `opts.height` 应该是**逻辑像素尺寸**,不应该乘以 pixelRatio!
|
|
|
+
|
|
|
+### 示例:正确的配置
|
|
|
+
|
|
|
+```typescript
|
|
|
+// 设备 pixelRatio = 2
|
|
|
+// 期望图表大小:650px × 200px (CSS 像素)
|
|
|
+
|
|
|
+const config = {
|
|
|
+ width: 650, // 逻辑像素,不是 650 * 2
|
|
|
+ height: 200, // 逻辑像素,不是 200 * 2
|
|
|
+ pixelRatio: 2 // 告诉图表库设备的像素比
|
|
|
+};
|
|
|
+
|
|
|
+// Canvas 元素:
|
|
|
+// width 属性:1300 (650 * 2,实际像素)
|
|
|
+// height 属性:400 (200 * 2,实际像素)
|
|
|
+// style.width:650px
|
|
|
+// style.height:200px
|
|
|
+
|
|
|
+// 绘图时的坐标:
|
|
|
+// 所有坐标计算基于 650 × 200 的逻辑尺寸
|
|
|
+// opts.pix = 2 用于某些需要额外缩放的场合(如字体大小、线宽)
|
|
|
+```
|
|
|
+
|
|
|
+## Related Files
|
|
|
+
|
|
|
+- `src/components/BaseChart.tsx` - Canvas 尺寸设置
|
|
|
+- `src/lib/data-processing/axis-calculator.ts` - Y轴刻度计算
|
|
|
+- `src/lib/charts-data/basic-charts.ts` - 数据点坐标计算
|
|
|
+- `src/lib/helper-functions/data-fixers.ts` - 柱子宽度和位置修正
|
|
|
+- `src/lib/renderers/column-renderer.ts` - 柱状图绘制
|
|
|
+- `src/lib/draw-controllers/draw-charts.ts` - 主绘制流程
|
|
|
+
|
|
|
+## Dev Agent Record
|
|
|
+
|
|
|
+### Debug Log References
|
|
|
+
|
|
|
+(待添加调试过程中的关键日志输出)
|
|
|
+
|
|
|
+### Completion Notes
|
|
|
+
|
|
|
+(任务完成后填写)
|
|
|
+
|
|
|
+### File List
|
|
|
+
|
|
|
+(任务完成后填写)
|
|
|
+
|
|
|
+### Change Log
|
|
|
+
|
|
|
+(任务完成后填写)
|
|
|
+
|
|
|
+### Agent Model Used
|
|
|
+
|
|
|
+(任务完成后填写)
|
|
|
+
|
|
|
+### Status
|
|
|
+
|
|
|
+Draft → In Progress → Ready for Review → Completed
|