Files
bansonic_beta_main/Assets/EasyChart/Docs/ManualWeb/manual-data.js
T

27 lines
114 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
window.EASYCHART_MANUAL = window.EASYCHART_MANUAL || {};
window.EASYCHART_MANUAL.generatedAt = "2026-03-18 17:29:31";
window.EASYCHART_MANUAL.chapters = [
{ id: "00_00-Index", relPath: "00_00-Index.md", title: "快速导览", content: "# 快速导览\n\n本手册面向通过 **`EasyChartLibraryWindow`** 在 Unity 编辑器里配置图表(`ChartProfile` 资产)的工作流。\n\n- 菜单入口:`EasyChart/Library Editor`\n- 手册查看器:`EasyChart/Manual`\n\n---\n\n## 目录\n\n### A. 上手与工作流\n\n- [快速导览](./00_00-Index.md)\n- [快速上手:2 分钟做出第一张图](./00_01-QuickStart.md)\n- [UIToolKit工作流(推荐)](./00_02-WorkflowAndLibrary.md)\n- [UGUI工作流](./00_03-UGUIWorkflow.md)\n- [运行时数据注入(UIToolKit](./00_04-RuntimeDataInjectionUIToolKit.md)\n- [运行时数据注入(UGUI](./00_05-RuntimeDataInjectionUGUI.md)\n\n### B. 编辑器与面板\n\n- [编辑器工作流与面板说明](./01_01-EditorWorkflow.md)\n- [Library 面板(资源树)](./01_02-LibraryPanel.md)\n- [JSON Injection 面板](./01_03-JsonInjectionPanel.md)\n- [Preview 面板](./02_04-PreviewPanel.md)\n- [Inspector 面板](./02_05-InspectorPanel.md)\n- [Series 面板](./02_06-SeriesPanel.md)\n\n### C. Series详细配置(用户目的导向)\n\n- [折线图(Line](./03_01-LineChart.md)\n- [柱状图(Bar](./03_02-BarChart.md)\n- [散点图(Scatter](./03_03-ScatterChart.md)\n- [热力图(Heatmap](./03_04-HeatmapChart.md)\n- [雷达图(Radar](./03_05-RadarChart.md)\n- [饼图(Pie](./03_06-PieChart.md)\n- [圆环图(RingChart](./03_07-RingChart.md)\n\n### D. 配置项参考(按字段分类,查字典)\n\n- [常用配方(Common Recipes](./04_08-CommonRecipes.md)\n- [FAQ(常见问题与最快排错路线)](./04_09-FAQ.md)\n\n### E. 更新与规划\n\n- [更新计划(Roadmap / Update Plan](./05_01-UpdatePlan.md)\n\n---\n\n## 约定与术语\n\n- **ChartProfile**:图表配置资产(可复用,可在编辑器预览)。\n- **Series / Serie**:数据序列(例如折线的一条线、柱状图的一组柱)。\n- **SeriesData**:序列中的数据点集合。\n- **Axis**:坐标轴配置(`AxisType=Category/Value`)。\n- **Category**:类目轴(使用 `labels` 列表)。\n- **Value**:数值轴(连续数值范围)。\n\n---\n\n## 推荐文件组织\n\n建议在项目中为图表配置建立一个统一目录:\n\n- `Assets/EasyChart/Library/Custom/`:你自己的 `ChartProfile` 资产\n- `Assets/EasyChart/Docs/Manual/`:本手册章节(Markdown\n\n---\n\n## 手册版本\n\n- 本手册将随 EasyChart 的字段与编辑器功能迭代同步更新。\n" },
{ id: "00_01-QuickStart", relPath: "00_01-QuickStart.md", title: "快速上手:2 分钟做出第一张图", content: "# 快速上手:2 分钟做出第一张图\n\n本章目标:按 EasyChart 推荐的最快路径跑通“**编辑 → 导出 → 在 UI 中使用**”的闭环。\n\n---\n\n## 打开编辑器窗口\n\n在 Unity 菜单栏选择:\n\n- `EasyChart/Library Editor`\n\n你会看到一个类似“资源库/配置面板/预览区”的窗口(后续章节会解释每个区域)。\n\n---\n\n## 克隆一个 Library(推荐)\n\n如果你想快速开始并保持风格一致,建议:\n\n- 先在窗口顶部工具栏选择一个已有 Library(例如内置 Demo 库)\n- 点击工具栏的 **Clone**,克隆出你的个人库(例如 `MyLibrary`)\n\n这样你后续所有修改都发生在自己的库里,避免污染原始示例。\n\n---\n\n## 克隆一个 ChartProfile(推荐)\n\n在资源树里找到一个接近你目标效果的图表(`ChartProfile`),右键:\n\n- `Clone`\n\n克隆后,你会得到一个新的 Profile(用于做“同款变体”)。选中它,右侧 Inspector 会显示你可以直接修改的所有配置。\n\n---\n\n## 修改配置并保存\n\n最少改动建议:\n\n- `coordinateSystem`:确保与你要的 Series 匹配(例如 Line/Bar/Scatter 用 `Cartesian2D`\n- `series`:确认 `type` 正确,并填充 `seriesData`\n- `axes`:最少保证 X/Y 轴类型与数据含义匹配\n\n完成修改后,点击窗口顶部工具栏的保存按钮(如果你的版本有),或等待 Unity 自动保存资产。\n\n---\n\n## 导出 UXML(用于 UI Builder 复用)\n\n推荐做法是把 Profile 导出为可复用的 `.uxml`\n\n- 在资源树里右键你的 Profile\n- 选择 `Export to UXML`\n\n导出的 UXML 会进入:\n\n- `Assets/EasyChart/LibraryUxml/`Mirror/Backup 相关操作也会在这个根目录下管理导出物)\n\n---\n\n## 在 QuickStart 场景里用 UIDocument + UI Builder 使用\n\n打开示例场景:\n\n- `Assets/EasyChart/Demo/Scenes/EasyChart_QuickStart.unity`\n\n然后在 Project 中找到:\n\n- `Assets/EasyChart/Demo/UIToolKit/NewUXMLTemplate.uxml`\n\n双击它打开(或在 UI Builder 中打开)。接下来:\n\n- 从 Project 里把你刚导出的图表 `.uxml` 拖入到 `NewUXMLTemplate.uxml` 的层级中\n- 保存 UXML\n- 确认场景里的 `UIDocument` 引用了你编辑后的 `NewUXMLTemplate.uxml`\n\n运行场景,你会看到图表渲染在 UI Toolkit 页面中。\n\n---\n\n## 备选:导出为 UGUI 预制体并使用\n\n如果你希望用 UGUICanvas/RectTransform)工作流,也可以在 Library Editor 中把选中的 Profile 导出为 UGUI 预制体并直接放进场景 UI(具体入口与细节取决于你当前版本提供的菜单项)。\n\n---\n\n## 下一步你应该看什么\n\n- 你要系统理解 UI Toolkit 推荐工作流:`00-WorkflowAndLibrary.md`\n- 你要用 UGUICanvas/RectTransform)把图表用起来:`33-UGUIWorkflow.md`\n\n" },
{ id: "00_02-WorkflowAndLibrary", relPath: "00_02-WorkflowAndLibrary.md", title: "UIToolKit工作流(推荐)", content: "# UIToolKit工作流(推荐)\n\n本章目标:先把 EasyChart 推荐的整体实现思路讲清楚(以 UI Toolkit 为主):\n\n1. 在编辑器中用 **`EasyChartLibraryWindow`** 编辑 `ChartProfile`\n2. 将 `ChartProfile` **导出为 `.uxml`**,作为你的“图表库”资源\n3. 在 UI Toolkit 中用 **UI Builder** / UXML 组合页面,实现快速搭建 UI\n\n本章专注于 **UI Toolkit(推荐)**。如果你需要 UGUICanvas/RectTransform)工作流,请看:\n\n- `33-UGUIWorkflow.md`\n\n\n## 0. 为什么推荐 UI Toolkit 工作流\n\n核心原因:把“图表配置源(ChartProfile)”和“UI 落地物(UXML)”分层管理。\n\n- `ChartProfile`:负责图表“长什么样/用什么轴/有哪些 Series/数据如何解释”,适合在编辑器中集中维护。\n- 导出的 `.uxml`:负责把图表以 UI Toolkit 组件形式落地到页面中,适合复用/组合/版本控制。\n\n你最终得到的是:\n\n- 配置可复用(多个页面引用同一套图表风格)\n- 页面可组装(UI Builder 拖拽组合,不需要每次从零搭 UI)\n- 团队协作更清晰(Profile 作为“源”,UXML 作为“产物/组件库”)\n\n---\n\n## 1. 为什么要导出 UXML\n\n在项目里,`ChartProfile` 负责描述“图表长什么样、用什么轴、有什么 Series、数据点怎么解释”。\n\n当你导出 `.uxml` 后,你得到的是一个可在 UI Toolkit 中复用的 UI 资源:\n\n- 可以被 UI Builder 直接拖拽使用\n- 可以被多个页面复用(同一套图表样式)\n- 可以被版本控制与资产管理(你的“图表库”)\n\n---\n\n## 2. 推荐工作流(从配置到页面)\n\n### Step 1:克隆出你的工作库与图表(推荐)\n\n- 在 Unity 菜单栏打开:`EasyChart/Library Editor`\n\n推荐流程:\n\n- **Clone Library**:先克隆一个你自己的 Library(避免直接改内置示例库)\n- **Clone ChartProfile**:在你的库里右键某个接近目标效果的 Profile,选择 `Clone` 生成变体\n- 在右侧 Inspector 修改:\n - `coordinateSystem`\n - `series`\n - `axes`\n\n> 建议:把你自己的 Profile 统一放在 `Assets/EasyChart/Library/Custom/`(或团队约定目录)。\n\n### Step 2:导出 UXML(生成库资源)\n\n你可以在 Library Editor 里执行导出:\n\n- 对某个 Profile`Export to UXML`\n- 对某个文件夹:\n - `Export Folder to UXML (Mirror)`\n - `Export Folder to UXML (Backup)`\n- 全量:\n - `Export All UXML (Mirror)`\n - `Export All UXML (Backup)`\n\n导出根目录:\n\n- `Assets/EasyChart/LibraryUxml/`\n\n多 Library 时通常结构为:\n\n- `Assets/EasyChart/LibraryUxml/<LibraryName>/...`\n\n其中 `_Backups` 子目录用于存放备份导出(以及一些导出过程附带的 JSON 备份文件):\n\n- `Assets/EasyChart/LibraryUxml/<LibraryName>/_Backups/...`\n\n导出的 UXML 核心结构类似:\n\n- 一个 `<ec:ChartElement profile-name=\"...\" />`\n- `profile-name` 对应某个 ChartProfile 的 key(通常是资产文件名)\n- 同时会写入图表的 width/height 样式\n\n> 重点:你应该把导出的 `.uxml` 当作“可复用图表组件”,而不是每次手写 UI。\n\n### Mirror vs Backup(你应该怎么选)\n\n- **Mirror**\n - 用于“把 Profile 当前状态镜像到 UXML”\n - 通常会覆盖同名导出物,并可能清理不再存在的旧文件(保持镜像一致)\n- **Backup**:\n - 用于“按时间/标签做一次备份导出”\n - 不建议作为页面直接引用的主路径(更适合作为历史快照/回滚)\n\n### Step 3:在 UI Builder 里组装页面\n\n在 UI Builder 中:\n\n- 打开你的页面 UXML\n- 从 Project 里拖入导出的图表 `.uxml`\n- 将它与其他 UILabel、Button、ListView 等)组合成完整页面\n\n如果你要最快验证导出链路,可以直接使用示例场景与模板:\n\n- 场景:`Assets/EasyChart/Demo/Scenes/EasyChart_QuickStart.unity`\n- 模板:`Assets/EasyChart/Demo/UIToolKit/NewUXMLTemplate.uxml`\n\n把导出的图表 `.uxml` 拖入 `NewUXMLTemplate.uxml`,然后确认场景中的 `UIDocument` 引用了该模板。\n\n#### 在 UI Builder 中的具体操作(建议按这个顺序)\n\n1. 打开 UI Builder(或直接双击你的页面 `.uxml`)。\n2. 在 Project 中找到你导出的图表 `.uxml`(通常位于 `Assets/EasyChart/LibraryUxml/<LibraryName>/...`)。\n3. 将该 `.uxml` 拖入页面的 Hierarchy(建议放进一个容器 `VisualElement` 内)。\n4. 保存页面 UXML。\n5. 回到场景,确认 `UIDocument` 引用的是你刚保存的页面 `.uxml`。\n\n#### 导出的图表 UXML 内部是什么\n\n导出的 `.uxml` 通常包含一个 `EasyChart.ChartElement`,并带有属性:\n\n- `profile-name`:通常对应 `ChartProfile` 的资产文件名(key\n- `profile-guid`:更稳定的资产定位方式\n\n因此:\n\n- 如果你只是修改了 Profile,页面不会自动变化:需要重新导出(Mirror)让 UXML 更新。\n- 如果你改了 Profile 的资产文件名,导出的 `profile-name` 也会随之变化(建议保持命名稳定)。\n\n### Step 4:运行时加载/替换数据(按你的业务决定)\n\n`ChartProfile`/UXML 负责“样式与结构”,而数据来源通常来自你的业务逻辑。\n\n- 静态展示:直接在 Profile 的 `seriesData` 中填写\n- 动态展示:运行时写入/替换 `seriesData`(并保持 `SeriesData.id` 稳定性)\n\n---\n\n## 3. 图表库的目录建议\n\n建议把“配置源”和“导出物”分开:\n\n- `Assets/EasyChart/Library/Custom/`:你维护的 `ChartProfile`\n- `Assets/EasyChart/LibraryUxml/`:导出的 UXML(镜像/备份都会落在这个根目录下)\n\n当你使用多 Library 时,导出物通常会按库名分子目录:\n\n- `Assets/EasyChart/LibraryUxml/<LibraryName>/...`\n\n建议约定:\n\n- **Profile 只在 `Assets/EasyChart/Library/...` 下维护**(作为配置源)\n- **页面只引用 Mirror 的导出物**(作为组件库)\n- Backup 永远只当“历史快照”\n\n> 这样做的好处是:\n> - 配置源可读、可编辑\n> - 导出物可复用、可组合、可直接用于 UI Builder\n\n---\n\n## 4. 常见问题与排错\n\n- **UI Builder 里找不到导出的图表 UXML**\n - 优先检查 `Assets/EasyChart/LibraryUxml/` 下是否已生成\n - 如果你使用了多 Library,检查是否在 `Assets/EasyChart/LibraryUxml/<LibraryName>/` 下\n - Mirror/Backup 的导出物可能位于 `_Backups`,不建议页面引用 `_Backups` 里的文件\n\n- **页面里引用了 UXML 但运行时不显示**\n - 确认场景里的 `UIDocument` 引用了你编辑的页面 `.uxml`\n - 回到 Library Editor 的 Preview 看该 Profile 是否能正常显示(先排除 Profile 配置问题)\n\n- **修改了 Profile 但页面没变化**\n - Profile 是“源”,页面引用的是导出的 UXML\n - 修改 Profile 后请重新执行导出(Mirror),再回到页面刷新/保存\n\n- **UI Builder 里看得到组件,但运行时仍然不显示**\n - 优先确认:场景里的 `UIDocument` 是否真的引用了该页面(而不是另一个旧页面)\n - 再确认:Profile 在 Library Editor 的 Preview 是否能正常显示(先排除配置问题)\n\n---\n\n## 5. 下一步你应该看什么\n\n- 你想快速跑通一张图:`01-QuickStart.md`\n- 你要用 UGUICanvas/RectTransform)把图表用起来:`33-UGUIWorkflow.md`\n\n---\n\n## 6. 编辑器工作流与面板速查(Library Editor)\n\n本节把原先分散在多个章节中的“编辑器工作流与面板说明”合并到一起,作为你在 `EasyChart/Library Editor` 中操作时的速查。\n\n### 6.1 你在编辑的是什么?(ChartProfile\n\n在 Library Editor 里被选中的图表,本质上是一个 `ChartProfile` 资产。\n\n- 它是可复用配置:同一个 Profile 可以被多个场景/Prefab 引用。\n- 它是可预览配置:在编辑器里修改后可以立即看到预览变化。\n\n### 6.2 Library Editor 的核心区域\n\n你可以把窗口理解为四块:\n\n- 左侧:Library(资源树)\n- 中部:Preview(预览区)\n- 右侧:Inspector(配置)\n- 右侧:Series(系列与数据)\n\n此外左侧通常还有 JSON InjectionJSON 注入面板)。\n\n### 6.3 Library 面板(资源树)\n\n功能概览:\n\n- 以树状结构展示图表库目录下的文件夹与 `ChartProfile``.asset`)。\n- 选中某个 `ChartProfile` 后,会驱动 Inspector/Series/Preview 的绑定与刷新。\n- 支持创建/重命名/删除/拖拽移动与排序。\n\n选择逻辑:\n\n- 选中的是文件夹:右侧 Inspector/Series 清空(无 Profile 可编辑)。\n- 选中的是 ChartProfile:右侧面板绑定到该 Profile。\n\n常用操作(标题栏与右键菜单,具体以版本为准):\n\n- FolderNew Folder / New Chart / Export Folder to UXMLMirror/Backup/ Rename / Delete\n- ChartProfileExport to UXML / Clone / Rename / Delete\n\n### 6.4 Preview 面板(预览区)\n\nPreview 的作用是把当前选中的 `ChartProfile` 直接渲染出来,方便你在编辑配置时即时验证效果。\n\n常见问题:\n\n- 预览为空:确认是否至少 1 条 `Serie`,且该 serie 的 `seriesData` 不为空。\n- 数据有但显示怪:确认坐标系与 SeriesType 匹配,轴范围是否把数据排除在外。\n\n### 6.5 Inspector 面板(配置面板)\n\nInspector 的定位是以“配置视角”编辑 Profile 的序列化字段(坐标系、轴、网格、交互、图例等),并驱动 Preview 更新。\n\n提示:\n\n- 如果你发现某些字段修改后没效果,先确认页面引用的是你导出的 UXML,而不是直接引用 Profile。\n\n### 6.6 Series 面板(系列与数据)\n\nSeries 面板以“图表结构”的方式编辑 `ChartProfile.series`\n\n- 添加/删除/排序系列\n- 为每条 serie 选择 `type` 并编辑 `settings`\n- 编辑 `seriesData`(数据点)\n\n### 6.7 JSON Injection 面板(JSON 注入)\n\n定位:把当前 Profile 的信息表达为可复制的 JSON,并支持解析 JSON 回写到当前 Profile。\n\n推荐工作流:\n\n1. 从当前 Profile 生成示例 JSON\n2. Copy 到外部编辑器做批量修改\n3. 粘贴回来并 ApplyToChart\n\n---\n\n## 7. 轴与范围(Axis & Range\n\n### 7.1 AxisTypeCategory vs Value\n\n- Category(类目轴):用 `labels` 定义离散类目(A/B/C 或 周一/周二/周三)。\n- Value(数值轴):连续数值范围(0~100-3~30~1e6)。\n\n#### 7.1.1 什么时候用 Category\n\n- X 轴是“文本标签序列”\n- 你希望数据点落在 `labels[i]` 上\n- 典型:柱状图(每类一组柱)、折线图(按类目对齐)\n\nCategory 的关键点:\n\n- `labels[0]` 对应类目索引 `0`\n- `labels[1]` 对应类目索引 `1`\n\n#### 7.1.2 什么时候用 Value\n\n- X 或 Y 轴是连续数值(例如时间戳、金额、温度)\n- 你希望轴可以按数值缩放/平移\n\nValue 的关键点:\n\n- 轴范围通常由自动范围计算得到(如果开启 auto range)\n- 你可以只锁定一端(例如固定最小值为 0,最大值自动)\n\n### 7.2 Category 轴:labels 与 LabelPlacement\n\n`labels` 决定类目个数与标签文本。\n\n`LabelPlacement` 影响对齐方式:\n\n- `Tick`:标签对齐刻度点,更适合 Line/Scatter。\n- `CellCenter`:标签对齐格子中心,更适合 Bar/Heatmap。\n\n常见现象:\n\n- 柱子落在两个标签之间:优先把 `LabelPlacement` 调成 `CellCenter`。\n\n### 7.3 Value 轴:autoRangeMin / autoRangeMax\n\n如果你看到范围“锁死”导致数据不显示,先把范围回退到全自动:\n\n- 打开 `autoRangeMin/autoRangeMax`\n\n确认可见后,再逐步加入业务约束(例如柱状图纵轴从 0 起)。\n\n#### 7.3.1 常见模板:Y 轴从 0 开始\n\n- `axisType = Value`\n- 固定 `minValue = 0`\n- `autoRangeMax = true`\n\n#### 7.3.2 常见模板:只锁定 Max(例如百分比)\n\n- 固定 `maxValue = 100`\n- `autoRangeMin = true`\n\n### 7.4 rounding / unit / labelFormat\n\n- rounding:让范围吸附到更“整”的单位。\n- unit:显示单位压缩(个/万/百万)。\n- labelFormat:控制数字格式(N0/N2/F1/百分比等)。\n\n#### 7.4.1 单位显示(showUnit / unitText\n\n当数值很大(例如 10,000 以上)时,常见做法是让轴末端显示单位(如“万”“k”“M”)。\n\n#### 7.4.2 快速排错\n\n- 标签对不齐 / 柱子夹在标签中间:优先检查 Category 轴的 `LabelPlacement`\n- 轴范围很怪(特别大/特别小):检查是否锁死 min/max;检查 rounding/unit\n- 刻度小数太多:优先设置 `labelFormat`\n\n---\n\n## 8. Series 与数据(Serie / SeriesData\n\n### 8.1 Serie(一条序列)\n\n在 `ChartProfile.series` 中每个元素是一个 `Serie`\n\n- `name`\n- `type`\n- `visible`\n- `settings`\n- `labelSettings`\n- `seriesData`\n\n补充:`settings` 通常是多态对象(`SerializeReference`)。切换 `type` 时,会尝试保留每种类型上一次的 settings(编辑体验更好)。\n\n### 8.2 SeriesData(一个数据点)\n\n`SeriesData` 常见字段:\n\n- `id`:稳定标识(tooltip/hover/隐藏状态)。\n- `x`X 坐标或 Category 索引。\n- `value`:主要数值。\n- `y`:第二维坐标(散点/热力图等)。\n- `z`:第三维(sizeMapping 等)。\n- `name`:点名称(Radar/Pie/Ring 等可能用到)。\n- `useColor` + `color`:点级颜色覆盖。\n\n如果启用了交互,建议保证 `SeriesData.id` 稳定,避免每次刷新数据都生成一套新的 id。\n\n### 8.3 SerieType 与坐标系的匹配\n\n- Cartesian2DLine/Bar/Scatter/Heatmap\n- Polar2DRadar\n\n不建议在同一个 ChartProfile(非 Pie)里混用 Polar 与 Cartesian 系列;如果你真的混用,要特别小心 axes/grid 语义是否一致。\n\n### 8.4 常用数据写法(按类型)\n\n#### 8.4.1 Line\n\n- 常见:Category X + Value Y\n - 数据点:`x=类目索引``value=数值`\n- 连续:Value X + Value Y\n - 数据点:`x=横轴数值``value=纵轴数值`\n\n#### 8.4.2 Bar\n\n- Category X + Value Y\n - 每个柱子一个点:`x=类目索引`,`value=柱高`\n- 并列:多条 Bar serie 共享同一套 Category X\n- 堆叠:`stacked=true` 且 `stackGroup` 相同的系列会堆叠\n\n#### 8.4.3 Scatter\n\n- 常用:X=ValueY=Value\n- 数据点推荐显式写 `x/y`\n\n#### 8.4.4 Heatmap\n\n- 三元组:`x=列索引``y=行索引``value=强度`\n\n#### 8.4.5 Radar\n\n- 常见理解:`x=维度索引``value=该维度数值``name=维度名称`\n\n### 8.5 数据常见坑(按现象排查)\n\n- Category 图表 X 轴是 Category,但数据点 x 不是 0/1/2...\n - 现象:点/柱子不在标签上\n - 处理:确保 `x=类目索引`,或者把 X 改成 Value\n\n- 出现 NaN/Infinity\n - 现象:整张图不渲染、范围爆炸\n - 处理:在数据源侧过滤异常值\n\n- 看不到图(但 seriesData 不为空)\n - 检查:坐标系是否匹配(Cartesian vs Polar\n - 检查:AxisType 是否匹配数据含义\n\n- 交互/tooltip 指向错乱\n - 检查:`SeriesData.id` 是否稳定(不要每次刷新都随机生成一套新的点)\n" },
{ id: "00_03-UGUIWorkflow", relPath: "00_03-UGUIWorkflow.md", title: "UGUI工作流", content: "# UGUI工作流\n\n本章目标:用 UGUICanvas/RectTransform)把 EasyChart 图表用起来,并理解两种渲染模式的选择:\n\n- `ScreenSpaceOverlay`:画质最好(不使用 RenderTexture),但通常只在 Game 视图可见\n- `WorldSpace`Scene/Game 都可见(使用 RenderTexture),适合 3D 世界空间 UI\n\n---\n\n## 1. 推荐方案:UGUIChartBridge\n\n推荐使用 `UGUIChartBridge` 组件。\n\n它的定位是:\n\n- 仍然使用 **UI Toolkit 的 `ChartElement`** 作为图表渲染核心\n- 通过桥接把图表“贴合”到某个 UGUI `RectTransform` 上\n\n因此它兼顾:\n\n- 图表能力与 UI Toolkit 渲染\n- UGUI 场景/Prefab 的搭建与布局习惯\n\n---\n\n## 2. 通用前置条件\n\n无论你选哪种模式,都建议先准备:\n\n- 一个要显示的 `ChartProfile`(建议从 `EasyChart/Library Editor` 克隆后修改得到)\n- 一个 `PanelSettings` 资产,并在 `UGUIChartBridge` 的 `Panel Settings Asset` 中指定\n\n> 备注:`Panel Settings Asset` 对字体渲染与整体稳定性更友好。\n\n---\n\n## 3. Screen Space Overlay(推荐用于 HUD/面板)\n\n### 适用场景\n\n- HUD、UI 面板、弹窗\n- 追求画质与清晰度\n\n### 特点\n\n- 不使用 RenderTexture\n- 通常只在 Game 视图可见\n\n### 搭建步骤(概览)\n\n1. 创建 `Canvas`\n2. 在 Canvas 下创建一个带 `RectTransform` 的节点(`Image` 或空物体均可)\n3. 添加 `UGUIChartBridge`\n4. 配置:\n - `Profile`\n - `Panel Settings Asset`\n - `Render Mode = ScreenSpaceOverlay`\n - `Sort Order`(用于层级覆盖;仅 Screen Space Overlay 模式生效)\n\n关键点:\n\n- 该模式会把图表渲染在一个运行时创建/复用的 `UIDocument` 里。\n- 如果被其他 UI 盖住,优先调大 `Sort Order`。\n\n---\n\n## 4. World Space(推荐用于 3D 世界空间面板)\n\n### 适用场景\n\n- 3D 世界里的看板/屏幕/面板\n- 希望 Scene 视图也能看到渲染结果\n\n### 特点\n\n- 使用 RenderTexture\n- Scene 与 Game 视图通常都可见\n- 画质可能略受 RenderTexture 分辨率影响\n\n### 搭建步骤(概览)\n\n1. 创建 `Canvas`\n2. 设置 `Render Mode = World Space`\n3. 在 Canvas 下创建一个带 `RectTransform` 的节点(建议 `RawImage`\n4. 添加 `UGUIChartBridge`\n5. 配置:\n - `Profile`\n - `Panel Settings Asset`\n - `Render Mode = WorldSpace`\n\n关键点:\n\n- World Space 模式会创建并维护一个 `RenderTexture`,并通过 `RawImage` 显示。\n- 清晰度与 `RenderTexture` 分辨率强相关:分辨率通常来自目标 `RectTransform` 的宽高。\n - 如果图表模糊,请优先把目标 `RectTransform` 设大一些(例如 600x400+)。\n\n---\n\n## 5. 选型建议(快速结论)\n\n- 优先选 **ScreenSpaceOverlay**\n - 你做的是传统 UI(HUD/面板)\n - 你最在意清晰度\n\n- 优先选 **WorldSpace**\n - 你的图表要出现在 3D 世界里\n - 你希望 Scene 视图也能看到\n\n---\n\n## 6. 常见问题与排错\n\n- **运行时不显示**\n - 确认目标物体的 `RectTransform` 尺寸不是 0\n - 确认 `Profile` 已赋值,且该 Profile 在 Library Editor 的 Preview 中能正常显示\n - 如果字体显示异常,优先检查 `Panel Settings Asset` 是否为空\n\n- **World Space 模式图表模糊**\n - 提升目标 `RectTransform` 尺寸(会提高 RenderTexture 分辨率)\n - 避免运行时频繁剧烈缩放(会触发 RenderTexture 调整)\n\n---\n\n## 7. 备选:导出 UGUI Prefab\n\n如果你的版本提供 `Export UGUI Prefab`\n\n- 你也可以将 Profile 导出为 UGUI 预制体并直接在 Canvas 下使用\n- 但对交互/兼容性的覆盖范围取决于导出器版本\n" },
{ id: "00_04-RuntimeDataInjectionUIToolKit", relPath: "00_04-RuntimeDataInjectionUIToolKit.md", title: "运行时数据注入(UIToolKit", content: "# 运行时数据注入(UIToolKit\n\n本章介绍:在 UI Toolkit 工作流下,如何在运行时给 `ChartElement` 注入数据。\n\n对应脚本:`EasyChartDataSource`\n\n---\n\n## 1. 这套方案适合什么场景?\n\n- 你的图表是 UI Toolkit 体系(`UIDocument` + UXML + `ChartElement`\n- 你希望提供一套“业务侧更容易调用”的注入 APIlabels / values / x-y / pie / ring\n- 或者你希望直接拿一段 JSON 注入(`ChartFeed`\n\n---\n\n## 2. 快速上手(最推荐的流程)\n\n1. 在场景里准备 `UIDocument`,并确保 UXML 里有 `ChartElement`。\n2. 在挂着 `UIDocument` 的 GameObject 上添加组件:`EasyChartDataSource`。\n3. 在 Inspector 里填写:\n - `uiDocument`\n - `chartElementName`(默认 `main-chart`,对应 UXML 中 `ChartElement` 的 `name`\n - `profile`(可选,但强烈建议填:让样式/Series 类型来自你在编辑器配置好的 `ChartProfile`\n4. 在运行时用代码调用:\n - `SetCategoryLabels(...)`\n - `SetSeriesValues(...)` / `SetSeriesXY(...)`\n - 或 `ApplyJson(...)`\n\n组件内部会:\n\n- 从 `UIDocument.rootVisualElement` 里找到目标 `ChartElement`\n- 必要时用 `profile` 初始化图表 Data\n- 修改 `ChartElement.Data` 并调用 `RefreshData()`\n\n---\n\n## 3. Inspector 字段说明\n\n`EasyChartDataSource` 的核心配置字段:\n\n- `uiDocument`\n - 指向当前 UI 的 `UIDocument`。\n - 如果不填,脚本会尝试 `GetComponent<UIDocument>()`。\n\n- `chartElementName`\n - 目标 `ChartElement` 的 `name`UXML/USS 的那个 name)。默认值为 `main-chart`。\n - 如果你希望用 JSON 中的 `chartId/chartName` 自动定位,也可以让 `ChartElement` 的 `name` 与之保持一致(见第 5 节)。\n\n- `profile`\n - 可选。\n - 如果赋值,组件会将 `ChartElement.Profile = profile`,用于初始化/保持样式、Series 结构等。\n\n- `playAnimationOnRefresh`\n - 每次注入后调用 `RefreshData(..., playAnimation: playAnimationOnRefresh)`。\n\n- `allowCreateSeriesFromFeed`\n - 当你用 JSON`ApplyJson`)注入时,如果 feed 中的 series 无法匹配到现有 Serie\n - `false`(默认):不创建新 Serie,只更新匹配到的部分。\n - `true`:允许根据 feed 创建新的 Serie(可能触发重建 renderers)。\n\n---\n\n## 4. 常用注入 API(不写 JSON\n\n### 4.1 设置类目轴标签\n\n`SetCategoryLabels(labels, axisId = AxisId.XBottom)`\n\n- 会把该轴设为 Category,并覆盖 `labels`。\n\n### 4.2 单序列 y 值(自动 x=0..n-1\n\n`SetSeriesValues(\"Sales\", values)`\n\n- 默认会找到/创建一条 Serie(默认类型为 Line,不强制改类型)。\n- 写入 `SeriesData.value`,并把 `SeriesData.x` 设为索引。\n\n### 4.3 XY 点\n\n`SetSeriesXY(\"Scatter\", x, y)`\n\n- 把 `x[]` 写入 `SeriesData.x`,把 `y[]` 写入 `SeriesData.value`。\n\n### 4.4 Pie / Ring 注入\n\n- `SetPie(serieName, names, values)`\n - 强制该 Serie 为 `Pie` 类型。\n - 使用 `SeriesData.name` 作为切片名,`SeriesData.value` 为数值。\n\n- `SetRing(serieName, names, percents)`\n - 强制该 Serie 为 `RingChart` 类型。\n - 使用 `SeriesData.name` 作为环名,`SeriesData.value` 为进度值。\n\n---\n\n## 5. JSON 注入(ChartFeed\n\n你可以用:`ApplyJson(json)`\n\n该方法会把 JSON 解析为 `ChartFeed` 并应用到 `ChartElement.Data`。\n\n### 5.1 `ChartFeed` 结构\n\n```json\n{\n \"chartId\": \"optional\",\n \"chartName\": \"optional\",\n \"axes\": [\n {\n \"axisId\": \"XBottom\",\n \"labels\": [\"Mon\", \"Tue\", \"Wed\"]\n }\n ],\n \"series\": [\n {\n \"serieId\": \"optional\",\n \"name\": \"optional\",\n \"type\": \"Line\",\n \"datas\": [\n { \"x\": 0, \"value\": 12 },\n { \"x\": 1, \"value\": 18 }\n ]\n }\n ]\n}\n```\n\n对应字段见运行时代码 `Scripts/Runtime/Feed/ChartFeed.cs`。\n\n### 5.2 ChartElement 的定位规则(`chartId` / `chartName`\n\n`ApplyJson` 内部会尝试:\n\n- 如果 feed 提供了 `chartId`:优先 `rootVisualElement.Q<ChartElement>(chartId)`\n- 其次如果提供了 `chartName`:尝试 `Q<ChartElement>(chartName)`\n- 都找不到才退回到 `chartElementName`(默认 `main-chart`\n\n因此:\n\n- 如果你只有一个图表,保持默认值也没问题。\n- 如果你一个 UI 里有多个 `ChartElement`,建议让每个图表的 `name` 与 feed 的 `chartId` 或 `chartName` 对齐。\n\n### 5.3 series 匹配与类型覆盖\n\n`ApplyJson` 会先检查 JSON 内是否出现过 `\"type\":`,若出现则认为你希望允许类型覆盖(`allowTypeOverride=true`)。\n\nSerie 匹配规则:\n\n- 如果 `serieId` 非空:按 `Serie.id` 匹配\n- 否则如果 `name` 非空:按 `Serie.name` 匹配\n- 否则(索引模式):按 feed 的序号匹配(第 i 条对第 i 条)\n\n当无法匹配到 Serie 时:\n\n- `allowCreateSeriesFromFeed=false`(默认):该条 feed 会被跳过(不创建)。\n- `allowCreateSeriesFromFeed=true`:会创建新的 Serie,并使用 feed 的 `type/name/serieId`。\n\n对已匹配到的 Serie\n\n- 仅当 `allowTypeOverride=true` 且不是索引模式时,才会允许覆盖 `id/name/type`。\n\n---\n\n## 6. 常见问题与排错\n\n- **不显示 / TryGetChart 失败**\n - 确认 `uiDocument` 赋值正确\n - 确认 UXML 中 `ChartElement` 的 `name` 与 `chartElementName` 一致\n\n- **JSON 解析失败**\n - `EasyChartDataSource` 解析 JSON 时:\n - 会优先尝试 Newtonsoft(若项目里存在 `Newtonsoft.Json`\n - 否则使用 Unity `JsonUtility`,并把 `type/axisId` 的字符串写法转换为枚举整数再解析\n - 建议先用一份已知能解析的 JSON(例如从编辑器 JSON 面板生成)再改。\n\n- **注入后 Series 对不上 / 更新错了线**\n - 优先使用 `serieId` 做稳定匹配。\n - 如果只用 `name`,且同名 Serie 存在多个,脚本会使用第一个并给 warning。\n\n- **JSON 想新增 Serie 但没新增**\n - 把 `allowCreateSeriesFromFeed` 打开。\n" },
{ id: "00_05-RuntimeDataInjectionUGUI", relPath: "00_05-RuntimeDataInjectionUGUI.md", title: "运行时数据注入(UGUI", content: "# 运行时数据注入(UGUI\n\n对应脚本:`UGUIRuntimeJsonInjection`、`UGUIRuntimeJsonInjectionEditor`\n\n本章介绍:在 UGUI 工作流(`UGUIChartBridge`)下,如何通过 JSON 在运行时把数据注入到图表中。\n\n---\n\n## 1. 这套方案适合什么场景?\n\n- 你有一份来自服务器/业务层的 JSON(或你希望在运行时快速手工编辑 JSON)\n- 你希望像编辑器里 `JSON Injection` 面板一样,直接“生成示例 → 修改 → 应用”\n- 你已经通过 `ChartProfile` 把样式、轴、Series 类型等结构配置好了\n\n这套注入逻辑的定位是:**更新数据为主**,结构变更(比如新增 Series、强行覆盖 Series 类型)不是它的主要目标。\n\n---\n\n## 2. 快速上手(最推荐的流程)\n\n1. 在场景中搭好 `UGUIChartBridge`(并确保 `Profile` 已赋值)。\n2. 在同一个 GameObject 上添加组件:`UGUIRuntimeJsonInjection`。\n3. 点击 **Generate Example JSON** 生成一份与你当前 Profile 匹配的示例 JSON。\n4. 在 `JSON Content` 文本框里修改数据。\n5. 点击 **Apply JSON to Chart**。\n\n你会看到组件内部:\n\n- 解析 JSON → 转成 `ChartFeed`\n- 将 `ChartFeed` 应用到 `UGUIChartBridge.Profile`\n- 调用 `_bridge.Refresh()` 刷新图表\n\n---\n\n## 3. 组件与 Inspector 字段说明\n\n`UGUIRuntimeJsonInjection` 必须和 `UGUIChartBridge` 在同一个物体上(脚本有 `[RequireComponent(typeof(UGUIChartBridge))]`)。\n\n### 3.1 JSON Generation Settings\n\n- **Example Mode`ChartJsonExampleMode`**\n - 控制“生成示例 JSON”时的格式。\n - 一般建议先用 `Standard` 或 `Standard_Axis`(更直观)。\n\n- **Data Mode`ChartJsonDatasMode`**\n - 控制 `datas` 的数据表达方式。\n - `Standard``datas` 为对象数组(例如 `{ \"x\": 0, \"value\": 12 }`)。\n - `Values``datas` 为纯数值数组(更短)。\n - 备注:该格式需要走 `ChartJsonUtils` 的“灵活解析器”(基于 Newtonsoft 的反射解析)。如果你的项目里没有 Newtonsoft`Newtonsoft.Json` / `Unity.Newtonsoft.Json`),可能会解析失败。\n - 因此 **推荐默认使用 `Standard`**,除非你确认项目已引入 Newtonsoft。\n\n- **API Envelope`UseApiEnvelope`**\n - 生成示例 JSON 时,是否包一层接口返回壳:\n - `{ \"code\": 200, \"message\": \"success\", \"data\": { ...真正的ChartFeed... } }`\n - 应用时也会尝试自动从壳里提取 `data`。\n\n- **Auto Generate`AutoGenerateJson`**\n - 当你切换 `Example Mode / Data Mode / API Envelope` 时,自动重新生成示例 JSON。\n\n### 3.2 JSON Content\n\n- **JSON Content`JsonContent`**\n - 你要注入的 JSON 字符串。\n - 如果为空,点击 Apply 时会直接警告并返回。\n\n---\n\n## 4. JSON 格式(ChartFeed\n\n底层的数据模型是 `ChartFeed`\n\n```json\n{\n \"chartId\": \"optional\",\n \"chartName\": \"optional\",\n \"axes\": [\n {\n \"axisId\": \"XBottom\",\n \"labels\": [\"Mon\", \"Tue\", \"Wed\"]\n }\n ],\n \"series\": [\n {\n \"serieId\": \"optional\",\n \"name\": \"optional\",\n \"type\": \"Line\",\n \"datas\": [\n { \"x\": 0, \"value\": 12 },\n { \"x\": 1, \"value\": 18 }\n ]\n }\n ]\n}\n```\n\n字段对应代码:\n\n- `chartId` / `chartName`\n - 在 `UGUIRuntimeJsonInjection` 的注入路径里 **不会覆盖** Profile 的 `chartId/chartName`(它调用 `ChartJsonUtils.ApplyFeedToProfile(profile, feed)`,内部 `allowMetaOverwrite=false`)。\n - 但这两个字段可以用来帮助别的注入器(例如 `EasyChartDataSource`)在 UI 树里“按名字/ID 寻找 ChartElement”。\n\n- `axes[]`\n - `axisId` 为 `AxisId` 枚举(如 `XBottom`、`XTop`、`YLeft`、`YRight` 等)。\n - `labels` 存在时会把该轴视为 Category,并直接覆盖 labels。\n\n- `series[]`\n - **匹配优先级**\n - 如果给了 `serieId`:按 `Serie.id` 精确匹配\n - 否则如果给了 `name`:按 `Serie.name` 匹配\n - 否则(`serieId` 与 `name` 都为空):按索引匹配(第 0 个 feed 对应 Profile 第 0 个 serie\n - `type`\n - 主要用于生成示例 JSON。\n - 在当前注入路径中:\n - 对已存在且能匹配到的 Serie:**不会强制改类型**(因为这里不允许覆盖 meta)。\n - 对“索引模式 + 超出 Profile 数量”而新建出来的 Serie:会使用 feed 里的 `type` 作为新 Serie 的类型。\n - `datas[]` 对应每个点:\n - `x/y/z/value` 数值\n - `id/name`(可选)\n - `useColor/color`(可选)\n\n---\n\n## 5. 应用时发生了什么?(注入流程)\n\n点击 **Apply JSON to Chart** 时:\n\n1. 若 JSON 是 API 壳(含 `data` 字段),会先尝试把 `data` 里的对象抽出来。\n2. 调用 `ChartJsonUtils.TryDeserializeFeed(json, out feed)` 反序列化为 `ChartFeed`。\n - 会优先尝试 Newtonsoft(如果项目里有),否则回退到 Unity `JsonUtility`。\n - `type: \"Line\"` / `axisId: \"XBottom\"` 这类字符串,也会在回退路径中被规范化为枚举值再解析。\n3. 调用 `ChartJsonUtils.ApplyFeedToProfile(_bridge.Profile, feed)` 把 feed 写回 Profile。\n4. 调用 `_bridge.Refresh()` 触发重绘。\n\n---\n\n## 6. 常见问题与排错\n\n- **点击 Apply 没反应 / 控制台有 warningNo UGUIChartBridge or ChartProfile found**\n - 确认对象上有 `UGUIChartBridge`\n - 确认 `UGUIChartBridge.Profile` 已赋值\n\n- **报错:Failed to parse JSON**\n - 先用 Generate 生成一份能解析的 JSON,再在它的基础上改。\n - 如果你的接口返回有外层包裹,优先勾选 `API Envelope`,或确保 JSON 的 `data` 字段内才是 `ChartFeed`。\n\n- **JSON 生效了但数据没变 / 只变了一部分**\n - 检查 `series` 的匹配方式(`serieId` / `name` / 索引模式)。\n - 如果你使用的是 `serieId/name` 匹配:确保 Profile 里确实存在对应的 Serie(该注入路径在这种模式下不会自动创建新 Serie)。\n - 如果你使用的是“索引模式”(`serieId` 与 `name` 都为空):\n - 当 feed 的 `series[]` 数量 **超过** Profile 的 Series 数量时,会自动补创建新的 Serie。\n - 如果你不希望自动创建,请给每条 serie 明确填 `name` 或 `serieId`。\n\n- **在编辑器 PlayMode 注入后,Profile 资产被改脏了**\n - 注入的本质是“把 feed 应用到 `ChartProfile` 上”。如果你把资产直接拖到桥接上,运行时改动可能会让该资产处于 dirty 状态。\n - 如果你不希望影响资产,建议在运行时对 Profile 做一份实例化拷贝再注入。\n" },
{ id: "01_01-EditorWorkflow", relPath: "01_01-EditorWorkflow.md", title: "编辑器工作流与面板说明", content: "# 编辑器工作流与面板说明\n\n本章目标:让你清楚在 `EasyChart/Library Editor` 里“**哪里改什么**”,以及常见编辑流程(创建、克隆、预览、导出)。\n\n---\n\n## 1. 你在编辑的是什么?(ChartProfile\n\n在 Library Editor 里被选中的图表,本质上是一个 `ChartProfile` 资产。\n\n- 它是 **可复用配置**:同一个 Profile 可以被多个场景/Prefab 引用。\n- 它是 **可预览配置**:在编辑器里修改后可以立即看到预览变化。\n\n建议:将你自己的 Profile 放到 `Assets/EasyChart/Library/Custom/`(或你团队约定目录)。\n\n---\n\n## 2. Library Editor 的三个核心区域\n\n虽然 UI 细节可能随版本略有变化,但整体可以按下面理解:\n\n### 2.1 左侧:资源树(Library Tree)\n\n这里展示的是图表资产(`ChartProfile`)所在的文件夹结构。\n\n常用操作:\n\n- 在文件夹上右键:\n - `New Folder...`:新建子目录\n - `New Chart...`:创建新的 `ChartProfile`\n- 在图表上右键:\n - `Clone`:复制一个新的 Profile(用于做变体)\n - `Export to UXML`:导出(若你的工作流需要把配置同步/落盘到 UXML\n - `Ping`:在 Project 面板定位该资产\n - `Rename...` / `Delete`\n\n> 建议:用 `Clone` 来做“同款不同配色/不同数据规模”的图表变体,避免从零配置。\n\n### 2.2 右侧:Inspector(配置面板)\n\n这里是你主要编辑的地方。\n\n通常会包含:\n\n- **基础设置**\n - `coordinateSystem`\n - `padding`(如果有)\n - `animationDuration`(如果有)\n- **Series 列表**:每个 Serie 代表一条线/一组柱/一个散点序列等\n- **Axes(坐标轴)**\n - 选择使用哪个 `XAxisId/YAxisId`\n - 对应 `AxisConfig` 的显示、label、range、ticks 等\n- **Legend / Tooltip / Grid**:若你的版本已暴露这些设置\n\n> 经验:先把 `coordinateSystem`、`Series`、`Axes` 配好,其他属于“锦上添花”。\n\n### 2.3 预览区(Preview\n\n用于检查:\n\n- 是否有数据\n- 轴范围是否正确\n- 标签是否拥挤/偏移\n- Tooltip / Legend 的交互(如果启用)\n\n预览出现异常时优先排查顺序:\n\n1. `coordinateSystem` 是否正确\n2. `series` 是否至少有 1 条且有数据点\n3. Axis 的 `axisType` 与数据 `x/y` 的含义是否匹配\n4. Value 轴是否被手动锁死范围(`autoRangeMin/autoRangeMax`\n\n### 2.4 JSON InjectionJSON 注入面板)\n\n在左侧面板下方有一个 **JSON Injection** 区域,用于:\n\n- 快速生成当前选中 `ChartProfile` 的“注入 JSON 示例”\n- 将你粘贴/编辑的 JSON 应用回当前选中 Profile`ApplyToChart`\n\n常用控件:\n\n- **API Envelope**:是否使用 `{ code, message, data }` 外层包裹。\n - 打开时:生成 JSON 会包一层;解析时也可以识别并自动取 `data`。\n- **Feed Mode**:示例 JSON 的“结构层级/字段完整度”(用于兼容不同注入协议)。\n- **Datas Format**`datas` 字段内部数据点格式(例如更紧凑的数组,或更易读的对象)。\n- **ApplyToChart**:将当前文本框中的 JSON 解析并写回到当前选中的 `ChartProfile`。\n\n---\n\n## 3. 推荐的编辑流程(从 0 到可复用)\n\n### Step 1:创建或选择一个 ChartProfile\n\n- 新建:在目标文件夹右键 `New Chart...`\n- 已有:在左侧树点击选择\n\n如果你希望使用“先克隆再修改”的方式(更推荐):\n\n- 先在窗口顶部工具栏 **Clone** 一个你自己的 Library\n- 然后在你自己的库里右键 Profile -> `Clone` 生成变体\n\n### Step 2:确定坐标系\n\n- `Cartesian2D`Line/Bar/Scatter/Heatmap\n- `Polar2D`Radar\n\n> 建议:坐标系先定下来,再选 SeriesType,避免后续切换带来风格/轴设置混淆。\n\n### Step 3:配置 Series\n\n- 添加 Series\n- 设置 `type`\n- 填充 `seriesData`\n\n建议:先用少量数据点(3~8 个)把效果跑通,再扩展数据量。\n\n### Step 4:配置 Axes\n\n最常见组合:\n\n- XCategory\n - `labels` 填文本\n- YValue\n - 开启自动范围(默认)\n\n当你希望更专业的轴显示:\n\n- 使用 `labelFormat`(例如 `F1`、`N0` 等)\n- 使用 `autoRangeMin/autoRangeMax` 只锁定一端范围\n- 如果是 Value 轴需要单位:\n - `showUnit=true`\n - `unitText=\"个\"/\"万\"`\n - `unitLabelStyle` 调字体/颜色/位置\n\n### Step 5:克隆出变体(推荐)\n\n当你需要同款图表做多个版本(配色、字号、轴显示略不同):\n\n- 右键图表 -> `Clone`\n- 修改差异项\n\n这样可以保证风格一致,也更便于版本管理。\n\n当你想把图表用于 UI\n\n- UI Toolkit:导出为 UXML,然后在 UI Builder 中组装页面(可参考示例场景 `Assets/EasyChart/Demo/Scenes/EasyChart_QuickStart.unity` 与模板 `Assets/EasyChart/Demo/UIToolKit/NewUXMLTemplate.uxml`\n- UGUI:可导出为 UGUI Prefab 并在 Canvas/RectTransform 工作流中使用\n\n---\n\n## 4. 常见坑(快速定位)\n\n- **看不到任何东西**\n - `seriesData` 是否为空\n - `AxisType` 是否和数据含义匹配(Category 轴配了 labels 吗)\n\n- **Value 轴显示很怪(范围太大/太小)**\n - 检查 `autoRangeMin/autoRangeMax`\n - 检查 rounding/unit 是否把范围吸附到不合适的单位上\n\n- **柱状图与标签不对齐**\n - 关注 `LabelPlacement`Tick vs CellCenter\n\n---\n\n## 下一章\n\n- `00-WorkflowAndLibrary.md`:轴类型、标签放置、自动范围、取整、单位显示等内容已合并到第 7 节\n" },
{ id: "01_02-LibraryPanel", relPath: "01_02-LibraryPanel.md", title: "Library 面板(资源树)", content: "# Library 面板(资源树)\n\n本章说明 `Unity Easy Chart/Library Editor` 窗口左侧的 **Library** 面板:用于管理你的图表资产(`ChartProfile`)与文件夹结构,并决定右侧各面板正在编辑的是哪个 Profile。\n\n---\n\n## 功能概览\n\n- **展示结构**:以树状结构展示“图表库根目录”下的文件夹与 `ChartProfile``.asset`)。\n- **选择驱动编辑**:点击某个 `ChartProfile` 后,会驱动:\n - Inspector 面板绑定到该 Profile\n - Series 面板绑定到该 Profile 的 `series`\n - Preview 预览刷新\n - JSON Injection 生成示例 JSON(并可 Apply 回写到该 Profile\n- **管理资产**:提供创建、重命名、删除、拖拽移动、展开/收起等操作。\n\n---\n\n## 界面结构说明\n\nLibrary 面板的顶部标题栏从左到右通常包含:\n\n- **Library**:标题。\n- **(当前库名称)**:括号内显示当前选中的库/根目录名称(用于区分你可能配置的多个库)。\n- **Menu(菜单按钮)**:常用操作入口(和右键菜单类似,但更集中)。\n- **Help(帮助按钮)**:打开本章节。\n\n窗口顶部全局工具栏(Window Toolbar)中,Library 下拉框右侧包含:\n\n- **+**:新增一个 Library。\n- **-**:删除当前 Library。\n- **Clone(克隆当前 Library**:把当前 Library 复制为一个新 Library(详见下文)。\n\n标题栏下面是:\n\n- **资源树(TreeView**\n - 文件夹\n - `ChartProfile` 资产(图表配置文件)\n\n---\n\n## 选择逻辑(非常重要)\n\n- **选中的是文件夹**\n - 右侧 Inspector/Series 会清空(因为没有具体 Profile 可以编辑)。\n - JSON Injection 会切换为“无选中 Profile”的示例或保持当前示例(具体以实现为准)。\n- **选中的是 ChartProfile**\n - Inspector/Series 立即绑定到该 Profile 的序列化数据。\n - 任何字段变化会触发 Preview 延迟刷新(`delayCall`)。\n\n建议:如果你发现右侧面板没有内容,先确认左侧是否选中了一个 `ChartProfile`。\n\n---\n\n## 常用操作(标题栏 Menu\n\n点击标题栏右侧 **Menu**(小菜单图标)会弹出操作菜单,常见项包括:\n\n- **New Chart**:在“目标文件夹”下创建新的 `ChartProfile`。\n- **New Folder**:在“目标文件夹”下创建新文件夹。\n- **Refresh**:重新扫描并重建树(当你在 Project 视图中手动移动/复制文件后很有用)。\n- **Expand All**:展开所有文件夹。\n- **Collapse All**:收起所有文件夹。\n- **Rename / Delete**:对“当前选中项”执行重命名/删除。\n - 如果当前选中的是库根目录,通常会被禁用。\n- **Export UGUI Prefab**(当选中的是 Profile 时可用):把选中 Profile 导出为 UGUI Prefab(用于运行时展示)。\n\n### 目标文件夹是如何决定的\n\nMenu 中的 **New Chart / New Folder** 会把资源创建在“目标文件夹”下:\n\n- 如果你当前选中的是 **文件夹**:目标就是该文件夹。\n- 如果你当前选中的是 **ChartProfile**:目标通常是该 Profile 所在的文件夹。\n- 如果没有选中或不明确:目标通常回退到库根目录。\n\n---\n\n## Clone Library(克隆当前 Library)\n\n当你需要把一整套图表库(包含 Profile 与 UXML)复制成一个新的库(用于分支/版本/主题变体等)时,可以使用窗口顶部工具栏里的 **Clone**。\n\n### 入口与操作\n\n- 点击 Library 下拉框右侧的 **Clone** 图标。\n- 输入新库名称并确认。\n\n### 克隆内容\n\n- `Assets/EasyChart/Library/<当前库>` 会被复制到 `Assets/EasyChart/Library/<新库>`。\n- `Assets/EasyChart/LibraryUxml/<当前库>` 会被复制到 `Assets/EasyChart/LibraryUxml/<新库>`(如果源库存在对应 UXML 目录)。\n\n### 限制与命名规则\n\n- `<Root>` 库不允许克隆。\n- 新名称会做基础清理(移除非法文件名字符),空白名称会被忽略。\n- 如果目标库已存在(同名文件夹已存在),会提示并取消。\n\n### 克隆后的行为\n\n- 会自动切换当前选中的 Library 为新库。\n- 会刷新 Library 下拉列表与左侧资源树,并触发右侧面板/预览的刷新。\n\n---\n\n## 常用操作(右键菜单)\n\n你也可以在树上的条目上 **右键**:\n\n### 右键文件夹\n\n- **New Folder...**:在该文件夹下创建子文件夹。\n- **New Chart...**:在该文件夹下创建新的 `ChartProfile`。\n- **Export Folder to UXML (Mirror/Backup)**:导出该文件夹下的内容到 UXML(用于备份/分发/版本化)。\n- **Rename...**:重命名文件夹。\n- **Delete**:删除文件夹(请谨慎,属于破坏性操作)。\n\n### 右键 ChartProfile\n\n- **Export to UXML**:导出当前 Profile 的 UXML。\n- **Clone**:克隆一个新的 Profile(用于快速派生相似图表)。\n- **Rename...**:重命名资产(同时会尝试同步更新 `profile.name` / `profile.chartName`)。\n- **Ping**:在 Project 视图中定位该资产。\n- **Delete**:删除资产。\n\n---\n\n## 拖拽移动与排序\n\nLibrary 树支持拖拽移动文件夹或 `ChartProfile`\n\n- **拖拽 ChartProfile 到文件夹**:会触发 `AssetDatabase.MoveAsset`,把 `.asset` 移动到目标文件夹。\n- **拖拽文件夹到文件夹**:会把整个文件夹移动到目标文件夹下。\n\n注意:\n\n- 如果目标无效(例如拖到自身/子目录),会拒绝(鼠标提示为 Rejected)。\n- 移动后会自动刷新树。\n\n---\n\n## 重命名(双击与内联编辑)\n\n在树上 **双击** 条目会进入内联重命名流程(等价于执行 Rename)。\n\n实现上会对名字做基础清理(移除非法文件名字符)。如果你输入空白或与原名相同,会取消重命名。\n\n---\n\n## 常见问题与排错\n\n- **右侧面板为空**:\n - 先确认左侧是否选中了 `ChartProfile`(而不是文件夹)。\n- **改了名字但 chartName 没更新**\n - ChartProfile 可能有额外同步逻辑;建议在 Inspector 里确认 `Chart Name` 字段是否一致。\n- **拖拽失败**:\n - 常见原因:拖到了自身、拖到子目录、或目标路径已存在同名资源。\n\n---\n\n## Help\n\n- 点击标题栏最右侧 **Help** 图标可回到本章节。\n" },
{ id: "01_03-JsonInjectionPanel", relPath: "01_03-JsonInjectionPanel.md", title: "JSON Injection 面板", content: "# JSON Injection 面板\n\n本章说明 `Unity Easy Chart/Library Editor` 窗口左侧底部的 **JSON Injection** 面板。\n\n它的定位是:用一段可读/可复制的 JSON 来表达当前 `ChartProfile` 的配置(或外部导入的配置),并支持 **ApplyToChart** 将 JSON 解析后回写到选中的 Profile。\n\n---\n\n## 面板位置与作用\n\n- **位置**:Library 面板(资源树)下方。\n- **主要用途**:\n - **导出**:把当前选中 `ChartProfile` 转成示例 JSONFeed\n - **编辑**:在文本框里手动修改 JSON\n - **导入/应用**:点击 **ApplyToChart**,把 JSON 解析并应用到当前选中的 `ChartProfile`\n\n适用场景:\n\n- **调试**:快速定位“某个字段是否生效”。\n- **批量修改**:复制 JSON 到外部编辑器(支持多光标/查找替换),再粘贴回来 Apply。\n- **与外部系统对接**:例如你的工具链/脚本生成 Feed,再在编辑器里 Apply。\n\n---\n\n## 控件说明(标题栏)\n\n标题栏从左到右一般包含:\n\n- **Min/Max**(按钮文字会变化)\n - 用于切换面板高度。\n - `Min`:收起为较小高度(更偏“辅助工具”)。\n - `Max`:展开为较大高度(更适合长 JSON)。\n\n- **ApplyToChart**(图标按钮)\n - 把当前文本框里的 JSON 尝试解析为 Feed,并应用到选中的 `ChartProfile`。\n - 成功后会:\n - 标记资产为 Dirty 并 `SaveAssets()`\n - 刷新 Series 列表\n - 刷新 Preview\n\n- **Help**(图标按钮)\n - 打开本章节。\n\n---\n\n## 控件说明(按钮行)\n\n标题栏下方还有一行按钮(可能会自动换行):\n\n- **API Envelope**(图标开关)\n - 控制示例 JSON 是否包裹为“API 返回格式”。\n - 你需要把 Feed 直接交给某个 HTTP API/服务时,这个选项会更方便。\n - 切换后会重新生成示例,并覆盖文本框(详见“覆盖规则”)。\n\n- **Feed Mode**(下拉框)\n - 用于控制“示例 JSON 输出包含哪些层级/字段”。\n - 选项来自内部枚举(常见有):\n - `Lite`\n - `Standard / ID`\n - `Standard / Default`\n - `Standard / With Axes`\n - `Full`\n - 一般建议:\n - **快速看结构**:用 `Lite`\n - **需要稳定引用**:用 `Standard / ID`\n - **需要包含轴配置**:用 `Standard / With Axes`\n - **需要完整复制/迁移**:用 `Full`\n\n- **Datas Format**(下拉框)\n - 控制 `seriesData`(数据点)字段的输出格式。\n - 常见选项:\n - `Values`:更精简,偏“只关心数值”。\n - `Standard`:默认格式,适合一般编辑与 Apply。\n - `Full`:更完整(可能包含更多字段/结构),适合迁移/还原。\n\n- **Copy**(图标按钮)\n - 复制当前文本框内容到剪贴板。\n\n---\n\n## 文本框与“覆盖规则”(非常重要)\n\nJSON 文本框是可编辑的,但为了避免你手写的内容被自动覆盖,面板内部有一个“脏标记”逻辑:\n\n- **只要你手动改过文本框内容**,就会认为“用户已修改”(dirty)。\n- 当处于 dirty 状态时:\n - 编辑器不会自动用示例 JSON 覆盖你的内容。\n- 但当你切换以下选项时,会**强制覆盖**(同时清除 dirty):\n - `API Envelope`\n - `Feed Mode`\n - `Datas Format`\n - 或在切换选中 Profile 时(会重置为该 Profile 的示例)\n\n建议:\n\n- 如果你要做大幅改动:\n - 先 Copy 到外部编辑器改\n - 改完再粘贴回来 Apply\n\n---\n\n## ApplyToChart 的行为与注意事项\n\n- **ApplyToChart 会修改当前选中的 `ChartProfile` 资产**。\n- 如果 JSON 解析失败,会在 Console 输出错误:\n - `ApplyToChart failed: invalid JSON or unsupported format.`\n- `Full` 模式下会允许覆盖更多“Meta/结构”信息(例如某些标识/配置),因此更强大也更危险。\n\n建议:\n\n- 在 Apply 前确保:\n - 左侧已选中正确的 `ChartProfile`\n - JSON 格式正确(括号/逗号)\n - 你理解当前 Feed Mode 会覆盖哪些内容\n\n---\n\n## 推荐工作流\n\n### 1) 从当前 Profile 导出并微调\n\n- 选中一个 `ChartProfile`\n- 选择合适的 `Feed Mode` / `Datas Format`\n- Copy 到外部编辑器微调\n- 粘贴回来\n- ApplyToChart\n\n### 2) 从外部导入配置\n\n- 把外部 JSON 粘贴到文本框\n- ApplyToChart\n- 去 Inspector / Series 进一步精调\n\n---\n\n## Help\n\n- 点击标题栏最右侧 **Help** 图标可回到本章节。\n" },
{ id: "02_04-PreviewPanel", relPath: "02_04-PreviewPanel.md", title: "Preview 面板", content: "# Preview 面板\n\n本章说明 `Unity Easy Chart/Library Editor` 中间区域顶部的 **Preview** 面板。\n\nPreview 的作用是:把当前选中的 `ChartProfile` 直接渲染出来,让你在编辑配置时能即时看到结果。\n\n---\n\n## Preview 会在什么时候刷新\n\nPreview 刷新是“延迟刷新”(避免你连续拖动/输入时频繁重绘):\n\n- 当你在 **Inspector** 或 **Series** 面板修改任何绑定字段时,会触发一次 `ScheduleUpdatePreview()`。\n- 当你在 **JSON Injection** 面板点击 **ApplyToChart** 后,会触发刷新。\n- 当你在左侧 **Library** 树切换到另一个 `ChartProfile` 时,会刷新到新 Profile。\n\n实现上会把刷新放到 `EditorApplication.delayCall`,因此你可能会感觉到“改完后稍后才更新”——这是预期行为。\n\n---\n\n## Preview 显示什么\n\n- Preview 使用一个运行时的图表组件(例如 `ChartElement`)进行绘制。\n- Preview 会直接读取当前选中 `ChartProfile` 的数据并渲染。\n\n你可以把 Preview 理解为:\n\n- **你编辑的就是它渲染的**\n- **你看到的就是运行时的效果**(大多数情况下)\n\n---\n\n## 常见问题与排错\n\n### 1) 预览为空\n\n优先排查:\n\n- 是否选中了一个 `ChartProfile`\n- 是否至少存在一条 `Serie`\n- `seriesData` 是否为空(没有数据点)\n\n### 2) 数据有但显示很怪 / 看不到\n\n常见原因:\n\n- **坐标系与 SeriesType 不匹配**:例如 Profile 是 `Polar2D`,但 Series 选择了非 Radar 的类型。\n- **轴范围/数据范围不匹配**:例如数值全都落在轴范围之外。\n- **分类轴可见数量(VisibleCount)太小**:导致只显示一小段。\n\n### 3) Console 报错 “Preview refresh failed”\n\n当刷新过程中出现异常,会在 Console 输出:\n\n- `[EasyChartLibraryWindow] Preview refresh failed: ...`\n\n这通常意味着:\n\n- 某个配置组合不合法\n- 或某个字段值超出预期(例如 null / NaN)\n\n建议处理:\n\n- 先回退最近一次改动\n- 再逐步改回去定位哪一个字段触发异常\n\n---\n\n## 提示\n\n- Preview 只负责“呈现结果”,结构性问题通常需要回到 **Inspector/Series/JSON Injection** 去修。\n- 如果你在短时间内修改了很多字段,Preview 可能在最后一次改动后才统一刷新(这是为了性能)。\n\n---\n\n## Help\n\n- 点击标题栏最右侧 **Help** 图标可回到本章节。\n" },
{ id: "02_05-InspectorPanel", relPath: "02_05-InspectorPanel.md", title: "Inspector 面板", content: "# Inspector 面板\n\n本章说明 `Unity Easy Chart/Library Editor` 中间区域底部的 **Inspector** 面板。\n\nInspector 的定位是:以“配置视角”直接编辑当前选中 `ChartProfile` 的序列化字段(坐标系、轴、网格、交互、图例等),并驱动 Preview 实时更新。\n\n---\n\n## 面板结构概览\n\n当你在左侧 Library 树选中一个 `ChartProfile` 后,Inspector 会构建一组折叠面板(Foldout),通常包括:\n\n- **Chart Settings**:图表基础设置(例如背景、名称等)\n- **Coordinate System**:坐标系选择与相关项\n- **Axis Settings**:轴配置(X/Y 或 Angle/Radius\n- **Grid Settings**:网格相关配置\n- **Hover Settings**:悬停/提示相关配置\n- **Legend Settings**:图例配置\n\n提示:\n\n- 如果你选中的是文件夹而不是 `ChartProfile`Inspector 会清空(这是正常的)。\n\n---\n\n## Chart Settings(常用)\n\n### Chart Name\n\nInspector 里有 `Chart Name` 文本框(来自 `ChartProfile.chartName`)。它不只是显示名,还会参与资产重命名流程:\n\n- 当你在该字段输入新名字并 **失去焦点** 或按 **Enter**\n - 编辑器会尝试把 `.asset` 文件重命名为该名字\n - 同时尽量保持 `profile.name` 与 `profile.chartName` 同步\n\n注意:\n\n- 名字会被做文件名清理(非法字符会被移除/替换)。\n- 如果重命名失败(例如同名冲突),会弹出 Error,并回退字段。\n\n### Background\n\n`Background` 通常是一个子折叠块,包含背景颜色/透明度等字段(具体以版本为准)。\n\n---\n\n## Coordinate System(坐标系)\n\n这里会显示 `coordinateSystem` 选择项。\n\n坐标系会影响:\n\n- Series 可选的类型/语义(例如 Polar2D 常见是 RadarPie 类属于特殊布局)\n- Axis Settings 中显示的是 CartesianX/Y)还是 PolarAngle/Radius)配置\n\n建议:\n\n- 在开始配置前先确定坐标系,避免后续大规模调整。\n\n---\n\n## Axis Settings(轴配置)\n\n### 轴选择(X Axis / Y Axis\n\n在 Cartesian 模式下,顶部会提供 X/Y 轴的选择下拉:\n\n- **X Axis**:例如 `XBottom` / `XTop`\n- **Y Axis**:例如 `YLeft` / `YRight`\n\n选择改变时会:\n\n- 确保轴列表里存在对应 AxisId 的元素(必要时自动创建)\n- 刷新下面的 Axis 字段 UI\n- 触发 Preview 刷新\n\n### 单个 Axis 的常见字段\n\n每个 Axis 配置通常包含:\n\n- `axisType`Category / Value 等\n- `visible`:是否显示\n- `color` / `width`:轴线样式\n\n#### LabelTexts(分类轴标签)\n\nInspector 会提供一个 `LabelTexts`(内部字段名 `labels`)用于配置分类标签。\n\n#### Range(范围)\n\n常见有:\n\n- `minValue` / `maxValue`\n- `autoRangeMin` / `autoRangeMax`(开关)\n- `autoRangeRounding`(自动范围的取整策略)\n- `autoRangeUnit`(某些取整策略下会出现)\n\n#### Ticks / VisibleCount\n\n如果轴支持自动刻度:\n\n- `autoTicks` 开启时会显示 `splitCount`。\n- 对 **Category Axis** 来说,这个字段会显示为 **VisibleCount**(表示可见分类数量)。\n\n#### Category Auto Scroll(分类轴自动滚动)\n\n如果轴支持分类滚动,常见字段包括:\n\n- `categoryAutoScroll`:是否自动滚动(跑马灯效果)。\n- `categorySmoothScroll`:是否平滑滚动。\n- `categoryScrollInterval`:滚动间隔。\n- `categoryScrollStep`:每次滚动步长。\n\n#### Unit(单位显示)\n\n常见字段:\n\n- `showUnit`:是否显示单位。\n- `unitText`:单位文本(例如 `ms`/`%`/`MB`)。\n- `unitLabelStyle`:单位文本样式。\n\n---\n\n## Polar Axis(极坐标轴)\n\n当 `coordinateSystem = Polar2D` 时,Axis Settings 会显示 `polarAxes`\n\n- **Angle Axis**angleAxis\n- **Radius Axis**radiusAxis\n\n常见字段含义与 Cartesian 类似:\n\n- `labels`:角度/维度标签(Radar 的维度名称通常来自这里)。\n- `visible/color/width`:轴线样式。\n- `showLabels/fontSize/labelColor/labelPosition/labelOffset`:标签显示控制。\n- `autoRangeMin/autoRangeMax/minValue/maxValue`:半径轴范围。\n- `autoTicks/splitCount`:刻度数量。\n\n---\n\n## Grid Settings(字段说明,仅 Cartesian2D\n\nGrid Settings 在 Cartesian2D 下可见,核心字段来自 `cartesianGrid`\n\n- **xGridColor / xGridLineWidth**X 方向网格线颜色与线宽。\n- **yGridColor / yGridLineWidth**Y 方向网格线颜色与线宽。\n\n如果需要虚线:\n\n- `xGridDashed` / `yGridDashed`:是否虚线。\n- `xGridDashLength` / `yGridDashLength`:虚线实线段长度。\n- `xGridDashGap` / `yGridDashGap`:虚线间隔。\n- `xGridDashOffset` / `yGridDashOffset`:虚线偏移。\n\n---\n\n## Hover Settings(字段说明,仅 Cartesian2D\n\nHover Settings 在 Cartesian2D 下可见,核心字段来自 `hover`\n\n- **cursorLineColor**:悬停光标线颜色。\n- **cursorLineWidth**:线宽。\n- **cursorLineDashed**:是否虚线。\n- **cursorLineDashLength / cursorLineDashGap / cursorLineDashOffset**:虚线参数。\n\n---\n\n## Legend Settings(字段说明)\n\nLegend Settings 来自 `legendSettings`(某些情况下会被自动隐藏,见下文)。\n\n- **enabled**:是否显示图例。\n- **position**:图例位置(Top/Bottom/Left/Right)。\n- **fontSize / color**:文字大小与颜色。\n- **backgroundColor**:图例背景色。\n- **itemSpacing**:图例项间距。\n- **offset**:相对边缘的偏移。\n - 当 offset 为默认值时,会随着 position 自动给一个常用偏移(例如 Bottom 默认 `y=-30`)。\n\n---\n\n## Legend Settings(可能会自动隐藏)\n\n当图表是“纯 Pie 系列”(只有 Pie/Ring/Pie3D,没有非 Pie 系列)时,Legend Settings 可能会被自动隐藏。\n\n这是为了避免在某些布局下显示无意义或冲突的图例配置。\n\n---\n\n## 编辑建议与排错\n\n- **改动较多时**:建议配合顶部工具栏的 `Save` 保存资产。\n- **修改了关键结构**(例如坐标系、轴类型、Series Type):\n - 改完观察 Preview 是否正确刷新\n - 如出现不一致,尝试切换一下选中 Profile 触发重建\n\n---\n\n## Help\n\n- 点击标题栏最右侧 **Help** 图标可回到本章节。\n" },
{ id: "02_06-SeriesPanel", relPath: "02_06-SeriesPanel.md", title: "Series 面板(数据与系列)", content: "# Series 面板(数据与系列)\n\n本章说明 `Unity Easy Chart/Library Editor` 右侧的 **Series** 面板。\n\nSeries 面板以“图表结构”的方式编辑 `ChartProfile.series`:你可以添加/删除/排序系列,设置每条 Serie 的类型与参数,并直接编辑 `seriesData`(数据点)。\n\n---\n\n## 面板结构概览\n\n当你选中一个 `ChartProfile` 后,Series 面板会显示:\n\n- 一组 Serie 卡片(每个卡片对应 `series[i]`\n- 最底部的 **+ Add Series** 按钮\n\n每个 Serie 卡片通常由三部分组成:\n\n- **Header(标题行)**:折叠按钮 + 标题\n- **Body(主体)**Name / Id / Type / Settings / Data\n- **Footer(右下角控制)**:↑ ↓ X\n\n---\n\n## Header:折叠/展开\n\n- Header 左侧有一个小按钮:\n - `▼` 表示已展开\n - `▶` 表示已折叠\n- 折叠状态会被记住(按 Profile + index 存储),用于减少长配置的视觉负担。\n\n---\n\n## Name 与 Serie Id\n\n### Name\n\n- `Name` 字段用于显示与编辑该 Serie 的名称。\n- 当你修改 Name 时,卡片标题会同步更新,并触发 Preview 刷新。\n\n### Serie Id(只读)\n\n如果该 Serie 支持 `id` 字段,面板会显示:\n\n- **Serie Id**(只读文本框)\n- **Copy**(按钮)复制 id 到剪贴板\n\n这个 id 常用于:\n\n- 交互/高亮/外部系统引用某条 serie\n- 保持引用稳定(尤其是你会重排/增删 series 时)\n\n---\n\n## Type(系列类型)与兼容性提示\n\n### Type 下拉框\n\n- `Type` 用于选择 SerieTypeLine/Bar/Scatter/Pie/Radar…)。\n- 下拉框会基于注册表提供可选类型;如果当前类型不在列表里,会临时插入以保证可见。\n\n### 兼容性警告\n\n当 SeriesType 与 Profile 的 `coordinateSystem` 不兼容时,Series 面板会显示一段警告文字:\n\n- 仍然允许渲染(不会强制阻止)\n- 但会提示坐标轴/网格语义可能不一致\n\n典型例子:\n\n- Profile 是 `Polar2D`,但 SeriesType 选择了 Line/Bar(不推荐)\n\n### Pro-only 类型限制\n\n某些类型在 Free 版本不可用(例如 RingChart / HorizontalBar / Heatmap / Pie3D 等)。\n\n- 当你尝试选择这些类型时,如果未安装 Pro:\n - 会显示提示文本\n - 并自动把下拉框回退到原来的类型(不会修改资产)\n\n---\n\n## Settings(系列参数)\n\nSeries 面板会为每条 serie 显示一组 Settings 配置:\n\n- 根折叠块名称会随类型变化(例如 `LineSettings` / `BarSettings` / `PieSettings` …)。\n- 某些类型会有更细分的子折叠(例如 Ring 的 layout/valueMapping 等)。\n\n提示:\n\n- 切换 Type 可能会触发“Settings 实例替换”(managedReference 结构变化)。\n- 发生替换时会延迟一帧重建 UI,以避免序列化句柄失效。\n\n---\n\n## DataseriesData(数据点)\n\nSeries 面板里会直接展示 `seriesData` 数组(Unity 的默认数组编辑器)。\n\n- 默认会强制展开(便于编辑)。\n- 当你增删/修改数据点时,会触发 Preview 刷新。\n\n建议:\n\n- 数据点较多时,可以配合 JSON Injection 面板进行批量编辑。\n\n---\n\n## Footer:排序与删除(渲染顺序)\n\n每个 serie 卡片右下角有三个按钮:\n\n- **↑**:把当前 serie 上移一位(`MoveArrayElement(index, index-1)`\n- **↓**:把当前 serie 下移一位(`MoveArrayElement(index, index+1)`\n- **X**:删除当前 serie`DeleteArrayElementAtIndex(index)`\n\n渲染顺序提示:\n\n- 通常 **后面的 serie 会绘制在更上层**。\n- 因此你可以用 ↑↓ 来控制遮挡关系(例如点/线盖住柱子)。\n\n---\n\n## + Add Series(新增系列)\n\n点击底部 **+ Add Series**\n\n- 会在 `series` 数组末尾插入一个新元素。\n- 注意:如果当前已经存在至少一条 serieUnity 的 `InsertArrayElementAtIndex(arraySize)` 会 **复制最后一个元素**(包括 type/settings)。\n- 如果这是第一条 serie,会根据坐标系设置默认类型:\n - Polar2D:默认 Radar\n - 其他:默认 Line\n\n新增后通常会:\n\n- 自动填入名称(如 `Serie N`\n- 触发 `EnsureRuntimeData()`\n- 刷新 Series 列表与 Preview\n\n---\n\n## 推荐工作流\n\n### 1) 从零创建一张基础图\n\n- + Add Series\n- Type 选择 Line 或 Bar\n- 在 seriesData 里加入几个点\n- 去 Inspector 调整轴范围/可见数量\n\n### 2) 调整遮挡关系\n\n- 用 ↑↓ 调整 series 顺序\n- 观察 Preview 中的层级变化\n\n### 3) 大量数据/批量修改\n\n- 在 JSON Injection 中切换 `Datas Format`\n- Copy 到外部编辑器批量生成/替换数据\n- 粘贴回来 ApplyToChart\n\n---\n\n## Help\n\n- 点击标题栏最右侧 **Help** 图标可回到本章节。\n" },
{ id: "03_01-LineChart", relPath: "03_01-LineChart.md", title: "折线图(Line", content: "# 折线图(Line\n\n本章目标:把“折线图在 EasyChart 里到底怎么配置、数据怎么解释、哪些字段会影响渲染”的关键点一次讲清楚。\n\n---\n\n## 1. 适用场景\n\n- 趋势变化(时间序列/按类目变化)\n- 多条曲线对比(同一套 X 维度)\n- 需要平滑/阶梯/直线等线型表达\n\n---\n\n## 2. 最小可用配置(Checklist\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. 轴(Axis Settings\n - X:通常用 **Category**(填写 `labels`)或 **Value**(数值横轴)\n - Y:通常用 **Value**\n3. SeriesSeries 面板)\n - 添加 1 条 `Serie`\n - `Serie.type = Line`\n - `Serie.seriesData` 至少 2 个点(折线需要至少两点才能连线)\n\n---\n\n## 3. Inspector 对应字段(你在面板里看到的是什么)\n\n- **ChartProfile / Coordinate System**\n - `coordinateSystem`\n\n- **Axis Settings**(与坐标系相关)\n - Cartesian`cartesian.xAxisId / cartesian.yAxisId`\n - 轴列表:`axes[]`(每个 Axis 的 `axisType/labels/min/max/autoRange/...`\n\n- **Series**(每条曲线)\n - `series[i].type = Line`\n - `series[i].settings`:实际类型为 `LineSettings`\n - `stroke`:线条(线型/颜色/宽度/纹理等)\n - `point`:点样式(开关/大小/纹理等)\n - `hover`:悬停强调(开启后才会有“拾取半径/高亮”)\n - `area`:面积填充(折线下方填充)\n - `series[i].labelSettings`:数据点标签(是否显示、格式、小数位、偏移等)\n\n---\n\n## 4. SeriesData 字段解释(最关键,按运行时代码)\n\n折线图渲染时使用:\n\n- **X 坐标**`SeriesData.x`\n- **Y 数值**`SeriesData.value`\n- `SeriesData.y` 在折线图中 **不参与渲染**(不要把 y 当作折线的纵值)。\n\n两种常见写法:\n\n### 4.1 Category X + Value Y(最常用)\n\n- X 轴设为 `AxisType.Category`\n- `AxisConfig.labels = [\"A\",\"B\",\"C\",...]`\n- 数据点:\n - `x = 类目索引`(0/1/2...,会按索引映射到 labels\n - `value = 数值`\n\n### 4.2 Value X + Value Y(数值横轴)\n\n- X 轴设为 `AxisType.Value`\n- 数据点:\n - `x = 横轴数值`\n - `value = 纵轴数值`\n\n> 额外说明:当你的轴维度是 **X=Value, Y=Category** 时,运行时会认为是“笛卡尔坐标转置”(transposed),会在渲染时交换 X/Y 的解释方式(用于横向布局的场景)。\n\n---\n\n## 5. 常用样式配置(LineSettings\n\n- **线型**`LineSettings.stroke.lineType`\n - `Straight`:直线\n - `Step`:阶梯线\n - `Smooth`:平滑曲线\n\n- **线条粗细/颜色**`LineSettings.stroke.width` / `LineSettings.stroke.color`\n\n- **点标记**`LineSettings.point.show/size/textureFill`\n\n- **面积填充**`LineSettings.area.show` + `LineSettings.area.textureFill`\n\n---\n\n## 6. 常见坑与排错(按现象)\n\n- **线断裂 / 不显示**\n - 检查 `SeriesData.value` 是否出现 `NaN/Infinity`\n - 折线至少 2 个有效点\n\n- **点不在标签上(Category X**\n - 检查 `x` 是否为 0..(labels.Count-1) 的索引\n - 检查是否误把 `x` 写成了“类目字符串”(EasyChart 这里是索引,不是字符串)\n\n- **我填了 y,但图不对**\n - 折线图纵值用的是 `value`,不是 `y`\n\n---\n\n## 7. 深入参考\n\n- 轴与范围、Series 与数据:`00-WorkflowAndLibrary.md`\n- 常用配方:`05-CommonRecipes.md`\n- FAQ`06-FAQ.md`\n" },
{ id: "03_02-BarChart", relPath: "03_02-BarChart.md", title: "柱状图(Bar", content: "# 柱状图(Bar\n\n本章目标:把柱状图在 EasyChart 中的 **数据解释规则(`SeriesData.x/value`**、**并列/堆叠的真实行为**、以及常用样式字段一次讲清楚。\n\n---\n\n## 1. 适用场景\n\n- 类目对比(A/B/C 的值对比)\n- 分组对比(同一类目下多条 Bar 并列)\n- 堆叠总量(同一类目下多条 Bar 堆叠)\n\n---\n\n## 2. 最小可用配置(Checklist\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. 轴\n - X:通常 `AxisType.Category`(填写 `labels`\n - Y:通常 `AxisType.Value`(建议从 0 起)\n3. Series\n - 添加 1 条 `Serie`\n - `Serie.type = Bar`\n - `Serie.seriesData` 至少 1 个点\n\n---\n\n## 3. Inspector 对应字段\n\n- **Axis Settings**\n - `cartesian.xAxisId / cartesian.yAxisId`\n - `axes[]`X/Y 对应 AxisConfig\n\n- **Series**\n - `series[i].type = Bar`\n - `series[i].settings`:实际类型为 `BarSettings`\n - `barWidth`\n - `stacked` / `stackGroup`\n - `barGap` / `categoryGap`\n - `cornerRadius` / `cornerSegments`\n - `textureFill`(颜色/纹理)\n - `border` / `background`\n - `hover`(开启后支持拾取/高亮)\n\n---\n\n## 4. SeriesData 字段解释(按运行时代码)\n\n柱状图核心使用:\n\n- **类目/横向位置**`SeriesData.x`\n - 运行时会对 `x` 做 `RoundToInt`,因此**你应该把它当作“类目索引”来用**。\n\n- **柱高**`SeriesData.value`\n\n- `SeriesData.y` / `SeriesData.z` 对 Bar 图 **不参与渲染**(不要把 y 当柱高)。\n\n---\n\n## 5. 最常见模板:Category X + Value Y\n\n### 5.1 X 轴(Category\n\n- `AxisType = Category`\n- `labels = [\"A\",\"B\",\"C\",...]`\n- 推荐 `labelPlacement = CellCenter`(柱子更容易居中对齐)\n\n### 5.2 数据写法\n\n- `x = 类目索引`0/1/2...\n- `value = 柱高`\n\n---\n\n## 6. 分组柱(多系列并列)的真实规则\n\n并列柱的关键点是:\n\n- 多条 `Serie`,都 `type=Bar`\n- 所有 serie 共享同一套 X 类目(同一套 labels)\n- 每条 serie 的每个点使用相同的 `x` 索引落到同一个类目\n\n并列间距相关字段:\n\n- `BarSettings.barGap`:同一类目下,各组柱之间的间隔\n- `BarSettings.categoryGap`:类目与类目之间的额外间隔(会影响边缘留白)\n\n---\n\n## 7. 堆叠柱(stacked)的真实规则\n\n堆叠发生在“同一个 stackGroup 的 Bar serie”之间:\n\n- `BarSettings.stacked = true`\n- `BarSettings.stackGroup = \"Group1\"`\n\n运行时堆叠逻辑要点:\n\n- 对同一个 `x`(类目索引)分别累计正值/负值(正负会分开堆)\n- 堆叠后的每根柱顶部 = 当前累计底 + `value`\n\n---\n\n## 8. 常见坑与排错\n\n- **柱子夹在两个标签之间 / 对不齐**\n - 优先检查 X 轴 `labelPlacement`(建议 `CellCenter`\n - 确认 `x` 是否为整数索引(运行时会 Round)\n\n- **柱子从中间起,不从 0 起**\n - 检查 Y 轴(Value Axis)的 `autoRangeMin` 是否关闭并锁定 `minValue=0`\n\n- **堆叠结果不对**\n - 检查是否所有需要堆叠的 serie 都设置了相同的 `stackGroup`\n - 注意:正值和负值会分别堆叠\n\n---\n\n## 9. 深入参考\n\n- 轴与范围、Series 与数据:`00-WorkflowAndLibrary.md`\n- 常用配方:`05-CommonRecipes.md`\n- FAQ`06-FAQ.md`\n" },
{ id: "03_03-ScatterChart", relPath: "03_03-ScatterChart.md", title: "散点图(Scatter", content: "# 散点图(Scatter\n\n本章目标:把散点图在 EasyChart 的“数据字段约定”说清楚,尤其是 `SeriesData.y/value` 的兼容逻辑,以及 `z` 维度如何驱动 `sizeMapping`。\n\n---\n\n## 1. 适用场景\n\n- 相关性分析(X/Y 两个数值维度)\n- 分布展示(点云)\n- 异常点识别(离群点)\n\n---\n\n## 2. 最小可用配置(Checklist\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. 轴\n - 常见:X=ValueY=Value\n3. Series\n - 添加 1 条 `Serie`\n - `Serie.type = Scatter`\n - `Serie.seriesData` 至少 2 个点\n\n---\n\n## 3. Inspector 对应字段\n\n- `series[i].type = Scatter`\n- `series[i].settings`:实际类型为 `ScatterSettings`\n - `point`:点样式(显示/大小/纹理)\n - `hover`:悬停高亮(enabled/pickRadius/scale 等,具体字段以版本为准)\n - `sizeMapping`:点大小映射\n\n---\n\n## 4. SeriesData 字段解释(按运行时代码)\n\n散点图渲染时使用:\n\n- **X 坐标**`SeriesData.x`\n- **Y 坐标**:优先使用 `SeriesData.y`\n - 兼容逻辑:如果 `y == 0` 且 `value != 0`,运行时会把 `value` 当成 y 来用\n- **点大小映射维度**`SeriesData.z`(当 `sizeMapping.enabled=true` 时)\n\n因此你有两种常见写法:\n\n### 4.1 推荐写法(显式 X/Y\n\n- `x = X 值`\n- `y = Y 值`\n\n### 4.2 兼容写法(旧数据:用 value 当 y\n\n- `x = X 值`\n- `value = Y 值`\n- `y = 0`\n\n> 建议:新数据直接写 `y`,这样不会跟“点的其他含义(value)”混在一起。\n\n---\n\n## 5. 标准模板:Value X + Value Y\n\n- X 轴:`AxisType = Value`\n- Y 轴:`AxisType = Value`\n- 数据:使用 4.1 的写法(x/y\n\n---\n\n## 6. sizeMapping(点大小映射)的真实规则\n\n当 `ScatterSettings.sizeMapping.enabled = true` 时:\n\n- 点半径会根据 `SeriesData.z` 映射得到\n- 映射范围:`minValue/maxValue` → `minSize/maxSize`\n- 若 `clamp = true`,会把超范围的 t 值夹到 0..1\n- `curve` 会对 t 做一次曲线变换(用于非线性映射)\n\n如果你发现 sizeMapping “没效果”,优先检查:\n\n- 是否真的给了 `z` 值(默认 0\n- `minValue/maxValue` 是否相等(相等会导致映射退化)\n\n---\n\n## 7. 常见坑与排错\n\n- **点全在一条水平线**\n - 你可能只填了 `value`,但又把 `y` 也写成了非 0(兼容逻辑不会触发)\n - 建议统一用 `y` 作为纵坐标\n\n- **hover 没反应**\n - `ScatterSettings.hover.enabled` 必须开启\n - `pickRadius` 太小也会导致很难拾取\n\n- **点太小/太大**\n - 调整 `ScatterSettings.point.size`\n - 或检查 sizeMapping 的 `minSize/maxSize`\n\n---\n\n## 8. 深入参考\n\n- 轴与范围、Series 与数据:`00-WorkflowAndLibrary.md`\n- 常用配方:`05-CommonRecipes.md`\n- FAQ`06-FAQ.md`\n" },
{ id: "03_04-HeatmapChart", relPath: "03_04-HeatmapChart.md", title: "热力图(Heatmap", content: "# 热力图(Heatmap\n\n本章目标:把热力图在 EasyChart 里的“坐标/格子如何映射、`SeriesData` 字段怎么解释、颜色范围怎么算”的规则讲清楚,并标明它是 Pro 功能。\n\n---\n\n## 1. 适用场景\n\n- 二维矩阵数据展示(行/列)\n- 密度/强度可视化\n\n---\n\n## 2. 重要说明(Pro 功能)\n\n- `SerieType.Heatmap` 的渲染器由 `EasyChartProBootstrap` 注册。\n- 如果没有安装/启用 EasyChartPro:该 serie 会被当作“动态渲染器”尝试创建,但通常不会显示。\n\n---\n\n## 3. 最小可用配置(Checklist\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. 轴(Axis Settings\n - 最常用:X=Category(列),Y=Category(行)\n - 也支持 X/Y 使用 Value 轴(见第 6 节)\n3. Series\n - 添加 1 条 `Serie`\n - `Serie.type = Heatmap`\n - `Serie.seriesData` 至少 1 个点\n\n---\n\n## 4. Inspector 对应字段\n\n- **Series**\n - `series[i].type = Heatmap`\n - `series[i].settings`:实际类型为 `HeatmapSettings`\n - `renderMode`Grid / Gradient / Contour\n - `cellGapPx`\n - `xSplitCount` / `ySplitCount`(当 X/Y 使用 Value 轴时用于分格)\n - `autoRange / minValue / maxValue`\n - `lowColor / midColor / highColor`\n - `clamp`\n - `influenceMode`None / Bleed / Smooth\n - `bleed / smooth / gradient / contour` 子配置\n\n---\n\n## 5. SeriesData 字段解释(按运行时代码)\n\n热力图每个数据点对应一个“格子/像素区域”,运行时使用:\n\n- **X 坐标(列)**`SeriesData.x`\n- **Y 坐标(行)**`SeriesData.y`\n- **强度值**`SeriesData.value`\n- **颜色覆盖**:如果 `SeriesData.useColor = true`,则直接用 `SeriesData.color`,跳过 `low/mid/high` 的插值。\n\n> 注意:Heatmap 的 `x/y` 不接受字符串类目;Category 轴场景下仍然用“索引”。\n\n---\n\n## 6. 标准模板:二维 CategoryX/Y+ value 强度(最常用)\n\n### 6.1 X 轴(Category:列)\n\n- `AxisType = Category`\n- `labels = [\"Col0\",\"Col1\",...]`\n\n### 6.2 Y 轴(Category:行)\n\n- `AxisType = Category`\n- `labels = [\"Row0\",\"Row1\",...]`\n\n### 6.3 数据写法\n\n- `x = 列索引`(运行时会对 `x` 做 `RoundToInt`\n- `y = 行索引`(运行时会对 `y` 做 `RoundToInt`\n- `value = 强度`\n\n### 6.4 重要细节:Category 轴下“格子数”与 `labelPlacement`\n\n运行时会用 Axis 的 `labelPlacement` 决定“按 labels.Count 分格”还是“按 labels.Count-1 分格”:\n\n- `CategoryLabelPlacement.CellCenter`\n - X 方向格子数 = `labels.Count`\n - Y 方向格子数 = `labels.Count`\n\n- 其他(非 CellCenter\n - X 方向格子数 = `max(1, labels.Count - 1)`\n - Y 方向格子数 = `max(1, labels.Count - 1)`\n\n这会直接影响你应该填的 `x/y` 索引范围。\n\n---\n\n## 7. Value 轴热力图(X/Y 为数值轴)\n\n当 X 或 Y 使用 `AxisType.Value` 时:\n\n- 格子数量不再来自 labels,而来自:\n - X`HeatmapSettings.xSplitCount`\n - Y`HeatmapSettings.ySplitCount`\n\n- `SeriesData.x/y` 会先根据 `_xMin/_xMax`、`_yMin/_yMax` 归一化,再映射到格子索引。\n\n这适合做“连续值域上的密度/强度分布”。\n\n---\n\n## 8. 常见坑与排错\n\n- **全部一个颜色 / 对比不明显**\n - 检查 `HeatmapSettings.autoRange` 是否开启\n - 或者手动设定 `minValue/maxValue`\n - 也检查是否所有点的 `value` 都几乎一样\n\n- **颜色不按 low/mid/high 来**\n - 检查是否某些点启用了 `useColor=true`(会覆盖调色盘插值)\n\n- **格子对不上(索引越界/偏一格)**\n - 检查 Category 轴的 `labelPlacement` 是否为 `CellCenter`\n - 根据第 6.4 节确定正确的格子数与索引范围\n\n- **格子缝太大/太密**\n - 调 `HeatmapSettings.cellGapPx`\n\n---\n\n## 9. 深入参考\n\n- 轴与范围、Series 与数据:`00-WorkflowAndLibrary.md`\n- 常用配方:`05-CommonRecipes.md`\n- FAQ`06-FAQ.md`\n" },
{ id: "03_05-RadarChart", relPath: "03_05-RadarChart.md", title: "雷达图(Radar", content: "# 雷达图(Radar\n\n本章目标:把雷达图在 EasyChart 中“维度标签来源、数值范围如何计算、数据点顺序如何解释”的规则讲清楚,并对应到 Inspector 字段。\n\n---\n\n## 1. 适用场景\n\n- 多维指标对比\n- 能力/属性雷达\n\n---\n\n## 2. 最小可用配置(Checklist\n\n1. `ChartProfile.coordinateSystem = Polar2D`\n2. Series\n - 添加 1 条 `Serie`\n - `Serie.type = Radar`\n - `Serie.seriesData` 建议至少 3 个点(少于等于 2 个维度运行时不会绘制/无法 hover\n3. PolarAxes(推荐配置)\n - `polarAxes.angleAxis.labels`:维度名\n - `polarAxes.radiusAxis`:数值范围(可自动/手动)\n\n---\n\n## 3. Inspector 对应字段\n\n- **ChartProfile / Coordinate System**\n - `coordinateSystem = Polar2D`\n\n- **PolarAxes(建议用这套来配 Radar 的轴)**\n - `polarAxes.angleAxis.labels`:维度标签\n - `polarAxes.radiusAxis.autoRangeMin/autoRangeMax/minValue/maxValue/autoRangeRounding/labelFormat/...`\n\n- **Series**\n - `series[i].type = Radar`\n - `series[i].settings`:实际类型为 `RadarSettings`\n - `radar`:布局(startAngleDeg / clockwise / innerRadius / outerRadius / plot / background\n - `stroke`:折线样式\n - `area`:面积填充\n - `point`:点样式(点显示也会影响 hover 拾取半径)\n - `series[i].labelSettings`:数据点标签(可显示维度名与数值)\n\n---\n\n## 4. SeriesData 字段解释(按运行时代码)\n\nRadar 的关键点是:**维度顺序由 `seriesData` 列表索引决定**。\n\n- **数值**:使用 `SeriesData.value`\n- **维度索引**:使用“点在 `seriesData` 里的位置 i”(0..dimensionCount-1\n- `SeriesData.x` 在 Radar 渲染中 **不参与定位**(不要依赖 x 来表达维度)\n\n维度数量(dimensionCount)来源:\n\n1. 优先 `Data.PolarAxes.angleAxis.labels.Count`\n2. 如果没配 angleAxis.labels,则使用(优先)某个 Category Axis 的 labels(见第 5 节)\n3. 再不行就用 `seriesData.Count`(或多条 serie 取最大 count\n\n---\n\n## 5. 维度标签(Dimension Label)的真实来源顺序\n\n运行时维度名按以下优先级解析:\n\n1. `polarAxes.angleAxis.labels[i]`\n2. `axes[]` 里某个 `AxisType.Category` 的 `labels[i]`\n - 会优先匹配 `Data.XAxisId` 对应的 Category 轴\n3. `seriesData[i].name`\n4. 都没有时显示 `Dim i`\n\n> 建议:做 Radar 时直接用 `polarAxes.angleAxis.labels` 统一管理维度名;`SeriesData.name` 作为兜底。\n\n---\n\n## 6. 数值范围(Radius Axis)如何计算\n\nRadar 的半径值域使用 `SeriesData.value` 计算:\n\n- 默认会对所有 Radar serie 的 value 做自动范围(auto range\n- 如果你配置了 `polarAxes.radiusAxis`\n - `autoRangeMin/autoRangeMax` 会决定 min/max 是否自动\n - `minValue/maxValue` 在对应 autoRange 关闭时生效\n - `autoRangeRounding` 会对自动出来的 min/max 做“整十/整百/自定义单位”的取整\n - `labelFormat` 会影响 tooltip/标签的格式化\n\n---\n\n## 7. 常见坑与排错\n\n- **看不到雷达图**\n - 检查 `coordinateSystem` 是否为 `Polar2D`\n - 维度数必须大于 2labels 或 seriesData 至少 3\n\n- **维度对不上/顺序错乱**\n - Radar 不看 `x`,它按 `seriesData` 的列表顺序当维度顺序\n - 需要你在 `seriesData` 里按维度顺序放点\n\n- **hover 很难触发**\n - Radar 的拾取半径和 `RadarSettings.point.size` 相关\n - 如果 `point.show=false`,拾取半径会变成 0(基本不可 hover\n\n---\n\n## 8. 深入参考\n\n- Series 与数据:`00-WorkflowAndLibrary.md`\n- 常用配方:`05-CommonRecipes.md`\n- FAQ`06-FAQ.md`\n" },
{ id: "03_06-PieChart", relPath: "03_06-PieChart.md", title: "饼图(Pie", content: "# 饼图(Pie\n\n本章目标:把饼图在 EasyChart 中“数据字段怎么解释、布局/聚合/图例/交互如何生效、哪些行为有隐藏前提”的规则讲清楚,并对应到 Inspector 字段。\n\n---\n\n## 1. 适用场景\n\n- 展示“占比/构成”\n- 强调每个分类在整体中的比例\n\n不适合:\n\n- 类别过多(通常 > 8~12 个会很难读)\n- 需要精确对比微小差异(更建议条形图)\n\n---\n\n## 2. 最小可用配置(Checklist\n\n1. `coordinateSystem`Pie 不依赖 Cartesian/Polar 坐标系(按你的 Profile 现有设置即可)\n2. 添加 1 条 `Serie`\n - `type = Pie`\n - `settings = PieSettings`\n - `seriesData` 至少 1 个点\n3. 确保每个点的 `value > 0`\n\n> 注意:Pie 当前会忽略 `value <= 0` 的点。\n\n---\n\n## 3. 重要限制(按运行时代码)\n\n- **只绘制第一条可见 Pie serie**:当前渲染器会遍历 `Data.Series`,找到第一条 `type=Pie` 且可见的 serie 绘制后就 `break`。\n- Pie 的切片隐藏状态来自 `ChartInteractionState.HiddenPieSliceIds`,会在图例点击时写入/移除。\n\n---\n\n## 4. SeriesData 字段解释(按运行时代码)\n\nPie 主要使用:\n\n- `value`:该切片的数值(权重)\n- `name`:切片名称(推荐填写)\n- `useColor + color`:切片自定义颜色(可选)\n- `id`:切片稳定标识(用于隐藏/交互状态,建议保持稳定)\n\n### 4.1 最推荐写法:显式写 name + value\n\n- `SeriesData.name = \"苹果\"`\n- `SeriesData.value = 12`\n\n### 4.2 name 为空时的名称来源\n\n当 `SeriesData.name` 为空时,Pie 会尝试从 **labels** 获取名称,但有一个前提:\n\n- 如果 `ChartData.CoordinateSystem == None`(通常是纯 Pie/无坐标系图),运行时会 **跳过 labels 兜底**,只使用 `SeriesData.name`。\n\n在非 None 坐标系下,名称兜底顺序是:\n\n- 优先使用 `Data.Cartesian.xAxisId` 对应的 Category 轴 labels\n- 若找不到,再使用任意一个 Category 轴 labels\n- 最后兜底:`Slice {index}`\n\n> 因此:如果你不想依赖轴配置,建议直接填 `SeriesData.name`。\n\n### 4.3 颜色来源\n\n- 若点上 `useColor=true`:使用 `SeriesData.color`\n- 否则:使用内置调色板按顺序分配\n\n---\n\n## 5. 常用配置(PieSettings\n\nPie 的 `settings` 是 `PieSettings`,主要包含:\n\n- `layout`:布局(角度/半径/间隙/居中偏移等)\n- `hover`:悬停交互(explode\n- `aggregation`:聚合(TopN + Others\n- `legend`Pie 专用图例配置(只在“纯 Pie 图表”场景下替代全局 legend\n\n### 4.1 layoutPieLayoutSettings\n\n常用字段:\n\n- `startAngleDeg`:起始角度(默认 -90 让第一片从“正上方”开始)\n- `clockwise`:顺时针/逆时针\n- `angleRangeDeg`:角度范围(默认 360,做“半圆饼”可设 180 等)\n- `outerRadius`:外半径\n - `<= 0`:自动\n - `0~1`:按控件大小比例\n - `> 1`:像素\n- `innerRadius`:内半径(Pie 通常为 0;>0 会变成“中间有洞”的效果,但更推荐用 RingChart 类型做圆环)\n- `innerRadiusColor`:内圈填充颜色\n- `sliceGapPx`:切片间隙(像素)\n- `sliceGapType`:间隙计算方式(Radial/Translate/Uniform\n- `cornerRadius`:圆角(像素,受切片厚度限制)\n- `plot.padding`:留白(避免切片/外侧标签被裁剪)\n- `plot.centerOffset`:中心偏移\n\n### 4.2 hoverPieHoverSettings\n\n- `hover.enabled`:是否启用悬停交互\n- `hover.explodeType`\n - `Translate`:整体平移\n - `Pull`:拉伸(拉出)\n - `Color`:变亮\n - `Stroke`:描边强调\n- `hover.explodeDistance`:平移/拉伸距离(像素)\n\n### 4.3 aggregationPieAggregationSettings\n\n当分类很多时,可以把小项合并为 `Others`\n\n- `aggregation.enabled = true`\n- `keepTopN`:保留前 N 个,其余合并\n- `sortByValue`:是否按 `value` 值排序后再取 TopN\n- `othersName`Others 的名称\n- `useOthersColor + othersColor`Others 颜色\n\n> 注意:聚合只在 `keepTopN > 0` 且切片数量超过 N 时生效。\n\n---\n\n## 6. 图例(PieLegendSettings)与“隐藏切片”交互\n\n当图表是“纯 Pie 图表”(只包含 Pie/RingChart/Pie3D 且没有其它类型)时:\n\n- 图例会优先使用 `PieSettings.legend`(或 RingChartSettings/Pie3DSettings 上的 legend),而不是 `ChartData.legend`。\n- 点击图例条目会切换 `HiddenPieSliceIds`\n - 普通切片:`SeriesData.id`(若为空则用索引字符串)\n - 聚合的 Others:固定使用 `__ec_pie_others__`\n\n`PieLegendSettings.source` 会影响“图例条目从哪里来”:\n\n- `Slice`:每个切片一条(默认)\n- `RingSlice`:为 RingChart/RingSlice 场景提供 label 来源(优先 PolarAxes.angleAxis.labels\n- `Series`:每条 serie 一条(不再是切片级)\n\n---\n\n## 7. 标签(SerieLabelSettings\n\nPie 标签由 `Serie.labelSettings` 控制:\n\n- `show`:是否显示\n- `fontSize / color / decimalPlaces`:字体与数值格式\n- `showName`:是否在标签里显示切片名称\n- `position``Outside/Inside/Center`\n- `offset`:偏移\n\n---\n\n## 8. 常见坑(按现象排查)\n\n- **某些切片不显示**\n - 检查该点 `value` 是否 `<= 0`\n\n- **切片名称不是我想要的**\n - 推荐:直接填写 `SeriesData.name`\n - 如果依赖 labels:确保你确实有一个 Category 轴并填写了 `labels`,且顺序与数据点索引一致\n\n- **切片颜色每次不一样/难以控制**\n - 对需要固定颜色的切片:给该点设置 `useColor=true` + `color`\n\n- **隐藏/交互状态不稳定**\n - 确保每个点的 `SeriesData.id` 稳定(不要每次刷新都重新生成一套新 id)\n\n---\n\n## 9. 下一章\n\n- 圆环图(RingChart):`16-RingChart.md`\n" },
{ id: "03_07-RingChart", relPath: "03_07-RingChart.md", title: "圆环图(RingChart", content: "# 圆环图(RingChart\n\n本章目标:说明 RingChart 的真实含义(它不是 donut pie),并把它在 EasyChart 中的 `SeriesData` 字段解释、`RingChartSettings` 配置与 Pro/基础差异对齐到运行时代码。\n\n---\n\n## 1. RingChart 是什么?(非常重要)\n\n在 EasyChart 当前实现中:\n\n- `SerieType.RingChart` 渲染的是 **多条“进度环”**(每个数据点一条环)\n- 每条环都是 **完整 360° 的底环 + 一段进度弧**\n- 它不是“多个 slice 分割圆周”的饼图\n\n如果你想要“占比构成”的圆环饼图(donut pie):\n\n- 目前更接近 `SerieType.Pie` + `layout.innerRadius > 0`\n- 但推荐仍按你的设计决定:\n - 构成占比:用 Pie\n - 多指标进度/完成率:用 RingChart\n\n---\n\n## 2. 重要说明(Pro 功能)\n\n- `SerieType.RingChart` 的渲染器由 `EasyChartProBootstrap` 注册。\n- 未安装/启用 Pro 时,该 serie 通常不会显示。\n\n---\n\n## 3. 最小可用配置(Checklist\n\n1. 添加 1 条 `Serie`\n - `type = RingChart`\n - `settings = RingChartSettings`\n - `seriesData` 至少 1 个点\n2. 每个点的 `value > 0`\n\n> 注意:RingChart 会忽略 `value <= 0` 的点。\n\n---\n\n## 4. SeriesData 字段解释(按运行时代码)\n\nRingChart 主要使用:\n\n- `value`:环的进度“原始值”\n- `name`:环的名称\n- `useColor + color`:环颜色(点级颜色覆盖)\n- `id`:稳定标识(用于 legend/隐藏状态,建议保持稳定)\n\n### 4.1 Percent 模式(默认):value 同时支持 0~1 和 0~100\n\n当 `RingChartSettings.valueMapping.mode = Percent`(默认)时:\n\n- `value <= 0`:该环会被过滤\n- `0~1`:按比例(0.72 = 72%\n- `> 1`:按百分比(72 = 72%,运行时会除以 100)\n\n建议:团队统一用一种写法(全 0~1 或全 0~100),避免误用。\n\n### 4.2 Range 模式:把 value 映射到 0..1\n\n当 `RingChartSettings.valueMapping.mode = Range` 时:\n\n- 会先确定范围 `min/max`\n - `autoRange=true`:从所有 ring 的 value 自动求范围\n - `autoRange=false`:使用 `minValue/maxValue`\n- 再把 `value` 映射为 `(value-min)/(max-min)` 并 clamp 到 0..1\n\n### 4.3 name 为空时的名称来源\n\n当 `SeriesData.name` 为空时,RingChart 会尝试从 labels 兜底:\n\n- 若 `ChartData.CoordinateSystem == None`:不会使用 labels 兜底,最终会退回到 `Ring {i}`\n- 否则优先:`Data.PolarAxes.angleAxis.labels[i]`\n- 再否则:Cartesian/任意 Category 轴的 `labels[i]`\n- 最终兜底:`Ring {i}`\n\n如果你不想依赖 PolarAxes 配置,建议直接填 `SeriesData.name`。\n\n---\n\n## 5. Inspector 对应字段(RingChartSettings\n\n- `series[i].type = RingChart`\n- `series[i].settings`:实际类型为 `RingChartSettings`\n - `layout`:角度/半径/内外环/留白/中心偏移\n - `valueMapping`Percent/Range 映射规则\n - `hover`:悬停强调(Translate/Pull/Color/Stroke\n - `legend`RingChart 的图例设置(纯 Pie 图表时生效)\n - `showBackground/backgroundAlpha/backgroundColor`:背景环\n - `cornerRadius`:端头圆角\n - `ringGapPx`:环与环间距\n\n### 5.1 layoutRingChartLayoutSettings\n\n常用字段:\n\n- `startAngleDeg`:起始角度\n- `clockwise`:顺/逆时针\n- `angleRangeDeg`:默认 360;可做“半环进度”\n- `outerRadius`:外半径(<=0 自动;0~1 比例;>1 像素)\n- `innerRadius`:内半径(0~1 比例或像素)\n- `plot.padding`:留白(避免 hover/标签被裁剪)\n- `plot.centerOffset`:中心偏移\n\n### 5.2 hoverPieHoverSettings\n\n- `hover.enabled`:是否启用\n- `hover.explodeType`\n - `Translate`:整条环平移\n - `Pull`:拉伸(拉出)\n - `Color`:变亮\n - `Stroke`:描边强调\n- `hover.explodeDistance`:平移/拉伸距离(像素)\n\n### 5.3 背景环与间距\n\n- `showBackground`:是否绘制背景环\n- `backgroundAlpha`:背景环透明度(最终会乘到颜色 alpha 上)\n- `backgroundColor`:背景环颜色(alpha=0 时会回退用 ring 本身颜色)\n- `ringGapPx`:环与环的间距\n- `cornerRadius`:端头圆角(受环厚度限制)\n\n---\n\n## 6. 图例与隐藏交互(与 Pie 共用 HiddenPieSliceIds\n\n- RingChart 与 Pie 共用 `ChartInteractionState.HiddenPieSliceIds`。\n- 每条环的隐藏 key:优先 `SeriesData.id`,否则使用索引字符串。\n- 图例条目 label 的来源受 `PieLegendSettings.source` 影响:\n - `RingSlice` 会优先从 `polarAxes.angleAxis.labels` 取名称。\n\n---\n\n## 7. 标签(SerieLabelSettings\n\nRingChart 的标签同样使用 `Serie.labelSettings`\n\n- `show`:是否显示\n- `showName`:是否显示 name\n- `decimalPlaces`:数值小数位(注意:这里显示的是原始 `value`,不是自动乘 100 的百分比文本)\n- `position`\n - `Outside`:外侧标签 + 引导线\n - `Center`:贴在环中间\n\n---\n\n## 6. 常见坑(按现象排查)\n\n- **我以为它是 donut pie,但显示不对**\n - 这是多环进度图:每个点是一条“进度环”\n\n- **进度不对(比如填 75 结果几乎满圈)**\n - `value>1` 会按百分比除以 100\n - 如果你想 75%:用 `0.75` 或 `75`\n\n- **某些环不显示**\n - 检查 `value <= 0` 是否被过滤\n\n- **交互/隐藏状态不稳定**\n - 确保 `SeriesData.id` 稳定\n\n---\n\n## 8. 深入参考\n\n- 饼图(构成占比):`15-PieChart.md`\n- Series 数据结构:`00-WorkflowAndLibrary.md`\n" },
{ id: "04_08-CommonRecipes", relPath: "04_08-CommonRecipes.md", title: "常用配方(Common Recipes", content: "# 常用配方(Common Recipes)\n\n本章目标:把常用图表的“最低可用配置”整理成可照抄的配方(Series + Axis + 常见坑),用于你快速创建/排错。\n\n---\n\n## 0. 开始之前:最小检查清单\n\n当你遇到“怎么都看不到/显示很怪”时,先按顺序检查:\n\n1. `coordinateSystem` 是否与 SeriesType 匹配(Cartesian2D vs Polar2D\n2. `series` 是否至少 1 条,且该 Serie 的 `seriesData.Count > 0`\n3. 轴类型是否匹配数据含义:\n - Category 轴:`labels` 非空,且数据点的 `x/y` 是索引(0/1/2...\n - Value 轴:数据点 `x/y` 是连续数值\n4. 是否存在 NaN/Infinity\n5. 是否把 Value 轴范围“锁死”了(`autoRangeMin/autoRangeMax` 或固定 min/max),导致数据落在范围外\n\n---\n\n## 1. 折线图(Line):类目 X + 数值 Y\n\n### 目标效果\n\n- X:类目标签(A/B/C/D\n- Y:数值\n- 折线按类目对齐\n\n### 配方\n\n1. `coordinateSystem = Cartesian2D`\n2. X 轴:\n - `axisType = Category`\n - `labels = [A, B, C, D]`\n - `LabelPlacement = Tick`\n3. Y 轴:\n - `axisType = Value`\n - `autoRangeMin/autoRangeMax = true`\n4. Series\n - `type = Line`\n - 数据点:`x=类目索引`,`y=数值`\n\n数据示例(概念):\n\n```txt\n(x=0, y=10)\n(x=1, y=20)\n(x=2, y=15)\n(x=3, y=30)\n```\n\n### 常见坑\n\n- **点不落在标签上**:检查 `x` 是否从 0 开始,是否越界(labels.Count\n- **线看起来“断了/跳”**:检查是否有 NaN/Infinity\n\n---\n\n## 2. 柱状图(Bar):类目居中 + Y 从 0 起\n\n### 目标效果\n\n- 每个类目一个柱子\n- 标签在柱子中心对齐\n- Y 轴从 0 起,避免误导\n\n### 配方\n\n1. `coordinateSystem = Cartesian2D`\n2. X 轴:\n - `axisType = Category`\n - `labels` 填类目\n - `LabelPlacement = CellCenter`\n3. Y 轴:\n - `axisType = Value`\n - 固定从 0 开始(例如 `minValue=0` + `autoRangeMax=true`,或等价字段组合)\n4. Series\n - `type = Bar`\n - `BarSettings.barWidth` 调整柱宽\n\n数据示例:\n\n```txt\n(x=0, y=12)\n(x=1, y=18)\n(x=2, y=9)\n```\n\n### 常见坑\n\n- **柱子夹在两个标签之间**:把 `LabelPlacement` 切到 `CellCenter`\n- **柱子太挤/太疏**:调 `barWidth`、`barGap`、`categoryGap`\n\n---\n\n## 3. 并列柱(Grouped Bar):多条 Serie 共享同一套类目\n\n### 配方\n\n- 多条 `Serie`,都设置 `type = Bar`\n- 每条 Serie 都写同一套 `x=类目索引`\n- 用 `Serie.name` 区分组名(图例/tooltip 会用到)\n\n示例(概念):\n\n```txt\nSerie A:\n (x=0, y=10) (x=1, y=12)\nSerie B:\n (x=0, y=8) (x=1, y=15)\n```\n\n---\n\n## 4. 堆叠柱(Stacked Bar):stacked + stackGroup\n\n### 配方\n\n- 需要堆叠的 Bar 系列:\n - `BarSettings.stacked = true`\n - `BarSettings.stackGroup = \"Group1\"`(同组会堆叠)\n\n### 常见坑\n\n- **堆叠后高度看起来不对**:确认所有参与堆叠的系列 `stackGroup` 完全一致\n\n---\n\n## 5. 散点图(Scatter):Value X/Y + hover + sizeMapping\n\n### 目标效果\n\n- X/Y 都是连续数值\n- 鼠标移上去点会变大(hover)\n- 点大小可按某个维度映射(sizeMapping\n\n### 配方\n\n1. `coordinateSystem = Cartesian2D`\n2. X/Y 轴都设为 `Value`\n3. `type = Scatter`\n4. 数据点:至少 `x/value`,可选使用 `z` 作为第三维\n5. `ScatterSettings.hover.enabled = true`\n\n### 常见坑\n\n- **点太小看不见**:提高 `PointSettings.size`\n- **hover 没反应**:检查 `HoverHighlightSettings.enabled` 和 `pickRadius`\n\n---\n\n## 6. 热力图(Heatmap):(x, y, value) 三元组\n\n### 目标效果\n\n- X/Y 是类目轴(二维标签)\n- 颜色由 value 决定\n\n### 配方\n\n1. `coordinateSystem = Cartesian2D`\n2. X 轴:Category + labels(列标签)\n3. Y 轴:Category + labels(行标签)\n4. `type = Heatmap`\n5. 数据点:\n - `x = 列索引`\n - `y = 行索引`\n - `value = 强度`\n\n示例(概念):\n\n```txt\n(x=0, y=0, value=0.2)\n(x=1, y=0, value=0.8)\n(x=0, y=1, value=0.5)\n```\n\n### 常见坑\n\n- **所有格子同一颜色**:检查 `HeatmapSettings.autoRange/minValue/maxValue/clamp`\n- **格子太小/太密**:调 `cellSizePx` / `cellGapPx`\n\n---\n\n## 7. 雷达图(Radar):维度索引 x + 数值 value\n\n### 配方\n\n1. `coordinateSystem = Polar2D`\n2. `type = Radar`\n3. 数据点:\n - `x = 维度索引`\n - `value = 数值`\n - `name = 维度名`(建议填,便于标签/tooltip\n\n示例:\n\n```txt\n(x=0, value=72, name=\"攻击\")\n(x=1, value=55, name=\"防御\")\n(x=2, value=90, name=\"速度\")\n```\n\n### 常见坑\n\n- **雷达图标签乱/缺失**:确保维度标签来源一致(不要依赖 Cartesian 的 axis 配置)\n- **看不到雷达**:检查 `coordinateSystem` 是否为 Polar2D\n\n---\n\n## 8. 交互/tooltip 稳定性:SeriesData.id\n\n如果你启用了选中、tooltip 或 hover,一般建议:\n\n- 每个数据点的 `SeriesData.id` 保持稳定\n\n> 否则当你每次刷新数据都生成一套新 id,会造成交互状态无法关联。\n\n---\n\n## 下一章\n\n- 如果你希望继续写:可以新增 `06-FAQ.md`(常见问题 + 最快排错路线)。\n" },
{ id: "04_09-FAQ", relPath: "04_09-FAQ.md", title: "FAQ(常见问题与最快排错路线)", content: "# FAQ(常见问题与最快排错路线)\n\n本章目标:当你遇到“看不到/显示不对/交互怪”等问题时,能用最短路径定位原因。\n\n---\n\n## 0. 最快排错路线(30 秒版)\n\n按顺序检查,通常能解决 80% 的问题:\n\n1. **坐标系是否匹配 SeriesType**\n - Cartesian2DLine/Bar/Scatter/Heatmap\n - Polar2DRadar\n\n2. **是否真的有数据**\n - `series.Count > 0`\n - 该 Serie `seriesData.Count > 0`\n\n3. **轴类型是否匹配数据含义**\n - Category 轴:`labels` 非空;数据点 `x/y` 使用索引(0/1/2...\n - Value 轴:`x/y` 为连续数值\n\n4. **是否存在 NaN / Infinity**\n\n5. **Value 轴范围是否把数据排除在外**\n - 检查是否固定了 min/max\n - 检查 `autoRangeMin/autoRangeMax` 是否关闭\n\n---\n\n## 1. 我点了预览但什么都没有\n\n### 可能原因\n\n- `seriesData` 为空\n- `Serie.visible = false`\n- 坐标系与 SerieType 不匹配(例如 Radar 放在 Cartesian2D\n- 轴范围不包含数据(常见于 Value 轴被手动锁死)\n\n### 你应该怎么做\n\n1. 在 Inspector 找到 `series` -> 展开某个 Serie\n2. 检查:\n - `visible` 是否为 true\n - `seriesData` 是否有元素\n3. 检查坐标系:\n - Radar -> `coordinateSystem = Polar2D`\n - Line/Bar/Scatter/Heatmap -> `coordinateSystem = Cartesian2D`\n4. 如果是 Value 轴:\n - 先把范围相关的“固定 min/max”关闭\n - 让 `autoRangeMin/autoRangeMax` 都开,确认能显示后再逐步锁定\n\n---\n\n## 2. Category 轴有 labels,但点/柱子不在标签上\n\n### 典型现象\n\n- 柱子落在两个标签中间\n- 折线的点对不上 A/B/C\n\n### 快速结论\n\n- Category 轴下,`x`(或 `y`)通常应该是 **类目索引**(0/1/2/...),而不是“随便的数值”。\n\n### 你应该怎么做\n\n- 检查数据点:\n - `labels[0]` 对应 `x=0`\n - `labels[1]` 对应 `x=1`\n- 如果你做的是柱状图:\n - 把 `LabelPlacement` 调成 `CellCenter`\n\n---\n\n## 3. Value 轴范围很怪(特别大/特别小)\n\n### 可能原因\n\n- Value 轴被锁死范围(min/max)\n- 只锁了一端但另一端的数据非常极端\n- rounding/unit 把范围吸附到不合适的单位\n\n### 你应该怎么做\n\n1. 先把范围回退到“全自动”,确认能显示\n2. 再逐步加入你的业务约束:\n - 柱状图常用:`minValue=0` + `autoRangeMax=true`\n3. 如果你看到很多奇怪的小数刻度:\n - 优先设置 `labelFormat`\n\n---\n\n## 4. 线条断断续续/整体不渲染\n\n### 最常见原因\n\n- 数据中存在 NaN / Infinity\n\n### 你应该怎么做\n\n- 在数据源侧过滤:\n - `float.IsNaN(x/y/z)`\n - `float.IsInfinity(x/y/z)`\n\n---\n\n## 5. 柱状图和标签就是对不齐\n\n### 快速结论\n\n- 99% 是 `LabelPlacement` 没配对\n\n### 你应该怎么做\n\n- Bar:优先 `LabelPlacement = CellCenter`\n- Line/Scatter:优先 `LabelPlacement = Tick`\n\n---\n\n## 6. Heatmap 全部一个颜色 / 看起来没有层次\n\n### 可能原因\n\n- `autoRange=false` 但 `minValue/maxValue` 设置不合理\n- `clamp=false` + 极端值导致颜色被拉爆\n- 数据点 `value` 全部相同(或全是 0\n\n### 你应该怎么做\n\n1. 开启 `autoRange`\n2. 检查数据点 `value` 是否有变化\n3. 如果你需要固定范围:\n - 合理设置 `minValue/maxValue`\n\n---\n\n## 7. Radar 标签缺失/混乱\n\n### 常见原因\n\n- 维度标签来源不统一\n\n### 推荐做法\n\n- 每个 Radar 点:\n - `x = 维度索引`\n - `value = 数值`\n - `name = 维度名`\n\n并确保 Radar 不依赖 Cartesian 的轴配置来取标签。\n\n---\n\n## 8. tooltip/hover/选中“指错点”或状态不稳定\n\n### 常见原因\n\n- 每次刷新数据都产生新的点标识\n\n### 你应该怎么做\n\n- 保证每个点的 `SeriesData.id` 稳定\n- 避免每次刷新都清空再 `Guid.NewGuid()` 生成一套全新的点\n\n---\n\n## 9. 我不知道应该看哪一章\n\n- 你在“创建/克隆/预览/导出”的流程阶段:看 `02-EditorWorkflow.md`\n- 你在“轴/范围/对齐/单位/格式”:看 `00-WorkflowAndLibrary.md` 的第 7 节\n- 你在“某种图的 data 写法/SeriesData.x/y/z”:看 `00-WorkflowAndLibrary.md` 的第 8 节\n- 你只想直接照抄模板:看 `05-CommonRecipes.md`\n" },
{ id: "05_01-UpdatePlan", relPath: "05_01-UpdatePlan.md", title: "更新计划(Roadmap / Update Plan", content: "# 更新计划(Roadmap / Update Plan\n\n本章用于说明 EasyChart 后续整体更新方向与计划项。\n\n- 本文件**不按版本阶段拆分**(后续会在各类型章节中再做细化计划)\n- 本文件以“能力分类”组织:你可以把它当作路线图的目录\n\n## Free / Pro 版本划分(发布策略)\n\n### Free(独立包)\n\n- 定位:覆盖 AssetStore 最常见使用场景,做到“可配置 + 可预览 + 可运行时注入数据”的闭环。\n- 包含:现有基础 2D 图表类型、运行时注入(`ChartFeed` / `ApplyJson`)、`EasyChartLibraryWindow` 等编辑器工作流。\n\n### Pro(独立包,包含 Free 全量)\n\n- 定位:在 Free 的基础上提供明显的差异化能力与长期扩展路线。\n- 包含:Free 全量 + Pro 增量功能(高级效果 / 新图表类型 / 3D / 工具链等)。\n\n### 兼容策略\n\n- Free 遇到 Pro-only 资产/配置:允许直接报错(不做降级兼容)。\n\n### Pro 首批卖点优先级\n\n- A:新增图表类型\n- B3D 图表\n- C:2D 高级视觉效果(如贴图UV动画、特效类渲染能力)\n\n---\n\n## 附录:版本计划(含时间,暂定)\n\n> 说明:以下为“按月/季度”的暂定节奏,具体日期可在确定团队人力与上架窗口后再收敛。\n\n### 2026 Q11-3 月):稳定化 + Free 完整闭环\n\n- 2026-01Free v1.0.x):\n - 修复/收尾:JSON Injection 面板与示例生成/解析的稳定性(按当前 TODO)\n - 文档与示例:对齐最新数据结构与面板能力\n- 2026-02Free v1.1.0):\n - 2D 体验增强(Free 范围):Bar 圆角、hover 效果(如尚未实现则在此版本落地)\n - 编辑器体验:LibraryWindow 常用 workflow 小优化(不引入 Pro 依赖)\n- 2026-03Free v1.1.x):\n - 回归修复 + 性能/GC 优化(大数据量刷新、tooltip/交互稳定性)\n\n### 2026 Q24-6 月):Pro v1.0(新图表类型优先)\n\n每个类型的Series都加一个动画组件集合,可以添加一些类型的动画例如Point的闪烁,TextureFill的UV动画这些,\n- 2026-04Pro v1.0.0):\n - 完成 Pro 包结构与发布流程固化(Pro 包含 Free 全量)\n - 新图表类型(第一批):Gauge / Funnel(二选一或都做,按复杂度控制)\n- 2026-05Pro v1.0.x):\n - 新图表类型(第二批):BoxPlot / Candlestick(优先实现其中一个)\n - Pro-only 报错提示与 Editor 侧可读错误信息完善\n- 2026-06Free v1.2.0 + Pro v1.1.0):\n - Free:继续补齐 2D 常用能力与稳定性\n - Pro:新图表类型扩展(Treemap / Sunburst 预研或首版)\n\n### 2026 H27-12 月):3D 路线与特效能力\n\n- 2026 Q37-9 月)(Pro v2.0 或 v1.2+):\n - 3D 图表(第一批):3D Bar / 3D Scatter(优先其中一个可用闭环)\n - 3D 渲染管线与交互基础(按最小可用集拆分迭代)\n- 2026 Q410-12 月):\n - 3D Surface(预研/试验性)\n - 2D 高级视觉效果(Pro):贴图 UV 动画(以及后续更复杂特效能力)\n - 工具链增强:Theme / 网络直连 / 自动化测试(择一作为质量提升主线)\n\n---\n\n## 1. 图表类型扩展计划(Chart Types\n\n### 1.1 2D 图表(现有体系增强)\n\n- 目标:在不增加过多 `SerieType` 的前提下,用“settings/variant”补齐常用表达。\n- 候选方向(示例):\n - Line:更多线型/填充/标注能力(如更丰富的标记/阈值线等),贴图UV动画(Pro)\n - Bar:更多堆叠模式、百分比堆叠、瀑布等模式化能力,Bar头部圆角(Free),hover效果(Free),贴图UV动画(Pro\n - Scatter:更多映射维度(size/color)、密度表达(如聚合/栅格化)\n - Pie:更多布局与聚合策略、标签策略与交互\n\n### 1.2 新增图表类型(可能新增 `SerieType`\n\n- 目标:支持 AssetStore 更常见的“独立图表品类”。\n- 候选方向(示例):\n - Gauge / 仪表盘(进度、刻度、阈值)\n - Funnel / 漏斗图\n - BoxPlot / 箱线图\n - Candlestick / K 线(OHLC\n - Treemap / Sunburst(层级可视化)\n - Sankey / Graph(更复杂的结构类图表,后置)\n\n### 1.3 3D 图表(3D Charts\n\n- 目标:提供一套 3D 图表能力(可能是独立渲染管线)。\n- 候选方向(示例):\n - 3D Bar / 3D Column\n - 3D Scatter\n - 3D Surface(难度更高,后置)\n\n---\n\n## 2. 多轴与坐标系能力(Multi-Axis & Coordinate Systems\n\n- 目标:在保持语义清晰的前提下,增强多轴场景。\n- 方向:\n - 支持更多轴组合(双 Y 轴、顶/底 X 轴、左右 Y 轴的混搭)\n - 更清晰的轴绑定策略(Serie 绑定到哪个轴、tooltip/label 使用哪个轴格式化)\n - 坐标系切换/混用的约束与提示(避免用户配置混乱)\n\n---\n\n## 3. 字体与文本系统(Font & Text)\n\n- 目标:统一文本渲染的观感与可配置项,降低 UI Toolkit 不同平台的差异。\n- 方向:\n - 更完整的文字样式(字体、字号、粗细、颜色、描边/阴影等)\n - 文本布局策略(自动换行、截断、省略号、对齐与锚点)\n - 数值格式化能力增强(千分位、单位、百分比、科学计数法等)\n\n---\n\n## 4. 时间轴与 Log 轴(Time Axis & Log Axis\n\n- 目标:增强对“时间序列”和“数量级跨度很大”的数据表达能力。\n- 方向:\n - 时间轴:时间刻度、格式化、间隔策略(天/周/月/年)\n - Log 轴:log10/log2 等刻度与标签\n - 与数据注入配合(如何喂时间数据、如何处理缺失点)\n\n---\n\n## 5. 主题系统(Theme / Palette\n\n- 目标:把“配色/字体/默认样式”从单个 Profile 抽象成可复用主题。\n- 方向:\n - Theme 资产(Palette + 字体 + 默认样式)\n - Profile 与 Theme 的覆盖策略(主题默认 vs Profile 局部覆盖)\n - 主题预览、主题切换、主题库\n\n---\n\n## 6. 网络接口直连(Direct Networking / Data Binding\n\n- 目标:降低“从网络接口到图表”的接入成本。\n- 方向:\n - 提供基于 `ChartFeed` 的标准输入协议\n - 提供可选的 API Envelope 支持(如 `{code,message,data}`\n - 提供示例:HTTP 拉取 -> 解析 -> Apply\n - 缓存、节流、错误提示与降级策略\n\n---\n\n## 7. 自动化测试与质量保障(Automated Tests & QA\n\n- 目标:降低迭代风险,让重构更安全。\n- 方向:\n - 数据结构迁移测试(序列化兼容性)\n - 渲染回归测试(截图对比/像素容差,或关键顶点/mesh 断言)\n - 交互测试(tooltip/hit test 的稳定性)\n - 性能基准(大数据量刷新、GC、帧耗时)\n\n---\n\n## 8. 编辑器工作流与工具链(Editor Workflow & Tooling\n\n- 目标:让配置、预览、注入与复用更顺手。\n- 方向:\n - LibraryWindow:模板/复制/导入导出/批量处理\n - JSON Injection:更强的协议兼容、错误定位、示例生成\n - 更清晰的手册与示例工程\n" }
];