# Chart

Mười một dạng chart định kiểu, với các role palette theo thứ tự, hình học responsive, inspect dùng chung và một bảng dữ liệu truy cập được. Ghép với Card và DataTrend cho các panel chỉ số.

**Phụ thuộc:** npm: 0 trực tiếp, 6 tổng; registry: 4 trực tiếp, 7 tổng.

## Cách dùng

### Khi nào dùng

- Hiện thay đổi, so sánh, composition, conversion, mức giữ chân hoặc khả dụng của dịch vụ từ data số.
- Giữ một bảng dữ liệu truy cập được cạnh các pattern hình và inspect từng điểm.

### Khi nào không dùng

- Một giá trị hiện tại và mức thay đổi của nó. Dùng DataTrend.
- Mức hoàn thành hướng tới một tổng đã biết. Dùng Progress.
- Sửa từng số đo. Dùng Table với các control của form.

## Biến thể

### type

Discriminant bắt buộc. Mỗi type chỉ nhận đúng hình dạng data của nó.

Giá trị: `line`, `area`, `bar`, `sparkline`, `composition`, `donut`, `funnel`, `timeline`, `cohort`, `uptime`, `activity`. Mặc định: `undefined`.

### table

Toggle hiện khung dữ liệu có ngữ nghĩa. Hidden giữ bảng vẫn truy cập được, với phần trình bày ẩn khỏi mắt. Sparkline mặc định hidden.

Giá trị: `toggle`, `visible`, `hidden`. Mặc định: `toggle`.

### xScale

Khoảng cách trục Cartesian. Các mode numeric và time cần giá trị x hữu hạn, tăng nghiêm ngặt; time dùng epoch millisecond. Không có formatX thì vị trí time hiện một ngày UTC ngắn.

Giá trị: `category`, `linear`, `time`. Mặc định: `category`.

### stack

Chỉ area: các series độc lập phủ chồng, hoặc một stack cộng không âm. Null làm đứt stack tại hàng đó.

Giá trị: `none`, `normal`. Mặc định: `none`.

### orientation

Chỉ bar: bar vertical hoặc horizontal.

Giá trị: `vertical`, `horizontal`. Mặc định: `vertical`.

### layout

Chỉ bar: grouped, stacked có dấu, hoặc composition phần trăm không âm. Hàng phần trăm có tổng zero thì để trống.

Giá trị: `grouped`, `stacked`, `percentage`. Mặc định: `grouped`.

## Ví dụ

### Line ba series

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="line" label="Hoạt động hàng tuần" data={sampleChartRows} series={sampleChartSeries} />
```

### Area phủ chồng

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="area" label="Đối tượng theo thời gian" data={sampleChartRows} series={sampleChartSeries} stack="none" />
```

### Area xếp stack

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="area" label="Phân bổ theo thời gian" data={sampleChartRows} series={sampleChartSeries} stack="normal" />
```

### Bar grouped chiều dọc

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Hoạt động theo nhóm" data={sampleChartRows} series={sampleChartSeries} orientation="vertical" layout="grouped" />
```

### Bar stacked chiều dọc

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Hoạt động xếp chồng" data={sampleChartRows} series={sampleChartSeries} orientation="vertical" layout="stacked" />
```

### Bar phần trăm chiều dọc

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Hoạt động theo phần trăm" data={sampleChartRows} series={sampleChartSeries} orientation="vertical" layout="percentage" />
```

### Bar grouped chiều ngang

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Hoạt động theo nhóm" data={sampleChartRows} series={sampleChartSeries} orientation="horizontal" layout="grouped" />
```

### Bar stacked chiều ngang

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Hoạt động xếp chồng" data={sampleChartRows} series={sampleChartSeries} orientation="horizontal" layout="stacked" />
```

### Bar phần trăm chiều ngang

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Hoạt động theo phần trăm" data={sampleChartRows} series={sampleChartSeries} orientation="horizontal" layout="percentage" />
```

### Bar compact trong bảng

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Lượt xem so với mức tối đa chung" data={sampleChartRows} series={sampleSparkSeries} orientation="horizontal" compact domain={[0, 600]} table="hidden" />
```

### Sparkline

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="sparkline" label="Lượt xem tuần này" data={sampleChartRows} series={sampleSparkSeries} />
```

### Composition

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="composition" label="Nguồn lưu lượng" data={sampleChartParts} />
```

### Donut

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="donut" label="Nguồn lưu lượng" data={sampleChartParts} />
```

### Funnel có thứ tự

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="funnel" label="Chuyển đổi hành trình" data={sampleFunnelParts} />
```

### Timeline

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="timeline" label="Lịch giao hàng" data={sampleChartRanges} range={[0, 28]} marker={{ value: 14, label: "Điểm kiểm tra" }} />
```

### Giữ chân cohort

Các cohort minh họa gốc. Null nghĩa là chưa quan sát; zero nghĩa là 0 phần trăm đã được quan sát.

```tsx
<Chart type="cohort" label="Giữ chân hàng tuần" data={sampleChartCohorts} columns={sampleCohortColumns} />
```

### Uptime dịch vụ

Các quan sát gốc, cùng thời lượng. Các kỳ unknown vẫn được nêu rõ; phần tóm tắt lấy trung bình khả dụng đã biết.

```tsx
<Chart type="uptime" label="Khả dụng dịch vụ hằng ngày" data={sampleChartUptime} />
```

### Hoạt động hằng ngày

Một ô cho mỗi ngày. Cột là tuần và hàng là thứ. Zero là ô trống và ngày thiếu vẫn trống với cạnh nét đứt. Tiêu đề cộng các giá trị đã biết.

```tsx
<Chart type="activity" label="events in the last year" data={sampleChartActivity} />
```

### Kỳ hiện tại và kỳ trước

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="line" label="Hoạt động hiện tại và trước đó" data={sampleComparisonRows} series={sampleComparisonSeries} />
```

### Giá trị thiếu

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="line" label="Hoạt động có khoảng trống quan sát" data={sampleMissingRows} series={sampleChartSeries} />
```

### Giá trị có dấu

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="bar" label="Thay đổi ròng theo khu vực" data={sampleSignedRows} series={sampleSignedSeries} layout="stacked" />
```

### Tổng trống

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="donut" label="Hoạt động đang chờ quan sát" data={sampleZeroParts} />
```

### Tám series

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="line" label="Tám nhóm được gắn nhãn" data={sampleEightRows} series={sampleEightSeries} />
```

### Làm mới pending

Data minh họa gốc vẫn hiện, chỉ plot bị mờ.

```tsx
<Chart type="line" label="Hoạt động đang được làm mới" data={sampleChartRows} series={sampleChartSeries} pending />
```

### Nhãn theo locale

Data minh họa gốc. Bản copy gồm toàn bộ thiết lập cục bộ.

```tsx
<Chart type="line" label="Hoạt động với nhãn tùy chỉnh" data={sampleMissingRows} series={sampleChartSeries} locale="en-GB" labels={sampleChartLabels} />
```

## Nên và không nên

### Nên

- Dùng mười contract data đã phân nhánh. Giữ id ổn định và nhãn hàng đầy đủ.
- Dùng series theo thứ tự chartPalette; đánh dấu so sánh bằng comparison=true và cung cấp nhãn trực tiếp hoặc pattern khi nhiều hơn bốn series.
- Đặt value và nhãn trên bề mặt neutral. Ghép chỉ số với cả khối DataTrend và mục tiêu với Progress.
- Giữ nội dung trước đó khi làm mới. Chỉ dùng Skeleton có độ trễ cho lần tải đầu.
- Gắn nhãn các bộ data mẫu là minh họa, và tính mọi chart, chỉ số và bảng trên một màn hình từ cùng các hàng.

### Không nên

- Đừng chọn hue tùy ý, áp alpha cho màu, thêm nấc opacity hoặc animate việc vẽ chart.
- Đừng nối qua giá trị thiếu, clamp số liệu không hợp lệ, hoặc coi null là zero.
- Đừng lấy trung bình các mẫu khả dụng có thời lượng không bằng nhau, hoặc đếm ô status thành uptime.
- Đừng ngụ ý rằng các dải nhiệt cohort là ngưỡng success.
- Đừng thêm một bề mặt Card thứ hai quanh chart đã nằm trong một Card.

## Props

| Tên | Kiểu | Giá trị | Mặc định | Mô tả |
| --- | --- | --- | --- | --- |
| `type` (bắt buộc) | `enum` | `line`, `area`, `bar`, `sparkline`, `composition`, `donut`, `funnel`, `timeline`, `cohort`, `uptime`, `activity` |  | Discriminant bắt buộc. Mỗi type chỉ nhận đúng hình dạng data của nó. |
| `label` (bắt buộc) | `string` |  |  | Tên chart cho truy cập, bắt buộc. |
| `description` | `string` |  |  | Ngữ cảnh tùy chọn gắn với chart. |
| `data` (bắt buộc) | `ChartRow[] \| ChartItem[] \| ChartRange[] \| ChartCohortRow[] \| ChartUptimeRow[] \| ChartActivityDay[]` |  |  | Data cục bộ có thứ tự, khớp type. Null giữ nghĩa thiếu hoặc chưa quan sát; giá trị không hợp lệ thì được báo. |
| `series` | `ChartSeries[]` |  |  | Bắt buộc cho line, area, bar và sparkline. Các id ổn định ánh xạ tới value; comparison thêm một nét đứt. Sparkline nhận một series. |
| `height` | `number` |  |  | Chiều cao plot theo pixel CSS. Mặc định 256, sparkline 48, bar compact 32. Timeline, cohort, uptime và activity mặc định cao theo các hàng; một height cố định timeline và giới hạn cohort, uptime cùng activity, rồi chúng cuộn. |
| `legend` | `boolean` |  | `true` | Hiện legend của series hoặc status. Mặc định true, trừ sparkline và bar một series. Composition, donut và funnel giữ nhãn trực tiếp, không legend trùng. |
| `interactive` | `boolean` |  | `true` | Bật inspect bằng pointer, cảm ứng và bàn phím. Mặc định true, trừ sparkline. |
| `pending` | `boolean` |  | `false` | Giữ data hiện tại, đánh dấu figure đang bận và chỉ làm mờ plot. |
| `table` | `enum` | `toggle`, `visible`, `hidden` | `toggle` | Toggle hiện khung dữ liệu có ngữ nghĩa. Hidden giữ bảng vẫn truy cập được, với phần trình bày ẩn khỏi mắt. Sparkline mặc định hidden. |
| `locale` | `string` |  | `en` | Locale định dạng số, đặt rõ, dùng chung cho server và client. |
| `labels` | `Partial<ChartLabels>` |  |  | Ghi đè chữ của viewData, hideData, loading, empty, missing, unobserved, invalid, noSeries, zeroTotal, value, total, cohortSize, conversion, share, coverage, success, warning, danger, unknown, neutral, start, end, status, point, less và more. Giá trị thô dùng formatValue; phần trăm dẫn xuất luôn dùng định dạng phần trăm theo locale. |
| `formatValue` | `(value: number, id: string) => string` |  |  | Định dạng một số hữu hạn và id ổn định của series hoặc item, không đổi hình học. |
| `xScale` | `enum` | `category`, `linear`, `time` | `category` | Khoảng cách trục Cartesian. Các mode numeric và time cần giá trị x hữu hạn, tăng nghiêm ngặt; time dùng epoch millisecond. Không có formatX thì vị trí time hiện một ngày UTC ngắn. |
| `formatX` | `(value: number) => string` |  |  | Định dạng tick numeric hoặc time cho chart Cartesian và timeline; nhãn đầy đủ của hàng vẫn còn. |
| `domain` | `[number, number]` |  |  | Biên giá trị Cartesian, hữu hạn, tăng dần, chứa mọi giá trị. Domain của bar phải chứa zero. |
| `axes` | `boolean` |  | `true` | Hiện các trục Cartesian. Mặc định true, trừ sparkline và bar compact. |
| `grid` | `boolean` |  | `true` | Hiện các đường lưới Cartesian. Mặc định true, trừ sparkline và bar compact. |
| `hiddenSeries` | `string[]` |  |  | Các id series Cartesian đang ẩn, ở chế độ controlled. Vị trí palette giữ nguyên. |
| `defaultHiddenSeries` | `string[]` |  |  | Các id series Cartesian ẩn ban đầu, ở chế độ uncontrolled. |
| `onHiddenSeriesChange` | `(ids: string[]) => void` |  |  | Nhận các id series đang ẩn sau một hành động trên legend. |
| `stack` | `enum` | `none`, `normal` | `none` | Chỉ area: các series độc lập phủ chồng, hoặc một stack cộng không âm. Null làm đứt stack tại hàng đó. |
| `orientation` | `enum` | `vertical`, `horizontal` | `vertical` | Chỉ bar: bar vertical hoặc horizontal. |
| `layout` | `enum` | `grouped`, `stacked`, `percentage` | `grouped` | Chỉ bar: grouped, stacked có dấu, hoặc composition phần trăm không âm. Hàng phần trăm có tổng zero thì để trống. |
| `compact` | `boolean` |  | `false` | Chỉ bar: ô số ngắn, không trục và không legend. Một domain dùng chung cho các độ dài so sánh được. |
| `range` | `[number, number]` |  |  | Chỉ timeline, bắt buộc: khoảng hữu hạn, tăng dần, theo đơn vị do người gọi định nghĩa. Mọi mục phải nằm trong khoảng. |
| `marker` | `{ value: number; label: string }` |  |  | Vị trí mốc trên timeline, tùy chọn. Vị trí ngoài khoảng vẫn được mô tả, không có marker nhìn thấy. |
| `columns` | `Array<{ id: string; label: string }>` |  |  | Chỉ cohort, bắt buộc các cột duy nhất. Mỗi hàng có một phần trăm hoặc null cho mỗi cột. |
| `thresholds` | `[number, number, number, number]` |  |  | Chỉ cohort: bốn mốc tăng dần trong (0, 100), xác định năm dải nhiệt có thứ tự của chart series 1, mỗi dải đậm hơn; giá trị in trên ô. Mặc định [20, 40, 60, 80]. |
| `weekStartsOn` | `number` |  | `0` | Chỉ activity. 0 bắt đầu mỗi tuần vào Chủ nhật và 1 bắt đầu vào Thứ hai. Các type chart khác bỏ qua. |

## Cấu tạo

| Phần | Mô tả |
| --- | --- |
| `root` | Figure có tên, với description và trạng thái loading. |
| `plot` | Plot responsive và một bề mặt inspect bằng bàn phím. Đường line và cạnh area là đường cong monotone mượt, không vượt quá một giá trị; phần tô area mờ từ màu series ở opacity-subtle tới trong suốt. Đường lưới nét đứt và nhẹ; đường zero chuyển solid trên domain có dấu. Bar mảnh, chỉ bo đầu phía giá trị và không có outline. Các phần composition và cung donut cách nhau một khe 2px thay vì outline. Điểm line và area đang inspect dùng nền series của chúng, một vòng trắng 2px color-border-chart-marker và drop-shadow-low. Phần composition đang inspect nở thêm 4px phía trên và dưới track, còn cung donut đang inspect nở thêm 4px ra ngoài, vẽ lên trên các phần kề. |
| `legend` | Các button bật tắt series, với khóa gọn (một nét ngắn cho line, một ô mẫu nhỏ cho dấu có tô) hoặc một danh sách status tĩnh với icon status. Composition và donut liệt kê từng danh mục với lượng và share; hàng funnel hiện conversion từ giai đoạn trước, lượng và share của giai đoạn đầu, và mọi giai đoạn dùng series 1, vì các giai đoạn là một thước đo. |
| `tooltip` | Các giá trị đang inspect, dạng gọn, cạnh pointer hoặc dấu được chọn bằng bàn phím, nằm trong plot và bo bằng radius-container. |
| `table` | Khung xem dữ liệu thô có ngữ nghĩa, với caption và header. |

## Khả năng truy cập

Role: `figure`

| Phím | Hành động |
| --- | --- |
| `Tab` | Vào plot một lần; các button legend và toggle dữ liệu vẫn là các control riêng. |
| `Arrow keys` | Inspect các hàng và series đang hiện; điều hướng các khoảng hoặc ô ma trận theo type của chart. |
| `Home / End` | Inspect hàng Cartesian đầu hoặc cuối. |
| `Escape` | Đóng inspect và trả focus về plot. |

- label bắt buộc đặt tên cho figure; description cung cấp ngữ cảnh. Mọi chart giữ một bảng dữ liệu có ngữ nghĩa, kể cả table=hidden.
- Null nghĩa là thiếu với giá trị Cartesian, và chưa quan sát với cohort. Zero là giá trị đã quan sát.
- Series giữ danh tính palette khi bị ẩn. Nhiều hơn bốn series thì thêm pattern và nét đứt; với bốn series trở xuống, giữ legend hoặc bảng dữ liệu hiện, vì legend ẩn thì màu là tín hiệu duy nhất.
- Chạm trên cảm ứng ghim inspect; chạm lần hai hoặc chạm ra ngoài thì đóng. Cuộn trang bình thường vẫn dùng được. Hover bằng chuột không nhận contour focus của bàn phím, và plot đang focus giữ focus ring khi chuột di chuyển. Mỗi nhóm bar là một dải chạm ngang trục giá trị; khe giữa các nhóm thì đóng inspect. Hàng uptime là target 44px, chọn kỳ nằm dưới pointer. Ở bar horizontal, Up và Down chuyển giữa các hàng, Left và Right chuyển giữa các series.
- Mẫu uptime đại diện cho các kỳ có thời lượng bằng nhau. Coverage và trung bình của khả dụng đã biết vẫn tách riêng.

## Cài đặt

```bash
npx werewolf-ui add chart
```

Chạy `npx werewolf-ui init` một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem [Cài đặt](https://www.werewolf-ui.dev/vi/docs/installation.md) để biết yêu cầu và cách cài qua registry.
