Approved
作为 图表库开发者, 我想要 将 u-charts 核心库中的配置和工具函数搬迁到独立模块并添加 TypeScript 类型定义, 以便 提高代码的可维护性、可测试性和类型安全性,为后续 React 组件封装打下基础。
config.ts 创建完成,包含 config、assign、util 并有完整类型注解utils/ 目录下所有文件创建完成,每个函数都有类型注解[ ] Task 1: 分析配置和工具函数 (AC: 1, 2, 5)
[ ] Task 2: 创建模块化目录结构 (AC: 1, 2)
src/lib/config.tssrc/lib/utils/ 目录src/lib/utils/color.tssrc/lib/utils/math.tssrc/lib/utils/coordinate.tssrc/lib/utils/text.tssrc/lib/utils/collision.tssrc/lib/utils/misc.ts(其他工具函数)src/lib/utils/index.ts 统一导出[ ] Task 3: 搬迁配置对象并添加类型注解 (AC: 1, 3, 4, 5)
[ ] Task 4: 搬迁颜色工具函数并添加类型注解 (AC: 2, 3, 4, 5)
[ ] Task 5: 搬迁数学工具函数并添加类型注解 (AC: 2, 3, 4, 5)
[ ] Task 6: 搬迁坐标转换工具函数并添加类型注解 (AC: 2, 3, 4, 5)
[ ] Task 7: 搬迁文本测量工具函数并添加类型注解 (AC: 2, 3, 4, 5)
[ ] Task 8: 搬迁碰撞检测工具函数并添加类型注解 (AC: 2, 3, 4, 5)
[ ] Task 9: 搬迁其他工具函数并添加类型注解 (AC: 2, 3, 4, 5)
[ ] Task 10: 更新导出和验证搬迁结果 (AC: 1, 2, 3, 5)
故事 016.001 完成状态:
mini-charts 包基础结构src/lib/u-charts.ts(7680行代码)@ts-nocheck 绕过原始库中的类型问题故事 016.001 关键技术决策:
@ts-nocheck 绕过原始 u-charts 库的类型问题process 变量与 Node.js 全局对象的冲突(重命名为 chartProcess)uChartsEvent 类语法问题迁移策略: 保持 u-charts 核心绘制逻辑不变,渐进式模块化并添加类型定义
来源: tech-stack.md
来源: source-tree.md
mini-ui-packages/
└── mini-charts/ # mini-charts 包
├── src/
│ ├── index.ts # 主入口文件
│ └── lib/
│ ├── u-charts.ts # u-charts 核心库(7680行)
│ ├── config.ts # [新增] 配置对象
│ └── utils/ # [新增] 工具函数目录
│ ├── index.ts # 工具函数统一导出
│ ├── color.ts # 颜色工具函数
│ ├── math.ts # 数学工具函数
│ ├── coordinate.ts # 坐标转换工具
│ ├── text.ts # 文本测量工具
│ ├── collision.ts # 碰撞检测工具
│ └── misc.ts # 其他工具函数
├── tests/
│ └── u-charts.test.ts
├── package.json
├── tsconfig.json
└── jest.config.cjs
{
"compilerOptions": {
"target": "ES2020",
"lib": ["DOM", "DOM.Iterable", "ES2020"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
本故事重要: 需要移除 @ts-nocheck,为所有函数添加完整的类型注解,确保 strict: true 模式下无类型错误。
来源: mini-charts/src/lib/u-charts.ts
文件统计:
配置对象:
颜色工具函数:
hexToRgb(hexValue, opc): 十六进制颜色转 RGBA数学工具函数:
findRange(num, type, limit): 计算数值范围calCandleMA(dayArr, nameArr, colorArr, kdata): 计算 K 线图移动平均线createCurveControlPoints(points, i): 创建曲线控制点坐标转换工具函数:
convertCoordinateOrigin(x, y, center): 坐标原点转换isInAngleRange(angle, startAngle, endAngle): 判断角度是否在范围内calValidDistance(self, distance, chartData, config, opts): 计算有效滚动距离文本测量工具函数:
measureText(text, fontSize, context): 测量文本宽度碰撞检测工具函数:
avoidCollision(obj, target): 避免碰撞util.isCollision(obj1, obj2): 检测两个对象是否碰撞其他工具函数:
getH5Offset(e): 兼容 H5 点击事件getTouches(touches, opts, e): 获取触摸点坐标dataCombine(series): 数据合并dataCombineStack(series, len): 堆叠数据合并fixPieSeries(series, opts, config): 修复饼图系列数据fillSeries(series, opts, config): 填充系列数据fillCustomColor(linearType, customColor, series, config): 填充自定义颜色getDataRange(minData, maxData): 获取数据范围本故事重要: 必须为所有函数添加完整的类型注解,避免使用 any 类型(除非必要)。
类型定义示例:
// config.ts 类型定义示例
export interface UChartsConfig {
version: string;
yAxisWidth: number;
xAxisHeight: number;
padding: [number, number, number, number];
rotate: boolean;
fontSize: number;
fontColor: string;
dataPointShape: string[];
color: string[];
linearColor: string[];
pieChartLinePadding: number;
pieChartTextPadding: number;
titleFontSize: number;
subtitleFontSize: number;
radarLabelTextMargin: number;
}
export const config: UChartsConfig = {
version: 'v2.5.0-20230101',
yAxisWidth: 15,
// ... 其他配置
};
export function assign<T>(target: T, ...varArgs: Partial<T>[]): T {
// 实现逻辑
}
export interface Util {
toFixed(num: number, limit?: number): number | string;
isFloat(num: number): boolean;
approximatelyEqual(num1: number, num2: number): boolean;
isSameSign(num1: number, num2: number): boolean;
isSameXCoordinateArea(p1: Point, p2: Point): boolean;
isCollision(obj1: CollisionObject, obj2: CollisionObject): boolean;
}
export const util: Util = {
toFixed: function toFixed(num, limit = 2) {
// 实现逻辑
},
// ... 其他工具函数
};
// utils/color.ts 类型定义示例
export interface RgbColor {
r: number;
g: number;
b: number;
}
export function hexToRgb(hexValue: string, opc: number): string {
// 实现逻辑
}
// utils/math.ts 类型定义示例
export function findRange(num: number, type?: 'upper' | 'lower', limit?: number): number {
// 实现逻辑
}
export interface CandleDataPoint {
[key: string]: number;
}
export interface MASeriesItem {
data: (number | null)[];
name: string;
color: string;
}
export function calCandleMA(
dayArr: number[],
nameArr: string[],
colorArr: string[],
kdata: CandleDataPoint[]
): MASeriesItem[] {
// 实现逻辑
}
// utils/coordinate.ts 类型定义示例
export interface Point {
x: number;
y: number;
}
export interface Center {
x: number;
y: number;
}
export function convertCoordinateOrigin(x: number, y: number, center: Center): Point {
// 实现逻辑
}
export function isInAngleRange(
angle: number,
startAngle: number,
endAngle: number
): boolean {
// 实现逻辑
}
// utils/text.ts 类型定义示例
export interface TextMeasure {
width: number;
}
export function measureText(
text: string,
fontSize: number,
context: CanvasRenderingContext2D
): TextMeasure {
// 实现逻辑
}
// utils/collision.ts 类型定义示例
export interface CollisionObject {
start: Point;
end?: Point;
width: number;
height: number;
center?: Point;
area?: {
start: Point;
end: Point;
width: number;
height: number;
};
}
export interface Point {
x: number;
y: number;
}
export function avoidCollision(
obj: CollisionObject,
target: CollisionObject[]
): CollisionObject[] {
// 实现逻辑
}
export function isCollision(obj1: CollisionObject, obj2: CollisionObject): boolean {
// 实现逻辑(来自 util.isCollision)
}
// utils/misc.ts 类型定义示例
export interface H5Event {
offsetX: number;
offsetY: number;
mp: {
changedTouches: Array<{ x: number; y: number }>;
};
}
export function getH5Offset(e: { offsetX: number; offsetY: number }): H5Event {
// 实现逻辑
}
export interface TouchPoint {
x: number;
y: number;
}
export function getTouches(
touches: TouchPoint[],
opts: { width: number; area: number[] },
e: any
): TouchPoint[] {
// 实现逻辑
}
export 语法导出函数和类型测试框架: Jest(mini 包使用 Jest,不是 Vitest)
测试位置: tests/ 目录(与源码并列)
测试类型:
测试要求:
测试命令:
# 进入包目录
cd mini-ui-packages/mini-charts
# 运行所有测试
pnpm test
# 运行特定测试
pnpm test --testNamePattern "工具函数测试"
# 类型检查
pnpm typecheck
mini-charts 包在 PNPM 工作空间中:
tsc 编译到 dist/ 目录tsc --noEmit 验证类型重要: 本故事完成后,应该可以:
pnpm build 成功生成 dist/ 目录pnpm typecheck 无类型错误开发命令:
# 进入包目录
cd mini-ui-packages/mini-charts
# 安装依赖(在根目录)
pnpm install
# 开发模式(监听文件变化)
pnpm dev
# 类型检查
pnpm typecheck
# 运行测试
pnpm test
# 构建
pnpm build
来源: CLAUDE.md
pnpm test --testNamePattern "测试名称" 运行特定测试pnpm typecheck 加 grep 来过滤要检查的指定文件来源: source-tree.md
所有新文件应创建在:
mini-ui-packages/mini-charts/src/lib/config.tsmini-ui-packages/mini-charts/src/lib/utils/color.ts: 颜色工具函数math.ts: 数学工具函数coordinate.ts: 坐标转换工具text.ts: 文本测量工具collision.ts: 碰撞检测工具misc.ts: 其他工具函数index.ts: 工具函数统一导出mini-ui-packages/mini-charts/src/index.ts(需要更新导出)mini-ui-packages/mini-charts/tests/(可选,本故事不强制要求)any 类型(除非必要)完成本故事后,应该满足:
src/lib/config.ts 文件存在,包含 config、assign、util 并有完整类型注解src/lib/utils/ 目录下所有文件存在,每个函数都有类型注解pnpm typecheck 无类型错误来源: epic-016 故事列表
以下工作不在本故事范围内:
测试框架: Jest(不是 Vitest)
测试位置: tests/ 目录(与源码并列)
测试要求:
测试命令:
# 运行所有测试
pnpm test
# 运行特定测试
pnpm test --testNamePattern "配置和工具函数测试"
| Date | Version | Description | Author |
|---|---|---|---|
| 2025-12-24 | 1.0 | 创建故事文档 | Bob (Scrum Master) |
此部分由开发代理在实施过程中填写
此部分由 QA 代理在审查完成后填写