diff --git a/skills/vchart-development-assistant/SKILL.md b/skills/vchart-development-assistant/SKILL.md
index e5702cf3fd..378824164b 100644
--- a/skills/vchart-development-assistant/SKILL.md
+++ b/skills/vchart-development-assistant/SKILL.md
@@ -1,6 +1,6 @@
---
name: vchart-development-assistant
-description: VChart图表库专家助手,支持问题诊断、配置生成、图片/Figma设计稿还原等场景,基于结构化知识库提供精确的图表开发解决方案
+description: VChart图表库专家助手,擅长创建、配置和调试VChart图表。当用户需要:生成柱状图/折线图/饼图等图表;修复图表不显示/点击事件不触发等问题;从图片或Figma设计稿还原图表样式;实现点击获取数据/数据动态更新/图表联动/导出图片/主题切换等交互功能;配置图例/坐标轴/标签/tooltip等组件时使用。即使用户没有提到"技能"或"VChart"这个词,只要涉及图表开发就触发。
---
# VChart 图表开发助手 Skill
@@ -29,6 +29,7 @@ description: VChart图表库专家助手,支持问题诊断、配置生成、
| **类型详情** | `references/type-details/*.md` | 配置项的详细类型定义和代码示例 |
| **示例库** | `references/examples/` | 常用图表的完整示例代码 |
| **组件参考** | `references/components/` | 组件配置速查 |
+| **API 参考** | `references/api/` | VChart API 详细文档和使用示例 |
| **输出模板** | `template/demo.html` | 生成可运行 HTML 示例的标准模板(纯 JS) |
| **诊断模板** | `template/diagnosis.html` | 问题诊断 HTML 模板(纯 JS) |
| **React 诊断** | `template/diagnosis-react.html` | React-VChart 问题诊断 HTML 模板 |
@@ -112,9 +113,39 @@ python3 scripts/generate_diagnosis_react_html.py \
- **普通图片模式**:从截图推断样式,中等精确度
- **Figma 设计稿模式**:提取精确样式值,高精确度
+#### API 交互需求识别(可嵌入任何场景)
+
+**重要**:API 交互不是独立场景,而是可以嵌入任何场景的**能力模块**。
+
+**识别信号**(在场景1/2/3中检测):
+
+- 用户询问"点击后..."、"hover 时..."、"选中后..."
+- 用户询问"动态更新"、"实时刷新"、"定时更新"
+- 用户询问"高亮"、"联动"、"外部控制"
+- 用户询问"导出"、"下载图片"
+- 用户询问"切换主题"、"深色模式"
+- 用户需要事件监听、状态管理、交互控制等功能
+
+**处理原则**:
+
+- 在**场景二(配置生成)**中检测到 API 需求 -> 同时生成 Spec + API 代码
+- 在**场景三(视觉还原)**中检测到 API 需求 -> 同时还原样式 + API 代码
+- 在**场景一(问题诊断)**中检测到 API 需求 -> 诊断 Spec + API 代码问题
+
+**API 能力分类**:
+
+| 能力类型 | 典型需求 | API 文档 |
+|---------|---------|---------|
+| 事件监听 | 点击响应、hover 效果 | `references/api/event-api.md` |
+| 数据操作 | 动态更新、实时刷新 | `references/api/data-api.md` |
+| 状态管理 | 高亮、选中 | `references/api/state-api.md` |
+| 交互控制 | 手动触发 tooltip | `references/api/interaction-api.md` |
+| 导出功能 | 下载图片 | `references/api/export-api.md` |
+| 主题切换 | 深色模式 | `references/api/theme-api.md` |
+
---
-### 对话中的场景动态切换 ⚠️
+### 对话中的场景动态切换
**核心原则**:根据最新用户输入重新评估场景,灵活切换。
@@ -128,6 +159,18 @@ python3 scripts/generate_diagnosis_react_html.py \
| 任何 | 提供新图片/截图 | 场景3 | 新的视觉还原 |
| 任何 | "重新生成"/全新需求 | 场景2 | 新的完整生成 |
+#### API 能力嵌入规则
+
+**在当前场景中检测到 API 需求时,不切换场景,而是增强输出**:
+
+| 当前场景 | 检测到 API 需求 | 增强动作 |
+| -------- | ------------------- | ------------------------------ |
+| 场景2 | "点击后获取数据" | 输出 Spec + 事件监听代码 |
+| 场景2 | "动态更新数据" | 输出 Spec + 数据更新函数 |
+| 场景3 | "联动高亮" | 输出 Spec + 状态管理代码 |
+| 场景3 | "导出图片" | 输出 Spec + 导出按钮和函数 |
+| 场景1 | API 代码报错 | 同时诊断 Spec 和 API 代码 |
+
#### 切换要点
- 保留之前代码作为上下文基础
@@ -136,7 +179,7 @@ python3 scripts/generate_diagnosis_react_html.py \
---
-## 生成后自检与问题预警 🔍
+## 生成后自检与问题预警
生成代码后立即检查以下高频错误点:
@@ -149,15 +192,15 @@ python3 scripts/generate_diagnosis_react_html.py \
### 主动提示
-发现风险时告知用户:
+发现风险��告知用户:
```
-✅ 已生成配置
-⚠️ 请确认数据字段名与 xField/yField 一致,否则图表可能无法显示
-💡 如遇问题请反馈,我会立即诊断
+已生成配置
+请确认数据字段名与 xField/yField 一致,否则图表可能无法显示
+如遇问题请反馈,我会立即诊断
```
-### 问题反馈关键词 → 立即切换场景1
+### 问题反馈关键词 -> 立即切换场景1
- "报错"/"error"/"不工作"/"失败"
- "没显示"/"空白"/"不出来"
@@ -178,7 +221,7 @@ python3 scripts/generate_diagnosis_react_html.py \
| **配置生成** | [workflows/scenario-2-generation.md](workflows/scenario-2-generation.md) | 完整生成、增量生成、意图识别 |
| **视觉还原** | [workflows/scenario-3-image-replication.md](workflows/scenario-3-image-replication.md) | 图片分析、Figma 精确还原、样式匹配 |
-**⚠️ 注意**:场景不是固定的!在对话中随时根据用户最新输入切换场景。参见上文"对话中的场景动态切换"部分。
+**注意**:场景不是固定的!在对话中随时根据用户最新输入切换场景。API 交互作为能力模块嵌入任何场景中。
---
@@ -189,19 +232,19 @@ python3 scripts/generate_diagnosis_react_html.py \
当需要查找配置项时,按以下顺序查询:
```
-用户意图 → topkey/*.json → type-meta/*.json → type-details/*.md
+用户意图 -> topkey/*.json -> type-meta/*.json -> type-details/*.md
```
**查询流程**:
-1. **意图识别**:用户说"加个标签" → 查询 `references/topkey/[图表类型].json` → 找到 `label` 配置项
-2. **结构查询**:需要 label 的属性 → 查询 `references/type-meta/[图表类型].json` → 找到 `label` 的类型定义
-3. **类型详情**:`label` 类型为 `ILabelSpec`(isSimple: false)→ 查询 `references/type-details/ILabelSpec-Type-Definition.md`
+1. **意图识别**:用户说"加个标签" -> 查询 `references/topkey/[图表类型].json` -> 找到 `label` 配置项
+2. **结构查询**:需要 label 的属性 -> 查询 `references/type-meta/[图表类型].json` -> 找到 `label` 的类型定义
+3. **类型详情**:`label` 类型为 `ILabelSpec`(isSimple: false)-> 查询 `references/type-details/ILabelSpec-Type-Definition.md`
> **常用配置项索引**:
>
-> - 通用配置(标题、图例、tooltip等)→ `references/topkey/all_common.json`
-> - 图表专属配置 → `references/topkey/[图表类型].json`
+> - 通用配置(标题、图例、tooltip等)-> `references/topkey/all_common.json`
+> - 图表专属配置 -> `references/topkey/[图表类型].json`
### 类型定义查询
@@ -213,6 +256,31 @@ python3 scripts/generate_diagnosis_react_html.py \
| `false` | `ILabelSpec`, `IData` | 查询 `references/type-details/[类型名]-Type-Definition.md` |
| 函数类型 | 回调函数 | 查询 `references/type-details/FunctionType-Type-Definition.md` |
+### API 查询
+
+当用户需要实现交互功能时,查询 API 文档:
+
+**快速索引**:`references/api/API_INDEX.md`
+
+| 用户需求 | 查询文档 |
+| ---------------- | -------------------------------------- |
+| 更新图表数据 | `references/api/data-api.md` |
+| 响应点击/hover | `references/api/event-api.md` |
+| 高亮/选中图元 | `references/api/state-api.md` |
+| 手动触发tooltip | `references/api/interaction-api.md` |
+| 切换主题 | `references/api/theme-api.md` |
+| 导出图片 | `references/api/export-api.md` |
+| 控制动画 | `references/api/animation-api.md` |
+| 坐标位置转换 | `references/api/coordinate-api.md` |
+| 控制图例 | `references/api/legend-api.md` |
+| 调整尺寸 | `references/api/layout-api.md` |
+
+**API 查询流程**:
+
+1. **需求识别**:用户说"点击图表获取数据" -> 识别为事件监听需求
+2. **文档查找**:查询 `references/api/event-api.md`
+3. **代码生成**:根据文档示例生成完整代码
+
---
## 通用查询策略
@@ -220,7 +288,10 @@ python3 scripts/generate_diagnosis_react_html.py \
### 查询优先级
```
-1. 本地知识库(references/topkey/ → references/type-meta/ → references/type-details/ → references/examples/ → references/faq)
+1. 本地知识库
+ - 配置相关:references/topkey/ -> references/type-meta/ -> references/type-details/
+ - 交互相关:references/api/
+ - 示例参考:references/examples/
2. 在线文档(仅当本地不足时)
```
@@ -240,7 +311,7 @@ python3 scripts/generate_diagnosis_react_html.py \
生成的代码应:
1. **类型正确**:属性值符合 `type-details` 中的类型定义
-2. **字段匹配**:数据字段名与 xField/yField 等严格对应(⚠️ 最常见错误源)
+2. **字段匹配**:数据字段名与 xField/yField 等严格对应(最常见错误源)
3. **必填完整**:包含 `type-meta` 中 `required: true` 的所有字段
4. **注释清晰**:关键配置项添加注释说明
5. **版本兼容**:使用 VChart 2.0.0+ 的 API
@@ -259,6 +330,7 @@ python3 scripts/generate_diagnosis_react_html.py \
| 配置生成 / 视觉还原 | `template/demo.html` | 替换标题/描述占位;替换 `{{SPEC_CODE}}` 为完整 spec |
| 问题诊断(纯 JS) | `template/diagnosis.html` | 嵌入用户代码/问题点,并给出修复后 spec |
| 问题诊断(React) | `template/diagnosis-react.html` | React 场景输出 React 诊断 HTML |
+| API 交互增强 | `template/demo.html` | 包含 spec + 事件监听 + 交互函数 + 控制按钮 |
**输出校验清单**(回答时提醒用户可直接保存为 .html 打开):
diff --git a/skills/vchart-development-assistant/references/api/API_INDEX.md b/skills/vchart-development-assistant/references/api/API_INDEX.md
new file mode 100644
index 0000000000..b747650e56
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/API_INDEX.md
@@ -0,0 +1,287 @@
+# VChart API 索引
+
+## API 分类概览
+
+VChart API 分为以下几大类别:
+
+| 分类 | 用途 | 常见场景 |
+|------|------|---------|
+| **数据操作** | 动态更新图表数据 | 数据刷新、实时数据、数据筛选 |
+| **图表更新** | 动态修改图表配置 | 切换图表类型、修改样式、更新标题 |
+| **状态管理** | 控制图元状态 | 高亮、选中、hover 效果 |
+| **事件监听** | 响应用户交互 | 点击、hover、图例筛选 |
+| **主题切换** | 动态切换主题 | 深色模式、品牌主题 |
+| **交互控制** | 手动触发交互 | 显示 tooltip、crosshair、dimension |
+| **导出功能** | 导出图表 | 图片导出、获取 dataURL |
+| **尺寸调整** | 响应式布局 | 窗口 resize、容器尺寸变化 |
+| **图例操作** | 控制图例状态 | 图例选中、获取图例数据 |
+| **动画控制** | 控制动画播放 | 暂停、恢复、停止动画 |
+| **坐标转换** | 数据与坐标转换 | 自定义标注、点击位置转换 |
+| **实例获取** | 获取内部实例 | 获取 chart、stage、canvas |
+
+---
+
+## 快速查找 API
+
+### 按用户需求查找
+
+| 用户需求 | 推荐 API | 文档链接 |
+|---------|---------|---------|
+| 更新图表数据 | `updateData` / `updateDataSync` | [data-api.md](data-api.md) |
+| 切换图表类型 | `updateSpec` / `updateSpecSync` | [spec-api.md](spec-api.md) |
+| 高亮某个数据 | `setHovered` / `setSelected` | [state-api.md](state-api.md) |
+| 响应点击事件 | `on('click')` | [event-api.md](event-api.md) |
+| 切换深色模式 | `setCurrentTheme` | [theme-api.md](theme-api.md) |
+| 手动显示 tooltip | `showTooltip` / `hideTooltip` | [interaction-api.md](interaction-api.md) |
+| 导出图片 | `exportImg` / `getDataURL` | [export-api.md](export-api.md) |
+| 窗口 resize | `resize` | [layout-api.md](layout-api.md) |
+| 控制图例选中 | `setLegendSelectedDataById` | [legend-api.md](legend-api.md) |
+| 暂停动画 | `pauseAnimation` / `resumeAnimation` | [animation-api.md](animation-api.md) |
+| 数据坐标转换 | `convertDatumToPosition` | [coordinate-api.md](coordinate-api.md) |
+
+---
+
+## 快速查找 API
+
+### 按用户需求查找
+
+| 用户需求 | 推荐 API | 文档链接 |
+|---------|---------|---------|
+| 更新图表数据 | `updateData` / `updateDataSync` | [data-api.md](data-api.md) |
+| 切换图表类型 | `updateSpec` / `updateSpecSync` | [spec-api.md](spec-api.md) |
+| 高亮某个数据 | `setHovered` / `setSelected` | [state-api.md](state-api.md) |
+| 响应点击事件 | `on('click')` | [event-api.md](event-api.md) |
+| 切换深色模式 | `setCurrentTheme` | [theme-api.md](theme-api.md) |
+| 手动显示 tooltip | `showTooltip` / `hideTooltip` | [tooltip-api.md](tooltip-api.md) |
+| 导出图片 | `exportImg` / `getDataURL` | [export-api.md](export-api.md) |
+| 窗口 resize | `resize` | [layout-api.md](layout-api.md) |
+| 控制图例选中 | `setLegendSelectedDataById` | [legend-api.md](legend-api.md) |
+| 暂停动画 | `pauseAnimation` / `resumeAnimation` | [animation-api.md](animation-api.md) |
+| 数据坐标转换 | `convertDatumToPosition` | [coordinate-api.md](coordinate-api.md) |
+
+---
+
+## API 详细文档
+
+### 核心数据操作 API
+
+**文档**: [data-api.md](data-api.md)
+
+| API | 同步/异步 | 用途 |
+|-----|----------|------|
+| `updateData` | 异步 | 更新指定数据集 |
+| `updateDataSync` | 同步 | 同步更新数据集 |
+| `updateDataInBatches` | 异步 | 批量更新多个数据集 |
+| `updateFullData` | 异步 | 更新完整数据对象 |
+| `updateFullDataSync` | 同步 | 同步更新完整数据 |
+
+### Spec 配置更新 API
+
+**文档**: [spec-api.md](spec-api.md)
+
+| API | 同步/异步 | 用途 |
+|-----|----------|------|
+| `updateSpec` | 异步 | 更新完整 spec |
+| `updateSpecSync` | 同步 | 同步更新 spec |
+| `updateModelSpec` | 异步 | 更新模块 spec |
+| `updateModelSpecSync` | 同步 | 同步更新模块 spec |
+
+### 状态管理 API
+
+**文档**: [state-api.md](state-api.md)
+
+| API | 用途 |
+|-----|------|
+| `setHovered` | 设置 hover 状态 |
+| `setSelected` | 设置选中状态 |
+| `updateState` | 更新自定义状态 |
+| `clearHovered` | 清除 hover 状态 |
+| `clearSelected` | 清除选中状态 |
+| `clearState` | 清除指定状态 |
+
+### 事件监听 API
+
+**文档**: [event-api.md](event-api.md)
+
+| API | 用途 |
+|-----|------|
+| `on` | 添加事件监听 |
+| `off` | 移除事件监听 |
+
+### 主题切换 API
+
+**文档**: [theme-api.md](theme-api.md)
+
+| API | 用途 |
+|-----|------|
+| `setCurrentTheme` | 设置当前主题 |
+| `getCurrentTheme` | 获取当前主题 |
+| `getCurrentThemeName` | 获取当前主题名称 |
+
+### 交互控制 API
+
+**文档**: [interaction-api.md](interaction-api.md)
+
+| API | 用途 |
+|-----|------|
+| `showTooltip` | 手动显示 tooltip |
+| `hideTooltip` | 隐藏 tooltip |
+| `setDimensionIndex` | 触发 dimension 交互 |
+| `disableTooltip` | 禁用/启用 tooltip |
+| `disableCrossHair` | 禁用/启用 crosshair |
+| `disableDimensionHoverEvent` | 禁用/启用 dimension hover |
+
+### 导出功能 API
+
+**文档**: [export-api.md](export-api.md)
+
+| API | 用途 |
+|-----|------|
+| `exportImg` | 导出图片文件 |
+| `getDataURL` | 获取 dataURL |
+| `exportCanvas` | 导出 canvas 元素 |
+| `getImageBuffer` | 获取图片 buffer(Node.js) |
+
+### 图例操作 API
+
+**文档**: [legend-api.md](legend-api.md)
+
+| API | 用途 |
+|-----|------|
+| `setLegendSelectedDataById` | 设置图例选中项 |
+| `setLegendSelectedDataByIndex` | 按索引设置图例选中项 |
+| `getLegendSelectedDataById` | 获取图例选中项 |
+| `getLegendDataById` | 获取图例数据 |
+
+### 动画控制 API
+
+**文档**: [animation-api.md](animation-api.md)
+
+| API | 用途 |
+|-----|------|
+| `pauseAnimation` | 暂停动画 |
+| `resumeAnimation` | 恢复动画 |
+| `stopAnimation` | 停止动画 |
+| `isAnimationEnable` | 检查动画是否启用 |
+
+### 坐标转换 API
+
+**文档**: [coordinate-api.md](coordinate-api.md)
+
+| API | 用途 |
+|-----|------|
+| `convertDatumToPosition` | 数据转换为坐标位置 |
+| `convertValueToPosition` | 数值转换为坐标位置 |
+
+### 布局与尺寸 API
+
+**文档**: [layout-api.md](layout-api.md)
+
+| API | 用途 |
+|-----|------|
+| `resize` | 调整图表尺寸 |
+| `updateViewBox` | 更新绘制区域 |
+| `setLayout` | 设置自定义布局 |
+| `reLayout` | 强制重新布局 |
+
+---
+
+## API 使用模式
+
+### 同步 vs 异步选择
+
+**推荐使用异步 API**(默认):
+```javascript
+// ✅ 推荐:异步 API
+await vchart.updateData('id', newData);
+await vchart.updateSpec(newSpec);
+await vchart.resize(800, 600);
+```
+
+**使用同步 API 的场景**:
+```javascript
+// 适用于需要立即获取结果的场景
+vchart.updateDataSync('id', newData);
+const position = vchart.convertDatumToPosition(datum);
+```
+
+### 链式调用
+
+大多数 API 返回 VChart 实例,支持链式调用:
+```javascript
+vchart
+ .updateDataSync('data', newData)
+ .setHovered(datum)
+ .showTooltip(datum, options);
+```
+
+### 事件监听模式
+
+```javascript
+// 添加事件监听
+vchart.on('click', (params) => {
+ console.log('点击了图表', params);
+});
+
+// 带查询条件的事件监听
+vchart.on('click', { seriesId: 'series0' }, (params) => {
+ console.log('点击了指定系列', params);
+});
+```
+
+---
+
+## API 最佳实践
+
+### 1. 数据更新场景选择
+
+| 场景 | 推荐 API | 原因 |
+|------|---------|------|
+| 单个数据集更新 | `updateData` | 简单高效 |
+| 多个数据集同时更新 | `updateDataInBatches` | 减少渲染次数 |
+| 完整数据替换 | `updateFullData` | 更清晰的数据结构 |
+| 实时数据刷新 | `updateDataSync` | 同步更新避免闪烁 |
+
+### 2. Spec 更新 vs 数据更新
+
+- **仅数据变化**:使用 `updateData` 系列 API
+- **配置变化**:使用 `updateSpec` 系列 API
+- **频繁更新**:优先考虑数据更新,性能更好
+
+### 3. 状态管理时机
+
+- **用户交互触发**:在事件回调中使用 `setHovered`/`setSelected`
+- **程序控制**:在数据更新后手动设置状态
+- **清除状态**:数据变化前调用 `clearHovered`/`clearSelected`
+
+---
+
+## 常见问题
+
+### Q1: updateData 和 updateSpec 的区别?
+
+**updateData**:仅更新数据,保留其他配置,性能更好。
+**updateSpec**:更新完整配置,包括数据、样式、组件等。
+
+### Q2: 何时使用同步 vs 异步 API?
+
+- **异步 API**:大多数场景,不阻塞主线程
+- **同步 API**:需要立即获取结果、调试场景
+
+### Q3: 如何实现图表的响应式布局?
+
+```javascript
+window.addEventListener('resize', () => {
+ const width = container.clientWidth;
+ const height = container.clientHeight;
+ vchart.resize(width, height);
+});
+```
+
+---
+
+## 参考资源
+
+- **官方 API 文档**: https://visactor.com/vchart/api/API/vchart
+- **事件文档**: [event-api.md](event-api.md)
+- **示例代码**: GitHub `docs/assets/examples/`
\ No newline at end of file
diff --git a/skills/vchart-development-assistant/references/api/animation-api.md b/skills/vchart-development-assistant/references/api/animation-api.md
new file mode 100644
index 0000000000..226f3c0710
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/animation-api.md
@@ -0,0 +1,221 @@
+# 动画控制 API
+
+## 概述
+
+动画控制 API 用于控制图表动画的播放、暂停和停止。
+
+---
+
+## API 列表
+
+### isAnimationEnable
+
+**检查动画是否启用**
+
+```typescript
+isAnimationEnable(): boolean;
+```
+
+**返回值**:动画是否启用
+
+**使用示例**:
+
+```javascript
+if (vchart.isAnimationEnable()) {
+ console.log('动画已启用');
+}
+```
+
+---
+
+### pauseAnimation
+
+**暂停动画**
+
+```typescript
+pauseAnimation(): void;
+```
+
+**使用示例**:
+
+```javascript
+vchart.pauseAnimation();
+```
+
+---
+
+### resumeAnimation
+
+**恢复动画**
+
+```typescript
+resumeAnimation(): void;
+```
+
+**使用示例**:
+
+```javascript
+vchart.resumeAnimation();
+```
+
+---
+
+### stopAnimation
+
+**停止动画**
+
+```typescript
+stopAnimation(): void;
+```
+
+**使用示例**:
+
+```javascript
+vchart.stopAnimation();
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 数据更新时跳过动画
+
+```javascript
+async function quickUpdate() {
+ // 暂停动画
+ vchart.pauseAnimation();
+
+ // 更新数据
+ await vchart.updateData('data', newData);
+
+ // 停止动画(不播放剩余动画)
+ vchart.stopAnimation();
+}
+```
+
+### 场景 2: 用户控制动画播放
+
+```javascript
+let isPaused = false;
+
+document.getElementById('toggle-animation').addEventListener('click', () => {
+ if (isPaused) {
+ vchart.resumeAnimation();
+ } else {
+ vchart.pauseAnimation();
+ }
+ isPaused = !isPaused;
+});
+```
+
+### 场景 3: 动画完成后执行操作
+
+```javascript
+vchart.on('animationFinished', () => {
+ console.log('动画播放完成');
+ // 显示操作提示
+ showTip('可以点击图表进行交互');
+});
+```
+
+---
+
+## 动画配置
+
+### Spec 中配置动画
+
+```javascript
+const spec = {
+ type: 'bar',
+ data: [{ id: 'data', values: [...] }],
+ xField: 'category',
+ yField: 'value',
+
+ // 动画配置
+ animation: true, // 启用动画
+ animationAppear: {
+ duration: 1000,
+ easing: 'cubicOut'
+ },
+ animationEnter: {
+ duration: 500,
+ easing: 'linear'
+ },
+ animationExit: {
+ duration: 300
+ },
+ animationUpdate: {
+ duration: 500
+ }
+};
+```
+
+### 关闭动画
+
+```javascript
+// 方式 1: spec 中关闭
+const spec = {
+ type: 'bar',
+ animation: false,
+ // ...
+};
+
+// 方式 2: 动态停止
+vchart.stopAnimation();
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/coordinate-api.md b/skills/vchart-development-assistant/references/api/coordinate-api.md
new file mode 100644
index 0000000000..0e8be121a3
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/coordinate-api.md
@@ -0,0 +1,288 @@
+# 坐标转换 API
+
+## 概述
+
+坐标转换 API 用于在数据值和画布坐标之间进行转换,常用于自定义标注、点击位置转换等场景。
+
+---
+
+## API 列表
+
+### convertDatumToPosition
+
+**将数据转换为坐标位置**
+
+```typescript
+convertDatumToPosition(
+ datum: Datum,
+ dataLinkInfo?: DataLinkSeries,
+ isRelativeToCanvas?: boolean,
+ checkInViewData?: boolean
+): IPoint | null;
+```
+
+**参数**:
+- `datum`: 数据对象
+- `dataLinkInfo`: 关联的系列信息(seriesId 或 seriesIndex),默认 { seriesIndex: 0 }
+- `isRelativeToCanvas`: 是否相对画布坐标,默认 false
+- `checkInViewData`: 是否检查数据是否在视图中
+
+**返回值**:坐标点 `{ x: number, y: number }` 或 null
+
+**使用示例**:
+
+```javascript
+// 获取数据点在图表中的位置
+const position = vchart.convertDatumToPosition({
+ category: 'A',
+ value: 20
+});
+console.log(position); // { x: 100, y: 200 }
+```
+
+---
+
+### convertValueToPosition
+
+**将数值转换为坐标位置**
+
+```typescript
+// 单值模式 - 用于轴转换
+convertValueToPosition(
+ value: StringOrNumber,
+ dataLinkInfo: DataLinkAxis,
+ isRelativeToCanvas?: boolean
+): number | null;
+
+// 双值模式 - 用于坐标系转换
+convertValueToPosition(
+ value: [StringOrNumber, StringOrNumber],
+ dataLinkInfo: DataLinkSeries,
+ isRelativeToCanvas?: boolean
+): IPoint | null;
+```
+
+**参数**:
+- `value`: 数值或数值对
+- `dataLinkInfo`: 关联的轴或系列信息
+- `isRelativeToCanvas`: 是否相对画布坐标
+
+**使用示例**:
+
+```javascript
+// 将 X 轴值转换为坐标
+const x = vchart.convertValueToPosition('A', { axisIndex: 0 });
+
+// 将 Y 轴值转换为坐标
+const y = vchart.convertValueToPosition(50, { axisIndex: 1 });
+
+// 将坐标点值转换为位置
+const point = vchart.convertValueToPosition(['A', 50], { seriesIndex: 0 });
+```
+
+---
+
+## 类型定义
+
+### DataLinkSeries
+
+```typescript
+type DataLinkSeries = {
+ seriesId?: StringOrNumber;
+ seriesIndex?: number;
+};
+```
+
+### DataLinkAxis
+
+```typescript
+type DataLinkAxis = {
+ axisId?: StringOrNumber;
+ axisIndex?: number;
+};
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 在数据点位置添加自定义标注
+
+```javascript
+// 获取数据点位置并添加自定义元素
+const data = { category: 'A', value: 30 };
+const position = vchart.convertDatumToPosition(data, { seriesIndex: 0 }, true);
+
+if (position) {
+ // 创建自定义标注元素
+ const marker = document.createElement('div');
+ marker.className = 'custom-marker';
+ marker.style.left = `${position.x}px`;
+ marker.style.top = `${position.y}px`;
+ container.appendChild(marker);
+}
+```
+
+### 场景 2: 点击位置转换为数据值
+
+```javascript
+vchart.on('click', (params) => {
+ const { x, y } = params.event;
+
+ // 根据点击位置获取数据
+ // 需要反向计算(根据具体需求实现)
+});
+```
+
+### 场景 3: 多图表联动定位
+
+```javascript
+// 图表1点击时,在图表2对应位置显示标记
+chart1.on('click', { level: 'mark' }, (params) => {
+ if (params.datum) {
+ // 获取图表1中的位置
+ const pos1 = chart1.convertDatumToPosition(params.datum, {}, true);
+
+ // 获取图表2中的对应数据位置
+ const pos2 = chart2.convertDatumToPosition(params.datum, {}, true);
+
+ // 在两个图表中显示联动标记
+ showLinkMarker(pos1, pos2);
+ }
+});
+```
+
+### 场景 4: 绘制自定义连线
+
+```javascript
+// 连接两个数据点
+function drawConnection(datum1, datum2) {
+ const pos1 = vchart.convertDatumToPosition(datum1, {}, true);
+ const pos2 = vchart.convertDatumToPosition(datum2, {}, true);
+
+ if (pos1 && pos2) {
+ const canvas = vchart.getCanvas();
+ const ctx = canvas.getContext('2d');
+ ctx.beginPath();
+ ctx.moveTo(pos1.x, pos1.y);
+ ctx.lineTo(pos2.x, pos2.y);
+ ctx.stroke();
+ }
+}
+```
+
+---
+
+## 注意事项
+
+### 1. 坐标系类型
+
+不同图表类型的坐标系不同:
+- **直角坐标系**(柱状图、折线图等):返回 { x, y }
+- **极坐标系**(饼图、雷达图等):返回极坐标位置
+- **地理坐标系**(地图):返回投影后的坐标
+
+### 2. 数据匹配
+
+传入的 datum 需要包含足够的字段来匹配数据:
+
+```javascript
+// ❌ 可能失败 - 字段不完整
+vchart.convertDatumToPosition({ category: 'A' });
+
+// ✅ 推荐 - 包含完整字段
+vchart.convertDatumToPosition({ category: 'A', value: 20, group: 'X' });
+```
+
+### 3. 渲染时机
+
+必须在图表渲染完成后调用:
+
+```javascript
+// ❌ 错误 - 渲染前调用
+const vchart = new VChart(spec, { dom });
+const pos = vchart.convertDatumToPosition(data); // null
+
+// ✅ 正确 - 渲染后调用
+await vchart.renderAsync();
+const pos = vchart.convertDatumToPosition(data); // 正确
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/data-api.md b/skills/vchart-development-assistant/references/api/data-api.md
new file mode 100644
index 0000000000..f82bf801d4
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/data-api.md
@@ -0,0 +1,368 @@
+# 数据操作 API
+
+## 概述
+
+数据操作 API 用于动态更新图表数据,支持同步和异步两种模式。
+
+---
+
+## API 列表
+
+### updateData
+
+**异步更新指定数据集**
+
+```typescript
+updateData(id: StringOrNumber, data: Datum[] | string, options?: IParserOptions): Promise
+```
+
+**参数**:
+- `id`: 数据集 ID(spec 中定义的 data.id)
+- `data`: 新数据数组或数据 URL
+- `options`: 数据解析选项(可选)
+
+**返回值**:Promise
+
+**使用示例**:
+
+```javascript
+const vchart = new VChart(spec, { dom: 'container' });
+await vchart.renderAsync();
+
+// 更新数据
+await vchart.updateData('myData', [
+ { category: 'A', value: 20 },
+ { category: 'B', value: 30 },
+ { category: 'C', value: 25 }
+]);
+```
+
+**适用场景**:
+- ✅ 单个数据集更新
+- ✅ 从 API 获取数据后更新
+- ✅ 数据筛选后更新
+
+---
+
+### updateDataSync
+
+**同步更新指定数据集**
+
+```typescript
+updateDataSync(id: StringOrNumber, data: Datum[], options?: IParserOptions): IVChart
+```
+
+**参数**:
+- `id`: 数据集 ID
+- `data`: 新数据数组
+- `options`: 数据解析选项(可选)
+
+**返回值**:IVChart(支持链式调用)
+
+**使用示例**:
+
+```javascript
+// 同步更新数据
+vchart.updateDataSync('myData', newData);
+
+// 链式调用
+vchart
+ .updateDataSync('data1', data1)
+ .updateDataSync('data2', data2);
+```
+
+**适用场景**:
+- ✅ 需要立即获取更新结果
+- ✅ 实时数据刷新(避免闪烁)
+- ✅ 调试场景
+
+---
+
+### updateDataInBatches
+
+**批量更新多个数据集**
+
+```typescript
+updateDataInBatches(list: { id: string; data: Datum[]; options?: IParserOptions }[]): Promise
+```
+
+**参数**:
+- `list`: 数据更新列表,每个元素包含 id、data、options
+
+**返回值**:Promise
+
+**使用示例**:
+
+```javascript
+// 批量更新多个数据集
+await vchart.updateDataInBatches([
+ { id: 'sales', data: salesData },
+ { id: 'profit', data: profitData },
+ { id: 'cost', data: costData }
+]);
+```
+
+**适用场景**:
+- ✅ 多个数据集同时更新
+- ✅ 减少渲染次数,提升性能
+- ✅ 组合图数据更新
+
+---
+
+### updateFullData
+
+**异步更新完整数据对象**
+
+```typescript
+updateFullData(data: IDataValues | IDataValues[], reRender?: boolean): Promise
+```
+
+**参数**:
+- `data`: 完整数据对象(包含 id、values 等)
+- `reRender`: 是否重新渲染,默认 true
+
+**返回值**:Promise
+
+**使用示例**:
+
+```javascript
+// 更新完整数据对象
+await vchart.updateFullData({
+ id: 'myData',
+ values: [
+ { category: 'A', value: 20 },
+ { category: 'B', value: 30 }
+ ]
+});
+
+// 更新多个数据对象
+await vchart.updateFullData([
+ { id: 'data1', values: data1Values },
+ { id: 'data2', values: data2Values }
+]);
+```
+
+**适用场景**:
+- ✅ 完整替换数据结构
+- ✅ 数据格式变化较大
+- ✅ 需要更新数据的元信息
+
+---
+
+### updateFullDataSync
+
+**同步更新完整数据对象**
+
+```typescript
+updateFullDataSync(data: IDataValues | IDataValues[], reRender?: boolean): IVChart
+```
+
+**参数**:
+- `data`: 完整数据对象
+- `reRender`: 是否重新渲染,默认 true
+
+**返回值**:IVChart
+
+**使用示例**:
+
+```javascript
+vchart.updateFullDataSync({
+ id: 'myData',
+ values: newData
+});
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 实时数据刷新
+
+**需求**:每秒更新图表数据
+
+```javascript
+// WebSocket 实时数据
+const ws = new WebSocket('wss://api.example.com/realtime');
+ws.onmessage = (event) => {
+ const data = JSON.parse(event.data);
+ vchart.updateDataSync('realtimeData', data);
+};
+```
+
+### 场景 2: 数据筛选
+
+**需求**:根据用户选择筛选数据
+
+```javascript
+function filterData(category) {
+ const filteredData = allData.filter(d => d.category === category);
+ vchart.updateData('myData', filteredData);
+}
+```
+
+### 场景 3: 组合图数据更新
+
+**需求**:双 Y 轴图表,同时更新两个系列的数据
+
+```javascript
+// 批量更新多个数据集
+async function updateComboChart(sales, profit) {
+ await vchart.updateDataInBatches([
+ { id: 'salesData', data: sales },
+ { id: 'profitData', data: profit }
+ ]);
+}
+```
+
+### 场景 4: API 数据加载
+
+**需求**:从后端 API 获取数据并更新
+
+```javascript
+async function loadDataFromAPI() {
+ const response = await fetch('/api/chart-data');
+ const data = await response.json();
+ await vchart.updateData('chartData', data);
+}
+```
+
+---
+
+## 性能优化建议
+
+### 1. 选择合适的更新方式
+
+| 数据量 | 更新频率 | 推荐 API |
+|--------|---------|---------|
+| 小(< 100 条) | 低频 | `updateData` |
+| 大(> 100 条) | 低频 | `updateData` + 数据预处理 |
+| 小(< 100 条) | 高频 | `updateDataSync` |
+| 大(> 100 条) | 高频 | `updateDataSync` + 增量更新 |
+
+### 2. 批量更新优化
+
+**❌ 不推荐**:多次单独更新
+```javascript
+await vchart.updateData('data1', data1);
+await vchart.updateData('data2', data2);
+await vchart.updateData('data3', data3);
+// 渲染 3 次
+```
+
+**✅ 推荐**:批量更新
+```javascript
+await vchart.updateDataInBatches([
+ { id: 'data1', data: data1 },
+ { id: 'data2', data: data2 },
+ { id: 'data3', data: data3 }
+]);
+// 只渲染 1 次
+```
+
+### 3. 数据预处理
+
+在更新数据前进行预处理,减少 VChart 内部的数据处理时间:
+
+```javascript
+// 预先排序数据
+const sortedData = data.sort((a, b) => b.value - a.value);
+await vchart.updateData('myData', sortedData);
+```
+
+---
+
+## 常见问题
+
+### Q1: updateData 后图表不更新?
+
+**原因**:数据 ID 不匹配或数据格式错误
+
+**解决方案**:
+```javascript
+// 检查 spec 中的 data.id
+const spec = {
+ data: [{ id: 'myData', values: [...] }] // 注意这个 id
+};
+
+// 更新时使用相同的 id
+await vchart.updateData('myData', newData);
+```
+
+### Q2: 高频更新导致性能问题?
+
+**解决方案**:
+1. 使用 `updateDataSync` 减少异步开销
+2. 实现数据节流/防抖
+3. 使用增量更新(仅更新变化的数据)
+
+```javascript
+// 节流更新
+let updateTimer;
+function throttledUpdate(data) {
+ if (updateTimer) clearTimeout(updateTimer);
+ updateTimer = setTimeout(() => {
+ vchart.updateDataSync('myData', data);
+ }, 100);
+}
+```
+
+### Q3: 如何判断数据更新完成?
+
+**异步 API**:使用 await 或 Promise.then()
+```javascript
+await vchart.updateData('myData', newData);
+console.log('数据更新完成');
+```
+
+**同步 API**:立即完成,无需等待
+```javascript
+vchart.updateDataSync('myData', newData);
+console.log('数据已更新');
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
\ No newline at end of file
diff --git a/skills/vchart-development-assistant/references/api/event-api.md b/skills/vchart-development-assistant/references/api/event-api.md
new file mode 100644
index 0000000000..590169eaec
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/event-api.md
@@ -0,0 +1,431 @@
+# 事件监听 API
+
+## 概述
+
+VChart 提供了完整的事件监听机制,支持基础 DOM 事件、组件事件、图元事件和生命周期事件。
+
+---
+
+## API 列表
+
+### on
+
+**注册事件监听器**
+
+```typescript
+on(event: string, callback: (params: EventParams) => void): void;
+on(event: string, query: EventQuery, callback: (params: EventParams) => void): void;
+```
+
+**参数**:
+- `event`: 事件名称
+- `query`: 事件过滤条件(可选)
+- `callback`: 事件回调函数
+
+**使用示例**:
+
+```javascript
+// 基础事件监听
+vchart.on('click', (params) => {
+ console.log('点击了图表', params);
+});
+
+// 带过滤条件的事件监听
+vchart.on('click', { level: 'mark', type: 'bar' }, (params) => {
+ console.log('点击了柱子', params.datum);
+});
+```
+
+---
+
+### off
+
+**移除事件监听器**
+
+```typescript
+off(event: string, callback?: (params: EventParams) => void): void;
+```
+
+**参数**:
+- `event`: 事件名称
+- `callback`: 要移除的回调函数(可选,不传则移除该事件所有监听)
+
+**使用示例**:
+
+```javascript
+const handler = (params) => console.log(params);
+
+// 添加监听
+vchart.on('click', handler);
+
+// 移除特定监听
+vchart.off('click', handler);
+
+// 移除所有 click 监听
+vchart.off('click');
+```
+
+---
+
+## 事件参数结构
+
+所有事件回调都接收统一的事件参数:
+
+```typescript
+type EventParams = {
+ /** 原始事件对象 */
+ event: SuperEvent;
+ /** 事件携带的数据 */
+ value?: any;
+ /** 事件源的 mark */
+ mark?: IMark;
+ /** 事件源的 model */
+ model?: IModel;
+ /** 事件源的 chart */
+ chart?: IChart;
+ /** 拾取到的图元数据 */
+ datum?: Datum;
+ /** 拾取到的图形节点 */
+ node?: INode;
+};
+```
+
+---
+
+## 事件分类
+
+### 1. 基础 DOM 事件
+
+#### 指针事件
+```javascript
+vchart.on('pointerdown', handler);
+vchart.on('pointerup', handler);
+vchart.on('pointermove', handler);
+vchart.on('pointerover', handler);
+vchart.on('pointerout', handler);
+vchart.on('pointertap', handler);
+```
+
+#### 鼠标事件
+```javascript
+vchart.on('click', handler);
+vchart.on('dblclick', handler);
+vchart.on('mousedown', handler);
+vchart.on('mouseup', handler);
+vchart.on('mousemove', handler);
+vchart.on('mouseover', handler);
+vchart.on('mouseout', handler);
+vchart.on('wheel', handler);
+```
+
+#### 触摸事件
+```javascript
+vchart.on('touchstart', handler);
+vchart.on('touchend', handler);
+vchart.on('touchmove', handler);
+vchart.on('tap', handler);
+```
+
+#### 拖拽事件
+```javascript
+vchart.on('dragstart', handler);
+vchart.on('drag', handler);
+vchart.on('dragend', handler);
+vchart.on('drop', handler);
+```
+
+### 2. 组件事件
+
+#### 图例事件
+```javascript
+// 图例点击
+vchart.on('legendItemClick', (params) => {
+ console.log('选中的图例项', params.value);
+});
+
+// 图例 hover
+vchart.on('legendItemHover', (params) => {
+ console.log('hover 的图例项', params.value);
+});
+```
+
+#### DataZoom 事件
+```javascript
+vchart.on('dataZoomChange', (params) => {
+ console.log('缩放范围', params.value.start, params.value.end);
+});
+```
+
+#### Brush 框选事件
+```javascript
+vchart.on('brushEnd', (params) => {
+ console.log('框选的数据', params.value.inBrushData);
+});
+```
+
+### 3. 生命周期事件
+
+```javascript
+// 图表初始化完成
+vchart.on('initialized', (params) => {
+ console.log('图表初始化完成');
+});
+
+// 渲染完成(只触发一次)
+vchart.on('rendered', (params) => {
+ console.log('图表首次渲染完成');
+});
+
+// 每次渲染完成
+vchart.on('renderFinished', (params) => {
+ console.log('图表渲染完成');
+});
+
+// 动画结束
+vchart.on('animationFinished', (params) => {
+ console.log('动画播放完成');
+});
+
+// 尺寸变化
+vchart.on('afterResize', (params) => {
+ console.log('图表尺寸变化');
+});
+```
+
+---
+
+## 事件过滤
+
+### 过滤规则
+
+| 过滤方式 | 说明 | 示例 |
+|---------|------|------|
+| `source` | 按事件源过滤 | `{ source: 'window' }` |
+| `level` | 按冒泡层级过滤 | `{ level: 'mark' }` |
+| `type` | 按组件/mark 类型过滤 | `{ type: 'axis' }` |
+| `nodeName` | 按图形节点名过滤 | `{ nodeName: 'axis-label' }` |
+| `markName` | 按 mark 名称过滤 | `{ markName: 'bar' }` |
+| `id` | 按 spec 中的 id 过滤 | `{ id: 'axis-left' }` |
+| `filter` | 自定义过滤函数 | `{ filter: (e) => e.model.id === 1 }` |
+
+### 常用过滤示例
+
+```javascript
+// 监听特定系列的点击
+vchart.on('click', { seriesId: 'sales' }, (params) => {
+ console.log('点击了 sales 系列');
+});
+
+// 监听坐标轴点击
+vchart.on('click', { level: 'model', type: 'axis' }, (params) => {
+ console.log('点击了坐标轴');
+});
+
+// 监听柱子点击
+vchart.on('click', { level: 'mark', type: 'bar' }, (params) => {
+ console.log('点击了柱子', params.datum);
+});
+
+// 监听标签点击(需要先开启标签交互)
+// spec: { label: { interactive: true } }
+vchart.on('click', { nodeName: 'label' }, (params) => {
+ console.log('点击了标签');
+});
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 点击图元获取数据
+
+```javascript
+vchart.on('click', { level: 'mark' }, (params) => {
+ if (params.datum) {
+ console.log('点击的数据:', params.datum);
+ // 跳转到详情页
+ window.location.href = `/detail?id=${params.datum.id}`;
+ }
+});
+```
+
+### 场景 2: 实现 Tooltip 外部控制
+
+```javascript
+// 鼠标悬停时更新外部信息面板
+vchart.on('pointermove', { level: 'mark' }, (params) => {
+ if (params.datum) {
+ updateInfoPanel(params.datum);
+ }
+});
+
+vchart.on('pointerout', () => {
+ hideInfoPanel();
+});
+```
+
+### 场景 3: 图例联动
+
+```javascript
+// 监听图例点击,联动其他图表
+vchart.on('legendItemClick', (params) => {
+ const selectedItems = params.value;
+ // 更新其他图表的显示
+ otherChart.updateData('mainData', filterByCategories(selectedItems));
+});
+```
+
+### 场景 4: 数据下钻
+
+```javascript
+vchart.on('dblclick', { level: 'mark' }, async (params) => {
+ if (params.datum) {
+ // 双击下钻
+ const drillData = await fetchDetailData(params.datum.category);
+ vchart.updateData('mainData', drillData);
+ }
+});
+```
+
+### 场景 5: 框选数据导出
+
+```javascript
+vchart.on('brushEnd', (params) => {
+ const selectedData = params.value.inBrushData;
+ // 导出选中数据
+ exportToExcel(selectedData);
+});
+```
+
+---
+
+## 性能优化
+
+### 节流与防抖
+
+事件过滤配置支持内置的节流和防抖:
+
+```javascript
+// 节流(每 200ms 最多触发一次)
+vchart.on('pointermove', { throttle: 200 }, handler);
+
+// 防抖(停止 200ms 后触发)
+vchart.on('pointermove', { debounce: 200 }, handler);
+```
+
+### 事件销毁
+
+组件销毁时记得移除事件监听:
+
+```javascript
+// 保存监听器引用
+const handlers = {
+ click: handleClick,
+ hover: handleHover
+};
+
+// 添加监听
+Object.entries(handlers).forEach(([event, handler]) => {
+ vchart.on(event, handler);
+});
+
+// 销毁时移除
+function destroy() {
+ Object.entries(handlers).forEach(([event, handler]) => {
+ vchart.off(event, handler);
+ });
+ vchart.release();
+}
+```
+
+---
+
+## 常见问题
+
+### Q1: 点击图元没有反应?
+
+**检查**:
+1. 是否正确使用了过滤条件
+2. 图元是否可交互(某些组件默认关闭交互)
+
+```javascript
+// 确保图元可交互
+vchart.on('click', { level: 'mark' }, handler);
+```
+
+### Q2: 如何获取点击的坐标?
+
+```javascript
+vchart.on('click', (params) => {
+ // 原始事件坐标
+ const clientX = params.event.client.x;
+ const clientY = params.event.client.y;
+
+ // 图表内坐标
+ const canvasX = params.event.offsetX;
+ const canvasY = params.event.offsetY;
+});
+```
+
+### Q3: 如何阻止事件冒泡?
+
+```javascript
+vchart.on('click', (params) => {
+ params.event.stopPropagation();
+});
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/export-api.md b/skills/vchart-development-assistant/references/api/export-api.md
new file mode 100644
index 0000000000..27c76711d1
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/export-api.md
@@ -0,0 +1,316 @@
+# 导出功能 API
+
+## 概述
+
+导出功能 API 用于将图表导出为图片或其他格式。
+
+---
+
+## API 列表
+
+### exportImg
+
+**导出图片文件(仅浏览器端)**
+
+```typescript
+exportImg(name?: string): Promise;
+```
+
+**参数**:
+- `name`: 保存的文件名(可选)
+
+**使用示例**:
+
+```javascript
+// 导出图片(会触发浏览器下载)
+await vchart.exportImg('my-chart');
+```
+
+---
+
+### getDataURL
+
+**获取图片 Data URL**
+
+```typescript
+getDataURL(): Promise;
+```
+
+**返回值**:Promise - base64 格式的图片数据
+
+**使用示例**:
+
+```javascript
+const dataURL = await vchart.getDataURL();
+console.log(dataURL); // data:image/png;base64,...
+
+// 用于 img 标签
+document.getElementById('preview').src = dataURL;
+```
+
+---
+
+### exportCanvas
+
+**导出 Canvas 元素**
+
+```typescript
+exportCanvas(): HTMLCanvasElement | undefined;
+```
+
+**返回值**:Canvas 元素或 undefined
+
+**使用示例**:
+
+```javascript
+const canvas = vchart.exportCanvas();
+if (canvas) {
+ // 进行自定义处理
+ const ctx = canvas.getContext('2d');
+ ctx.fillStyle = 'red';
+ ctx.fillRect(0, 0, 10, 10);
+}
+```
+
+---
+
+### getImageBuffer
+
+**获取图片 Buffer(仅 Node.js 环境)**
+
+```typescript
+getImageBuffer(): void;
+```
+
+**使用示例**:
+
+```javascript
+// Node.js 环境
+const buffer = vchart.getImageBuffer();
+require('fs').writeFileSync('chart.png', buffer);
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 下载图表为图片
+
+```javascript
+async function downloadChart() {
+ await vchart.exportImg('chart-' + Date.now());
+}
+```
+
+### 场景 2: 预览图表缩略图
+
+```javascript
+async function showThumbnail() {
+ const dataURL = await vchart.getDataURL();
+ document.getElementById('thumbnail').src = dataURL;
+}
+```
+
+### 场景 3: 上传图表到服务器
+
+```javascript
+async function uploadChart() {
+ const dataURL = await vchart.getDataURL();
+
+ // 将 base64 转为 Blob
+ const response = await fetch(dataURL);
+ const blob = await response.blob();
+
+ // 上传
+ const formData = new FormData();
+ formData.append('chart', blob, 'chart.png');
+
+ await fetch('/api/upload', {
+ method: 'POST',
+ body: formData
+ });
+}
+```
+
+### 场景 4: 打印图表
+
+```javascript
+async function printChart() {
+ const dataURL = await vchart.getDataURL();
+
+ const printWindow = window.open('', '_blank');
+ printWindow.document.write(`
+
+
+
+
+
+ `);
+ printWindow.document.close();
+ printWindow.print();
+}
+```
+
+### 场景 5: 生成报告
+
+```javascript
+async function generateReport() {
+ const chartImage = await vchart.getDataURL();
+
+ const report = {
+ title: '销售报告',
+ date: new Date().toISOString(),
+ chart: chartImage,
+ data: chartData
+ };
+
+ // 发送到报告生成服务
+ await fetch('/api/report', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(report)
+ });
+}
+```
+
+---
+
+## 导出选项
+
+### 设置导出尺寸
+
+在 spec 中配置:
+
+```javascript
+const spec = {
+ type: 'bar',
+ width: 800, // 导出宽度
+ height: 600, // 导出高度
+ // ...
+};
+```
+
+### 设置背景色
+
+```javascript
+const spec = {
+ type: 'bar',
+ background: 'white', // 导出背景色
+ // ...
+};
+```
+
+### 设置设备像素比
+
+```javascript
+const vchart = new VChart(spec, {
+ dom: 'chart',
+ mode: 'desktop-browser',
+ modeParams: {
+ devicePixelRatio: 2 // 高清导出
+ }
+});
+```
+
+---
+
+## 注意事项
+
+### 1. 渲染完成后导出
+
+```javascript
+// ❌ 错误 - 渲染前导出
+const vchart = new VChart(spec, { dom });
+await vchart.exportImg(); // 可能失败
+
+// ✅ 正确 - 渲染后导出
+await vchart.renderAsync();
+await vchart.exportImg();
+```
+
+### 2. 动画完成后再导出
+
+```javascript
+// 等待动画完成
+vchart.on('animationFinished', async () => {
+ await vchart.exportImg('chart');
+});
+```
+
+### 3. 跨域问题
+
+如果图表中包含跨域图片,导出可能会失败:
+
+```javascript
+// 解决方案:使用代理或转存图片
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/interaction-api.md b/skills/vchart-development-assistant/references/api/interaction-api.md
new file mode 100644
index 0000000000..6d9844c0d5
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/interaction-api.md
@@ -0,0 +1,301 @@
+# 交互控制 API
+
+## 概述
+
+交互控制 API 用于手动触发或禁用图表的交互效果,包括 Tooltip、Crosshair、Dimension 等。
+
+---
+
+## API 列表
+
+### showTooltip
+
+**手动显示 Tooltip**
+
+```typescript
+showTooltip(datum: Datum, options: IShowTooltipOption): boolean;
+```
+
+**参数**:
+- `datum`: 要显示 tooltip 的数据
+- `options`: 显示选项
+
+**返回值**:是否成功显示
+
+**使用示例**:
+
+```javascript
+// 显示指定数据的 tooltip
+vchart.showTooltip(
+ { category: 'A', value: 20 },
+ { position: { x: 100, y: 100 } }
+);
+```
+
+---
+
+### hideTooltip
+
+**隐藏 Tooltip**
+
+```typescript
+hideTooltip(): boolean;
+```
+
+**返回值**:是否成功隐藏
+
+**使用示例**:
+
+```javascript
+vchart.hideTooltip();
+```
+
+---
+
+### setDimensionIndex
+
+**手动触发 dimension 交互效果**
+
+```typescript
+setDimensionIndex(value: StringOrNumber, options?: DimensionIndexOption): void;
+```
+
+**参数**:
+- `value`: 维度值
+- `options`: 触发配置
+
+**使用示例**:
+
+```javascript
+// 触发指定维度的交互效果
+vchart.setDimensionIndex('A'); // 显示 'A' 类别的 crosshair 和 tooltip
+```
+
+---
+
+### disableTooltip
+
+**禁用/启用 Tooltip**
+
+```typescript
+disableTooltip(disabled: boolean): void;
+```
+
+**参数**:
+- `disabled`: true 禁用,false 启用
+
+**使用示例**:
+
+```javascript
+// 禁用 tooltip
+vchart.disableTooltip(true);
+
+// 重新启用
+vchart.disableTooltip(false);
+```
+
+---
+
+### disableCrossHair
+
+**禁用/启用 Crosshair**
+
+```typescript
+disableCrossHair(disabled: boolean): void;
+```
+
+**参数**:
+- `disabled`: true 禁用,false 启用
+
+**使用示例**:
+
+```javascript
+vchart.disableCrossHair(true);
+```
+
+---
+
+### disableDimensionHoverEvent
+
+**禁用/启用 dimension hover 事件**
+
+```typescript
+disableDimensionHoverEvent(disabled?: boolean): void;
+```
+
+**参数**:
+- `disabled`: true 禁用,false 启用
+
+**使用示例**:
+
+```javascript
+vchart.disableDimensionHoverEvent(true);
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 外部触发 Tooltip
+
+```javascript
+// 通过外部按钮显示 tooltip
+function showTooltipForCategory(category) {
+ const data = chartData.find(d => d.category === category);
+ if (data) {
+ const position = vchart.convertDatumToPosition(data);
+ vchart.showTooltip(data, { position });
+ }
+}
+```
+
+### 场景 2: 联动 Crosshair
+
+```javascript
+// 两个图表联动 crosshair
+chart1.on('pointermove', (params) => {
+ if (params.value?.dimension) {
+ chart2.setDimensionIndex(params.value.dimension);
+ }
+});
+
+chart1.on('pointerout', () => {
+ chart2.setDimensionIndex(null);
+});
+```
+
+### 场景 3: 条件禁用交互
+
+```javascript
+// 数据加载时禁用交互
+async function reloadData() {
+ vchart.disableTooltip(true);
+ vchart.disableCrossHair(true);
+
+ await vchart.updateData('data', newData);
+
+ vchart.disableTooltip(false);
+ vchart.disableCrossHair(false);
+}
+```
+
+### 场景 4: 自定义 Tooltip 触发
+
+```javascript
+// 点击外部元素显示 tooltip
+document.getElementById('info-panel').addEventListener('mouseenter', (e) => {
+ const category = e.target.dataset.category;
+ const data = chartData.find(d => d.category === category);
+ vchart.showTooltip(data, {});
+});
+
+document.getElementById('info-panel').addEventListener('mouseleave', () => {
+ vchart.hideTooltip();
+});
+```
+
+---
+
+## TooltipHandler 自定义
+
+### setTooltipHandler
+
+**设置自定义 Tooltip 处理器**
+
+```typescript
+setTooltipHandler(tooltipHandler: ITooltipHandler): void;
+```
+
+**使用示例**:
+
+```javascript
+const customHandler = {
+ showTooltip: (activeTooltip, params) => {
+ // 自定义显示逻辑
+ console.log('显示 tooltip', activeTooltip);
+ return true;
+ },
+ hideTooltip: () => {
+ // 自定义隐藏逻辑
+ console.log('隐藏 tooltip');
+ return true;
+ },
+ release: () => {
+ // 清理资源
+ }
+};
+
+vchart.setTooltipHandler(customHandler);
+```
+
+### getTooltipHandler
+
+**获取当前 Tooltip 处理器**
+
+```typescript
+getTooltipHandler(): ITooltipHandler | undefined;
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/layout-api.md b/skills/vchart-development-assistant/references/api/layout-api.md
new file mode 100644
index 0000000000..78916344fb
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/layout-api.md
@@ -0,0 +1,176 @@
+# 布局与尺寸 API
+
+## 概述
+
+布局与尺寸 API 用于控制图表的尺寸和布局。
+
+---
+
+## API 列表
+
+### resize
+
+**调整图表尺寸**
+
+```typescript
+resize(width: number, height: number): Promise;
+```
+
+**参数**:
+- `width`: 新宽度
+- `height`: 新高度
+
+**使用示例**:
+
+```javascript
+await vchart.resize(800, 600);
+```
+
+---
+
+### updateViewBox
+
+**更新绘制区域**
+
+```typescript
+updateViewBox(viewBox: IBoundsLike, reRender?: boolean): IVChart;
+```
+
+**参数**:
+- `viewBox`: 绘制区域 { x1, y1, x2, y2 }
+- `reRender`: 是否重新渲染,默认 true
+
+---
+
+### setLayout
+
+**设置自定义布局**
+
+```typescript
+setLayout(layout: LayoutCallBack): void;
+```
+
+---
+
+### reLayout
+
+**强制重新布局**
+
+```typescript
+reLayout(): void;
+```
+
+---
+
+### getCurrentSize
+
+**获取当前容器尺寸**
+
+```typescript
+getCurrentSize(): IContainerSize;
+```
+
+**返回值**:`{ width: number, height: number }`
+
+---
+
+## 使用场景
+
+### 场景 1: 响应式布局
+
+```javascript
+// 监听容器尺寸变化
+const resizeObserver = new ResizeObserver((entries) => {
+ const { width, height } = entries[0].contentRect;
+ vchart.resize(width, height);
+});
+
+resizeObserver.observe(document.getElementById('chart-container'));
+```
+
+### 场景 2: 窗口 resize
+
+```javascript
+window.addEventListener('resize', () => {
+ const container = document.getElementById('chart');
+ vchart.resize(container.clientWidth, container.clientHeight);
+});
+```
+
+### 场景 3: 全屏切换
+
+```javascript
+function toggleFullscreen() {
+ if (document.fullscreenElement) {
+ document.exitFullscreen();
+ vchart.resize(600, 400);
+ } else {
+ document.getElementById('chart').requestFullscreen();
+ vchart.resize(window.innerWidth, window.innerHeight);
+ }
+}
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/legend-api.md b/skills/vchart-development-assistant/references/api/legend-api.md
new file mode 100644
index 0000000000..0b11d77c1d
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/legend-api.md
@@ -0,0 +1,186 @@
+# 图例操作 API
+
+## 概述
+
+图例操作 API 用于获取图例数据和设置图例选中状态。
+
+---
+
+## API 列表
+
+### getLegendDataById
+
+**根据 ID 获取图例数据**
+
+```typescript
+getLegendDataById(id: string): Datum[];
+```
+
+**参数**:
+- `id`: 图例组件 ID
+
+**返回值**:图例数据数组
+
+---
+
+### getLegendDataByIndex
+
+**根据索引获取图例数据**
+
+```typescript
+getLegendDataByIndex(index?: number): Datum[];
+```
+
+**参数**:
+- `index`: 图例索引,默认 0
+
+---
+
+### getLegendSelectedDataById
+
+**根据 ID 获取图例选中项**
+
+```typescript
+getLegendSelectedDataById(id: string): StringOrNumber[];
+```
+
+**返回值**:选中的图例项值数组
+
+---
+
+### getLegendSelectedDataByIndex
+
+**根据索引获取图例选中项**
+
+```typescript
+getLegendSelectedDataByIndex(index?: number): StringOrNumber[];
+```
+
+---
+
+### setLegendSelectedDataById
+
+**根据 ID 设置图例选中项**
+
+```typescript
+setLegendSelectedDataById(id: string, selectedData: StringOrNumber[]): void;
+```
+
+**参数**:
+- `id`: 图例组件 ID
+- `selectedData`: 要选中的图例项值数组
+
+---
+
+### setLegendSelectedDataByIndex
+
+**根据索引设置图例选中项**
+
+```typescript
+setLegendSelectedDataByIndex(index: number, selectedData: StringOrNumber[]): void;
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 获取当前图例选中状态
+
+```javascript
+const selected = vchart.getLegendSelectedDataByIndex(0);
+console.log('当前选中:', selected); // ['A', 'B']
+```
+
+### 场景 2: 程序控制图例选中
+
+```javascript
+// 只显示指定类别
+vchart.setLegendSelectedDataByIndex(0, ['A', 'B']);
+
+// 全选
+const allData = vchart.getLegendDataByIndex(0);
+const allValues = allData.map(d => d.value);
+vchart.setLegendSelectedDataByIndex(0, allValues);
+```
+
+### 场景 3: 图例状态保存与恢复
+
+```javascript
+// 保存图例状态
+function saveLegendState() {
+ return vchart.getLegendSelectedDataByIndex(0);
+}
+
+// 恢复图例状态
+function restoreLegendState(selected) {
+ vchart.setLegendSelectedDataByIndex(0, selected);
+}
+```
+
+### 场景 4: 多图表图例联动
+
+```javascript
+// 图表1图例变化时,同步到图表2
+chart1.on('legendItemClick', (params) => {
+ chart2.setLegendSelectedDataByIndex(0, params.value);
+});
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/state-api.md b/skills/vchart-development-assistant/references/api/state-api.md
new file mode 100644
index 0000000000..37e1d61398
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/state-api.md
@@ -0,0 +1,376 @@
+# 状态管理 API
+
+## 概述
+
+状态管理 API 用于控制图元的高亮、选中等交互状态,支持自定义状态配置。
+
+---
+
+## API 列表
+
+### setHovered
+
+**设置图元 hover 状态**
+
+```typescript
+setHovered(
+ datum: MaybeArray | null,
+ filter?: (series: ISeries, mark: IMark) => boolean,
+ region?: IRegionQuerier
+): void;
+```
+
+**参数**:
+- `datum`: 要 hover 的数据(单条或数组),传 null 清除
+- `filter`: 过滤函数,指定哪些 series/mark 受影响
+- `region`: 区域过滤
+
+**使用示例**:
+
+```javascript
+// 设置单个数据 hover
+vchart.setHovered({ category: 'A', value: 20 });
+
+// 设置多个数据 hover
+vchart.setHovered([
+ { category: 'A', value: 20 },
+ { category: 'B', value: 30 }
+]);
+
+// 清除 hover 状态
+vchart.setHovered(null);
+```
+
+---
+
+### setSelected
+
+**设置图元选中状态**
+
+```typescript
+setSelected(
+ datum: MaybeArray | null,
+ filter?: (series: ISeries, mark: IMark) => boolean,
+ region?: IRegionQuerier
+): void;
+```
+
+**参数**:
+- `datum`: 要选中的数据,传 null 清除
+- `filter`: 过滤函数
+- `region`: 区域过滤
+
+**使用示例**:
+
+```javascript
+// 选中单个数据
+vchart.setSelected({ category: 'A', value: 20 });
+
+// 选中多个数据
+vchart.setSelected([
+ { category: 'A', value: 20 },
+ { category: 'B', value: 30 }
+]);
+
+// 清除选中状态
+vchart.setSelected(null);
+```
+
+---
+
+### clearHovered
+
+**清除所有 hover 状态**
+
+```typescript
+clearHovered(): void;
+```
+
+**使用示例**:
+
+```javascript
+vchart.clearHovered();
+```
+
+---
+
+### clearSelected
+
+**清除所有选中状态**
+
+```typescript
+clearSelected(): void;
+```
+
+**使用示例**:
+
+```javascript
+vchart.clearSelected();
+```
+
+---
+
+### clearState
+
+**清除指定状态**
+
+```typescript
+clearState(state: string): void;
+```
+
+**参数**:
+- `state`: 状态名称
+
+**使用示例**:
+
+```javascript
+// 清除自定义状态
+vchart.clearState('customState');
+```
+
+---
+
+### updateState
+
+**更新自定义状态配置**
+
+```typescript
+updateState(
+ state: Record, 'style'>>,
+ filter?: (series: ISeries, mark: IMark, stateKey: string) => boolean
+): void;
+```
+
+**参数**:
+- `state`: 状态配置对象
+- `filter`: 过滤函数
+
+**使用示例**:
+
+```javascript
+// 配置自定义状态
+vchart.updateState({
+ highlight: {
+ filter: (datum) => datum.value > 50
+ }
+});
+```
+
+---
+
+## 使用场景
+
+### 场景 1: 外部控制图元高亮
+
+```javascript
+// 根据外部表格 hover 高亮图表
+table.on('rowHover', (row) => {
+ vchart.setHovered({ category: row.category });
+});
+
+table.on('rowLeave', () => {
+ vchart.clearHovered();
+});
+```
+
+### 场景 2: 多图表联动高亮
+
+```javascript
+// 图表1 hover 联动图表2
+chart1.on('pointerover', { level: 'mark' }, (params) => {
+ if (params.datum) {
+ chart2.setHovered(params.datum);
+ }
+});
+
+chart1.on('pointerout', () => {
+ chart2.clearHovered();
+});
+```
+
+### 场景 3: 点击选中并保持状态
+
+```javascript
+let selectedData = null;
+
+vchart.on('click', { level: 'mark' }, (params) => {
+ if (params.datum) {
+ // 切换选中状态
+ if (selectedData === params.datum) {
+ vchart.clearSelected();
+ selectedData = null;
+ } else {
+ vchart.setSelected(params.datum);
+ selectedData = params.datum;
+ }
+ }
+});
+```
+
+### 场景 4: 条件筛选高亮
+
+```javascript
+// 高亮数值大于 50 的数据
+const highValues = data.filter(d => d.value > 50);
+vchart.setHovered(highValues);
+
+// 或使用 filter 函数
+vchart.setHovered(
+ data,
+ (series, mark) => mark.name === 'bar'
+);
+```
+
+---
+
+## 状态样式配置
+
+### Spec 中配置状态样式
+
+```javascript
+const spec = {
+ type: 'bar',
+ data: [{ id: 'data', values: [...] }],
+ xField: 'category',
+ yField: 'value',
+
+ // hover 状态样式
+ hover: {
+ enable: true,
+ style: {
+ fillOpacity: 0.8,
+ stroke: '#000',
+ lineWidth: 2
+ }
+ },
+
+ // 选中状态样式
+ select: {
+ enable: true,
+ style: {
+ fill: '#ff6b6b',
+ stroke: '#333',
+ lineWidth: 3
+ }
+ },
+
+ // 自定义状态
+ state: {
+ highlight: {
+ style: {
+ fill: '#ffd43b'
+ }
+ }
+ }
+};
+```
+
+### 通过 updateState 动态配置
+
+```javascript
+vchart.updateState({
+ highlight: {
+ filter: (datum) => datum.value > 100
+ },
+ dim: {
+ filter: (datum) => datum.value < 20
+ }
+});
+```
+
+---
+
+## 注意事项
+
+### 1. 数据匹配
+
+`setHovered`/`setSelected` 中的 datum 需要与原始数据结构匹配:
+
+```javascript
+// 原始数据
+const data = [
+ { category: 'A', value: 20, year: 2024 }
+];
+
+// ✅ 正确 - 匹配数据结构
+vchart.setHovered({ category: 'A', value: 20, year: 2024 });
+
+// ❌ 可能不匹配 - 字段不完整
+vchart.setHovered({ category: 'A' });
+```
+
+### 2. 状态优先级
+
+当同时设置多个状态时,优先级为:
+1. selected
+2. hovered
+3. 自定义状态
+
+### 3. 性能考虑
+
+频繁设置状态会影响性能,建议:
+
+```javascript
+// ❌ 不推荐 - 频繁调用
+data.forEach(d => vchart.setHovered(d));
+
+// ✅ 推荐 - 批量设置
+vchart.setHovered(data);
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/references/api/theme-api.md b/skills/vchart-development-assistant/references/api/theme-api.md
new file mode 100644
index 0000000000..cedc6a60d3
--- /dev/null
+++ b/skills/vchart-development-assistant/references/api/theme-api.md
@@ -0,0 +1,250 @@
+# 主题切换 API
+
+## 潜述
+
+主题切换 API 用于动态切换图表主题,支持内置主题和自定义主题。
+
+---
+
+## 实例 API
+
+### setCurrentTheme
+
+**设置当前图表的主题**
+
+```typescript
+setCurrentTheme(name: string): Promise;
+```
+
+**参数**:
+- `name`: 主题名称
+
+**使用示例**:
+
+```javascript
+// 切换到深色主题
+await vchart.setCurrentTheme('dark');
+
+// 切换回默认主题
+await vchart.setCurrentTheme('default');
+```
+
+---
+
+### getCurrentTheme
+
+**获取当前主题配置**
+
+```typescript
+getCurrentTheme(): ITheme;
+```
+
+**返回值**:当前主题配置对象
+
+**使用示例**:
+
+```javascript
+const theme = vchart.getCurrentTheme();
+console.log(theme.colors); // 主题色板
+```
+
+---
+
+### getCurrentThemeName
+
+**获取当前主题名称**
+
+```typescript
+getCurrentThemeName(): string;
+```
+
+**返回值**:主题名称
+
+**使用示例**:
+
+```javascript
+const themeName = vchart.getCurrentThemeName();
+console.log(themeName); // 'dark' 或 'default' 等
+```
+
+---
+
+## 静态 API(VChart.ThemeManager)
+
+### registerTheme
+
+**注册自定义主题**
+
+```typescript
+VChart.ThemeManager.registerTheme(name: string, theme: Partial): void;
+```
+
+**使用示例**:
+
+```javascript
+// 注册自定义主题
+VChart.ThemeManager.registerTheme('myTheme', {
+ colors: ['#5B8FF9', '#5AD8A6', '#5D7092'],
+ background: '#f5f5f5',
+ title: {
+ textStyle: {
+ fill: '#333'
+ }
+ }
+});
+
+// 使用自定义主题
+await vchart.setCurrentTheme('myTheme');
+```
+
+---
+
+### getTheme
+
+**获取指定主题**
+
+```typescript
+VChart.ThemeManager.getTheme(name: string): ITheme;
+```
+
+---
+
+### removeTheme
+
+**移除指定主题**
+
+```typescript
+VChart.ThemeManager.removeTheme(name: string): boolean;
+```
+
+---
+
+### themeExist
+
+**检查主题是否存在**
+
+```typescript
+VChart.ThemeManager.themeExist(name: string): boolean;
+```
+
+---
+
+### setCurrentTheme(全局)
+
+**设置全局默认主题**
+
+```typescript
+VChart.ThemeManager.setCurrentTheme(name: string): void;
+```
+
+---
+
+## 内置主题
+
+VChart 提供以下内置主题:
+
+| 主题名 | 说明 |
+|-------|------|
+| `default` | 默认主题 |
+| `dark` | 深色主题 |
+| `cloud` | 云端主题 |
+
+---
+
+## 使用场景
+
+### 场景 1: 深色模式切换
+
+```javascript
+let isDarkMode = false;
+
+function toggleDarkMode() {
+ isDarkMode = !isDarkMode;
+ vchart.setCurrentTheme(isDarkMode ? 'dark' : 'default');
+}
+
+// 监听系统主题变化
+window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
+ vchart.setCurrentTheme(e.matches ? 'dark' : 'default');
+});
+```
+
+### 场景 2: 品牌主题
+
+```javascript
+// 注册品牌主题
+VChart.ThemeManager.registerTheme('brand', {
+ colors: ['#FF6B6B', '#4ECDC4', '#45B7D1'],
+ background: '#FAFAFA'
+});
+
+// 应用品牌主题
+await vchart.setCurrentTheme('brand');
+```
+
+### 场景 3: 用户偏好主题
+
+```javascript
+// 保存用户主题偏好
+function saveThemePreference(themeName) {
+ localStorage.setItem('chart-theme', themeName);
+}
+
+// 加载用户主题偏好
+function loadThemePreference() {
+ const theme = localStorage.getItem('chart-theme') || 'default';
+ vchart.setCurrentTheme(theme);
+}
+```
+
+---
+
+## 完整示例
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
diff --git a/skills/vchart-development-assistant/scripts/generate_demo_html.py b/skills/vchart-development-assistant/scripts/generate_demo_html.py
index 7194104799..2cfcf763e5 100644
--- a/skills/vchart-development-assistant/scripts/generate_demo_html.py
+++ b/skills/vchart-development-assistant/scripts/generate_demo_html.py
@@ -16,6 +16,7 @@
from pathlib import Path
import argparse
+import sys
def escape_js_string(s: str) -> str:
"""转义 JavaScript 字符串中的特殊字符"""
@@ -24,33 +25,71 @@ def escape_js_string(s: str) -> str:
s = s.replace("\n", "\\n")
return s
+def validate_spec_code(spec_code: str) -> bool:
+ """验证 spec 代码基本格式"""
+ # 检查是否包含基本的 spec 结构
+ if "const spec" not in spec_code and "let spec" not in spec_code and "var spec" not in spec_code:
+ return False
+ if "type:" not in spec_code:
+ return False
+ return True
+
def main():
- parser = argparse.ArgumentParser(description="Generate demo HTML from template/demo.html")
- parser.add_argument("--title", default="VChart 图表示例", help="页面标题")
- parser.add_argument("--desc", default="基于需求生成的可运行图表配置", help="页面描述")
- parser.add_argument("--feature", default="补充主要功能说明", help="主要功能说明")
- parser.add_argument("--tips", default="补充编辑提示", help="编辑提示")
- parser.add_argument("--spec-file", help="包含完整 spec 代码的文件路径")
- parser.add_argument("--output", default="output/demo.html", help="输出 HTML 文件路径")
- args = parser.parse_args()
-
- template_path = Path("template/demo.html")
- if not template_path.exists():
- raise FileNotFoundError(f"❌ 模板不存在: {template_path}\n💡 请确保在项目根目录运行脚本")
-
- html = template_path.read_text(encoding="utf-8")
- html = html.replace("{{REPORT_TITLE}}", args.title)
- html = html.replace("{{REPORT_DESC}}", args.desc)
- html = html.replace("{{FEATURE_DESC}}", args.feature)
- html = html.replace("{{EDIT_TIPS}}", args.tips)
-
- if args.spec_file:
- spec_path = Path(args.spec_file)
- if not spec_path.exists():
- raise FileNotFoundError(f"❌ Spec 文件不存在: {spec_path}")
- spec_code = spec_path.read_text(encoding="utf-8")
- else:
- spec_code = """const spec = {
+ try:
+ parser = argparse.ArgumentParser(
+ description="Generate demo HTML from template/demo.html",
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ epilog="""
+示例:
+ # 使用自定义 spec 文件
+ python3 scripts/generate_demo_html.py --spec-file my-spec.js --output demo.html
+
+ # 完整参数
+ python3 scripts/generate_demo_html.py \\
+ --title "柱状图示例" \\
+ --desc "基础柱状图配置" \\
+ --spec-file spec.js \\
+ --output output/demo.html
+ """
+ )
+ parser.add_argument("--title", default="VChart 图表示例", help="页面标题")
+ parser.add_argument("--desc", default="基于需求生成的可运行图表配置", help="页面描述")
+ parser.add_argument("--feature", default="补充主要功能说明", help="主要功能说明")
+ parser.add_argument("--tips", default="补充编辑提示", help="编辑提示")
+ parser.add_argument("--spec-file", help="包含完整 spec 代码的文件路径")
+ parser.add_argument("--output", default="output/demo.html", help="输出 HTML 文件路径")
+ parser.add_argument("--validate", action="store_true", help="验证 spec 代码格式")
+ args = parser.parse_args()
+
+ # 检查模板文件
+ template_path = Path("template/demo.html")
+ if not template_path.exists():
+ print(f"❌ 错误: 模板文件不存在: {template_path}", file=sys.stderr)
+ print(f"💡 提示: 请确保在 skills/vchart-development-assistant 目录运行脚本", file=sys.stderr)
+ sys.exit(1)
+
+ html = template_path.read_text(encoding="utf-8")
+ html = html.replace("{{REPORT_TITLE}}", args.title)
+ html = html.replace("{{REPORT_DESC}}", args.desc)
+ html = html.replace("{{FEATURE_DESC}}", args.feature)
+ html = html.replace("{{EDIT_TIPS}}", args.tips)
+
+ # 读取或使用默认 spec
+ if args.spec_file:
+ spec_path = Path(args.spec_file)
+ if not spec_path.exists():
+ print(f"❌ 错误: Spec 文件不存在: {spec_path}", file=sys.stderr)
+ sys.exit(1)
+
+ spec_code = spec_path.read_text(encoding="utf-8")
+
+ # 验证 spec 代码格式
+ if args.validate and not validate_spec_code(spec_code):
+ print(f"⚠️ 警告: Spec 代码格式可能不正确", file=sys.stderr)
+ print(f" 请确保包含 'const spec = {{...}}' 和 'type: \"...\"'", file=sys.stderr)
+ else:
+ # 使用内置示例
+ spec_code = """const spec = {
type: "line",
data: {
values: [
@@ -64,21 +103,37 @@ def main():
xField: "time",
yField: "value"
};"""
+ print(f"ℹ️ 使用内置示例 spec", file=sys.stderr)
+
+ # 转义 spec 代码供 JavaScript 字符串使用
+ initial_code_escaped = escape_js_string(spec_code.strip())
+
+ # 填充 spec 和 initialCode 模板变量
+ html = html.replace("{{SPEC_CODE}}", spec_code)
+ html = html.replace("{{INITIAL_CODE}}", initial_code_escaped)
- # 转义 spec 代码供 JavaScript 字符串使用
- initial_code_escaped = escape_js_string(spec_code.strip())
+ # 检查模板占位符是否都被替换
+ if "{{SPEC_CODE}}" in html or "{{INITIAL_CODE}}" in html:
+ print(f"❌ 错误: 模板占位符替换失败", file=sys.stderr)
+ print(f"💡 提示: 请检查模板文件: {template_path}", file=sys.stderr)
+ sys.exit(1)
- # 填充 spec 和 initialCode 模板变量
- html = html.replace("{{SPEC_CODE}}", spec_code)
- html = html.replace("{{INITIAL_CODE}}", initial_code_escaped)
- filled = html
+ # 创建输出目录并写入文件
+ output_path = Path(args.output)
+ output_path.parent.mkdir(parents=True, exist_ok=True)
+ output_path.write_text(html, encoding="utf-8")
- output_path = Path(args.output)
- output_path.parent.mkdir(parents=True, exist_ok=True)
- output_path.write_text(filled, encoding="utf-8")
+ print(f"✅ 示例 HTML 已生成: {output_path.resolve()}")
+ print(f"📖 请在浏览器中打开以查看交互式图表")
- print(f"✅ 示例 HTML 已生成: {output_path.resolve()}")
- print(f"📊 请在浏览器中打开以查看可运行示例")
+ except FileNotFoundError as e:
+ print(f"❌ 文件错误: {e}", file=sys.stderr)
+ sys.exit(1)
+ except Exception as e:
+ print(f"❌ 未知错误: {e}", file=sys.stderr)
+ import traceback
+ traceback.print_exc()
+ sys.exit(1)
if __name__ == "__main__":
- main()
+ main()
\ No newline at end of file