@fui-org/fui-cli 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -2
- package/dist/fui.js +347 -44
- package/package.json +15 -3
- package/skills/fui/SKILL.md +149 -66
- package/skills/fui-skill/README.md +112 -0
- package/skills/fui-skill/SKILL.md +269 -0
- package/skills/fui-skill/assets/projectdefaultstyle.css +518 -0
- package/skills/fui-skill/design-md/airbnb/DESIGN.md +545 -0
- package/skills/fui-skill/design-md/airbnb/README.md +5 -0
- package/skills/fui-skill/design-md/airtable/DESIGN.md +554 -0
- package/skills/fui-skill/design-md/airtable/README.md +5 -0
- package/skills/fui-skill/design-md/apple/DESIGN.md +562 -0
- package/skills/fui-skill/design-md/apple/README.md +5 -0
- package/skills/fui-skill/design-md/asu/DESIGN.md +179 -0
- package/skills/fui-skill/design-md/asu/README.md +107 -0
- package/skills/fui-skill/design-md/binance/DESIGN.md +634 -0
- package/skills/fui-skill/design-md/binance/README.md +5 -0
- package/skills/fui-skill/design-md/bmw/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/bmw/README.md +5 -0
- package/skills/fui-skill/design-md/bmw-m/DESIGN.md +503 -0
- package/skills/fui-skill/design-md/bmw-m/README.md +5 -0
- package/skills/fui-skill/design-md/bugatti/DESIGN.md +454 -0
- package/skills/fui-skill/design-md/bugatti/README.md +5 -0
- package/skills/fui-skill/design-md/cal/DESIGN.md +542 -0
- package/skills/fui-skill/design-md/cal/README.md +5 -0
- package/skills/fui-skill/design-md/claude/DESIGN.md +589 -0
- package/skills/fui-skill/design-md/claude/README.md +5 -0
- package/skills/fui-skill/design-md/clay/DESIGN.md +541 -0
- package/skills/fui-skill/design-md/clay/README.md +5 -0
- package/skills/fui-skill/design-md/clickhouse/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/clickhouse/README.md +5 -0
- package/skills/fui-skill/design-md/cohere/DESIGN.md +451 -0
- package/skills/fui-skill/design-md/cohere/README.md +5 -0
- package/skills/fui-skill/design-md/coinbase/DESIGN.md +570 -0
- package/skills/fui-skill/design-md/coinbase/README.md +5 -0
- package/skills/fui-skill/design-md/composio/DESIGN.md +506 -0
- package/skills/fui-skill/design-md/composio/README.md +5 -0
- package/skills/fui-skill/design-md/cursor/DESIGN.md +537 -0
- package/skills/fui-skill/design-md/cursor/README.md +5 -0
- package/skills/fui-skill/design-md/elevenlabs/DESIGN.md +504 -0
- package/skills/fui-skill/design-md/elevenlabs/README.md +5 -0
- package/skills/fui-skill/design-md/expo/DESIGN.md +526 -0
- package/skills/fui-skill/design-md/expo/README.md +5 -0
- package/skills/fui-skill/design-md/ferrari/DESIGN.md +531 -0
- package/skills/fui-skill/design-md/ferrari/README.md +5 -0
- package/skills/fui-skill/design-md/figma/DESIGN.md +578 -0
- package/skills/fui-skill/design-md/figma/README.md +5 -0
- package/skills/fui-skill/design-md/framer/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/framer/README.md +5 -0
- package/skills/fui-skill/design-md/fui/DESIGN.md +532 -0
- package/skills/fui-skill/design-md/hashicorp/DESIGN.md +575 -0
- package/skills/fui-skill/design-md/hashicorp/README.md +5 -0
- package/skills/fui-skill/design-md/ibm/DESIGN.md +550 -0
- package/skills/fui-skill/design-md/ibm/README.md +5 -0
- package/skills/fui-skill/design-md/intercom/DESIGN.md +546 -0
- package/skills/fui-skill/design-md/intercom/README.md +5 -0
- package/skills/fui-skill/design-md/kraken/DESIGN.md +125 -0
- package/skills/fui-skill/design-md/kraken/README.md +5 -0
- package/skills/fui-skill/design-md/lamborghini/DESIGN.md +288 -0
- package/skills/fui-skill/design-md/lamborghini/README.md +5 -0
- package/skills/fui-skill/design-md/linear.app/DESIGN.md +548 -0
- package/skills/fui-skill/design-md/linear.app/README.md +5 -0
- package/skills/fui-skill/design-md/lovable/DESIGN.md +298 -0
- package/skills/fui-skill/design-md/lovable/README.md +5 -0
- package/skills/fui-skill/design-md/mastercard/DESIGN.md +365 -0
- package/skills/fui-skill/design-md/mastercard/README.md +5 -0
- package/skills/fui-skill/design-md/meta/DESIGN.md +683 -0
- package/skills/fui-skill/design-md/meta/README.md +5 -0
- package/skills/fui-skill/design-md/minimax/DESIGN.md +746 -0
- package/skills/fui-skill/design-md/minimax/README.md +5 -0
- package/skills/fui-skill/design-md/mintlify/DESIGN.md +852 -0
- package/skills/fui-skill/design-md/mintlify/README.md +5 -0
- package/skills/fui-skill/design-md/miro/DESIGN.md +825 -0
- package/skills/fui-skill/design-md/miro/README.md +5 -0
- package/skills/fui-skill/design-md/mistral.ai/DESIGN.md +773 -0
- package/skills/fui-skill/design-md/mistral.ai/README.md +5 -0
- package/skills/fui-skill/design-md/mongodb/DESIGN.md +767 -0
- package/skills/fui-skill/design-md/mongodb/README.md +5 -0
- package/skills/fui-skill/design-md/nike/DESIGN.md +575 -0
- package/skills/fui-skill/design-md/nike/README.md +5 -0
- package/skills/fui-skill/design-md/notion/DESIGN.md +821 -0
- package/skills/fui-skill/design-md/notion/README.md +5 -0
- package/skills/fui-skill/design-md/nvidia/DESIGN.md +640 -0
- package/skills/fui-skill/design-md/nvidia/README.md +5 -0
- package/skills/fui-skill/design-md/ollama/DESIGN.md +539 -0
- package/skills/fui-skill/design-md/ollama/README.md +5 -0
- package/skills/fui-skill/design-md/opencode.ai/DESIGN.md +521 -0
- package/skills/fui-skill/design-md/opencode.ai/README.md +5 -0
- package/skills/fui-skill/design-md/pinterest/DESIGN.md +597 -0
- package/skills/fui-skill/design-md/pinterest/README.md +5 -0
- package/skills/fui-skill/design-md/playstation/DESIGN.md +661 -0
- package/skills/fui-skill/design-md/playstation/README.md +5 -0
- package/skills/fui-skill/design-md/posthog/DESIGN.md +690 -0
- package/skills/fui-skill/design-md/posthog/README.md +5 -0
- package/skills/fui-skill/design-md/raycast/DESIGN.md +669 -0
- package/skills/fui-skill/design-md/raycast/README.md +5 -0
- package/skills/fui-skill/design-md/renault/DESIGN.md +589 -0
- package/skills/fui-skill/design-md/renault/README.md +5 -0
- package/skills/fui-skill/design-md/replicate/DESIGN.md +616 -0
- package/skills/fui-skill/design-md/replicate/README.md +5 -0
- package/skills/fui-skill/design-md/resend/DESIGN.md +585 -0
- package/skills/fui-skill/design-md/resend/README.md +5 -0
- package/skills/fui-skill/design-md/revolut/DESIGN.md +636 -0
- package/skills/fui-skill/design-md/revolut/README.md +5 -0
- package/skills/fui-skill/design-md/runwayml/DESIGN.md +244 -0
- package/skills/fui-skill/design-md/runwayml/README.md +5 -0
- package/skills/fui-skill/design-md/sanity/DESIGN.md +357 -0
- package/skills/fui-skill/design-md/sanity/README.md +5 -0
- package/skills/fui-skill/design-md/sentry/DESIGN.md +551 -0
- package/skills/fui-skill/design-md/sentry/README.md +5 -0
- package/skills/fui-skill/design-md/shopify/DESIGN.md +516 -0
- package/skills/fui-skill/design-md/shopify/README.md +5 -0
- package/skills/fui-skill/design-md/slack/DESIGN.md +482 -0
- package/skills/fui-skill/design-md/spacex/DESIGN.md +363 -0
- package/skills/fui-skill/design-md/spacex/README.md +5 -0
- package/skills/fui-skill/design-md/spotify/DESIGN.md +246 -0
- package/skills/fui-skill/design-md/spotify/README.md +5 -0
- package/skills/fui-skill/design-md/starbucks/DESIGN.md +580 -0
- package/skills/fui-skill/design-md/starbucks/README.md +5 -0
- package/skills/fui-skill/design-md/stripe/DESIGN.md +487 -0
- package/skills/fui-skill/design-md/stripe/README.md +5 -0
- package/skills/fui-skill/design-md/supabase/DESIGN.md +462 -0
- package/skills/fui-skill/design-md/supabase/README.md +5 -0
- package/skills/fui-skill/design-md/superhuman/DESIGN.md +448 -0
- package/skills/fui-skill/design-md/superhuman/README.md +5 -0
- package/skills/fui-skill/design-md/tesla/DESIGN.md +286 -0
- package/skills/fui-skill/design-md/tesla/README.md +5 -0
- package/skills/fui-skill/design-md/theverge/DESIGN.md +339 -0
- package/skills/fui-skill/design-md/theverge/README.md +5 -0
- package/skills/fui-skill/design-md/together.ai/DESIGN.md +633 -0
- package/skills/fui-skill/design-md/together.ai/README.md +5 -0
- package/skills/fui-skill/design-md/uber/DESIGN.md +636 -0
- package/skills/fui-skill/design-md/uber/README.md +5 -0
- package/skills/fui-skill/design-md/vercel/DESIGN.md +736 -0
- package/skills/fui-skill/design-md/vercel/README.md +5 -0
- package/skills/fui-skill/design-md/vodafone/DESIGN.md +538 -0
- package/skills/fui-skill/design-md/vodafone/README.md +5 -0
- package/skills/fui-skill/design-md/voltagent/DESIGN.md +521 -0
- package/skills/fui-skill/design-md/voltagent/README.md +5 -0
- package/skills/fui-skill/design-md/warp/DESIGN.md +526 -0
- package/skills/fui-skill/design-md/warp/README.md +5 -0
- package/skills/fui-skill/design-md/webflow/DESIGN.md +588 -0
- package/skills/fui-skill/design-md/webflow/README.md +5 -0
- package/skills/fui-skill/design-md/wired/DESIGN.md +497 -0
- package/skills/fui-skill/design-md/wired/README.md +5 -0
- package/skills/fui-skill/design-md/wise/DESIGN.md +544 -0
- package/skills/fui-skill/design-md/wise/README.md +5 -0
- package/skills/fui-skill/design-md/x.ai/DESIGN.md +465 -0
- package/skills/fui-skill/design-md/x.ai/README.md +5 -0
- package/skills/fui-skill/design-md/zapier/DESIGN.md +537 -0
- package/skills/fui-skill/design-md/zapier/README.md +5 -0
- package/skills/fui-skill/examples/component.vue +162 -0
- package/skills/fui-skill/examples/f-table-patterns.json +331 -0
- package/skills/fui-skill/examples/module-patterns.json +973 -0
- package/skills/fui-skill/examples/project-patterns.json +222 -0
- package/skills/fui-skill/metadata.json +75 -0
- package/skills/fui-skill/references/INDEX.md +144 -0
- package/skills/fui-skill/references/advanced-techniques.md +160 -0
- package/skills/fui-skill/references/coding-standards.md +112 -0
- package/skills/fui-skill/references/component-design.md +455 -0
- package/skills/fui-skill/references/component-quickref.md +77 -0
- package/skills/fui-skill/references/component-table.md +276 -0
- package/skills/fui-skill/references/components-dialog.md +192 -0
- package/skills/fui-skill/references/components-display.md +147 -0
- package/skills/fui-skill/references/components-echart.md +391 -0
- package/skills/fui-skill/references/components-input.md +359 -0
- package/skills/fui-skill/references/controls-patterns.md +847 -0
- package/skills/fui-skill/references/controls-styling-vocabulary.md +140 -0
- package/skills/fui-skill/references/db-table-design.md +77 -0
- package/skills/fui-skill/references/db-workflow.md +504 -0
- package/skills/fui-skill/references/default-function.md +415 -0
- package/skills/fui-skill/references/design-modes.md +85 -0
- package/skills/fui-skill/references/echart-templates.md +481 -0
- package/skills/fui-skill/references/fastproject.md +97 -0
- package/skills/fui-skill/references/fsheet.md +218 -0
- package/skills/fui-skill/references/fullstack-workflow.md +351 -0
- package/skills/fui-skill/references/module-data-patterns.md +126 -0
- package/skills/fui-skill/references/module-json-anatomy.md +137 -0
- package/skills/fui-skill/references/module-structure.md +260 -0
- package/skills/fui-skill/references/new-session.md +108 -0
- package/skills/fui-skill/references/pdfmake.md +60 -0
- package/skills/fui-skill/references/permission-system.md +169 -0
- package/skills/fui-skill/references/platform-architecture.md +294 -0
- package/skills/fui-skill/references/project-config.md +335 -0
- package/skills/fui-skill/references/project-provisioning.md +383 -0
- package/skills/fui-skill/references/script-map.md +296 -0
- package/skills/fui-skill/references/sql-clr-functions.md +224 -0
- package/skills/fui-skill/references/system-design.md +116 -0
- package/skills/fui-skill/references/tapi-file-api.md +191 -0
- package/skills/fui-skill/references/tapi-permission-patterns.md +158 -0
- package/skills/fui-skill/references/tapi-reference.md +549 -0
- package/skills/fui-skill/references/tools-registry.md +460 -0
- package/skills/fui-skill/references/ui-crosswindow-patterns.md +317 -0
- package/skills/fui-skill/references/ui-dialog-patterns.md +229 -0
- package/skills/fui-skill/references/ui-layout-patterns.md +176 -0
- package/skills/fui-skill/references/ui-patterns.md +315 -0
- package/skills/fui-skill/references/ui-screenshot-review.md +94 -0
- package/skills/fui-skill/references/ui-table-cell-patterns.md +316 -0
- package/skills/fui-skill/references/ui-templates.md +29 -0
- package/skills/fui-skill/references/verification.md +246 -0
- package/skills/fui-skill/references/watcher-patterns.md +196 -0
- package/skills/fui-skill/references/websocket-realtime.md +254 -0
- package/skills/fui-skill/scripts/component-3.0.js +2549 -0
- package/skills/fui-skill/scripts/component.js +3142 -0
- package/skills/fui-skill/scripts/componentTable-3.0.js +909 -0
- package/skills/fui-skill/scripts/componentTable.js +769 -0
- package/skills/fui-skill/scripts/defaultfunction-3.0.js +781 -0
- package/skills/fui-skill/scripts/defaultfunction.js +966 -0
- package/skills/fui-skill/scripts/fastproject-3.0.js +870 -0
- package/skills/fui-skill/scripts/fastproject.js +828 -0
- package/skills/fui-skill/scripts/fechart.js +890 -0
- package/skills/fui-skill/scripts/fsheet.js +1330 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
# f-echart — Biểu đồ ECharts V5 (Core)
|
|
2
|
+
|
|
3
|
+
> File này sở hữu: **`f-echart` core: import, kiến trúc, props, config, theme, DataView, lỗi thường gặp**. Template từng loại chart xem [echart-templates.md](echart-templates.md).
|
|
4
|
+
|
|
5
|
+
Dùng `f-echart` cho mọi loại biểu đồ: bar, line, pie, scatter, gauge, radar, heatmap, sankey, tree, map, graph...
|
|
6
|
+
|
|
7
|
+
> ⚠️ `:option` / `:config` của `f-echart` là nơi luật **"`:attr` chỉ nhận expression thuần"** hay bị vi phạm nhất — logic dựng option nhiều bước phải nằm trong hàm `script.js` gọi qua `EXE`, không nhét IIFE / `var` / `return` vào JSON (vi phạm ⇒ trang trắng, 0 JS error, 0 Vue warn). Luật đầy đủ: [advanced-techniques.md](advanced-techniques.md) §1.
|
|
8
|
+
|
|
9
|
+
File này là **core**: import, kiến trúc, props, config, theme, DataView, events, lỗi thường gặp. **Template từng loại chart + các pattern module.json** đã tách sang [echart-templates.md](echart-templates.md) — load thêm khi đã biết cần vẽ loại chart nào.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Import — Bắt buộc, đúng thứ tự
|
|
14
|
+
|
|
15
|
+
`f-echart` yêu cầu 2 file JS nền tảng. Không có → component không tồn tại, trang trắng.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
1. /include/chart/echarts.min.js ← ECharts core (phải đứng TRƯỚC)
|
|
19
|
+
2. /include/chart/fechart.js ← FUI wrapper (phải đứng SAU)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Quy trình `file_import_list` → `file_import_new` → `file_import_delete`: xem
|
|
23
|
+
[component-quickref.md](component-quickref.md). **Điểm đặc thù của f-echart** — sort number quyết
|
|
24
|
+
định thứ tự load, và `fechart.js` phụ thuộc biến `echarts` global nên **PHẢI có sort lớn hơn**
|
|
25
|
+
`echarts.min.js` (ví dụ `echarts.min.js` = 100, `fechart.js` = 110).
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Kiến trúc — Direct Mode
|
|
30
|
+
|
|
31
|
+
`f-echart` **xây dựng hoàn toàn trên Apache ECharts V5** (echarts.apache.org). `fechart.js` chỉ là lớp bọc mỏng: nạp theme, vài shortcut trong `config`, DataView, events. **Mọi thứ trong `option` chính là ECharts option** — khi cần cấu hình chart, **dùng thẳng kiến thức Apache ECharts** (option, series, axis, visualMap, dataZoom...); chỉ `config` là shortcut riêng của FUI.
|
|
32
|
+
|
|
33
|
+
`f-echart` là **Direct Mode only**. Bạn viết ECharts `option` trực tiếp — không có Auto mode, không có `config.type`.
|
|
34
|
+
|
|
35
|
+
| Prop | Vai trò |
|
|
36
|
+
|---|---|
|
|
37
|
+
| `option` | **Primary** — full ECharts option, truyền thẳng vào `echarts.setOption()`. Dùng kiến thức Apache ECharts |
|
|
38
|
+
| `config` | Meta/shortcut riêng FUI: height, theme, title, toolbox... Là defaults, bị `option` merge đè |
|
|
39
|
+
|
|
40
|
+
**Thứ tự merge:** `config` xây base → `option` merge đè lên bằng `_.merge` (lodash).
|
|
41
|
+
- Plain objects → **deep-merge**
|
|
42
|
+
- Primitives → **replace**
|
|
43
|
+
- Arrays → **merge theo chỉ số**, KHÔNG phải replace ⚠️
|
|
44
|
+
|
|
45
|
+
Bẫy của merge-theo-chỉ-số: `config` chỉ sinh ra hai mảng là `color` (từ `config.color`) và `dataZoom` (từ `config.zoom`). Nếu cả `config.color` lẫn `option.color` cùng có, mảng ngắn hơn **không xoá được đuôi của mảng dài hơn**:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
config.color = ['#111','#222','#333','#444']; option.color = ['#aaa','#bbb'];
|
|
49
|
+
// → ['#aaa','#bbb','#333','#444'] ← 2 màu cũ còn sót lại
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
⇒ Chọn **một chỗ duy nhất** để khai palette (khuyến nghị `config.color`), đừng khai cả hai. Với `series`/`xAxis`/`yAxis`/`grid` thì `config` không bao giờ sinh ra nên không có va chạm — cứ khai thoải mái trong `option`.
|
|
53
|
+
|
|
54
|
+
Sau khi merge, chart luôn được vẽ bằng `setOption(opt, true)` (**notMerge**) — mỗi lần render là thay toàn bộ option, không sót cấu hình của lần trước.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Quy ước hiển thị MẶC ĐỊNH (làm đúng ngay từ đầu, không chờ user nhắc)
|
|
59
|
+
|
|
60
|
+
Đúc kết từ các yêu cầu chỉnh sửa lặp lại nhiều lần của user thật. Áp dụng mặc định cho mọi chart mới/refactor — chỉ bỏ qua khi user yêu cầu rõ kiểu khác:
|
|
61
|
+
|
|
62
|
+
1. **Luôn hiển thị giá trị trên chart** — bar: `label: { show: true, position: 'top' }` (horizontal bar → `position: 'right'`); line: `label: { show: true, position: 'top' }`.
|
|
63
|
+
2. **Grid padding**: mặc định chart có hệ trục dùng `left: 0`, `right: 0`, `top: 50`, `bottom: 50`; `top`/`bottom` tự tăng nếu title/legend cần thêm chỗ. Chỉ khai cạnh mà user yêu cầu đổi; thêm `containLabel: true` khi nhãn trục có nguy cơ bị cắt. Xem "Grid padding và boundaryGap".
|
|
64
|
+
3. **Số hiển thị đầy đủ** có phân cách nghìn (`1,500,000`) — không rút gọn `1.5M`/`1.2k` trừ khi user yêu cầu (mặc định `formatFull` của tooltip đã đúng — đừng override).
|
|
65
|
+
4. **Pie**: không để labelLine ("râu") dài rối; label ngắn gọn (tên + % nếu cần) hoặc dồn thông tin về legend + tooltip.
|
|
66
|
+
5. **Không tự dựng nút "Xem dữ liệu"** — dùng `config.dataView: true` có sẵn của f-echart.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Props
|
|
71
|
+
|
|
72
|
+
| Prop | Type | Default | Mô tả |
|
|
73
|
+
|---|---|---|---|
|
|
74
|
+
| `config` | Object | `{}` | Shortcut settings |
|
|
75
|
+
| `option` | Object | `{}` | Full ECharts option — primary |
|
|
76
|
+
|
|
77
|
+
> Component chỉ có 2 props: `config` và `option`. **Không có `data` prop.**
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## config keys
|
|
82
|
+
|
|
83
|
+
| Key | Type | Default | Mô tả |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| `height` | number\|string | `400` | Số = `px`; string = `'50vh'`... |
|
|
86
|
+
| `theme` | string | `'fui'` | **Chỉ nhận** `'fui'`\|`'shine'`\|`'v5'`. Tên khác (kể cả theme tự `echarts.registerTheme`) và `null` đều **âm thầm rơi về `'fui'`** — đổi màu thì dùng `config.color` |
|
|
87
|
+
| `backgroundColor` | string | `'transparent'` | Override background |
|
|
88
|
+
| `title` | string | | → `option.title.text` |
|
|
89
|
+
| `subtitle` | string | | → `option.title.subtext` |
|
|
90
|
+
| `titleAlign` | string | `'center'` | `'left'`/`'center'`/`'right'` (bí danh cũ: `titleLeft`) |
|
|
91
|
+
| `titleSize` | number | `16` | Cỡ chữ title (px) |
|
|
92
|
+
| `titleColor` | string | | Màu chữ title — bỏ trống thì theo theme |
|
|
93
|
+
| `titleWeight` | string\|number | `'bold'` | `'normal'`/`'bold'`/`500`... |
|
|
94
|
+
| `titleFont` | string | | font-family cho cả title lẫn subtitle |
|
|
95
|
+
| `titleStyle` | Object | | ECharts textStyle đầy đủ — **thắng mọi key `title*` ở trên** |
|
|
96
|
+
| `subtitleSize` / `subtitleColor` / `subtitleStyle` | | `12` | Tương tự, cho subtitle |
|
|
97
|
+
| `color` | string[] | | Override color palette |
|
|
98
|
+
| `animation` | boolean | | `false` = tắt animation |
|
|
99
|
+
| `animationDuration` | number | | ms |
|
|
100
|
+
| `animationEasing` | string | | ECharts easing name |
|
|
101
|
+
| `legend` | true\|false\|Object | | `false` = ẩn; `true`/Object = bật, merge với `{ type:'scroll', left:'center' }` — **không đặt top/bottom**, vị trí dọc do layout engine tính |
|
|
102
|
+
| `legendPosition` | string | `'bottom'` | Cạnh legend neo vào: `'top'`/`'bottom'`. **Chỉ có tác dụng khi legend được bật qua `config.legend`/`config.legendConfig`** — xem "Khoảng trống & bố cục dọc" |
|
|
103
|
+
| `legendRows` | number | `1` | Số hàng legend cần chừa chỗ — đặt >1 khi nhiều mục xuống dòng. Có tác dụng với mọi cách khai legend |
|
|
104
|
+
| `legendConfig` | Object | | Extra legend props (merge sau `legend`) |
|
|
105
|
+
| `tooltip` | Object | | Merge vào default `{ confine: true }`. **Không có `trigger` mặc định** → ECharts dùng `'item'`; chart nhiều series theo trục phải tự khai `tooltip: { trigger: 'axis' }` trong `option` |
|
|
106
|
+
| `tooltipFormat` | string | `'auto'` | `'number'`/`'percent'`/`'currency'`/`'short'`/`'auto'`. `'auto'` = số đầy đủ có phân cách nghìn (`1,500,000`); `'short'` = co gọn (`1.5M`) — chỉ dùng khi user yêu cầu rõ |
|
|
107
|
+
| `decimals` | number | | Số chữ số thập phân cho `tooltipFormat` `'number'`/`'percent'`/`'currency'` |
|
|
108
|
+
| `symbol` | string | `'₫'` | Ký hiệu tiền tệ cho `tooltipFormat: 'currency'` |
|
|
109
|
+
| `tooltipFormatter` | Function | | Custom tooltip fn — **thắng `tooltipFormat`** |
|
|
110
|
+
| `toolbox` | boolean | `false` | Hiện toolbox (saveAsImage + restore) |
|
|
111
|
+
| `toolboxConfig` | Object | | Override/extend toolbox features |
|
|
112
|
+
| `dataView` | boolean | `false` | Hiện nút bảng (Vue overlay) — tự trích xuất data từ `option` |
|
|
113
|
+
| `zoom` | boolean | | dataZoom inside + slider |
|
|
114
|
+
| `zoomConfig` | Array | | Override dataZoom config |
|
|
115
|
+
| `refreshInterval` | number | | ms — auto-refresh |
|
|
116
|
+
|
|
117
|
+
**Tooltip mặc định đã đẹp sẵn — KHÔNG cần cấu hình gì thêm:** title (tên category) canh giữa, mỗi dòng series gồm chấm màu + label canh trái, giá trị canh phải, số hiển thị đầy đủ có phân cách nghìn (`2,535` chứ không phải `2.5K`). Chỉ đụng vào `tooltipFormat`/`tooltipFormatter` khi user yêu cầu format khác (`percent`, `currency`, co gọn `short`...).
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Grid padding và `boundaryGap` — chọn đúng cấu hình
|
|
122
|
+
|
|
123
|
+
Hai khái niệm này giải quyết hai loại khoảng trống khác nhau:
|
|
124
|
+
|
|
125
|
+
| User muốn thay đổi | Cấu hình đúng | Vị trí khai |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| Khoảng cách từ vùng vẽ tới mép canvas | `grid.top` / `grid.bottom` / `grid.left` / `grid.right` | `option.grid` |
|
|
128
|
+
| Khoảng hở từ điểm/cột đầu và cuối tới hai đầu trục | `boundaryGap` | ngay trong `xAxis` hoặc `yAxis` tương ứng |
|
|
129
|
+
|
|
130
|
+
`f-echart` không có prop `padding`, và `boundaryGap` không thay thế cho `grid`. Số trong `grid` là px; chuỗi như `'10%'` dùng phần trăm. Mặc định wrapper cho chart Cartesian là:
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
grid: { top: 50, bottom: 50, left: 0, right: 0 }
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`top`/`bottom` là mức tối thiểu: layout engine có thể tăng để tránh title/legend. Mỗi cạnh user khai trong `option.grid` sẽ thắng mặc định và không còn được engine tự tính. Vì vậy, nếu user chỉ yêu cầu đổi padding ngang, chỉ khai hai cạnh ngang:
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
grid: { left: 12, right: 24, containLabel: true }
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Nếu user yêu cầu con số chính xác cho cả bốn cạnh, khai đủ bốn cạnh; cần kiểm tra title/legend không đè vùng vẽ:
|
|
143
|
+
|
|
144
|
+
```js
|
|
145
|
+
grid: { top: 40, bottom: 60, left: 12, right: 24, containLabel: true }
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`containLabel: true` giúp giữ nhãn trục trong vùng `grid`; dùng khi nhãn dài hoặc sát mép. `grid` chỉ điều khiển chart Cartesian có `xAxis`/`yAxis`. Pie, funnel, treemap, sankey và graph bỏ qua `grid`; chỉnh khoảng trống của chúng bằng `series.top` / `bottom` / `left` / `right` (hoặc `center` / `radius` theo loại chart).
|
|
149
|
+
|
|
150
|
+
`fechart.js` không đặt `boundaryGap`, nên giữ mặc định ECharts:
|
|
151
|
+
|
|
152
|
+
- Trục `category`: `boundaryGap: true`.
|
|
153
|
+
- Trục `value`, `time`, `log`: `boundaryGap: [0, 0]`.
|
|
154
|
+
|
|
155
|
+
Khi user muốn line chart chạm hai đầu trục category, đặt `boundaryGap: false` trên chính trục category:
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
xAxis: { type: 'category', boundaryGap: false, data: labels }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Bar chart thường giữ `boundaryGap: true` để cột đầu/cuối không bị ép sát mép. Với horizontal bar, trục category là `yAxis`, nên đặt ở `yAxis.boundaryGap`. Với trục `value`/`time`, có thể chừa biên theo hai phía:
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
xAxis: { type: 'time', boundaryGap: ['5%', '5%'] }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Khi user nói "bỏ khoảng trắng hai đầu đường dữ liệu", ưu tiên kiểm tra `boundaryGap`; khi user nói "giảm padding quanh biểu đồ/canvas", chỉnh `grid`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Khoảng trống & bố cục dọc (layout box model)
|
|
172
|
+
|
|
173
|
+
ECharts đặt title / legend / vùng vẽ bằng toạ độ tuyệt đối — nó **không** biết "khối này nằm dưới khối kia". `f-echart` bù lại bằng một layout engine chạy sau khi merge `config` + `option`: đi từ mép trên xuống và từ mép dưới lên, mỗi khối hiện diện lấy **đúng chiều cao của mình + một khoảng hở**, phần chưa ai lấy là vùng vẽ.
|
|
174
|
+
|
|
175
|
+
| Hằng số | px | Dùng cho |
|
|
176
|
+
|---|---|---|
|
|
177
|
+
| padding | 8 | khoảng hở với mép canvas |
|
|
178
|
+
| gap | 12 | khoảng hở tối thiểu giữa hai khối bất kỳ |
|
|
179
|
+
| grid trái / phải | 0 / 0 | mặc định vùng vẽ Cartesian; module có thể override từng cạnh |
|
|
180
|
+
| grid trên / dưới | 50 / 50 | mức tối thiểu khi module không khai; title/legend có thể làm tăng |
|
|
181
|
+
| chiều cao title | `round(fontSize × 1.4)` | mặc định `16px` → 22 |
|
|
182
|
+
| chiều cao subtitle | `4 + round(fontSize × 1.4)` | mặc định `12px` → 4+17 |
|
|
183
|
+
| một hàng legend | 24 | nhân với `legendRows` |
|
|
184
|
+
| chừa nhãn trục hoành | 26 | cộng thêm vào `grid.bottom` |
|
|
185
|
+
| chừa nhãn trục tung | 10 | cộng thêm vào `grid.top` |
|
|
186
|
+
|
|
187
|
+
Vùng vẽ nhận phần còn lại qua **hai cơ chế khác nhau**:
|
|
188
|
+
- chart **có hệ trục** (`xAxis`/`yAxis`) → `grid.top` / `grid.bottom`
|
|
189
|
+
- **pie / funnel / treemap / sankey / graph** → `series.top` / `series.bottom`, vì các loại này **bỏ qua `grid` hoàn toàn**. Ngoại lệ: series khai `center` bằng px thì engine không đụng vào (đổi box sẽ dịch hình đi).
|
|
190
|
+
|
|
191
|
+
Số thực tế (đo trên chính `fechart.js`), chart có trục, title mặc định:
|
|
192
|
+
|
|
193
|
+
| Cấu hình | `title.top` | `legend` | `grid.top` | `grid.bottom` |
|
|
194
|
+
|---|---|---|---|---|
|
|
195
|
+
| không title, không legend | — | — | 50 | 50 |
|
|
196
|
+
| chỉ title | 8 | — | 52 | 50 |
|
|
197
|
+
| title + `config.legend: true` | 8 | `bottom: 8` | 52 | 70 |
|
|
198
|
+
| title + `legendPosition:'top'` | 8 | `top: 42` | 88 | 50 |
|
|
199
|
+
| như trên + `legendRows: 2` | 8 | `top: 42` | 112 | 50 |
|
|
200
|
+
| title `titleSize: 24` + subtitle | 8 | — | 85 | 50 |
|
|
201
|
+
|
|
202
|
+
### Legend neo cạnh nào — luật quyết định
|
|
203
|
+
|
|
204
|
+
Đọc theo thứ tự, dừng ở điều kiện đầu tiên đúng:
|
|
205
|
+
|
|
206
|
+
1. `legend.top` có giá trị → neo **trên**; `legend.bottom` có giá trị → neo **dưới** (giá trị module khai được giữ nguyên).
|
|
207
|
+
2. Legend bật qua `config.legend` / `config.legendConfig` → `config.legendPosition`, mặc định **`'bottom'`**.
|
|
208
|
+
3. Legend chỉ khai trong `option.legend` (không qua `config`) → neo **trên**. ⚠️ Trong ca này `config.legendPosition` **không có tác dụng** — muốn legend xuống đáy thì hoặc đặt `option.legend.bottom: 0`, hoặc bật legend qua `config.legend: true`.
|
|
209
|
+
|
|
210
|
+
**Hệ quả khi viết module:** đừng tự chỉnh `grid.top`/`grid.bottom`/`legend.top` để "né" title — thêm title, đổi `titleSize`, hay chuyển `legendPosition` thì khoảng trống tự cộng lại. Giá trị **do module tự khai luôn được tôn trọng** (khai `grid.top: 5` thì engine không đụng vào, và khối sau vẫn cộng dồn từ giá trị đó), nên chỉ khai khi thật sự cần một bố cục riêng. Legend nhiều mục xuống dòng thì báo `legendRows` thay vì tự đẩy `grid.top`.
|
|
211
|
+
|
|
212
|
+
Hai giới hạn đã biết: (a) engine chỉ tính được `top`/`bottom` dạng **số px** — khai `'10%'`/`'middle'` thì nó chỉ giữ một mức tối thiểu, phần còn lại tự canh; (b) `option.grid` dạng **mảng** (multi-grid) thì engine bỏ qua hoàn toàn, module tự lo bố cục.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## DataView
|
|
217
|
+
|
|
218
|
+
`config.dataView: true` → hiện icon bảng (góc trên phải chart). Click → overlay bảng dữ liệu phủ lên chart.
|
|
219
|
+
|
|
220
|
+
**DataView tự trích xuất từ `option` — không cần truyền data riêng:**
|
|
221
|
+
- Ưu tiên `option.dataset.source` (object-array hoặc array-of-arrays)
|
|
222
|
+
- Fallback: `option.series[].data` + `xAxis.data` / `yAxis.data`
|
|
223
|
+
- Không có data phù hợp → nút bảng ẩn tự động
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{
|
|
227
|
+
"el": "f-echart", "w": "12",
|
|
228
|
+
"attr": {
|
|
229
|
+
":config": "{ title: 'Doanh thu', dataView: true, height: 350 }",
|
|
230
|
+
":option": "vueData.chartOpt"
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
> DataView là **Vue overlay tùy chỉnh** — **không phải** ECharts toolbox DataView. `config.toolbox: true` chỉ thêm saveAsImage + restore.
|
|
236
|
+
|
|
237
|
+
Bỏ `dataView` khi option không có series array rõ ràng (gauge giá trị đơn, sankey node/link, tree hierarchical...).
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Series auto-enhancement
|
|
242
|
+
|
|
243
|
+
`f-echart` tự động áp style theo loại series — điều khiển bởi **enhancement policy** của theme:
|
|
244
|
+
|
|
245
|
+
| Policy | Áp cho | Hành vi |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| `lighten` | `bar`, `pie`, `funnel` | Fill màu nhạt 50% + viền màu gốc |
|
|
248
|
+
| `separator` | `treemap`, `sunburst` | Viền trắng mờ giữa các ô/lớp |
|
|
249
|
+
| `outline` | `scatter`, `effectScatter` | Viền trắng quanh điểm |
|
|
250
|
+
|
|
251
|
+
**`lighten` detail:**
|
|
252
|
+
- `bar` — per-series: một màu nhạt + viền cho toàn bộ cột
|
|
253
|
+
- `pie` / `funnel` — per-item: mỗi lát/phần tử lấy màu riêng từ palette rồi làm nhạt
|
|
254
|
+
|
|
255
|
+
**Override:**
|
|
256
|
+
- Tắt lighten cho bar: đặt `itemStyle.color` tường minh trong `option.series[]`
|
|
257
|
+
- Tắt lighten cho pie item: đặt `itemStyle.color` vào từng phần tử `data[]`
|
|
258
|
+
- Tắt separator/outline: đặt `itemStyle.borderWidth: 0` trong `option.series[]`
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Theme
|
|
263
|
+
|
|
264
|
+
3 theme nhúng sẵn trong `fechart.js` — không cần file ngoài:
|
|
265
|
+
|
|
266
|
+
| Theme | Màu | Đặc điểm |
|
|
267
|
+
|---|---|---|
|
|
268
|
+
| `'fui'` | 56 màu | **Mặc định** — palette rộng, nhiều series |
|
|
269
|
+
| `'shine'` | 8 màu | Classic axis style, màu đậm nét |
|
|
270
|
+
| `'v5'` | 9 màu | ECharts V5 default style |
|
|
271
|
+
|
|
272
|
+
```json
|
|
273
|
+
":config": "{ theme: 'shine' }"
|
|
274
|
+
":config": "{ theme: 'v5' }"
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
> ⚠️ **Chỉ ba tên trên là hợp lệ.** Mọi tên khác — kể cả theme tự đăng ký bằng `echarts.registerTheme('myTheme', …)` — và cả `theme: null` đều **âm thầm rơi về `'fui'`**, không lỗi, không cảnh báo. Đừng dùng `config.theme` cho theme custom.
|
|
278
|
+
|
|
279
|
+
**Đổi bảng màu thì dùng `config.color`** — đây là đường được hỗ trợ, và cũng là bảng màu mà series auto-enhancement đọc để tính màu fill/viền:
|
|
280
|
+
|
|
281
|
+
```json
|
|
282
|
+
":config": "{ color: ['#e63946', '#457b9d', '#2a9d8f'] }"
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
## Events
|
|
288
|
+
|
|
289
|
+
| Event | Payload | Mô tả |
|
|
290
|
+
|---|---|---|
|
|
291
|
+
| `chart-click` | params | Click data point |
|
|
292
|
+
| `drilldown` | params | Alias của `chart-click` |
|
|
293
|
+
| `legend-change` | params | Chọn/bỏ legend item |
|
|
294
|
+
| `rendered` | — | Sau mỗi lần `setOption` |
|
|
295
|
+
| `finished` | — | Sau khi animation xong |
|
|
296
|
+
|
|
297
|
+
```json
|
|
298
|
+
{ "v-on:drilldown": "CALL(vueData.loadDetail, { row: $event })" }
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Exposed methods (`$refs`)
|
|
304
|
+
|
|
305
|
+
```js
|
|
306
|
+
this.$refs.myChart.getInstance() // ECharts instance gốc
|
|
307
|
+
this.$refs.myChart.refresh() // Force re-render (gọi lại setOption)
|
|
308
|
+
this.$refs.myChart.exportImage('chart.png')
|
|
309
|
+
this.$refs.myChart.resizeChart() // Hiếm khi cần — xem ghi chú dưới
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
> **Không cần gọi `resizeChart()` thủ công trong hầu hết trường hợp**: component đã tự nghe `window.resize` **và** `ResizeObserver` trên chính thẻ chứa chart, nên chart co giãn đúng cả khi container đổi kích thước mà viewport không đổi (Vuetify grid settle sau mount, mở tab/dialog, thu gọn sidebar).
|
|
313
|
+
|
|
314
|
+
```js
|
|
315
|
+
// Native ECharts API
|
|
316
|
+
const chart = vueData.$refs.myChart.getInstance();
|
|
317
|
+
chart.dispatchAction({ type: 'highlight', seriesIndex: 0, dataIndex: 2 });
|
|
318
|
+
chart.on('mouseover', p => { vueData.hoverLabel = p.name; });
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## FEchartFormatter (global, dùng trong script.js)
|
|
324
|
+
|
|
325
|
+
Đúng 6 hàm, không có gì khác:
|
|
326
|
+
|
|
327
|
+
```js
|
|
328
|
+
FEchartFormatter.build('currency', { symbol: '₫', decimals: 0 })(1500000) // → '₫1,500,000'
|
|
329
|
+
FEchartFormatter.formatShort(1500000) // → '1.5M' (co gọn — chỉ dùng khi cần tiết kiệm chỗ, vd axis label)
|
|
330
|
+
FEchartFormatter.formatNumber(1500000) // → '1,500,000' (decimals thứ 2, mặc định 0)
|
|
331
|
+
FEchartFormatter.formatFull(2535.678) // → '2,535.68' (đầy đủ, tối đa 2 số thập phân — mặc định của tooltip)
|
|
332
|
+
// Tạo tooltip formatter từ config.tooltipFormat ('auto'/không khai → formatFull, số đầy đủ)
|
|
333
|
+
FEchartFormatter.buildTooltip({ tooltipFormat: 'currency', symbol: '₫' })
|
|
334
|
+
FEchartFormatter.buildDefault() // formatter tooltip mặc định (formatFull)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Hai điểm dễ sai:
|
|
338
|
+
- **Không có** `formatPercent` / `formatCurrency` rời — muốn hai kiểu đó thì đi qua `build('percent', { decimals })` / `build('currency', { symbol, decimals })`.
|
|
339
|
+
- Truy cập bằng **tên trần** `FEchartFormatter`, **không phải** `window.FEchartFormatter` (khai bằng `const` ở cấp script nên không gắn lên `window`; `window.FEchartFormatter` là `undefined`).
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Sort dữ liệu
|
|
344
|
+
|
|
345
|
+
Không có `config.sort`. Sort trong `script.js` trước khi gán:
|
|
346
|
+
|
|
347
|
+
```js
|
|
348
|
+
vueData.rows = (d.data || []).slice().sort((a, b) => b.doanhThu - a.doanhThu);
|
|
349
|
+
// String sort
|
|
350
|
+
vueData.rows = (d.data || []).slice().sort((a, b) => a.name.localeCompare(b.name));
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
> **Không dùng ECharts `dataset.transform sort`** với object-array — không ổn định với ECharts V5.
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Pattern trong module.json (controls)
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"el": "f-echart",
|
|
362
|
+
"w": "12",
|
|
363
|
+
"attr": {
|
|
364
|
+
":config": "{ title: 'Tiêu đề', height: 350, dataView: true }",
|
|
365
|
+
":option": "vueData.chartOpt"
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
`vueData.chartOpt` được build trong `script.js` (callback sau khi fetch data). `dataView: true` tự trích xuất dữ liệu từ `option` để hiển thị bảng.
|
|
371
|
+
|
|
372
|
+
> **Template từng loại chart (bar/line/pie/gauge/radar/heatmap/sankey/tree/graph...) + 5 pattern module.json (inline, vueData ref, dynamic height, conditional option, no-dataview):** xem [echart-templates.md](echart-templates.md).
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Lỗi thường gặp
|
|
377
|
+
|
|
378
|
+
| Lỗi | Nguyên nhân | Giải pháp |
|
|
379
|
+
|---|---|---|
|
|
380
|
+
| Trang trắng / component không tồn tại | Thiếu `fechart.js` trong import | `file_import_list` → thêm nếu thiếu |
|
|
381
|
+
| `echarts is not defined` | `fechart.js` sort nhỏ hơn `echarts.min.js` | Đảo sort: `echarts.min.js` phải có số nhỏ hơn |
|
|
382
|
+
| Chart trống dù data có | Data nằm ngoài `option` (ví dụ cố truyền qua prop `data` không tồn tại) | Data chart phải trong `option.series` — không có prop `data` |
|
|
383
|
+
| Nút DataView không hiện | `option` không có series array hoặc axis data | DataView chỉ hiện khi tự trích được data từ `option` |
|
|
384
|
+
| Bar fill nhạt | Auto lighten enhancement (50%) | Set `itemStyle.color` tường minh trong `option.series[]` |
|
|
385
|
+
| Chart không update khi filter thay đổi | `config`/`option` đều có **deep watch** nên sửa lồng sâu vẫn vẽ lại — không update nghĩa là biến **chưa khai trong `data[]`** (Vue không theo dõi được) | Khai key trong `data[]` module.json rồi mới gán; cùng lắm gọi `$refs.myChart.refresh()` |
|
|
386
|
+
| `config.type` không có tác dụng | f-echart không có config.type | Đặt `type` trong `option.series[].type` |
|
|
387
|
+
| Theme custom không ăn | `config.theme` chỉ nhận `'fui'`/`'shine'`/`'v5'`, tên khác **âm thầm** về `'fui'` | Đổi màu bằng `config.color` |
|
|
388
|
+
| Palette lạ, có màu không khai ở đâu | Khai màu ở **cả** `config.color` lẫn `option.color` → merge theo chỉ số, đuôi mảng dài hơn còn sót | Chỉ khai palette ở một chỗ |
|
|
389
|
+
| Legend nằm trên đầu dù đặt `legendPosition: 'bottom'` | Legend khai trong `option` (không qua `config.legend`) thì neo **trên**, `legendPosition` vô hiệu | `option.legend.bottom: 0`, hoặc bật legend bằng `config.legend: true` |
|
|
390
|
+
| Tooltip chỉ hiện 1 series khi rê chuột | Không có `trigger` mặc định → ECharts dùng `'item'` | Khai `tooltip: { trigger: 'axis' }` trong `option` |
|
|
391
|
+
| Legend nhiều hàng đè lên chart | Engine mặc định chừa chỗ cho **1 hàng** legend | `config.legendRows: 2` (hoặc hơn) |
|