27 lines
116 KiB
JavaScript
27 lines
116 KiB
JavaScript
window.EASYCHART_MANUAL_EN = window.EASYCHART_MANUAL_EN || {};
|
||
window.EASYCHART_MANUAL_EN.generatedAt = "2026-03-18 17:29:31";
|
||
window.EASYCHART_MANUAL_EN.chapters = [
|
||
{ id: "00_00-Index", relPath: "00_00-Index.md", title: "Quick Overview", content: "# Quick Overview\n\nThis manual is intended for a workflow where you configure charts (the `ChartProfile` asset) in the Unity Editor via **`EasyChartLibraryWindow`**.\n\n- Menu entry: `EasyChart/Library Editor`\n- Manual viewer: `EasyChart/Manual`\n\n---\n\n## Table of Contents\n\n### A. Getting Started & Workflows\n\n- [Quick overview](./00_00-Index.md)\n- [Quick start: create your first chart in 2 minutes](./00_01-QuickStart.md)\n- [UIToolKit workflow (recommended)](./00_02-WorkflowAndLibrary.md)\n- [UGUI workflow](./00_03-UGUIWorkflow.md)\n- [Runtime data injection (UIToolKit)](./00_04-RuntimeDataInjectionUIToolKit.md)\n- [Runtime data injection (UGUI)](./00_05-RuntimeDataInjectionUGUI.md)\n\n### B. Editor & Panels\n\n- [Editor workflow and panels](./01_01-EditorWorkflow.md)\n- [Library panel (asset tree)](./01_02-LibraryPanel.md)\n- [JSON Injection panel](./01_03-JsonInjectionPanel.md)\n- [Preview panel](./02_04-PreviewPanel.md)\n- [Inspector panel](./02_05-InspectorPanel.md)\n- [Series panel](./02_06-SeriesPanel.md)\n\n### C. Series Configuration (Goal-Oriented)\n\n- [Line chart](./03_01-LineChart.md)\n- [Bar chart](./03_02-BarChart.md)\n- [Scatter chart](./03_03-ScatterChart.md)\n- [Heatmap chart](./03_04-HeatmapChart.md)\n- [Radar chart](./03_05-RadarChart.md)\n- [Pie chart](./03_06-PieChart.md)\n- [Ring chart](./03_07-RingChart.md)\n\n### D. Reference (Lookup by Field)\n\n- [Common recipes](./04_08-CommonRecipes.md)\n- [FAQ (fastest troubleshooting path)](./04_09-FAQ.md)\n\n### E. Updates & Roadmap\n\n- [Roadmap / update plan](./05_01-UpdatePlan.md)\n\n---\n\n## Conventions & Terminology\n\n- **ChartProfile**: A chart configuration asset (reusable; previewable in the editor).\n- **Series / Serie**: A data series (e.g. one line in a line chart, or one group of bars in a bar chart).\n- **SeriesData**: The set of data points in a series.\n- **Axis**: Axis configuration (`AxisType=Category/Value`).\n- **Category**: Category axis (uses the `labels` list).\n- **Value**: Value axis (continuous numeric range).\n\n---\n\n## Recommended Project Structure\n\nRecommended to create a dedicated folder in your project for chart assets:\n\n- `Assets/EasyChart/Library/Custom/`: your own `ChartProfile` assets\n- `Assets/EasyChart/Docs/Manual/`: this manual (Markdown chapters)\n\n---\n\n## Manual Version\n\n- This manual will be kept in sync with EasyChart field and editor feature updates.\n" },
|
||
{ id: "00_01-QuickStart", relPath: "00_01-QuickStart.md", title: "Quick Start: Create Your First Chart in 2 Minutes", content: "# Quick Start: Create Your First Chart in 2 Minutes\n\nGoal of this chapter: follow the fastest recommended EasyChart path to complete the loop of **Edit → Export → Use in UI**.\n\n---\n\n## Open the Editor Window\n\nIn the Unity menu bar, choose:\n\n- `EasyChart/Library Editor`\n\nYou will see a window with sections like a library tree, configuration panels, and a preview area (later chapters explain each area).\n\n---\n\n## Clone a Library (Recommended)\n\nIf you want to get started quickly and keep a consistent style, it's recommended to:\n\n- Select an existing Library from the top toolbar (e.g. a built-in Demo library)\n- Click **Clone** on the toolbar to create your personal library (e.g. `MyLibrary`)\n\nThis way, all subsequent changes happen in your own library, avoiding modifications to the original examples.\n\n---\n\n## Clone a ChartProfile (Recommended)\n\nIn the library tree, find a chart (`ChartProfile`) close to what you want, then right-click:\n\n- `Clone`\n\nAfter cloning, you'll get a new Profile (a \"variant\" of the original). Select it, and the Inspector on the right will show all editable settings.\n\n---\n\n## Modify Settings and Save\n\nMinimal recommended changes:\n\n- `coordinateSystem`: make sure it matches your intended Series (e.g. Line/Bar/Scatter use `Cartesian2D`)\n- `series`: confirm `type` is correct, and fill in `seriesData`\n- `axes`: at minimum, make sure X/Y axis types match the meaning of your data\n\nAfter editing, click the save button on the top toolbar (if your version has it), or let Unity auto-save the asset.\n\n---\n\n## Export to UXML (Reusable in UI Builder)\n\nThe recommended workflow is exporting the Profile to a reusable `.uxml`:\n\n- Right-click your Profile in the tree\n- Choose `Export to UXML`\n\nThe exported UXML will be placed under:\n\n- `Assets/EasyChart/LibraryUxml/` (Mirror/Backup operations also manage exported assets under this root)\n\n---\n\n## Use It in the QuickStart Scene via UIDocument + UI Builder\n\nOpen the demo scene:\n\n- `Assets/EasyChart/Demo/Scenes/EasyChart_QuickStart.unity`\n\nThen in the Project window, locate:\n\n- `Assets/EasyChart/Demo/UIToolKit/NewUXMLTemplate.uxml`\n\nDouble-click to open it (or open with UI Builder). Next:\n\n- Drag the chart `.uxml` you just exported into the hierarchy of `NewUXMLTemplate.uxml`\n- Save the UXML\n- Make sure the `UIDocument` in the scene references your updated `NewUXMLTemplate.uxml`\n\nRun the scene, and you should see the chart rendered in the UI Toolkit UI.\n\n---\n\n## Alternative: Export as a UGUI Prefab\n\nIf you prefer a UGUI (Canvas/RectTransform) workflow, you can also export the selected Profile as a UGUI prefab in the Library Editor and place it directly into your scene UI (exact menu entry and details depend on your current version).\n\n---\n\n## What to Read Next\n\n- To understand the recommended UI Toolkit workflow: `00_02-WorkflowAndLibrary.md`\n- To use charts with UGUI (Canvas/RectTransform): `00_03-UGUIWorkflow.md`\n\n" },
|
||
{ id: "00_02-WorkflowAndLibrary", relPath: "00_02-WorkflowAndLibrary.md", title: "UI Toolkit Workflow (Recommended)", content: "# UI Toolkit Workflow (Recommended)\n\nGoal of this chapter: explain the overall recommended EasyChart approach (primarily for UI Toolkit):\n\n1. Edit `ChartProfile` in the editor with **`EasyChartLibraryWindow`**\n2. **Export** `ChartProfile` **to `.uxml`** as your chart library assets\n3. Compose pages in UI Toolkit using **UI Builder** / UXML, enabling fast UI assembly\n\nThis chapter focuses on **UI Toolkit (recommended)**. If you need the UGUI (Canvas/RectTransform) workflow, see:\n\n- `00_03-UGUIWorkflow.md`\n\n## 0. Why the UI Toolkit workflow is recommended\n\nThe key idea is to separate the \"chart configuration source\" (`ChartProfile`) from the \"UI artifact\" (exported UXML).\n\n- `ChartProfile`: defines what the chart looks like, which axes it uses, what Series it has, and how data should be interpreted. This is best maintained centrally in the editor.\n- Exported `.uxml`: places the chart into a page as a UI Toolkit component. This is best suited for reuse, composition, and version control.\n\nWhat you get:\n\n- Reusable configuration (multiple pages can share one chart style)\n- Composable pages (drag & drop in UI Builder; no need to rebuild UI from scratch each time)\n- Clearer collaboration (Profile as the \"source\", UXML as the \"product/component library\")\n\n---\n\n## 1. Why export to UXML\n\nIn a project, `ChartProfile` describes \"what the chart looks like\", \"which axes it uses\", \"which Series it has\", and \"how data points are interpreted\".\n\nAfter exporting to `.uxml`, you get a reusable UI asset for UI Toolkit:\n\n- Can be dragged directly in UI Builder\n- Can be reused by multiple pages (same chart style)\n- Can be managed by version control and asset pipelines (your \"chart library\")\n\n---\n\n## 2. Recommended workflow (from configuration to page)\n\n### Step 1: Clone your working library and charts (recommended)\n\n- Open from the Unity menu: `EasyChart/Library Editor`\n\nRecommended process:\n\n- **Clone Library**: clone your own Library first (avoid modifying the built-in demo library directly)\n- **Clone ChartProfile**: in your library tree, right-click a Profile close to your target look, then choose `Clone` to create a variant\n- Modify in the Inspector on the right:\n - `coordinateSystem`\n - `series`\n - `axes`\n\n> Recommendation: keep your own Profiles under `Assets/EasyChart/Library/Custom/` (or a team-agreed folder).\n\n### Step 2: Export to UXML (generate library assets)\n\nYou can export from the Library Editor:\n\n- For a Profile: `Export to UXML`\n- For a folder:\n - `Export Folder to UXML (Mirror)`\n - `Export Folder to UXML (Backup)`\n- For all:\n - `Export All UXML (Mirror)`\n - `Export All UXML (Backup)`\n\nExport root folder:\n\n- `Assets/EasyChart/LibraryUxml/`\n\nWith multiple Libraries, the usual structure is:\n\n- `Assets/EasyChart/LibraryUxml/<LibraryName>/...`\n\nThe `_Backups` subfolder is used for backup exports (and some JSON backups generated during exporting):\n\n- `Assets/EasyChart/LibraryUxml/<LibraryName>/_Backups/...`\n\nThe exported UXML usually looks like:\n\n- A `<ec:ChartElement profile-name=\"...\" />`\n- `profile-name` corresponds to the ChartProfile key (usually the asset file name)\n- Width/height styles for the chart are written into the UXML as well\n\n> Key point: treat exported `.uxml` as **reusable chart components**, not something you hand-write for every UI.\n\n### Mirror vs Backup (which one should you use?)\n\n- **Mirror**:\n - used to \"mirror the current Profile state into UXML\"\n - typically overwrites exports with the same name, and may remove stale files that no longer exist (keep the mirror consistent)\n- **Backup**:\n - used to \"export a snapshot\" by time/tag\n - not recommended as the primary path that your pages reference (better for history/rollback)\n\n### Step 3: Compose pages in UI Builder\n\nIn UI Builder:\n\n- Open your page UXML\n- Drag the exported chart `.uxml` from the Project window\n- Combine it with other UI (Label, Button, ListView, etc.) into a full page\n\nFor the quickest export-pipeline verification, you can use the demo scene and template:\n\n- Scene: `Assets/EasyChart/Demo/Scenes/EasyChart_QuickStart.unity`\n- Template: `Assets/EasyChart/Demo/UIToolKit/NewUXMLTemplate.uxml`\n\nDrag the exported chart `.uxml` into `NewUXMLTemplate.uxml`, then make sure the `UIDocument` in the scene references that template.\n\n#### Exact steps in UI Builder (recommended order)\n\n1. Open UI Builder (or double-click your page `.uxml`).\n2. In the Project window, locate the exported chart `.uxml` (usually under `Assets/EasyChart/LibraryUxml/<LibraryName>/...`).\n3. Drag the `.uxml` into the page hierarchy (recommended to put it inside a container `VisualElement`).\n4. Save the page UXML.\n5. Back in the scene, make sure `UIDocument` references the page `.uxml` you just saved.\n\n#### What's inside an exported chart UXML\n\nExported `.uxml` typically contains an `EasyChart.ChartElement` with attributes like:\n\n- `profile-name`: usually the ChartProfile asset file name (key)\n- `profile-guid`: a more stable way to locate the asset\n\nTherefore:\n\n- If you only modify the Profile, the page will not change automatically: you need to re-export (Mirror) so the UXML gets updated.\n- If you rename the Profile asset, the exported `profile-name` will also change (so keep naming stable when possible).\n\n### Step 4: Load/replace data at runtime (depends on your product)\n\n`ChartProfile`/UXML defines the \"style and structure\", while your data usually comes from business logic.\n\n- Static display: fill data directly in the Profile `seriesData`\n- Dynamic display: write/replace `seriesData` at runtime (and keep `SeriesData.id` stable)\n\n---\n\n## 3. Folder layout recommendations for your chart library\n\nRecommended to separate the \"source configuration\" and the \"exported artifacts\":\n\n- `Assets/EasyChart/Library/Custom/`: the `ChartProfile` assets you maintain\n- `Assets/EasyChart/LibraryUxml/`: exported UXML (both Mirror and Backup exports live under this root)\n\nWhen using multiple Libraries, exported assets are typically organized by library name:\n\n- `Assets/EasyChart/LibraryUxml/<LibraryName>/...`\n\nRecommended conventions:\n\n- **Maintain Profiles only under `Assets/EasyChart/Library/...`** (as the source of truth)\n- **Pages reference only Mirror exports** (as your component library)\n- Treat Backup exports purely as **historical snapshots**\n\n> Benefits:\n> - Your configuration source stays readable and editable\n> - Exported artifacts are reusable, composable, and can be used directly in UI Builder\n\n---\n\n## 4. Common issues & troubleshooting\n\n- **Can't find the exported chart UXML in UI Builder**\n - First check whether files were generated under `Assets/EasyChart/LibraryUxml/`\n - If you use multiple Libraries, check under `Assets/EasyChart/LibraryUxml/<LibraryName>/`\n - Mirror/Backup exports may appear under `_Backups`; pages should not reference files under `_Backups`\n\n- **The page references the UXML, but nothing shows at runtime**\n - Make sure the scene `UIDocument` references the page `.uxml` you edited\n - In the Library Editor, use Preview to verify the Profile renders correctly (rule out Profile configuration issues first)\n\n- **You modified the Profile but the page didn't change**\n - The Profile is the \"source\"; the page references exported UXML\n - After modifying a Profile, re-export (Mirror), then return to the page and refresh/save\n\n- **The component is visible in UI Builder, but still doesn't show at runtime**\n - First verify the scene `UIDocument` truly references the intended page (not an older page)\n - Then verify the Profile renders correctly in the Library Editor Preview\n\n---\n\n## 5. What to read next\n\n- To quickly complete a single chart end-to-end: `00_01-QuickStart.md`\n- To use charts with UGUI (Canvas/RectTransform): `00_03-UGUIWorkflow.md`\n\n---\n\n## 6. Editor workflow & panels quick reference (Library Editor)\n\nThis section consolidates the editor workflow and panel explanations that were previously spread across multiple chapters, serving as a quick reference when working in `EasyChart/Library Editor`.\n\n### 6.1 What are you editing? (ChartProfile)\n\nThe chart selected in the Library Editor is essentially a `ChartProfile` asset.\n\n- It's a reusable configuration: the same Profile can be referenced by multiple scenes/prefabs.\n- It's previewable: changes in the editor can be previewed immediately.\n\n### 6.2 Main areas of the Library Editor\n\nYou can think of the window as four areas:\n\n- Left: Library (asset tree)\n- Center: Preview\n- Right: Inspector (configuration)\n- Right: Series (series and data)\n\nAdditionally, there is usually a JSON Injection panel on the left.\n\n### 6.3 Library panel (asset tree)\n\nOverview:\n\n- Displays folders and `ChartProfile` (`.asset`) files in a tree.\n- Selecting a `ChartProfile` drives binding and refresh for Inspector/Series/Preview.\n- Supports create/rename/delete, drag-move, and sorting.\n\nSelection logic:\n\n- Selecting a folder: clears the Inspector/Series panels (no Profile to edit).\n- Selecting a ChartProfile: binds the right panels to that Profile.\n\nCommon actions (title bar and right-click menu; may vary by version):\n\n- Folder: New Folder / New Chart / Export Folder to UXML (Mirror/Backup) / Rename / Delete\n- ChartProfile: Export to UXML / Clone / Rename / Delete\n\n### 6.4 Preview panel\n\nPreview renders the currently selected `ChartProfile` directly, so you can validate changes while editing.\n\nCommon issues:\n\n- Preview is empty: make sure there is at least 1 `Serie` and its `seriesData` is not empty.\n- Data exists but looks wrong: verify CoordinateSystem matches the SeriesType, and axis ranges are not excluding your data.\n\n### 6.5 Inspector panel\n\nInspector edits the serialized fields of the Profile (coordinate system, axes, grid, interaction, legend, etc.), and drives Preview updates.\n\nTip:\n\n- If some field changes appear to have no effect, confirm the page references the exported UXML, not the Profile directly.\n\n### 6.6 Series panel\n\nThe Series panel edits `ChartProfile.series` from a \"chart-structure\" perspective:\n\n- Add/remove/reorder series\n- Choose `type` for each serie and edit `settings`\n- Edit `seriesData` (data points)\n\n### 6.7 JSON Injection panel\n\nPurpose: represent the current Profile as copyable JSON, and support parsing JSON to write back into the current Profile.\n\nRecommended workflow:\n\n1. Generate example JSON from the current Profile\n2. Copy it into an external editor for batch edits\n3. Paste it back and ApplyToChart\n\n---\n\n## 7. Axes & ranges (Axis & Range)\n\n### 7.1 AxisType: Category vs Value\n\n- Category: use `labels` to define discrete categories (A/B/C, or Mon/Tue/Wed).\n- Value: continuous numeric range (0~100, -3~3, 0~1e6).\n\n#### 7.1.1 When to use Category\n\n- The X axis is a sequence of text labels\n- You want points to land on `labels[i]`\n- Typical: bar charts (one bar group per category), line charts (aligned by categories)\n\nKey points for Category:\n\n- `labels[0]` corresponds to category index `0`\n- `labels[1]` corresponds to category index `1`\n\n#### 7.1.2 When to use Value\n\n- X or Y is a continuous numeric value (timestamp, money, temperature, etc.)\n- You want to scale/pan the axis by numeric values\n\nKey points for Value:\n\n- Axis range is usually computed by auto range (if enabled)\n- You can lock only one side (e.g. fix min=0 and keep max auto)\n\n### 7.2 Category axis: labels and LabelPlacement\n\n`labels` determines the number of categories and the label text.\n\n`LabelPlacement` affects alignment:\n\n- `Tick`: labels align to tick marks; better for Line/Scatter.\n- `CellCenter`: labels align to the center of a cell; better for Bar/Heatmap.\n\nCommon symptom:\n\n- Bars appear between two labels: set `LabelPlacement` to `CellCenter`.\n\n### 7.3 Value axis: autoRangeMin / autoRangeMax\n\nIf the range is \"locked\" and data is not visible, revert to full auto range first:\n\n- Enable `autoRangeMin/autoRangeMax`\n\nAfter it's visible, add business constraints gradually (e.g. make bar chart Y start at 0).\n\n#### 7.3.1 Common template: Y axis starts at 0\n\n- `axisType = Value`\n- Fix `minValue = 0`\n- `autoRangeMax = true`\n\n#### 7.3.2 Common template: lock only Max (e.g. percentages)\n\n- Fix `maxValue = 100`\n- `autoRangeMin = true`\n\n### 7.4 rounding / unit / labelFormat\n\n- rounding: snap the range to \"nicer\" numbers.\n- unit: display unit scaling (K/M, ten-thousand/million, etc.).\n- labelFormat: control number formatting (N0/N2/F1/percent, etc.).\n\n#### 7.4.1 Unit display (showUnit / unitText)\n\nWhen values are large (e.g. 10,000+), a common approach is showing a unit at the end of the axis (e.g. \"k\", \"M\").\n\n#### 7.4.2 Quick troubleshooting\n\n- Labels misaligned / bars centered between labels: check Category axis `LabelPlacement`\n- Range looks weird (too large/too small): check if min/max is locked; check rounding/unit\n- Too many decimals in ticks: set `labelFormat`\n\n---\n\n## 8. Series and data (Serie / SeriesData)\n\n### 8.1 Serie (one series)\n\nEach element in `ChartProfile.series` is a `Serie`:\n\n- `name`\n- `type`\n- `visible`\n- `settings`\n- `labelSettings`\n- `seriesData`\n\nNote: `settings` is usually a polymorphic object (`SerializeReference`). When you change `type`, the editor will try to preserve the last used settings for each type (better editing experience).\n\n### 8.2 SeriesData (one data point)\n\nCommon `SeriesData` fields:\n\n- `id`: stable identifier (tooltip/hover/hidden state).\n- `x`: X coordinate or Category index.\n- `value`: main value.\n- `y`: second dimension (scatter/heatmap, etc.).\n- `z`: third dimension (e.g. sizeMapping).\n- `name`: point name (often used by Radar/Pie/Ring).\n- `useColor` + `color`: point-level color override.\n\nIf interactions are enabled, keep `SeriesData.id` stable to avoid generating a new set of ids on every data refresh.\n\n### 8.3 Matching SerieType and coordinate system\n\n- Cartesian2D: Line/Bar/Scatter/Heatmap\n- Polar2D: Radar\n\nIt's not recommended to mix Polar and Cartesian series in a single (non-Pie) ChartProfile. If you do mix them, be careful about whether axes/grid semantics remain consistent.\n\n### 8.4 Common data patterns (by type)\n\n#### 8.4.1 Line\n\n- Common: Category X + Value Y\n - Data point: `x=category index`, `value=value`\n- Continuous: Value X + Value Y\n - Data point: `x=x value`, `value=y value`\n\n#### 8.4.2 Bar\n\n- Category X + Value Y\n - One point per bar: `x=category index`, `value=bar height`\n- Grouped: multiple Bar series share the same Category X\n- Stacked: series with `stacked=true` and the same `stackGroup` will stack\n\n#### 8.4.3 Scatter\n\n- Common: X=Value, Y=Value\n- Recommended to explicitly write `x/y` for data points\n\n#### 8.4.4 Heatmap\n\n- Triplet: `x=column index`, `y=row index`, `value=intensity`\n\n#### 8.4.5 Radar\n\n- Typical: `x=dimension index`, `value=value of that dimension`, `name=dimension label`\n\n### 8.5 Common data pitfalls (symptom-driven)\n\n- Category chart uses Category axis on X, but point `x` is not 0/1/2...\n - Symptom: points/bars don't align with labels\n - Fix: ensure `x=category index`, or change X axis to Value\n\n- NaN/Infinity appears\n - Symptom: chart doesn't render, range explodes\n - Fix: filter invalid values at the data source\n\n- Chart is not visible (but `seriesData` is not empty)\n - Check: coordinate system matches (Cartesian vs Polar)\n - Check: AxisType matches your data meaning\n\n- Interactions/tooltip mapping feels wrong\n - Check: `SeriesData.id` is stable (don't randomly regenerate ids on each refresh)\n" },
|
||
{ id: "00_03-UGUIWorkflow", relPath: "00_03-UGUIWorkflow.md", title: "UGUI Workflow", content: "# UGUI Workflow\n\nGoal of this chapter: use EasyChart with a UGUI workflow (Canvas/RectTransform), and understand the choice between two rendering modes:\n\n- `ScreenSpaceOverlay`: best visual quality (no RenderTexture), but typically visible only in the Game view\n- `WorldSpace`: visible in both Scene/Game views (uses RenderTexture), suitable for 3D world-space UI\n\n---\n\n## 1. Recommended approach: UGUIChartBridge\n\nRecommended component: `UGUIChartBridge`.\n\nIts role is:\n\n- Still uses **UI Toolkit `ChartElement`** as the core chart renderer\n- Bridges the chart so it \"fits\" onto a target UGUI `RectTransform`\n\nSo you get the best of both:\n\n- Chart capability + UI Toolkit rendering\n- UGUI scene/prefab layout workflow and habits\n\n---\n\n## 2. Common prerequisites\n\nNo matter which mode you choose, prepare the following first:\n\n- A `ChartProfile` to display (recommended: clone one from `EasyChart/Library Editor` and modify it)\n- A `PanelSettings` asset, and assign it to `UGUIChartBridge` via `Panel Settings Asset`\n\n> Note: providing `Panel Settings Asset` is usually better for font rendering and overall stability.\n\n---\n\n## 3. Screen Space Overlay (recommended for HUD/panels)\n\n### Use cases\n\n- HUD, UI panels, dialogs\n- You care most about clarity and visual quality\n\n### Characteristics\n\n- No RenderTexture\n- Typically visible only in the Game view\n\n### Setup steps (overview)\n\n1. Create a `Canvas`\n2. Under the Canvas, create a node with `RectTransform` (`Image` or an empty GameObject both work)\n3. Add `UGUIChartBridge`\n4. Configure:\n - `Profile`\n - `Panel Settings Asset`\n - `Render Mode = ScreenSpaceOverlay`\n - `Sort Order` (controls overlay order; effective only in Screen Space Overlay mode)\n\nKey points:\n\n- This mode renders the chart inside a runtime-created/reused `UIDocument`.\n- If the chart is covered by other UI, increase `Sort Order` first.\n\n---\n\n## 4. World Space (recommended for 3D world-space panels)\n\n### Use cases\n\n- Billboards/screens/panels inside a 3D world\n- You want to see the result in the Scene view as well\n\n### Characteristics\n\n- Uses RenderTexture\n- Usually visible in both Scene and Game views\n- Visual quality can be affected by RenderTexture resolution\n\n### Setup steps (overview)\n\n1. Create a `Canvas`\n2. Set `Render Mode = World Space`\n3. Under the Canvas, create a node with `RectTransform` (recommended: `RawImage`)\n4. Add `UGUIChartBridge`\n5. Configure:\n - `Profile`\n - `Panel Settings Asset`\n - `Render Mode = WorldSpace`\n\nKey points:\n\n- World Space mode creates and maintains a `RenderTexture` and displays it via `RawImage`.\n- Clarity is strongly tied to the `RenderTexture` resolution, which usually comes from the target `RectTransform` width/height.\n - If the chart looks blurry, make the target `RectTransform` larger first (e.g. 600x400+).\n\n---\n\n## 5. Mode selection (quick conclusion)\n\n- Prefer **ScreenSpaceOverlay** when:\n - you're building traditional UI (HUD/panels)\n - clarity is your top priority\n\n- Prefer **WorldSpace** when:\n - your chart needs to appear in a 3D world\n - you want it visible in the Scene view\n\n---\n\n## 6. Common issues & troubleshooting\n\n- **Not visible at runtime**\n - Make sure the target `RectTransform` size is not 0\n - Make sure `Profile` is assigned, and the Profile renders correctly in Library Editor Preview\n - If fonts look wrong, check whether `Panel Settings Asset` is missing\n\n- **Blurry chart in World Space mode**\n - Increase the target `RectTransform` size (this increases RenderTexture resolution)\n - Avoid frequent aggressive scaling at runtime (may trigger RenderTexture resizing)\n\n---\n\n## 7. Alternative: export as a UGUI Prefab\n\nIf your version provides `Export UGUI Prefab`:\n\n- You can export the Profile to a UGUI prefab and use it directly under a Canvas\n- Coverage for interaction/compatibility depends on the exporter version\n" },
|
||
{ id: "00_04-RuntimeDataInjectionUIToolKit", relPath: "00_04-RuntimeDataInjectionUIToolKit.md", title: "Runtime Data Injection (UI Toolkit)", content: "# Runtime Data Injection (UI Toolkit)\n\nThis chapter explains how to inject data into `ChartElement` at runtime in a UI Toolkit workflow.\n\nRelated component: `EasyChartDataSource`\n\n---\n\n## 1. When should you use this approach?\n\n- Your chart is built with UI Toolkit (`UIDocument` + UXML + `ChartElement`)\n- You want a set of injection APIs that are easier to call from gameplay/business logic (labels / values / x-y / pie / ring)\n- Or you want to inject a JSON payload directly (`ChartFeed`)\n\n---\n\n## 2. Quick start (recommended flow)\n\n1. Prepare a `UIDocument` in the scene, and make sure there is a `ChartElement` in your UXML.\n2. Add `EasyChartDataSource` to the same GameObject that has the `UIDocument`.\n3. Fill in the Inspector fields:\n - `uiDocument`\n - `chartElementName` (default: `main-chart`, matches the `name` of the `ChartElement` in UXML)\n - `profile` (optional, but strongly recommended: lets style/Series type come from an editor-authored `ChartProfile`)\n4. At runtime, call from code:\n - `SetCategoryLabels(...)`\n - `SetSeriesValues(...)` / `SetSeriesXY(...)`\n - or `ApplyJson(...)`\n\nInternally, the component will:\n\n- Find the target `ChartElement` from `UIDocument.rootVisualElement`\n- Initialize chart data from `profile` when needed\n- Modify `ChartElement.Data` and call `RefreshData()`\n\n---\n\n## 3. Inspector fields\n\nKey fields of `EasyChartDataSource`:\n\n- `uiDocument`\n - Points to the current UI `UIDocument`.\n - If not set, the script will try `GetComponent<UIDocument>()`.\n\n- `chartElementName`\n - The `name` of the target `ChartElement` (the UXML/USS name). Default is `main-chart`.\n - If you want JSON `chartId/chartName` to locate the chart automatically, keep the `ChartElement.name` consistent with those values (see section 5).\n\n- `profile`\n - Optional.\n - If set, the component assigns `ChartElement.Profile = profile` to initialize/preserve styles, Series structure, etc.\n\n- `playAnimationOnRefresh`\n - After each injection, call `RefreshData(..., playAnimation: playAnimationOnRefresh)`.\n\n- `allowCreateSeriesFromFeed`\n - When injecting via JSON (`ApplyJson`), if a series in the feed does not match any existing Serie:\n - `false` (default): do not create new Serie; only update matched ones.\n - `true`: allow creating new Serie from the feed (may rebuild renderers).\n\n---\n\n## 4. Common injection APIs (without JSON)\n\n### 4.1 Set category axis labels\n\n`SetCategoryLabels(labels, axisId = AxisId.XBottom)`\n\n- Sets the axis to Category and overwrites `labels`.\n\n### 4.2 Single-series Y values (auto x=0..n-1)\n\n`SetSeriesValues(\"Sales\", values)`\n\n- Finds/creates a Serie by default (default type is Line; it does not force the type to change).\n- Writes to `SeriesData.value` and sets `SeriesData.x` to the index.\n\n### 4.3 XY points\n\n`SetSeriesXY(\"Scatter\", x, y)`\n\n- Writes `x[]` into `SeriesData.x` and `y[]` into `SeriesData.value`.\n\n### 4.4 Pie / Ring injection\n\n- `SetPie(serieName, names, values)`\n - Forces the Serie type to `Pie`.\n - Uses `SeriesData.name` as slice name and `SeriesData.value` as slice value.\n\n- `SetRing(serieName, names, percents)`\n - Forces the Serie type to `RingChart`.\n - Uses `SeriesData.name` as ring name and `SeriesData.value` as progress value.\n\n---\n\n## 5. JSON injection (ChartFeed)\n\nYou can call: `ApplyJson(json)`\n\nThis method parses JSON into `ChartFeed` and applies it to `ChartElement.Data`.\n\n### 5.1 `ChartFeed` schema\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\nSee the runtime code `Scripts/Runtime/Feed/ChartFeed.cs` for the exact fields.\n\n### 5.2 ChartElement lookup rules (`chartId` / `chartName`)\n\nInternally, `ApplyJson` tries:\n\n- If `chartId` is provided: `rootVisualElement.Q<ChartElement>(chartId)` first\n- Else if `chartName` is provided: try `Q<ChartElement>(chartName)`\n- If still not found: fall back to `chartElementName` (default `main-chart`)\n\nTherefore:\n\n- If you only have one chart, keeping the default is fine.\n- If you have multiple `ChartElement` in one UI, it's recommended to align each chart's `name` with the feed `chartId` or `chartName`.\n\n### 5.3 Series matching and type override\n\n`ApplyJson` checks whether the JSON contains `\"type\":`. If present, it assumes you want to allow type override (`allowTypeOverride=true`).\n\nSerie matching rules:\n\n- If `serieId` is not empty: match by `Serie.id`\n- Else if `name` is not empty: match by `Serie.name`\n- Else (index mode): match by feed index (i-th to i-th)\n\nWhen no Serie can be matched:\n\n- `allowCreateSeriesFromFeed=false` (default): the feed series is skipped (no creation).\n- `allowCreateSeriesFromFeed=true`: create a new Serie using the feed `type/name/serieId`.\n\nFor matched Serie:\n\n- Only when `allowTypeOverride=true` and it's not index mode, overriding `id/name/type` is allowed.\n\n---\n\n## 6. Common issues & troubleshooting\n\n- **Not visible / TryGetChart failed**\n - Make sure `uiDocument` is assigned correctly\n - Make sure the `ChartElement` `name` in UXML matches `chartElementName`\n\n- **JSON parse failed**\n - When `EasyChartDataSource` parses JSON:\n - it tries Newtonsoft first (if `Newtonsoft.Json` exists in your project)\n - otherwise falls back to Unity `JsonUtility`, normalizing string forms like `type/axisId` into enum integers before parsing\n - Recommendation: start from a known-good JSON (e.g. generated from the editor JSON panel) and modify it.\n\n- **Series mismatch after injection / updated the wrong line**\n - Prefer `serieId` for stable matching.\n - If you only use `name` and there are multiple series with the same name, the script uses the first one and logs a warning.\n\n- **JSON wanted to add a Serie but none was added**\n - Enable `allowCreateSeriesFromFeed`.\n" },
|
||
{ id: "00_05-RuntimeDataInjectionUGUI", relPath: "00_05-RuntimeDataInjectionUGUI.md", title: "Runtime Data Injection (UGUI)", content: "# Runtime Data Injection (UGUI)\n\nRelated scripts: `UGUIRuntimeJsonInjection`, `UGUIRuntimeJsonInjectionEditor`\n\nThis chapter explains how to inject data into charts at runtime via JSON in a UGUI workflow (`UGUIChartBridge`).\n\n---\n\n## 1. When should you use this approach?\n\n- You have JSON coming from a server/business layer (or you want to quickly edit JSON at runtime)\n- You want an editor-like workflow: \"Generate example → Modify → Apply\" (similar to the `JSON Injection` panel)\n- You already configured the chart structure (style/axes/Series types) via `ChartProfile`\n\nThis injector is primarily designed for **updating data**. Structural changes (e.g. adding Series, force-overriding Series types) are not its main goal.\n\n---\n\n## 2. Quick start (recommended flow)\n\n1. Set up `UGUIChartBridge` in the scene (and make sure `Profile` is assigned).\n2. Add `UGUIRuntimeJsonInjection` to the same GameObject.\n3. Click **Generate Example JSON** to generate sample JSON that matches your current Profile.\n4. Modify the data in the `JSON Content` text box.\n5. Click **Apply JSON to Chart**.\n\nInternally, the component will:\n\n- Parse JSON → convert to `ChartFeed`\n- Apply `ChartFeed` to `UGUIChartBridge.Profile`\n- Call `_bridge.Refresh()` to redraw\n\n---\n\n## 3. Component and Inspector fields\n\n`UGUIRuntimeJsonInjection` must be on the same GameObject as `UGUIChartBridge` (the script has `[RequireComponent(typeof(UGUIChartBridge))]`).\n\n### 3.1 JSON Generation Settings\n\n- **Example Mode (`ChartJsonExampleMode`)**\n - Controls the format when generating example JSON.\n - Generally recommended to start with `Standard` or `Standard_Axis` (more intuitive).\n\n- **Data Mode (`ChartJsonDatasMode`)**\n - Controls how `datas` is represented.\n - `Standard`: `datas` is an array of objects (e.g. `{ \"x\": 0, \"value\": 12 }`).\n - `Values`: `datas` is an array of raw numbers (shorter).\n - Note: this format requires the \"flexible parser\" in `ChartJsonUtils` (reflection-based parsing via Newtonsoft). If your project does not include Newtonsoft (`Newtonsoft.Json` / `Unity.Newtonsoft.Json`), parsing may fail.\n - Therefore **`Standard` is recommended by default**, unless you're sure Newtonsoft is available.\n\n- **API Envelope (`UseApiEnvelope`)**\n - When generating example JSON, whether to wrap it with an API envelope:\n - `{ \"code\": 200, \"message\": \"success\", \"data\": { ...the real ChartFeed... } }`\n - When applying, it will also try to extract `data` automatically.\n\n- **Auto Generate (`AutoGenerateJson`)**\n - Automatically regenerates example JSON when you change `Example Mode / Data Mode / API Envelope`.\n\n### 3.2 JSON Content\n\n- **JSON Content (`JsonContent`)**\n - The JSON string to inject.\n - If empty, clicking Apply will log a warning and return.\n\n---\n\n## 4. JSON format (ChartFeed)\n\nThe underlying data model is `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\nField-to-code mapping notes:\n\n- `chartId` / `chartName`\n - In the `UGUIRuntimeJsonInjection` injection path, it **will not overwrite** the Profile `chartId/chartName` (it calls `ChartJsonUtils.ApplyFeedToProfile(profile, feed)` with `allowMetaOverwrite=false`).\n - But these fields can help other injectors (e.g. `EasyChartDataSource`) locate a `ChartElement` by name/ID in the UI tree.\n\n- `axes[]`\n - `axisId` is the `AxisId` enum (e.g. `XBottom`, `XTop`, `YLeft`, `YRight`).\n - If `labels` exists, that axis is treated as Category and labels are overwritten.\n\n- `series[]`\n - **Matching priority**:\n - If `serieId` is provided: match by `Serie.id`\n - Else if `name` is provided: match by `Serie.name`\n - Else (both `serieId` and `name` are empty): match by index (feed 0 -> profile 0)\n - `type`\n - Mainly used when generating example JSON.\n - In the current injection path:\n - For existing matched Serie: it **will not force the type to change** (meta overwrite is not allowed).\n - For newly created Serie in \"index mode + feed exceeds Profile series count\": it will use the feed `type` as the new Serie type.\n - `datas[]` for each point:\n - numeric `x/y/z/value`\n - optional `id/name`\n - optional `useColor/color`\n\n---\n\n## 5. What happens when you apply? (injection flow)\n\nWhen you click **Apply JSON to Chart**:\n\n1. If the JSON is wrapped in an API envelope (contains `data`), it first tries to extract the object under `data`.\n2. Calls `ChartJsonUtils.TryDeserializeFeed(json, out feed)` to deserialize into `ChartFeed`.\n - Tries Newtonsoft first (if available); otherwise falls back to Unity `JsonUtility`.\n - String values like `type: \"Line\"` / `axisId: \"XBottom\"` are normalized to enum values in the fallback path before parsing.\n3. Calls `ChartJsonUtils.ApplyFeedToProfile(_bridge.Profile, feed)` to write the feed back into the Profile.\n4. Calls `_bridge.Refresh()` to redraw.\n\n---\n\n## 6. Common issues & troubleshooting\n\n- **Click Apply does nothing / console warns: No UGUIChartBridge or ChartProfile found**\n - Make sure the object has `UGUIChartBridge`\n - Make sure `UGUIChartBridge.Profile` is assigned\n\n- **Error: Failed to parse JSON**\n - Generate a known-good JSON first, then modify it.\n - If your API response has an outer wrapper, enable `API Envelope`, or ensure the JSON `data` field contains the `ChartFeed`.\n\n- **JSON applied but data didn't change / only partially changed**\n - Check how `series` is matched (`serieId` / `name` / index mode).\n - If you use `serieId/name` matching: make sure the corresponding Serie exists in the Profile (this injection path won't auto-create new Serie in this mode).\n - If you use \"index mode\" (both `serieId` and `name` are empty):\n - When feed `series[]` count **exceeds** the Profile series count, it will auto-create additional Serie.\n - If you don't want auto-creation, provide an explicit `name` or `serieId` for each serie.\n\n- **After injecting in Play Mode, the Profile asset became dirty**\n - Injection essentially \"applies the feed to the `ChartProfile`\". If you drag the asset directly into the bridge, runtime changes may mark the asset dirty.\n - If you don't want to modify the asset, instantiate a runtime copy of the Profile and inject into that copy.\n" },
|
||
{ id: "01_01-EditorWorkflow", relPath: "01_01-EditorWorkflow.md", title: "Editor Workflow and Panel Guide", content: "# Editor Workflow and Panel Guide\n\nThis chapter helps you understand **what to edit where** in `EasyChart/Library Editor`, and the common editing workflows (create, clone, preview, export).\n\n---\n\n## 1. What are you editing? (ChartProfile)\n\nThe chart selected in the Library Editor is essentially a `ChartProfile` asset.\n\n- It is a **reusable configuration**: the same Profile can be referenced by multiple scenes/prefabs.\n- It is a **previewable configuration**: after modifying it in the editor, you can see the preview update immediately.\n\nRecommendation: put your own Profiles under `Assets/EasyChart/Library/Custom/` (or a folder agreed by your team).\n\n---\n\n## 2. The three core areas of the Library Editor\n\nAlthough UI details may change slightly across versions, you can understand the overall layout like this:\n\n### 2.1 Left: Library Tree\n\nThis shows the folder structure where chart assets (`ChartProfile`) are located.\n\nCommon actions:\n\n- Right-click a folder:\n - `New Folder...`: create a subfolder\n - `New Chart...`: create a new `ChartProfile`\n- Right-click a chart:\n - `Clone`: duplicate a new Profile (to create variants)\n - `Export to UXML`: export (if your workflow needs to sync/export configuration into UXML)\n - `Ping`: locate the asset in the Project window\n - `Rename...` / `Delete`\n\n> Tip: use `Clone` to create variants like \"same chart with different colors / different data scale\", instead of configuring from scratch.\n\n### 2.2 Right: Inspector\n\nThis is where you do most of your editing.\n\nIt typically includes:\n\n- **Basic settings**:\n - `coordinateSystem`\n - `padding` (if present)\n - `animationDuration` (if present)\n- **Series list**: each Serie represents a line, a group of bars, a scatter series, etc.\n- **Axes**:\n - choose which `XAxisId/YAxisId` to use\n - configure display/labels/range/ticks of the corresponding `AxisConfig`\n- **Legend / Tooltip / Grid**: if your version exposes these settings\n\n> Practical tip: configure `coordinateSystem`, `Series`, and `Axes` first. The rest is \"nice to have\".\n\n### 2.3 Preview\n\nUse it to check:\n\n- whether data exists\n- whether axis ranges are correct\n- whether labels are crowded/misaligned\n- Tooltip / Legend interactions (if enabled)\n\nWhen preview looks wrong, troubleshoot in this order:\n\n1. Is `coordinateSystem` correct?\n2. Does `series` contain at least 1 serie and data points?\n3. Does the axis `axisType` match the meaning of your data `x/y`?\n4. Is the Value axis range locked manually (`autoRangeMin/autoRangeMax`)?\n\n### 2.4 JSON Injection\n\nBelow the left panel there is a **JSON Injection** area, used to:\n\n- quickly generate an \"injection JSON example\" for the selected `ChartProfile`\n- apply your pasted/edited JSON back to the selected Profile (`ApplyToChart`)\n\nCommon controls:\n\n- **API Envelope**: whether to wrap with `{ code, message, data }`.\n - When enabled: generated JSON will be wrapped; parsing can also recognize it and automatically extract `data`.\n- **Feed Mode**: the structure/field completeness of the example JSON (to support different injection protocols).\n- **Datas Format**: the point format inside the `datas` field (e.g. compact arrays, or more readable objects).\n- **ApplyToChart**: parse JSON from the text box and write it back into the selected `ChartProfile`.\n\n---\n\n## 3. Recommended editing flow (from zero to reusable)\n\n### Step 1: Create or select a ChartProfile\n\n- New: right-click the target folder and choose `New Chart...`\n- Existing: click to select in the left tree\n\nIf you prefer the \"clone first, then modify\" approach (recommended):\n\n- First, use **Clone** in the top toolbar to create your own Library\n- Then in your own library, right-click a Profile -> `Clone` to create variants\n\n### Step 2: Decide the coordinate system\n\n- `Cartesian2D`: Line/Bar/Scatter/Heatmap\n- `Polar2D`: Radar\n\n> Tip: decide the coordinate system first, then choose SeriesType, to avoid style/axis confusion after switching later.\n\n### Step 3: Configure Series\n\n- Add Series\n- Set `type`\n- Fill `seriesData`\n\nTip: start with a small number of points (3–8) to validate the look, then scale up.\n\n### Step 4: Configure Axes\n\nMost common combination:\n\n- X: Category\n - put text into `labels`\n- Y: Value\n - enable auto range (default)\n\nWhen you want more professional axis formatting:\n\n- Use `labelFormat` (e.g. `F1`, `N0`)\n- Use `autoRangeMin/autoRangeMax` to lock only one side of the range\n- If the Value axis needs a unit:\n - `showUnit=true`\n - `unitText=\"items\"/\"10k\"`\n - use `unitLabelStyle` to adjust font/color/position\n\n### Step 5: Clone variants (recommended)\n\nWhen you need multiple versions of the same chart (colors, font size, slightly different axis display):\n\n- Right-click the chart -> `Clone`\n- Modify only the differences\n\nThis keeps style consistent and is easier for version management.\n\nWhen you want to use the chart in UI:\n\n- UI Toolkit: export to UXML, then compose the page in UI Builder (see demo scene `Assets/EasyChart/Demo/Scenes/EasyChart_QuickStart.unity` and template `Assets/EasyChart/Demo/UIToolKit/NewUXMLTemplate.uxml`)\n- UGUI: export to a UGUI prefab and use it in a Canvas/RectTransform workflow\n\n---\n\n## 4. Common pitfalls (quick diagnosis)\n\n- **Nothing shows up**\n - Is `seriesData` empty?\n - Does `AxisType` match the meaning of your data (does the Category axis have labels)?\n\n- **Value axis looks weird (range too large/too small)**\n - Check `autoRangeMin/autoRangeMax`\n - Check whether rounding/unit snapped the range to an unsuitable unit\n\n- **Bars and labels are misaligned**\n - Check `LabelPlacement` (Tick vs CellCenter)\n\n---\n\n## Next\n\n- `00_02-WorkflowAndLibrary.md`: axis types, label placement, auto range, rounding, and unit display are merged into section 7\n" },
|
||
{ id: "01_02-LibraryPanel", relPath: "01_02-LibraryPanel.md", title: "Library Panel (Asset Tree)", content: "# Library Panel (Asset Tree)\n\nThis chapter explains the **Library** panel on the left side of `Unity Easy Chart/Library Editor`. It manages your chart assets (`ChartProfile`) and folder structure, and determines which Profile the panels on the right are currently editing.\n\n---\n\n## Feature Overview\n\n- **Structure Display**: shows folders and `ChartProfile` (`.asset`) under the library root in a tree.\n- **Selection Drives Editing**: selecting a `ChartProfile` triggers:\n - Inspector binds to that Profile\n - Series binds to that Profile `series`\n - Preview refresh\n - JSON Injection generates example JSON (and can Apply back to that Profile)\n- **Asset Management**: create/rename/delete, drag-move, expand/collapse, etc.\n\n---\n\n## UI Structure\n\nThe header bar at the top of the Library panel typically contains (left to right):\n\n- **Library**: title.\n- **(Current Library Name)**: shows the selected library/root name (useful if you have multiple libraries).\n- **Menu**: entry for common actions (similar to right-click, but centralized).\n- **Help**: opens this chapter.\n\nIn the global window toolbar at the top, on the right side of the Library dropdown you may see:\n\n- **+**: add a new Library.\n- **-**: delete the current Library.\n- **Clone**: duplicate the current Library (see below).\n\nBelow the header is:\n\n- **TreeView**:\n - folders\n - `ChartProfile` assets (chart configuration assets)\n\n---\n\n## Selection Logic (Important)\n\n- **When a Folder is Selected**:\n - Inspector/Series on the right are cleared (no Profile to edit).\n - JSON Injection switches to a \"no selected Profile\" example or keeps the current example (implementation-dependent).\n- **When a ChartProfile is Selected**:\n - Inspector/Series immediately bind to the Profile's serialized data.\n - Any field change triggers a delayed Preview refresh (`delayCall`).\n\nTip: if the right panels are empty, first confirm a `ChartProfile` (not a folder) is selected on the left.\n\n---\n\n## Common Actions (Header Menu)\n\nClicking **Menu** (the small menu icon) opens an action menu. Common items include:\n\n- **New Chart**: create a new `ChartProfile` under the target folder.\n- **New Folder**: create a new folder under the target folder.\n- **Refresh**: rescan and rebuild the tree (useful after manual moves/copies in the Project view).\n- **Expand All**: expand all folders.\n- **Collapse All**: collapse all folders.\n- **Rename / Delete**: rename/delete the currently selected item.\n - If the library root is selected, these are typically disabled.\n- **Export UGUI Prefab** (available when a Profile is selected): export the selected Profile as a UGUI prefab (for runtime display).\n\n### How the Target Folder is Determined\n\n**New Chart / New Folder** create assets under the \"target folder\":\n\n- If a **folder** is selected: the target is that folder.\n- If a **ChartProfile** is selected: the target is usually the Profile's parent folder.\n- If nothing is selected or unclear: the target usually falls back to the library root.\n\n---\n\n## Clone Library\n\nWhen you need to duplicate a full chart library (including Profiles and UXML) into a new library (for branching/versions/theme variants), use **Clone** in the top toolbar.\n\n### Entry and Usage\n\n- Click the **Clone** icon to the right of the Library dropdown.\n- Enter the new library name and confirm.\n\n### What Gets Cloned\n\n- `Assets/EasyChart/Library/<CurrentLibrary>` is copied to `Assets/EasyChart/Library/<NewLibrary>`.\n- `Assets/EasyChart/LibraryUxml/<CurrentLibrary>` is copied to `Assets/EasyChart/LibraryUxml/<NewLibrary>` (if the source UXML folder exists).\n\n### Limitations and Naming Rules\n\n- The `<Root>` library cannot be cloned.\n- The new name is sanitized (invalid filename characters removed); blank names are ignored.\n- If the target library already exists (folder already exists), it will prompt and cancel.\n\n### After Cloning\n\n- Automatically switches the current Library selection to the new library.\n- Refreshes the Library dropdown and tree view, and triggers refresh for right panels/preview.\n\n---\n\n## Common Actions (Context Menu)\n\nYou can also **right-click** items in the tree:\n\n### Right-click a Folder\n\n- **New Folder...**: create a subfolder.\n- **New Chart...**: create a new `ChartProfile` in that folder.\n- **Export Folder to UXML (Mirror/Backup)**: export the folder contents to UXML (backup/distribution/versioning).\n- **Rename...**: rename the folder.\n- **Delete**: delete the folder (destructive; be careful).\n\n### Right-click a ChartProfile\n\n- **Export to UXML**: export UXML for the current Profile.\n- **Clone**: clone a new Profile (quickly derive a similar chart).\n- **Rename...**: rename the asset (also tries to sync-update `profile.name` / `profile.chartName`).\n- **Ping**: locate the asset in the Project view.\n- **Delete**: delete the asset.\n\n---\n\n## Drag-move and Sorting\n\nThe Library tree supports dragging folders or `ChartProfile`:\n\n- **Drag a ChartProfile onto a folder**: triggers `AssetDatabase.MoveAsset` to move the `.asset` into the target folder.\n- **Drag a folder onto a folder**: moves the whole folder under the target folder.\n\nNotes:\n\n- If the target is invalid (dragging into itself/child folder), it will be rejected (cursor shows Rejected).\n- After moving, the tree refreshes automatically.\n\n---\n\n## Rename (Double-click and Inline Editing)\n\n**Double-clicking** a tree item enters inline rename (equivalent to running Rename).\n\nInternally, names are sanitized (invalid filename characters removed). If the new name is blank or unchanged, rename is canceled.\n\n---\n\n## Common Issues & Troubleshooting\n\n- **Right panels are empty**:\n - First confirm a `ChartProfile` (not a folder) is selected.\n- **Renamed but chartName didn't update**:\n - ChartProfile may have additional sync logic; verify the `Chart Name` field in Inspector.\n- **Drag failed**:\n - Common causes: dragging onto itself/child folder, or a name conflict at target path.\n\n---\n\n## Help\n\n- Click the rightmost **Help** icon in the header to open this chapter.\n" },
|
||
{ id: "01_03-JsonInjectionPanel", relPath: "01_03-JsonInjectionPanel.md", title: "JSON Injection Panel", content: "# JSON Injection Panel\n\nThis chapter explains the **JSON Injection** panel at the bottom-left of `Unity Easy Chart/Library Editor`.\n\nIts purpose is to represent the current `ChartProfile` configuration (or externally imported configuration) as readable/copyable JSON, and supports **ApplyToChart** to parse the JSON and write it back into the selected Profile.\n\n---\n\n## Location and purpose\n\n- **Location**: below the Library panel (tree view).\n- **Main uses**:\n - **Export**: convert the selected `ChartProfile` into example JSON (Feed)\n - **Edit**: manually edit the JSON in the text box\n - **Import/Apply**: click **ApplyToChart** to parse and apply JSON into the selected `ChartProfile`\n\nUse cases:\n\n- **Debugging**: quickly validate whether a specific field takes effect.\n- **Batch edits**: copy JSON to an external editor (multi-cursor/find-replace), then paste back and Apply.\n- **Integrations**: e.g. your toolchain/scripts generate a Feed and you Apply it in the editor.\n\n---\n\n## Controls (header bar)\n\nThe header bar typically contains (left to right):\n\n- **Min/Max** (label changes)\n - Toggles panel height.\n - `Min`: collapse to a smaller height (more like an auxiliary tool).\n - `Max`: expand to a larger height (better for long JSON).\n\n- **ApplyToChart** (icon button)\n - Attempts to parse the JSON in the text box as a Feed and apply it to the selected `ChartProfile`.\n - On success it will:\n - mark the asset dirty and call `SaveAssets()`\n - refresh the Series list\n - refresh Preview\n\n- **Help** (icon button)\n - Opens this chapter.\n\n---\n\n## Controls (button row)\n\nBelow the header there is a row of buttons (may wrap):\n\n- **API Envelope** (icon toggle)\n - Controls whether the example JSON is wrapped in an \"API response\" envelope.\n - Useful when you want to send the Feed directly to an HTTP API/service.\n - Toggling regenerates the example and overwrites the text box (see \"overwrite rules\").\n\n- **Feed Mode** (dropdown)\n - Controls which levels/fields are included in the example JSON.\n - Options come from an internal enum (common ones include):\n - `Lite`\n - `Standard / ID`\n - `Standard / Default`\n - `Standard / With Axes`\n - `Full`\n - General recommendations:\n - **Quickly inspect structure**: use `Lite`\n - **Need stable references**: use `Standard / ID`\n - **Need to include axes config**: use `Standard / With Axes`\n - **Need full copy/migration**: use `Full`\n\n- **Datas Format** (dropdown)\n - Controls the output format of `seriesData` (data points).\n - Common options:\n - `Values`: more compact, mostly \"values only\".\n - `Standard`: default format, good for editing and Apply.\n - `Full`: more complete (may include more fields/structure), good for migration/restoration.\n\n- **Copy** (icon button)\n - Copies the current text box content to the clipboard.\n\n---\n\n## Text box and \"overwrite rules\" (important)\n\nThe JSON text box is editable. To prevent your manual edits from being overwritten automatically, the panel has a \"dirty\" flag logic:\n\n- **As soon as you manually change the text box**, it is considered \"user modified\" (dirty).\n- When dirty:\n - the editor will not automatically overwrite your content with example JSON.\n- However, switching the following options will **force overwrite** (and clear dirty):\n - `API Envelope`\n - `Feed Mode`\n - `Datas Format`\n - or when switching the selected Profile (resets to that Profile's example)\n\nRecommendation:\n\n- If you plan to do major edits:\n - Copy to an external editor first\n - Paste back and Apply when done\n\n---\n\n## ApplyToChart behavior and notes\n\n- **ApplyToChart modifies the selected `ChartProfile` asset**.\n- If JSON parsing fails, an error is logged to the Console:\n - `ApplyToChart failed: invalid JSON or unsupported format.`\n- In `Full` mode, more meta/structural information may be overwritten (IDs/config, etc.), which is more powerful but also more dangerous.\n\nRecommendations:\n\n- Before applying, make sure:\n - the correct `ChartProfile` is selected on the left\n - JSON format is valid (brackets/commas)\n - you understand what the current Feed Mode will overwrite\n\n---\n\n## Recommended workflows\n\n### 1) Export from current Profile and tweak\n\n- Select a `ChartProfile`\n- Choose appropriate `Feed Mode` / `Datas Format`\n- Copy to an external editor for tweaks\n- Paste back\n- ApplyToChart\n\n### 2) Import configuration from external sources\n\n- Paste external JSON into the text box\n- ApplyToChart\n- Fine-tune further in Inspector / Series\n\n---\n\n## Help\n\n- Click the rightmost **Help** icon in the header to open this chapter.\n" },
|
||
{ id: "02_04-PreviewPanel", relPath: "02_04-PreviewPanel.md", title: "Preview Panel", content: "# Preview Panel\n\nThis chapter explains the **Preview** panel at the top of the middle area in `Unity Easy Chart/Library Editor`.\n\nThe purpose of Preview is to render the currently selected `ChartProfile` directly, so you can see results immediately while editing.\n\n---\n\n## When does Preview refresh\n\nPreview refresh is **delayed** (to avoid excessive redraw while you are continuously dragging/typing):\n\n- When you modify any bound field in **Inspector** or **Series**, it triggers `ScheduleUpdatePreview()`.\n- When you click **ApplyToChart** in **JSON Injection**, it triggers a refresh.\n- When you switch to another `ChartProfile` in the left **Library** tree, Preview refreshes to the new Profile.\n\nImplementation-wise, the refresh is scheduled via `EditorApplication.delayCall`, so you may feel it updates \"a moment after\" your change. This is expected.\n\n---\n\n## What does Preview display\n\n- Preview draws using a runtime chart component (e.g. `ChartElement`).\n- Preview reads data from the currently selected `ChartProfile` and renders it.\n\nYou can think of Preview as:\n\n- **what you edit is what it renders**\n- **what you see is (mostly) the runtime effect**\n\n---\n\n## Common issues and troubleshooting\n\n### 1) Preview is empty\n\nCheck first:\n\n- Is a `ChartProfile` selected?\n- Is there at least one `Serie`?\n- Is `seriesData` empty (no data points)?\n\n### 2) Data exists but looks wrong / not visible\n\nCommon causes:\n\n- **Coordinate system and SeriesType mismatch**: e.g. the Profile is `Polar2D` but the Series type is not Radar.\n- **Axis range and data range mismatch**: e.g. all values are outside the axis range.\n- **Category axis visible count (VisibleCount) is too small**: only a small segment is shown.\n\n### 3) Console shows \"Preview refresh failed\"\n\nIf an exception occurs during refresh, the Console logs:\n\n- `[EasyChartLibraryWindow] Preview refresh failed: ...`\n\nThis usually means:\n\n- some configuration combination is invalid\n- or some field value is unexpected (e.g. null / NaN)\n\nRecommended handling:\n\n- revert the most recent change first\n- then re-apply changes step by step to locate which field triggers the exception\n\n---\n\n## Tips\n\n- Preview only focuses on rendering results. Structural issues usually need to be fixed in **Inspector/Series/JSON Injection**.\n- If you modify many fields in a short time, Preview may refresh only after your last change (for performance).\n\n---\n\n## Help\n\n- Click the rightmost **Help** icon in the title bar to open this chapter.\n" },
|
||
{ id: "02_05-InspectorPanel", relPath: "02_05-InspectorPanel.md", title: "Inspector Panel", content: "# Inspector Panel\n\nThis chapter explains the **Inspector** panel at the bottom of the middle area in `Unity Easy Chart/Library Editor`.\n\nInspector is designed to edit the serialized fields of the currently selected `ChartProfile` from a \"configuration\" perspective (coordinate system, axes, grid, interactions, legend, etc.), and drive the Preview to update.\n\n---\n\n## Panel structure overview\n\nAfter you select a `ChartProfile` in the left Library tree, Inspector builds a set of foldouts (Foldout), typically including:\n\n- **Chart Settings**: basic chart settings (e.g. background, name)\n- **Coordinate System**: coordinate system selection and related options\n- **Axis Settings**: axis configuration (X/Y or Angle/Radius)\n- **Grid Settings**: grid-related configuration\n- **Hover Settings**: hover/tooltip related configuration\n- **Legend Settings**: legend configuration\n\nTip:\n\n- If you select a folder instead of a `ChartProfile`, Inspector will be empty (this is expected).\n\n---\n\n## Chart Settings (common)\n\n### Chart Name\n\nInspector contains a `Chart Name` text field (from `ChartProfile.chartName`). It is not only a display name, it also participates in asset renaming:\n\n- When you type a new name and then **lose focus** or press **Enter**:\n - the editor attempts to rename the `.asset` file to that name\n - and tries to keep `profile.name` and `profile.chartName` in sync\n\nNotes:\n\n- The name will be sanitized for filenames (invalid characters are removed/replaced).\n- If renaming fails (e.g. name conflict), an Error dialog is shown and the field is reverted.\n\n### Background\n\n`Background` is usually a sub-foldout that contains background color/alpha fields (depending on version).\n\n---\n\n## Coordinate System\n\nThis area shows the `coordinateSystem` selector.\n\nThe coordinate system affects:\n\n- available Series types/semantics (e.g. Polar2D is commonly Radar; Pie is a special layout)\n- whether Axis Settings shows Cartesian (X/Y) or Polar (Angle/Radius) configuration\n\nRecommendation:\n\n- decide the coordinate system before you start configuring, to avoid large adjustments later.\n\n---\n\n## Axis Settings\n\n### Axis selection (X Axis / Y Axis)\n\nIn Cartesian mode, the top provides X/Y axis dropdowns:\n\n- **X Axis**: e.g. `XBottom` / `XTop`\n- **Y Axis**: e.g. `YLeft` / `YRight`\n\nWhen the selection changes, it will:\n\n- ensure the axes list contains an element for that AxisId (auto-create if needed)\n- refresh the Axis field UI below\n- trigger a Preview refresh\n\n### Common fields of a single Axis\n\nEach Axis configuration typically contains:\n\n- `axisType`: Category / Value, etc.\n- `visible`: whether to show\n- `color` / `width`: axis line style\n\n#### LabelTexts (Category axis labels)\n\nInspector provides `LabelTexts` (internal field name `labels`) to configure category labels.\n\n#### Range\n\nCommon fields include:\n\n- `minValue` / `maxValue`\n- `autoRangeMin` / `autoRangeMax`\n- `autoRangeRounding`\n- `autoRangeUnit`\n\n#### Ticks / VisibleCount\n\nIf the axis supports auto ticks:\n\n- When `autoTicks` is enabled, it shows `splitCount`.\n- For **Category Axis**, this field is displayed as **VisibleCount** (number of visible categories).\n\n#### Category Auto Scroll\n\nIf the axis supports category scrolling, common fields include:\n\n- `categoryAutoScroll`: whether to auto scroll (marquee effect).\n- `categorySmoothScroll`: whether to scroll smoothly.\n- `categoryScrollInterval`: scroll interval.\n- `categoryScrollStep`: scroll step per tick.\n\n#### Unit (unit display)\n\nCommon fields:\n\n- `showUnit`: whether to show unit.\n- `unitText`: unit text (e.g. `ms`/`%`/`MB`).\n- `unitLabelStyle`: unit label style.\n\n---\n\n## Polar Axis\n\nWhen `coordinateSystem = Polar2D`, Axis Settings shows `polarAxes`:\n\n- **Angle Axis** (angleAxis)\n- **Radius Axis** (radiusAxis)\n\nCommon field meanings are similar to Cartesian:\n\n- `labels`: angle/dimension labels (Radar dimension names typically come from here).\n- `visible/color/width`: axis line style.\n- `showLabels/fontSize/labelColor/labelPosition/labelOffset`: label display controls.\n- `autoRangeMin/autoRangeMax/minValue/maxValue`: radius axis range.\n- `autoTicks/splitCount`: tick count.\n\n---\n\n## Grid Settings (fields, Cartesian2D only)\n\nGrid Settings is visible in Cartesian2D. Key fields come from `cartesianGrid`:\n\n- **xGridColor / xGridLineWidth**: X-direction grid line color and width.\n- **yGridColor / yGridLineWidth**: Y-direction grid line color and width.\n\nIf you need dashed lines:\n\n- `xGridDashed` / `yGridDashed`: enable dashed.\n- `xGridDashLength` / `yGridDashLength`: dash segment length.\n- `xGridDashGap` / `yGridDashGap`: dash gap.\n- `xGridDashOffset` / `yGridDashOffset`: dash offset.\n\n---\n\n## Hover Settings (fields, Cartesian2D only)\n\nHover Settings is visible in Cartesian2D. Key fields come from `hover`:\n\n- **cursorLineColor**: hover cursor line color.\n- **cursorLineWidth**: line width.\n- **cursorLineDashed**: dashed or not.\n- **cursorLineDashLength / cursorLineDashGap / cursorLineDashOffset**: dash parameters.\n\n---\n\n## Legend Settings (fields)\n\nLegend Settings comes from `legendSettings` (it may be auto-hidden in some cases; see below).\n\n- **enabled**: whether to show legend.\n- **position**: legend position (Top/Bottom/Left/Right).\n- **fontSize / color**: text size and color.\n- **backgroundColor**: legend background color.\n- **itemSpacing**: spacing between legend items.\n- **offset**: offset relative to the edge.\n - When offset is default, a common offset is applied based on position (e.g. Bottom defaults to `y=-30`).\n\n---\n\n## Legend Settings (may be auto-hidden)\n\nWhen the chart is a \"pure Pie series\" (only Pie/Ring/Pie3D, with no non-Pie series), Legend Settings may be hidden automatically.\n\nThis avoids showing meaningless or conflicting legend configuration in some layouts.\n\n---\n\n## Editing tips and troubleshooting\n\n- **When making many changes**: use `Save` in the top toolbar to save the asset.\n- **When changing key structure** (e.g. coordinate system, axis type, Series Type):\n - after the change, check whether Preview refreshes correctly\n - if inconsistent, try switching selection to trigger a rebuild\n\n---\n\n## Help\n\n- Click the rightmost **Help** icon in the title bar to open this chapter.\n" },
|
||
{ id: "02_06-SeriesPanel", relPath: "02_06-SeriesPanel.md", title: "Series Panel (Data and Series)", content: "# Series Panel (Data and Series)\n\nThis chapter explains the **Series** panel on the right side of `Unity Easy Chart/Library Editor`.\n\nThe Series panel edits `ChartProfile.series` from a \"chart structure\" perspective: you can add/remove/reorder series, set each Serie's type and parameters, and directly edit `seriesData` (data points).\n\n---\n\n## Panel structure overview\n\nAfter you select a `ChartProfile`, the Series panel shows:\n\n- a list of Serie cards (each card corresponds to `series[i]`)\n- a **+ Add Series** button at the bottom\n\nEach Serie card typically consists of three parts:\n\n- **Header**: fold toggle + title\n- **Body**: Name / Id / Type / Settings / Data\n- **Footer** (bottom-right controls): ↑ ↓ X\n\n---\n\n## Header: Collapse/Expand\n\n- On the left side of the Header there is a small toggle:\n - `▼` means expanded\n - `▶` means collapsed\n- The fold state is remembered (stored by Profile + index) to reduce visual clutter for long configurations.\n\n---\n\n## Name and Serie Id\n\n### Name\n\n- The `Name` field displays and edits the name of the Serie.\n- When you change Name, the card title updates and triggers a Preview refresh.\n\n### Serie Id (read-only)\n\nIf the Serie supports an `id` field, the panel shows:\n\n- **Serie Id** (read-only text field)\n- **Copy** button to copy the id to the clipboard\n\nThis id is commonly used for:\n\n- interaction/highlighting/external systems referencing a serie\n- keeping references stable (especially when you reorder/add/remove series)\n\n---\n\n## Type (series type) and compatibility tips\n\n### Type dropdown\n\n- `Type` is used to select the SerieType (Line/Bar/Scatter/Pie/Radar...).\n- The dropdown provides options based on the registry. If the current type is not in the list, it will be temporarily inserted to keep it visible.\n\n### Compatibility warning\n\nWhen the SeriesType is incompatible with the Profile `coordinateSystem`, the Series panel shows a warning message:\n\n- rendering is still allowed (not forcibly blocked)\n- but it warns that axis/grid semantics may be inconsistent\n\nTypical example:\n\n- Profile is `Polar2D` but the SeriesType is Line/Bar (not recommended)\n\n### Pro-only type restrictions\n\nSome types are not available in the Free version (e.g. RingChart / HorizontalBar / Heatmap / Pie3D).\n\n- When you try to select these types without Pro installed:\n - a hint text will be shown\n - and the dropdown will automatically revert to the previous type (it will not modify the asset)\n\n---\n\n## Settings (series parameters)\n\nThe Series panel shows a group of Settings for each serie:\n\n- The root foldout name changes by type (e.g. `LineSettings` / `BarSettings` / `PieSettings` ...).\n- Some types have more detailed sub-foldouts (e.g. Ring layout/valueMapping, etc.).\n\nNotes:\n\n- Switching Type may trigger a \"Settings instance replacement\" (managedReference structure changes).\n- When replacement happens, the UI rebuild is delayed by one frame to avoid invalid serialized handles.\n\n---\n\n## Data: seriesData (data points)\n\nThe Series panel directly shows the `seriesData` array (Unity's default array editor).\n\n- It is expanded by default (easier to edit).\n- When you add/remove/modify points, it triggers a Preview refresh.\n\nRecommendation:\n\n- If you have many data points, use the JSON Injection panel for batch editing.\n\n---\n\n## Footer: Reorder and delete (render order)\n\nEach serie card has three buttons at the bottom-right:\n\n- **↑**: move the serie up (`MoveArrayElement(index, index-1)`)\n- **↓**: move the serie down (`MoveArrayElement(index, index+1)`)\n- **X**: delete the serie (`DeleteArrayElementAtIndex(index)`)\n\nRender order tip:\n\n- Usually, **later series are drawn on top**.\n- So you can use ↑↓ to control overlap (e.g. points/lines on top of bars).\n\n---\n\n## + Add Series\n\nClick **+ Add Series** at the bottom:\n\n- Inserts a new element at the end of the `series` array.\n- Note: if there is already at least one serie, Unity's `InsertArrayElementAtIndex(arraySize)` will **duplicate the last element** (including type/settings).\n- If this is the first serie, a default type is chosen based on coordinate system:\n - Polar2D: defaults to Radar\n - otherwise: defaults to Line\n\nAfter adding, it typically will:\n\n- auto-fill a name (e.g. `Serie N`)\n- call `EnsureRuntimeData()`\n- refresh the Series list and Preview\n\n---\n\n## Recommended workflows\n\n### 1) Create a basic chart from scratch\n\n- + Add Series\n- Choose Line or Bar in Type\n- Add a few points in seriesData\n- Adjust axis range/visible count in Inspector\n\n### 2) Adjust overlap\n\n- Use ↑↓ to adjust series order\n- Observe layering changes in Preview\n\n### 3) Large data / batch editing\n\n- Switch `Datas Format` in JSON Injection\n- Copy to an external editor to batch-generate/replace data\n- Paste back and ApplyToChart\n\n---\n\n## Help\n\n- Click the rightmost **Help** icon in the title bar to open this chapter.\n" },
|
||
{ id: "03_01-LineChart", relPath: "03_01-LineChart.md", title: "Line Chart (Line)", content: "# Line Chart (Line)\n\nThis chapter explains the key points of configuring a Line chart in EasyChart: how to set it up, how data is interpreted, and which fields affect rendering.\n\n---\n\n## 1. Use cases\n\n- Trend changes (time series / category-based)\n- Comparing multiple curves (same X dimension)\n- Line styles such as smooth / step / straight\n\n---\n\n## 2. Minimum viable setup (checklist)\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. Axes (Axis Settings)\n - X: usually **Category** (fill `labels`) or **Value** (numeric X axis)\n - Y: usually **Value**\n3. Series (Series panel)\n - Add 1 `Serie`\n - `Serie.type = Line`\n - `Serie.seriesData` has at least 2 points (a line needs at least two points)\n\n---\n\n## 3. Inspector fields (what you see in panels)\n\n- **ChartProfile / Coordinate System**\n - `coordinateSystem`\n\n- **Axis Settings** (depends on coordinate system)\n - Cartesian: `cartesian.xAxisId / cartesian.yAxisId`\n - Axis list: `axes[]` (each Axis has `axisType/labels/min/max/autoRange/...`)\n\n- **Series** (each curve)\n - `series[i].type = Line`\n - `series[i].settings`: actual type is `LineSettings`\n - `stroke`: line stroke (type/color/width/texture, etc.)\n - `point`: point marker style (toggle/size/texture, etc.)\n - `hover`: hover emphasis (enables pick radius / highlight)\n - `area`: area fill (fill under the line)\n - `series[i].labelSettings`: point labels (visibility/format/decimals/offset, etc.)\n\n---\n\n## 4. SeriesData field interpretation (runtime behavior)\n\nLine chart uses:\n\n- **X coordinate**: `SeriesData.x`\n- **Y value**: `SeriesData.value`\n- `SeriesData.y` is **not used for rendering** in line charts (do not treat `y` as the Y value).\n\nTwo common patterns:\n\n### 4.1 Category X + Value Y (most common)\n\n- X axis: `AxisType.Category`\n- `AxisConfig.labels = [\"A\",\"B\",\"C\",...]`\n- Data points:\n - `x = category index` (0/1/2..., mapped into labels)\n - `value = numeric value`\n\n### 4.2 Value X + Value Y (numeric X axis)\n\n- X axis: `AxisType.Value`\n- Data points:\n - `x = X value`\n - `value = Y value`\n\n> Additional note: when your axis dimensions are **X=Value, Y=Category**, runtime treats it as a transposed Cartesian layout (`transposed`) and swaps how X/Y are interpreted during rendering (useful for horizontal layouts).\n\n---\n\n## 5. Common style settings (LineSettings)\n\n- **Line type**: `LineSettings.stroke.lineType`\n - `Straight`: straight lines\n - `Step`: step line\n - `Smooth`: smooth curve\n\n- **Stroke width/color**: `LineSettings.stroke.width` / `LineSettings.stroke.color`\n\n- **Point markers**: `LineSettings.point.show/size/textureFill`\n\n- **Area fill**: `LineSettings.area.show` + `LineSettings.area.textureFill`\n\n---\n\n## 6. Common pitfalls and troubleshooting (by symptoms)\n\n- **Line breaks / not visible**\n - Check whether `SeriesData.value` contains `NaN/Infinity`\n - A line needs at least 2 valid points\n\n- **Points do not align with labels (Category X)**\n - Check that `x` is an index within 0..(labels.Count-1)\n - Do not write `x` as a category string (EasyChart uses index, not string)\n\n- **I filled `y`, but the chart is wrong**\n - Line chart uses `value` as the Y value, not `y`\n\n---\n\n## 7. Further reading\n\n- Axes/range, Series and data: `00_02-WorkflowAndLibrary.md`\n- Common recipes: `04_08-CommonRecipes.md`\n- FAQ: `04_09-FAQ.md`\n" },
|
||
{ id: "03_02-BarChart", relPath: "03_02-BarChart.md", title: "Bar Chart (Bar)", content: "# Bar Chart (Bar)\n\nThis chapter explains bar charts in EasyChart: the data interpretation rules (`SeriesData.x/value`), how grouping/stacking really behaves, and commonly used style fields.\n\n---\n\n## 1. Use cases\n\n- Category comparisons (compare values of A/B/C)\n- Grouped comparison (multiple Bar series side-by-side under the same category)\n- Stacked totals (stack bars within the same category)\n\n---\n\n## 2. Minimum viable setup (checklist)\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. Axes\n - X: usually `AxisType.Category` (fill `labels`)\n - Y: usually `AxisType.Value` (recommended to start from 0)\n3. Series\n - Add 1 `Serie`\n - `Serie.type = Bar`\n - `Serie.seriesData` has at least 1 point\n\n---\n\n## 3. Inspector fields\n\n- **Axis Settings**\n - `cartesian.xAxisId / cartesian.yAxisId`\n - `axes[]` (AxisConfig for X/Y)\n\n- **Series**\n - `series[i].type = Bar`\n - `series[i].settings`: actual type is `BarSettings`\n - `barWidth`\n - `stacked` / `stackGroup`\n - `barGap` / `categoryGap`\n - `cornerRadius` / `cornerSegments`\n - `textureFill` (color/texture)\n - `border` / `background`\n - `hover` (enables picking/highlight)\n\n---\n\n## 4. SeriesData field interpretation (runtime behavior)\n\nBar charts primarily use:\n\n- **Category / horizontal position**: `SeriesData.x`\n - Runtime rounds `x` with `RoundToInt`, so **treat it as a category index**.\n\n- **Bar height**: `SeriesData.value`\n\n- `SeriesData.y` / `SeriesData.z` are **not used for rendering** in Bar charts (do not treat `y` as height).\n\n---\n\n## 5. Most common template: Category X + Value Y\n\n### 5.1 X axis (Category)\n\n- `AxisType = Category`\n- `labels = [\"A\",\"B\",\"C\",...]`\n- Recommended: `labelPlacement = CellCenter` (easier to center-align bars)\n\n### 5.2 Data pattern\n\n- `x = category index` (0/1/2...)\n- `value = bar height`\n\n---\n\n## 6. Grouped bars (multiple series side-by-side): the actual rule\n\nKey points:\n\n- multiple `Serie`, all `type=Bar`\n- all series share the same X categories (same labels)\n- each series uses the same `x` index to land in the same category\n\nSpacing fields:\n\n- `BarSettings.barGap`: gap between bar groups within a category\n- `BarSettings.categoryGap`: extra gap between categories (affects edge padding)\n\n---\n\n## 7. Stacked bars (stacked): the actual rule\n\nStacking happens between Bar series with the same stackGroup:\n\n- `BarSettings.stacked = true`\n- `BarSettings.stackGroup = \"Group1\"`\n\nRuntime stacking notes:\n\n- for the same `x` (category index), it accumulates positive and negative values separately (positive/negative stacks are separate)\n- the top of each stacked segment = current accumulated base + `value`\n\n---\n\n## 8. Common pitfalls and troubleshooting\n\n- **Bars appear between labels / not aligned**\n - Check X axis `labelPlacement` (recommend `CellCenter`)\n - Ensure `x` is an integer index (runtime rounds)\n\n- **Bars do not start from 0**\n - Check whether Y axis (Value Axis) has `autoRangeMin` disabled and `minValue=0` locked\n\n- **Stacking result is wrong**\n - Check that all series that should stack use the same `stackGroup`\n - Remember: positive and negative values stack separately\n\n---\n\n## 9. Further reading\n\n- Axes/range, Series and data: `00_02-WorkflowAndLibrary.md`\n- Common recipes: `04_08-CommonRecipes.md`\n- FAQ: `04_09-FAQ.md`\n" },
|
||
{ id: "03_03-ScatterChart", relPath: "03_03-ScatterChart.md", title: "Scatter Chart (Scatter)", content: "# Scatter Chart (Scatter)\n\nThis chapter explains the data field conventions for Scatter charts in EasyChart, especially the compatibility behavior of `SeriesData.y/value`, and how the `z` dimension drives `sizeMapping`.\n\n---\n\n## 1. Use cases\n\n- Correlation analysis (two numeric dimensions X/Y)\n- Distribution visualization (point cloud)\n- Outlier detection\n\n---\n\n## 2. Minimum viable setup (checklist)\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. Axes\n - Common: X=Value, Y=Value\n3. Series\n - Add 1 `Serie`\n - `Serie.type = Scatter`\n - `Serie.seriesData` has at least 2 points\n\n---\n\n## 3. Inspector fields\n\n- `series[i].type = Scatter`\n- `series[i].settings`: actual type is `ScatterSettings`\n - `point`: point style (visible/size/texture)\n - `hover`: hover highlight (enabled/pickRadius/scale, etc. depending on version)\n - `sizeMapping`: point size mapping\n\n---\n\n## 4. SeriesData field interpretation (runtime behavior)\n\nScatter chart uses:\n\n- **X coordinate**: `SeriesData.x`\n- **Y coordinate**: prefers `SeriesData.y`\n - Compatibility: if `y == 0` and `value != 0`, runtime uses `value` as y\n- **Size mapping dimension**: `SeriesData.z` (when `sizeMapping.enabled=true`)\n\nSo there are two common patterns:\n\n### 4.1 Recommended (explicit X/Y)\n\n- `x = X value`\n- `y = Y value`\n\n### 4.2 Compatibility (legacy data: use value as y)\n\n- `x = X value`\n- `value = Y value`\n- `y = 0`\n\n> Recommendation: for new data, write `y` directly to avoid mixing meanings with `value`.\n\n---\n\n## 5. Standard template: Value X + Value Y\n\n- X axis: `AxisType = Value`\n- Y axis: `AxisType = Value`\n- Data: use pattern 4.1 (x/y)\n\n---\n\n## 6. sizeMapping: actual behavior\n\nWhen `ScatterSettings.sizeMapping.enabled = true`:\n\n- point radius is mapped from `SeriesData.z`\n- mapping range: `minValue/maxValue` -> `minSize/maxSize`\n- if `clamp = true`, t is clamped to 0..1\n- `curve` applies a curve transform to t (non-linear mapping)\n\nIf sizeMapping \"doesn't work\", check first:\n\n- did you actually set `z` values (default 0)\n- is `minValue/maxValue` equal (degenerates mapping)\n\n---\n\n## 7. Common pitfalls and troubleshooting\n\n- **All points are on a horizontal line**\n - you may have filled only `value`, but also set `y` to a non-zero value (compatibility won't trigger)\n - recommend using `y` consistently as the Y coordinate\n\n- **Hover does not respond**\n - `ScatterSettings.hover.enabled` must be enabled\n - too small `pickRadius` makes picking difficult\n\n- **Points are too small / too large**\n - adjust `ScatterSettings.point.size`\n - or check `minSize/maxSize` in sizeMapping\n\n---\n\n## 8. Further reading\n\n- Axes/range, Series and data: `00_02-WorkflowAndLibrary.md`\n- Common recipes: `04_08-CommonRecipes.md`\n- FAQ: `04_09-FAQ.md`\n" },
|
||
{ id: "03_04-HeatmapChart", relPath: "03_04-HeatmapChart.md", title: "Heatmap Chart (Heatmap)", content: "# Heatmap Chart (Heatmap)\n\nThis chapter explains the rules for Heatmaps in EasyChart: how coordinates/cells are mapped, how `SeriesData` fields are interpreted, and how the value-to-color range is calculated. It also notes that Heatmap is a Pro feature.\n\n---\n\n## 1. Use cases\n\n- 2D matrix visualization (rows/columns)\n- Density/intensity visualization\n\n---\n\n## 2. Important note (Pro feature)\n\n- The renderer for `SerieType.Heatmap` is registered by `EasyChartProBootstrap`.\n- If EasyChartPro is not installed/enabled, this serie may be treated as a \"dynamic renderer\" and attempted to be created, but it usually won't render.\n\n---\n\n## 3. Minimum viable setup (checklist)\n\n1. `ChartProfile.coordinateSystem = Cartesian2D`\n2. Axes (Axis Settings)\n - Most common: X=Category (columns), Y=Category (rows)\n - X/Y can also use Value axes (see section 7)\n3. Series\n - Add 1 `Serie`\n - `Serie.type = Heatmap`\n - `Serie.seriesData` has at least 1 point\n\n---\n\n## 4. Inspector fields\n\n- **Series**\n - `series[i].type = Heatmap`\n - `series[i].settings`: actual type is `HeatmapSettings`\n - `renderMode`: Grid / Gradient / Contour\n - `cellGapPx`\n - `xSplitCount` / `ySplitCount` (used when X/Y are Value axes)\n - `autoRange / minValue / maxValue`\n - `lowColor / midColor / highColor`\n - `clamp`\n - `influenceMode`: None / Bleed / Smooth\n - sub settings: `bleed / smooth / gradient / contour`\n\n---\n\n## 5. SeriesData field interpretation (runtime behavior)\n\nEach Heatmap data point corresponds to one \"cell/pixel area\". Runtime uses:\n\n- **X coordinate (column)**: `SeriesData.x`\n- **Y coordinate (row)**: `SeriesData.y`\n- **Intensity**: `SeriesData.value`\n- **Color override**: if `SeriesData.useColor = true`, runtime uses `SeriesData.color` directly and skips interpolation from `low/mid/high`.\n\n> Note: Heatmap `x/y` do not accept string categories. With Category axes, you still use indices.\n\n---\n\n## 6. Standard template: 2D Category (X/Y) + value intensity (most common)\n\n### 6.1 X axis (Category: columns)\n\n- `AxisType = Category`\n- `labels = [\"Col0\",\"Col1\",...]`\n\n### 6.2 Y axis (Category: rows)\n\n- `AxisType = Category`\n- `labels = [\"Row0\",\"Row1\",...]`\n\n### 6.3 Data pattern\n\n- `x = column index` (runtime applies `RoundToInt`)\n- `y = row index` (runtime applies `RoundToInt`)\n- `value = intensity`\n\n### 6.4 Important detail: cell count vs `labelPlacement` for Category axes\n\nRuntime uses the axis `labelPlacement` to decide whether to split into `labels.Count` cells or `labels.Count-1` cells:\n\n- `CategoryLabelPlacement.CellCenter`\n - X cell count = `labels.Count`\n - Y cell count = `labels.Count`\n\n- Others (non CellCenter)\n - X cell count = `max(1, labels.Count - 1)`\n - Y cell count = `max(1, labels.Count - 1)`\n\nThis directly affects the valid range of indices you should write into `x/y`.\n\n---\n\n## 7. Heatmap with Value axes (X/Y are numeric axes)\n\nWhen X or Y uses `AxisType.Value`:\n\n- Cell count no longer comes from labels. It comes from:\n - X: `HeatmapSettings.xSplitCount`\n - Y: `HeatmapSettings.ySplitCount`\n\n- `SeriesData.x/y` are normalized using `_xMin/_xMax` and `_yMin/_yMax`, then mapped into cell indices.\n\nThis is suitable for intensity/density distribution over a continuous value range.\n\n---\n\n## 8. Common pitfalls and troubleshooting\n\n- **All cells look the same / low contrast**\n - Check whether `HeatmapSettings.autoRange` is enabled\n - Or manually set `minValue/maxValue`\n - Also check whether all points have almost the same `value`\n\n- **Colors do not follow low/mid/high**\n - Check whether some points set `useColor=true` (it overrides palette interpolation)\n\n- **Cells are misaligned (out-of-range / off-by-one)**\n - Check whether Category axis `labelPlacement` is `CellCenter`\n - Use section 6.4 to determine correct cell count and index ranges\n\n- **Cell gaps are too large/too tight**\n - Adjust `HeatmapSettings.cellGapPx`\n\n---\n\n## 9. Further reading\n\n- Axes/range, Series and data: `00_02-WorkflowAndLibrary.md`\n- Common recipes: `04_08-CommonRecipes.md`\n- FAQ: `04_09-FAQ.md`\n" },
|
||
{ id: "03_05-RadarChart", relPath: "03_05-RadarChart.md", title: "Radar Chart (Radar)", content: "# Radar Chart (Radar)\n\nThis chapter explains how Radar charts work in EasyChart: where dimension labels come from, how value ranges are calculated, and how data point order is interpreted, mapped to Inspector fields.\n\n---\n\n## 1. Use cases\n\n- Multi-dimensional metric comparison\n- Ability/attribute radar\n\n---\n\n## 2. Minimum viable setup (checklist)\n\n1. `ChartProfile.coordinateSystem = Polar2D`\n2. Series\n - Add 1 `Serie`\n - `Serie.type = Radar`\n - `Serie.seriesData` is recommended to have at least 3 points (with <= 2 dimensions, runtime will not draw / hover won't work)\n3. PolarAxes (recommended)\n - `polarAxes.angleAxis.labels`: dimension names\n - `polarAxes.radiusAxis`: value range (auto/manual)\n\n---\n\n## 3. Inspector fields\n\n- **ChartProfile / Coordinate System**\n - `coordinateSystem = Polar2D`\n\n- **PolarAxes** (recommended for configuring Radar axes)\n - `polarAxes.angleAxis.labels`: dimension labels\n - `polarAxes.radiusAxis.autoRangeMin/autoRangeMax/minValue/maxValue/autoRangeRounding/labelFormat/...`\n\n- **Series**\n - `series[i].type = Radar`\n - `series[i].settings`: actual type is `RadarSettings`\n - `radar`: layout (startAngleDeg / clockwise / innerRadius / outerRadius / plot / background)\n - `stroke`: polyline style\n - `area`: area fill\n - `point`: point style (point visibility also affects hover pick radius)\n - `series[i].labelSettings`: data point labels (can show dimension name and value)\n\n---\n\n## 4. SeriesData field interpretation (runtime behavior)\n\nKey point for Radar: **dimension order is defined by the index of items in the `seriesData` list**.\n\n- **Value**: uses `SeriesData.value`\n- **Dimension index**: uses the position `i` in `seriesData` (0..dimensionCount-1)\n- `SeriesData.x` is **not used for positioning** in Radar rendering (do not rely on x to represent dimensions)\n\nWhere does dimensionCount come from:\n\n1. Prefer `Data.PolarAxes.angleAxis.labels.Count`\n2. If angleAxis.labels is not configured, it uses labels from a Category Axis (see section 5)\n3. Otherwise, fall back to `seriesData.Count` (or the maximum count among multiple series)\n\n---\n\n## 5. Actual priority order for dimension labels\n\nRuntime resolves dimension names in this priority order:\n\n1. `polarAxes.angleAxis.labels[i]`\n2. `labels[i]` from a `AxisType.Category` axis in `axes[]`\n - it prefers the Category axis that matches `Data.XAxisId`\n3. `seriesData[i].name`\n4. If none exists, it shows `Dim i`\n\n> Recommendation: for Radar, manage dimension names via `polarAxes.angleAxis.labels`. Use `SeriesData.name` as a fallback.\n\n---\n\n## 6. How radius value range is calculated\n\nRadar radius range is calculated from `SeriesData.value`:\n\n- By default, it computes auto range from values across all Radar series\n- If you configure `polarAxes.radiusAxis`:\n - `autoRangeMin/autoRangeMax` decides whether min/max are automatic\n - `minValue/maxValue` take effect when the corresponding auto range is disabled\n - `autoRangeRounding` rounds auto min/max to tens/hundreds/custom unit\n - `labelFormat` affects tooltip/label formatting\n\n---\n\n## 7. Common pitfalls and troubleshooting\n\n- **Radar chart not visible**\n - Check `coordinateSystem` is `Polar2D`\n - Dimension count must be > 2 (labels or seriesData must be at least 3)\n\n- **Dimensions do not match / order is wrong**\n - Radar does not use `x`. It uses `seriesData` list order as dimension order\n - Put points in `seriesData` in the intended dimension order\n\n- **Hover is hard to trigger**\n - Radar pick radius is related to `RadarSettings.point.size`\n - If `point.show=false`, pick radius becomes 0 (almost impossible to hover)\n\n---\n\n## 8. Further reading\n\n- Series and data: `00_02-WorkflowAndLibrary.md`\n- Common recipes: `04_08-CommonRecipes.md`\n- FAQ: `04_09-FAQ.md`\n" },
|
||
{ id: "03_06-PieChart", relPath: "03_06-PieChart.md", title: "Pie Chart (Pie)", content: "# Pie Chart (Pie)\n\nThis chapter explains how Pie charts work in EasyChart: how data fields are interpreted, how layout/aggregation/legend/interactions take effect, and which behaviors have hidden prerequisites, mapped to Inspector fields.\n\n---\n\n## 1. Use cases\n\n- Showing proportions/composition\n- Emphasizing the share of each category in the whole\n\nNot suitable for:\n\n- Too many categories (usually > 8–12 becomes hard to read)\n- Precise comparison of tiny differences (a bar chart is usually better)\n\n---\n\n## 2. Minimum viable setup (checklist)\n\n1. `coordinateSystem`: Pie does not rely on Cartesian/Polar coordinate systems (keep your Profile setting)\n2. Add 1 `Serie`:\n - `type = Pie`\n - `settings = PieSettings`\n - `seriesData` has at least 1 point\n3. Ensure each point has `value > 0`\n\n> Note: Pie currently ignores points with `value <= 0`.\n\n---\n\n## 3. Important limitations (runtime behavior)\n\n- **Only the first visible Pie serie is drawn**: the renderer iterates `Data.Series`, finds the first visible serie with `type=Pie`, draws it, then `break`s.\n- Slice hidden state comes from `ChartInteractionState.HiddenPieSliceIds`, which is added/removed when clicking legend items.\n\n---\n\n## 4. SeriesData field interpretation (runtime behavior)\n\nPie mainly uses:\n\n- `value`: numeric value (weight) of the slice\n- `name`: slice name (recommended)\n- `useColor + color`: per-slice custom color (optional)\n- `id`: stable slice identifier (for hidden/interaction state; keep it stable)\n\n### 4.1 Recommended pattern: explicit name + value\n\n- `SeriesData.name = \"Apple\"`\n- `SeriesData.value = 12`\n\n### 4.2 Name fallback when name is empty\n\nWhen `SeriesData.name` is empty, Pie may try to use **labels**, but with an important prerequisite:\n\n- If `ChartData.CoordinateSystem == None` (typically pure Pie / no coordinate system), runtime **skips label fallback** and uses only `SeriesData.name`.\n\nWhen coordinate system is not None, the fallback order is:\n\n- Prefer Category axis labels that match `Data.Cartesian.xAxisId`\n- Otherwise, use labels from any Category axis\n- Final fallback: `Slice {index}`\n\n> Therefore: if you do not want to depend on axis configuration, fill `SeriesData.name` directly.\n\n### 4.3 Color source\n\n- If `useColor=true` on the point: use `SeriesData.color`\n- Otherwise: use the built-in palette in order\n\n---\n\n## 5. Common settings (PieSettings)\n\nPie `settings` is `PieSettings`, mainly including:\n\n- `layout`: layout (angle/radius/gaps/center offset, etc.)\n- `hover`: hover interaction (explode)\n- `aggregation`: aggregation (TopN + Others)\n- `legend`: Pie-specific legend settings (replaces global legend only for \"pure Pie chart\" cases)\n\n### 4.1 layout (PieLayoutSettings)\n\nCommon fields:\n\n- `startAngleDeg`: start angle (default -90 makes the first slice start at the top)\n- `clockwise`: clockwise/counter-clockwise\n- `angleRangeDeg`: angle range (default 360; use 180 for half-pie, etc.)\n- `outerRadius`: outer radius\n - `<= 0`: auto\n - `0~1`: normalized by control size\n - `> 1`: pixels\n- `innerRadius`: inner radius (Pie usually 0; >0 creates a hole, but RingChart is recommended for ring/progress style)\n- `innerRadiusColor`: inner fill color\n- `sliceGapPx`: gap between slices (pixels)\n- `sliceGapType`: gap mode (Radial/Translate/Uniform)\n- `cornerRadius`: corner radius (pixels, limited by slice thickness)\n- `plot.padding`: padding (avoid clipping slices/outside labels)\n- `plot.centerOffset`: center offset\n\n### 4.2 hover (PieHoverSettings)\n\n- `hover.enabled`: enable hover interaction\n- `hover.explodeType`:\n - `Translate`: translate the whole slice\n - `Pull`: pull out / stretch\n - `Color`: brighten\n - `Stroke`: stroke emphasis\n- `hover.explodeDistance`: translate/pull distance (pixels)\n\n### 4.3 aggregation (PieAggregationSettings)\n\nWhen there are many categories, you can merge small items into `Others`:\n\n- `aggregation.enabled = true`\n- `keepTopN`: keep top N, merge the rest\n- `sortByValue`: sort by `value` before taking TopN\n- `othersName`: name for Others\n- `useOthersColor + othersColor`: Others color\n\n> Note: aggregation only takes effect when `keepTopN > 0` and slice count exceeds N.\n\n---\n\n## 6. Legend (PieLegendSettings) and \"hide slice\" interaction\n\nWhen the chart is a \"pure Pie chart\" (only Pie/RingChart/Pie3D and no other types):\n\n- Legend prefers `PieSettings.legend` (or the legend on RingChartSettings/Pie3DSettings), instead of `ChartData.legend`.\n- Clicking a legend item toggles `HiddenPieSliceIds`:\n - normal slices: `SeriesData.id` (if empty, uses index string)\n - aggregated Others: always `__ec_pie_others__`\n\n`PieLegendSettings.source` affects where legend items come from:\n\n- `Slice`: one entry per slice (default)\n- `RingSlice`: provides label source for RingChart/RingSlice scenarios (prefers PolarAxes.angleAxis.labels)\n- `Series`: one entry per serie (not slice-level)\n\n---\n\n## 7. Labels (SerieLabelSettings)\n\nPie labels are controlled by `Serie.labelSettings`:\n\n- `show`: whether to show\n- `fontSize / color / decimalPlaces`: font and value format\n- `showName`: whether to include slice name\n- `position`: `Outside/Inside/Center`\n- `offset`: offset\n\n---\n\n## 8. Common pitfalls (by symptoms)\n\n- **Some slices are not visible**\n - Check whether the point `value` is `<= 0`\n\n- **Slice name is not what I expect**\n - Recommended: fill `SeriesData.name` directly\n - If you rely on labels: ensure you have a Category axis with `labels`, and the order matches data point indices\n\n- **Slice colors change each time / hard to control**\n - For slices that need fixed colors: set `useColor=true` + `color` on the point\n\n- **Hidden/interaction state is unstable**\n - Ensure each point `SeriesData.id` is stable (do not regenerate ids on each refresh)\n\n---\n\n## 9. Next\n\n- Ring chart (RingChart): `03_07-RingChart.md`\n" },
|
||
{ id: "03_07-RingChart", relPath: "03_07-RingChart.md", title: "Ring Chart (RingChart)", content: "# Ring Chart (RingChart)\n\nThis chapter explains what RingChart really means (it is not a donut pie), and aligns its `SeriesData` interpretation, `RingChartSettings` configuration, and Pro/base differences with runtime behavior.\n\n---\n\n## 1. What is RingChart? (very important)\n\nIn the current EasyChart implementation:\n\n- `SerieType.RingChart` renders **multiple progress rings** (one ring per data point)\n- each ring is a **full 360° background ring + one progress arc**\n- it is not a pie chart that splits the circle into multiple slices\n\nIf you want a donut pie chart that shows composition:\n\n- it is closer to `SerieType.Pie` + `layout.innerRadius > 0`\n- but you should choose based on intent:\n - composition/proportion: use Pie\n - multi-metric progress/completion: use RingChart\n\n---\n\n## 2. Important note (Pro feature)\n\n- The renderer for `SerieType.RingChart` is registered by `EasyChartProBootstrap`.\n- Without Pro installed/enabled, this serie usually won't render.\n\n---\n\n## 3. Minimum viable setup (checklist)\n\n1. Add 1 `Serie`\n - `type = RingChart`\n - `settings = RingChartSettings`\n - `seriesData` has at least 1 point\n2. Each point has `value > 0`\n\n> Note: RingChart ignores points with `value <= 0`.\n\n---\n\n## 4. SeriesData field interpretation (runtime behavior)\n\nRingChart mainly uses:\n\n- `value`: the raw progress value\n- `name`: ring name\n- `useColor + color`: ring color (per-point override)\n- `id`: stable identifier (for legend/hidden state; keep it stable)\n\n### 4.1 Percent mode (default): value supports both 0~1 and 0~100\n\nWhen `RingChartSettings.valueMapping.mode = Percent` (default):\n\n- `value <= 0`: the ring is filtered out\n- `0~1`: treated as ratio (0.72 = 72%)\n- `> 1`: treated as percent (72 = 72%, runtime divides by 100)\n\nRecommendation: standardize one convention within your team (all 0~1 or all 0~100) to avoid mistakes.\n\n### 4.2 Range mode: map value to 0..1\n\nWhen `RingChartSettings.valueMapping.mode = Range`:\n\n- It first determines the range `min/max`:\n - `autoRange=true`: compute from values across all rings\n - `autoRange=false`: use `minValue/maxValue`\n- Then it maps to `(value-min)/(max-min)` and clamps to 0..1\n\n### 4.3 Name fallback when name is empty\n\nWhen `SeriesData.name` is empty, RingChart tries to fall back to labels:\n\n- If `ChartData.CoordinateSystem == None`: it won't use labels, and falls back to `Ring {i}`\n- Otherwise it prefers: `Data.PolarAxes.angleAxis.labels[i]`\n- Otherwise: labels from Cartesian/any Category axis `labels[i]`\n- Final fallback: `Ring {i}`\n\nIf you do not want to depend on PolarAxes configuration, fill `SeriesData.name` directly.\n\n---\n\n## 5. Inspector fields (RingChartSettings)\n\n- `series[i].type = RingChart`\n- `series[i].settings`: actual type is `RingChartSettings`\n - `layout`: angles/radius/inner-outer ring/padding/center offset\n - `valueMapping`: Percent/Range mapping rules\n - `hover`: hover emphasis (Translate/Pull/Color/Stroke)\n - `legend`: RingChart legend settings (effective for pure Pie charts)\n - `showBackground/backgroundAlpha/backgroundColor`: background ring\n - `cornerRadius`: rounded cap\n - `ringGapPx`: gap between rings\n\n### 5.1 layout (RingChartLayoutSettings)\n\nCommon fields:\n\n- `startAngleDeg`: start angle\n- `clockwise`: clockwise/counter-clockwise\n- `angleRangeDeg`: default 360; use for half-ring progress, etc.\n- `outerRadius`: outer radius (<=0 auto; 0~1 normalized; >1 pixels)\n- `innerRadius`: inner radius (0~1 normalized or pixels)\n- `plot.padding`: padding (avoid clipping hover/labels)\n- `plot.centerOffset`: center offset\n\n### 5.2 hover (PieHoverSettings)\n\n- `hover.enabled`: enable\n- `hover.explodeType`:\n - `Translate`: translate the whole ring\n - `Pull`: pull/stretch\n - `Color`: brighten\n - `Stroke`: stroke emphasis\n- `hover.explodeDistance`: translate/pull distance (pixels)\n\n### 5.3 Background ring and spacing\n\n- `showBackground`: draw background ring\n- `backgroundAlpha`: background ring alpha (multiplied into final color alpha)\n- `backgroundColor`: background ring color (when alpha=0, it falls back to ring color)\n- `ringGapPx`: gap between rings\n- `cornerRadius`: rounded cap (limited by ring thickness)\n\n---\n\n## 6. Legend and hide interaction (shared HiddenPieSliceIds with Pie)\n\n- RingChart shares `ChartInteractionState.HiddenPieSliceIds` with Pie.\n- Hidden key for each ring: prefer `SeriesData.id`, otherwise use the index string.\n- Legend label source is affected by `PieLegendSettings.source`:\n - `RingSlice` prefers `polarAxes.angleAxis.labels`.\n\n---\n\n## 7. Labels (SerieLabelSettings)\n\nRingChart labels also use `Serie.labelSettings`:\n\n- `show`: whether to show\n- `showName`: whether to show name\n- `decimalPlaces`: decimals (note: this displays the raw `value`, not a percent text multiplied by 100)\n- `position`:\n - `Outside`: outside label + leader line\n - `Center`: centered on the ring\n\n---\n\n## 6. Common pitfalls (by symptoms)\n\n- **I thought it was a donut pie, but it looks wrong**\n - This is a multi-ring progress chart: each point is one progress ring\n\n- **Progress is wrong (e.g. I set 75 but it is almost full)**\n - `value>1` is treated as percent and divided by 100\n - For 75%: use `0.75` or `75`\n\n- **Some rings are not visible**\n - Check whether `value <= 0` is being filtered\n\n- **Interaction/hidden state is unstable**\n - Ensure `SeriesData.id` is stable\n\n---\n\n## 8. Further reading\n\n- Pie (composition/proportion): `03_06-PieChart.md`\n- Series data structure: `00_02-WorkflowAndLibrary.md`\n" },
|
||
{ id: "04_08-CommonRecipes", relPath: "04_08-CommonRecipes.md", title: "Common Recipes", content: "\n# Common Recipes\n\nThis chapter provides copy-ready recipes for common charts (Series + Axes + common pitfalls) to help you create and troubleshoot quickly.\n\n---\n\n## 0. Before you start: minimum checklist\n\nWhen you see \"nothing shows\" or \"it looks weird\", check in this order:\n\n1. Does `coordinateSystem` match the SeriesType (Cartesian2D vs Polar2D)\n2. Does `series` contain at least 1 serie, and does that serie have `seriesData.Count > 0`\n3. Do axis types match what your data means:\n - Category axis: `labels` is not empty, and data `x/y` are indices (0/1/2...)\n - Value axis: data `x/y` are continuous numeric values\n4. Do you have any NaN/Infinity\n5. Did you lock Value axis range (`autoRangeMin/autoRangeMax` or fixed min/max) so data is outside the range\n\n---\n\n## 1. Line chart (Line): Category X + numeric Y\n\n### Target\n\n- X: category labels (A/B/C/D)\n- Y: numeric values\n- line points aligned to categories\n\n### Recipe\n\n1. `coordinateSystem = Cartesian2D`\n2. X axis:\n - `axisType = Category`\n - `labels = [A, B, C, D]`\n - `LabelPlacement = Tick`\n3. Y axis:\n - `axisType = Value`\n - `autoRangeMin/autoRangeMax = true`\n4. Series:\n - `type = Line`\n - points: `x=category index`, `y=value`\n\nData example (conceptual):\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### Common pitfalls\n\n- **Points do not align with labels**: check `x` starts from 0 and is within range (labels.Count)\n- **Line looks broken/jumpy**: check NaN/Infinity\n\n---\n\n## 2. Bar chart (Bar): centered categories + Y starts from 0\n\n### Target\n\n- one bar per category\n- labels centered under bars\n- Y axis starts from 0 to avoid misleading scaling\n\n### Recipe\n\n1. `coordinateSystem = Cartesian2D`\n2. X axis:\n - `axisType = Category`\n - fill `labels` with categories\n - `LabelPlacement = CellCenter`\n3. Y axis:\n - `axisType = Value`\n - force start at 0 (e.g. `minValue=0` + `autoRangeMax=true`, or equivalent)\n4. Series:\n - `type = Bar`\n - adjust bar width via `BarSettings.barWidth`\n\nData example:\n\n```txt\n(x=0, y=12)\n(x=1, y=18)\n(x=2, y=9)\n```\n\n### Common pitfalls\n\n- **Bars appear between labels**: switch `LabelPlacement` to `CellCenter`\n- **Bars too dense/too sparse**: adjust `barWidth`, `barGap`, `categoryGap`\n\n---\n\n## 3. Grouped bars (Grouped Bar): multiple series share the same categories\n\n### Recipe\n\n- multiple `Serie`, all `type = Bar`\n- each Serie uses the same `x=category index` convention\n- use `Serie.name` as group name (used by legend/tooltip)\n\nExample (conceptual):\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 bars (Stacked Bar): stacked + stackGroup\n\n### Recipe\n\n- Bar series that should stack:\n - `BarSettings.stacked = true`\n - `BarSettings.stackGroup = \"Group1\"` (same group stacks)\n\n### Common pitfalls\n\n- **Stack height looks wrong**: ensure all stacked series use exactly the same `stackGroup`\n\n---\n\n## 5. Scatter chart (Scatter): Value X/Y + hover + sizeMapping\n\n### Target\n\n- X/Y are continuous numeric values\n- point grows on hover\n- point size can be mapped by a dimension (sizeMapping)\n\n### Recipe\n\n1. `coordinateSystem = Cartesian2D`\n2. Set both X/Y axes to `Value`\n3. `type = Scatter`\n4. Data points: at least `x/value`, optionally use `z` as third dimension\n5. `ScatterSettings.hover.enabled = true`\n\n### Common pitfalls\n\n- **Points are too small**: increase `PointSettings.size`\n- **Hover does not respond**: check `HoverHighlightSettings.enabled` and `pickRadius`\n\n---\n\n## 6. Heatmap chart (Heatmap): (x, y, value) triplets\n\n### Target\n\n- X/Y are Category axes (2D labels)\n- color is determined by value\n\n### Recipe\n\n1. `coordinateSystem = Cartesian2D`\n2. X axis: Category + labels (column labels)\n3. Y axis: Category + labels (row labels)\n4. `type = Heatmap`\n5. Data points:\n - `x = column index`\n - `y = row index`\n - `value = intensity`\n\nExample (conceptual):\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### Common pitfalls\n\n- **All cells look the same**: check `HeatmapSettings.autoRange/minValue/maxValue/clamp`\n- **Cells too small/too dense**: adjust `cellSizePx` / `cellGapPx`\n\n---\n\n## 7. Radar chart (Radar): dimension index + value\n\n### Recipe\n\n1. `coordinateSystem = Polar2D`\n2. `type = Radar`\n3. Data points:\n - `x = dimension index`\n - `value = numeric value`\n - `name = dimension name` (recommended for labels/tooltip)\n\nExample:\n\n```txt\n(x=0, value=72, name=\"Attack\")\n(x=1, value=55, name=\"Defense\")\n(x=2, value=90, name=\"Speed\")\n```\n\n### Common pitfalls\n\n- **Radar labels are missing/messy**: ensure your dimension label source is consistent (do not depend on Cartesian axes)\n- **Radar not visible**: check `coordinateSystem` is Polar2D\n\n---\n\n## 8. Interaction/tooltip stability: SeriesData.id\n\nIf you enabled selection/tooltip/hover, it is generally recommended:\n\n- keep each point `SeriesData.id` stable\n\n> Otherwise, if you generate new ids every refresh, interaction state cannot be associated correctly.\n\n---\n\n## Next\n\n- Next: `04_09-FAQ.md` (common issues + the fastest troubleshooting path)\n" },
|
||
{ id: "04_09-FAQ", relPath: "04_09-FAQ.md", title: "FAQ (Common Issues and the Fastest Troubleshooting Path)", content: "# FAQ (Common Issues and the Fastest Troubleshooting Path)\n\nThis chapter helps you locate the cause with the shortest path when you encounter \"nothing shows\", \"wrong rendering\", or \"weird interactions\".\n\n---\n\n## 0. Fast troubleshooting path (30-second version)\n\nCheck in order. This usually solves 80% of issues:\n\n1. **Does coordinate system match SeriesType**\n - Cartesian2D: Line/Bar/Scatter/Heatmap\n - Polar2D: Radar\n\n2. **Do you actually have data**\n - `series.Count > 0`\n - the serie has `seriesData.Count > 0`\n\n3. **Do axis types match what your data means**\n - Category axis: `labels` is not empty; data `x/y` are indices (0/1/2...)\n - Value axis: `x/y` are continuous numeric values\n\n4. **Any NaN / Infinity**\n\n5. **Is data excluded by Value axis range**\n - Check if min/max are fixed\n - Check if `autoRangeMin/autoRangeMax` are disabled\n\n---\n\n## 1. I clicked Preview but nothing shows\n\n### Possible causes\n\n- `seriesData` is empty\n- `Serie.visible = false`\n- coordinate system does not match SerieType (e.g. Radar in Cartesian2D)\n- axis range does not include your data (common when Value axis range is locked manually)\n\n### What to do\n\n1. In the Inspector, find `series` and expand a Serie\n2. Check:\n - whether `visible` is true\n - whether `seriesData` has any elements\n3. Check the coordinate system:\n - Radar -> `coordinateSystem = Polar2D`\n - Line/Bar/Scatter/Heatmap -> `coordinateSystem = Cartesian2D`\n4. If you are using Value axes:\n - first disable any \"fixed min/max\" range settings\n - enable both `autoRangeMin/autoRangeMax`, confirm it renders, then lock step-by-step\n\n---\n\n## 2. Category axis has labels, but points/bars are not on labels\n\n### Typical symptoms\n\n- bars appear between two labels\n- line points do not align to A/B/C\n\n### Quick conclusion\n\n- With a Category axis, `x` (or `y`) should usually be the **category index** (0/1/2/...), not an arbitrary value.\n\n### What to do\n\n- Check your data points:\n - `labels[0]` corresponds to `x=0`\n - `labels[1]` corresponds to `x=1`\n- If you are making a bar chart:\n - set `LabelPlacement` to `CellCenter`\n\n---\n\n## 3. Value axis range is weird (too large/too small)\n\n### Possible causes\n\n- Value axis range is locked (min/max)\n- only one side is locked but the other side has extreme values\n- rounding/unit snapped the range to an unsuitable unit\n\n### What to do\n\n1. First, revert to full auto range and confirm it renders\n2. Then gradually add your constraints:\n - common for bar charts: `minValue=0` + `autoRangeMax=true`\n3. If you see lots of weird decimal ticks:\n - set `labelFormat` first\n\n---\n\n## 4. Line is broken / nothing renders\n\n### Most common cause\n\n- NaN / Infinity exists in your data\n\n### What to do\n\n- Filter at the data source:\n - `float.IsNaN(x/y/z)`\n - `float.IsInfinity(x/y/z)`\n\n---\n\n## 5. Bar chart and labels do not align\n\n### Quick conclusion\n\n- 99% of the time, `LabelPlacement` is not the right one\n\n### What to do\n\n- Bar: prefer `LabelPlacement = CellCenter`\n- Line/Scatter: prefer `LabelPlacement = Tick`\n\n---\n\n## 6. Heatmap is all one color / looks flat\n\n### Possible causes\n\n- `autoRange=false` but `minValue/maxValue` are unreasonable\n- `clamp=false` and extreme values stretch the color range\n- all data points have the same `value` (or all are 0)\n\n### What to do\n\n1. Enable `autoRange`\n2. Check whether data point `value` varies\n3. If you need a fixed range:\n - set `minValue/maxValue` reasonably\n\n---\n\n## 7. Radar labels are missing/messy\n\n### Common cause\n\n- dimension label sources are inconsistent\n\n### Recommended approach\n\n- For each Radar point:\n - `x = dimension index`\n - `value = numeric value`\n - `name = dimension name`\n\nAlso ensure Radar does not rely on Cartesian axis configuration to obtain labels.\n\n---\n\n## 8. tooltip/hover/selection points to the wrong item or state is unstable\n\n### Common cause\n\n- new point identifiers are generated on every refresh\n\n### What to do\n\n- keep each point `SeriesData.id` stable\n- avoid clearing and generating a completely new set of points with `Guid.NewGuid()` on every refresh\n\n---\n\n## 9. I don't know which chapter to read\n\n- If you are in the workflow stage (create/clone/preview/export): see `01_01-EditorWorkflow.md`\n- If you are dealing with axes/range/alignment/unit/format: see section 7 of `00_02-WorkflowAndLibrary.md`\n- If you need the data conventions for a specific chart (SeriesData.x/y/z): see section 8 of `00_02-WorkflowAndLibrary.md`\n- If you just want copy-ready templates: see `04_08-CommonRecipes.md`\n" },
|
||
{ id: "05_01-UpdatePlan", relPath: "05_01-UpdatePlan.md", title: "Roadmap / Update Plan", content: "# Roadmap / Update Plan\n\nThis chapter describes the overall direction and planned items for future EasyChart updates.\n\n- This file is **not split by version phases** (more detailed planning can be added inside each chart type chapter later)\n- This file is organized by \"capability categories\" (you can treat it as a roadmap table of contents)\n\n## Free / Pro split (release strategy)\n\n### Free (standalone package)\n\n- Positioning: cover the most common AssetStore use cases, forming a full loop of \"configurable + previewable + runtime data injection\".\n- Includes: existing basic 2D chart types, runtime injection (`ChartFeed` / `ApplyJson`), editor workflow such as `EasyChartLibraryWindow`.\n\n### Pro (standalone package, includes all Free)\n\n- Positioning: provide clear differentiated capabilities and a long-term expansion path on top of Free.\n- Includes: everything in Free + Pro incremental features (advanced effects / new chart types / 3D / tooling, etc.).\n\n### Compatibility strategy\n\n- When Free encounters Pro-only assets/configurations: it is allowed to fail with a direct error (no downgrade compatibility required).\n\n### Pro initial selling points priority\n\n- A: new chart types\n- B: 3D charts\n- C: advanced 2D visual effects (e.g. texture UV animation, special rendering effects)\n\n---\n\n## Appendix: version plan (tentative timeline)\n\n> Note: the following is a tentative monthly/quarterly cadence. Specific dates can be refined after team capacity and release window are confirmed.\n\n### 2026 Q1 (Jan–Mar): stabilization + complete Free loop\n\n- 2026-01 (Free v1.0.x):\n - Fix/finalize: stability of JSON Injection panel and example generation/parsing (based on current TODO)\n - Docs & samples: align with the latest data structures and panel capabilities\n- 2026-02 (Free v1.1.0):\n - 2D UX improvements (Free scope): Bar rounded corners, hover effects (if not implemented yet, land in this version)\n - Editor UX: small workflow improvements in LibraryWindow (no Pro dependencies)\n- 2026-03 (Free v1.1.x):\n - Regression fixes + performance/GC optimization (large data refresh, tooltip/interaction stability)\n\n### 2026 Q2 (Apr–Jun): Pro v1.0 (new chart types first)\n\nEach series type adds an animation component collection, allowing effects such as Point blinking and TextureFill UV animation.\n- 2026-04 (Pro v1.0.0):\n - Finalize Pro package structure and release workflow (Pro includes all Free)\n - New chart types (batch 1): Gauge / Funnel (one or both depending on complexity)\n- 2026-05 (Pro v1.0.x):\n - New chart types (batch 2): BoxPlot / Candlestick (implement one with higher priority)\n - Improve Pro-only error hints and readable Editor-side error messages\n- 2026-06 (Free v1.2.0 + Pro v1.1.0):\n - Free: continue filling common 2D capabilities and stability\n - Pro: expand new chart types (Treemap / Sunburst research or first version)\n\n### 2026 H2 (Jul–Dec): 3D roadmap and effects\n\n- 2026 Q3 (Jul–Sep) (Pro v2.0 or v1.2+):\n - 3D charts (batch 1): 3D Bar / 3D Scatter (prioritize one to complete an end-to-end workflow)\n - 3D rendering pipeline and interaction foundations (iterate by minimum viable slices)\n- 2026 Q4 (Oct–Dec):\n - 3D Surface (research/experimental)\n - Advanced 2D visual effects (Pro): texture UV animation (and more complex effects later)\n - Tooling improvements: Theme / direct networking / automated tests (pick one as the main quality track)\n\n---\n\n## 1. Chart type expansion plan (Chart Types)\n\n### 1.1 2D charts (enhancements to existing system)\n\n- Goal: without adding too many `SerieType`, fill common expressions via settings/variants.\n- Candidate directions (examples):\n - Line: more line types/fills/annotations (richer markers/threshold lines, etc.), texture UV animation (Pro)\n - Bar: more stacking modes, percent stacking, waterfall modes, rounded bar caps (Free), hover effects (Free), texture UV animation (Pro)\n - Scatter: more mapping dimensions (size/color), density expressions (aggregation/gridding)\n - Pie: more layout/aggregation strategies, label strategies, interactions\n\n### 1.2 New chart types (may add new `SerieType`)\n\n- Goal: support more common standalone chart categories in AssetStore.\n- Candidate directions (examples):\n - Gauge\n - Funnel\n - BoxPlot\n - Candlestick (OHLC)\n - Treemap / Sunburst (hierarchical visualization)\n - Sankey / Graph (more complex structural charts; later)\n\n### 1.3 3D charts (3D Charts)\n\n- Goal: provide a 3D chart capability set (possibly a separate rendering pipeline).\n- Candidate directions (examples):\n - 3D Bar / 3D Column\n - 3D Scatter\n - 3D Surface (higher complexity; later)\n\n---\n\n## 2. Multi-axis & coordinate systems\n\n- Goal: enhance multi-axis scenarios while keeping semantics clear.\n- Directions:\n - more axis combinations (dual Y axes, top/bottom X, mixed left/right Y)\n - clearer axis binding strategy (which axis a Serie binds to, which axis tooltip/label formats with)\n - constraints and hints for switching/mixing coordinate systems (avoid confusing configs)\n\n---\n\n## 3. Font & text system\n\n- Goal: unify text rendering look and configurable options, reducing UI Toolkit cross-platform differences.\n- Directions:\n - more complete text styles (font, size, weight, color, outline/shadow, etc.)\n - text layout strategies (wrap, truncate, ellipsis, alignment, anchors)\n - enhanced number formatting (thousands separator, units, percent, scientific notation, etc.)\n\n---\n\n## 4. Time axis & log axis\n\n- Goal: improve expression for time series and wide-range values.\n- Directions:\n - time axis: ticks, formatting, interval strategies (day/week/month/year)\n - log axis: log10/log2 ticks and labels\n - integration with data injection (how to feed time data, handle missing points)\n\n---\n\n## 5. Theme / palette system\n\n- Goal: abstract \"colors/fonts/default styles\" from individual Profiles into reusable themes.\n- Directions:\n - Theme assets (Palette + fonts + default styles)\n - override strategy between Profile and Theme (theme defaults vs Profile overrides)\n - theme preview, switching, theme library\n\n---\n\n## 6. Direct networking / data binding\n\n- Goal: reduce integration cost from network API to chart.\n- Directions:\n - standard input protocol based on `ChartFeed`\n - optional API Envelope support (e.g. `{code,message,data}`)\n - samples: HTTP fetch -> parse -> Apply\n - caching, throttling, error hints, fallback strategies\n\n---\n\n## 7. Automated tests & QA\n\n- Goal: reduce iteration risk and make refactors safer.\n- Directions:\n - data migration tests (serialization compatibility)\n - rendering regression tests (screenshot diff/pixel tolerance, or key mesh assertions)\n - interaction tests (tooltip/hit test stability)\n - performance benchmarks (large data refresh, GC, frame time)\n\n---\n\n## 8. Editor workflow & tooling\n\n- Goal: make configuration, preview, injection, and reuse smoother.\n- Directions:\n - LibraryWindow: templates/copy/import-export/batch operations\n - JSON Injection: stronger protocol compatibility, better error localization, better example generation\n - clearer manual and sample project\n" }
|
||
];
|