# Charts (ChartView)

> 图表——折线、面积、柱状、堆叠柱状/面积、饼图、环形图和组合图——共享一个渲染核心。

Source: https://crossfly.dev/zh/docs/ui/widgets/chartview — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Charts (ChartView + subclasses)

`dev.crossfly.ui.chart` 模块有一个**共享的渲染核心**（`ChartView`，继承自
`Component`）和 **8 个具体子类**，它们是推荐的入口点——每一个都
预配置了类型并暴露符合人体工学的流式方法：

| 类 | 类型 | 如何添加数据 |
|---|---|---|
| `LineChart` | 折线 | `.withSeries(nome, valores[, cor])` |
| `AreaChart` | 带填充面积的折线（继承 `LineChart`） | `.withSeries(...)` · `.areaOpacity(int)` |
| `BarChart` | 分组柱状 | `.withSeries(...)` |
| `StackedBarChart` | 堆叠柱状 | `.series(nome, valores[, cor])` |
| `StackedAreaChart` | 堆叠面积（渐变） | `.series(...)` · `.areaOpacity(int)` |
| `PieChart` | 饼图 | `.slice(nome, valor[, cor])` |
| `DonutChart` | 环形图 | `.slice(...)` · `.hole(float)` |
| `ComboChart` | 柱状 + 折线（次 Y 轴） | `.addBarSeries(...)` · `.addLineSeries(...)` |

> 🟡 · **包：** `dev.crossfly.ui.chart` · **继承：** `Component` · **样式：** `ComponentStyle`
>
> ⚠️ **2026 年重命名：** 旧类 `LineChartView`/`BarChartView`/`PieChartView`/
> `DonutChartView`/`ComboChartView` 已被**重命名**为 `LineChart`/`BarChart`/`PieChart`/
> `DonutChart`/`ComboChart`（移除了 `View` 后缀）。此外，饼图/环形图现在使用 **`slice(...)`**（不再是
> `withSlice`）。

## 何时使用
- 按类别的趋势（折线/面积）、量级（柱状）、随时间的构成（堆叠）、
  整体中的占比（饼图/环形图），或量级 + 比率同时呈现（组合图）。

## 何时不要使用
- X 任意的 XY 散点、3D 或仪表盘 → 不支持。自由绘图 → [`whiteboard`](/docs/ui/widgets/whiteboard)。

## 完整示例（复制、粘贴并运行）
在 CrossFly 中你只需编写**一个 `Window` 类**（主屏幕）——`Main` 和 launcher 是
**平台样板代码**。将 launcher 指向此类（`classname` 参数）并运行
`gradlew :lwjgl3:run`：
```java
package com.exemplo;

import dev.crossfly.ui.*;          // Window, Component, LAY_FILL…
import dev.crossfly.ui.layout.*;   // VerticalLayout
import dev.crossfly.ui.chart.*;    // ChartView, LineChart…

/**
 * 主可执行界面。将启动器指向此类 (classname)
 * 并运行：gradlew :lwjgl3:run
 */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      LineChart line = new LineChart();
      line.withSeries("Revenue", new double[]{42, 55, 51, 68, 73, 88}, 0xFF42A5F5)
          .withSeries("Target",  new double[]{40, 50, 56, 60, 70, 82}, 0xFFAB47BC);
      line.title("Receita por mês");
      line.categories(new String[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun"});
      line.smooth(true);            // Catmull-Rom
      line.yAxis(0, 100, 5);         // 固定的 Y 范围（或 autoYAxis()）

      add(LAY_FILL, line);
   }
}
```

> 下面的代码片段只展示**核心部分**（放进 `onShow()` 内的内容），以聚焦于该功能。
> 要运行它们，请把核心部分放入上面的 `MainWindow` 骨架中。

## 基本用法（按子类——推荐）
```java
LineChart line = new LineChart();
line.withSeries("Revenue", new double[]{42, 55, 51, 68, 73, 88}, 0xFF42A5F5)
    .withSeries("Target",  new double[]{40, 50, 56, 60, 70, 82}, 0xFFAB47BC);
line.title("Receita por mês");
line.categories(new String[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun"});
line.smooth(true);                       // Catmull-Rom
line.yAxis(0, 100, 5);                    // 固定的 Y 范围（或 autoYAxis()）
add(LAY_FILL, line);
```

### 柱状与堆叠柱状
```java
BarChart bar = new BarChart();
bar.withSeries("North", new double[]{120, 140, 138, 165}, 0xFF5C6BC0)
   .withSeries("South", new double[]{95, 110, 123, 131}, 0xFF26C6DA);
bar.title("Vendas trimestrais").categories(new String[]{"Q1", "Q2", "Q3", "Q4"});

StackedBarChart stacked = new StackedBarChart();
stacked.series("Direct",  new double[]{6.2, 13.7, 19.9, 8}, 0xFF1976D2)
       .series("Mail Ad", new double[]{18.2, 11, 8, 17.8}, 0xFF81C784);
stacked.yAxis(0, 100, 5);
```

### 面积与堆叠面积
```java
AreaChart area = new AreaChart();
area.withSeries("Load", new double[]{180, 260, 210, 300, 280}, 0xFF26C6DA);
area.areaOpacity(110);                    // 填充的 alpha 0–255

StackedAreaChart sarea = new StackedAreaChart();
sarea.series("Line 1", new double[]{140, 232, 101, 264}, 0xFF6DDB92)
     .series("Line 2", new double[]{120, 282, 111, 234}, 0xFF00D4FF);
sarea.areaOpacity(210);
sarea.decimals = 0;                        // 用于微调的公有字段
```

### 饼图与环形图
```java
PieChart pie = new PieChart();
pie.slice("Organic", 38, 0xFF42A5F5)
   .slice("Paid",    24, 0xFFAB47BC)
   .slice("Social",  20, 0xFF26A69A);
pie.title("Fontes de tráfego");

DonutChart donut = new DonutChart();
donut.slice("Organic", 38).slice("Paid", 24).slice("Social", 20)
     .hole(0.58f);                          // 孔的半径 [0..0.95]
```

### 组合图（柱状 + 折线于次轴）
```java
ComboChart combo = new ComboChart();
combo.addBarSeries("Sessions",     new double[]{1000, 1250, 1180, 1340}, 0xFF90CAF9)
     .addLineSeries("Conversion %", new double[]{2.8, 3.1, 2.9, 3.4}, 0xFF1E88E5);  // 右侧 Y 轴
combo.title("Conversão x Sessões").yAxis(0, 1600, 8);
```

## 数据模型
- **`ChartView.Series`**（笛卡尔）：`new Series(nome, double[] valores[, cor])`；流式方法 `.line()` /
  `.bar()` 设置 `renderMode`（用于组合图）。
- **`ChartView.PieSlice`**（径向）：`new PieSlice(nome, double valor[, cor])`。
- **颜色 `0` = 自动**（调色板 `DEFAULT_COLORS`，9 种颜色）。要固定颜色，请使用**带 alpha** 的 ARGB（`0xFF…`）。

## 配置（公有字段 + 流式方法）
| 成员 | 类型 | 默认值 | 作用 |
|---|---|---|---|
| `title(String)` · `categories(String[])` | 流式 | — | 标题 / X 轴标签 |
| `yAxis(min, max, steps)` · `autoYAxis()` | 流式 | 自动 | Y 轴范围 |
| `smooth(bool)` / `smoothLines` | 流式/字段 | `false` | Catmull-Rom 插值 |
| `area(bool)` / `showArea` | 流式/字段 | `false` | 填充折线下方的面积 |
| `areaOpacity(int)` / `areaAlpha` | 流式/字段 | `0x55` | 填充的 alpha（0–255） |
| `showLegend`/`showGrid`/`showTitle`/`showPoints`/`showValues` | 字段 | `true` | 显示标志 |
| `decimals` | 字段 | `2` | 标签/工具提示中的小数位数 |
| `axisColor`/`axisTextColor`/`legendTextColor`/`gridColor` | 字段 | 主题 | 颜色（ARGB） |
| `pointRadius`/`lineThickness`/`barInnerGap`/`splineSteps` | 字段 | — | 绘制的精细调整 |
| `donutHoleRatio` / `hole(float)` | 字段/流式 | `0.56` | 环形图的孔 |
| `enableHoverSelection`/`enableInteractionAnimations` | 字段 | `true` | 悬停选择 / 高亮动画 |

> 在流式方法之外修改**公有字段**后，请调用 `repaint()`。

## 回调与状态
- **`onAction(Action)`** 在**选择改变**（点/柱/扇区）时触发——通过 `runActions()`。
  读取 `selectedSeries`+`selectedIndex`（笛卡尔）或 `selectedSlice`（径向）；`-1` = 无。
- 交互通过 `onTouchUp`（选择最近的）和 `onHover`（高亮光标下的）实现。没有 `onClick`。

## 样式
与任何 `Component` 一样：`chart.getStyle().backColor(...)`/`borderColor(...)`；使用 `.copy()` 来
派生而不改变共享的样式：
```java
chart.style(chart.getStyle().copy().backColor(0xFFFFFFFF).borderColor(0xFFE0E0E0));
```

## 最佳实践
- 优先使用**具体子类**（`LineChart`、`BarChart`……）而非裸的 `ChartView`——流式方法
  更清晰。
- 笛卡尔使用 `series`/`withSeries`；径向使用 `slices`/`slice`——不要在同一类型中混用。
- 固定 `yAxis(min,max,steps)` 以获得稳定的坐标轴（自动模式会包含零，可能“压平”）。

## 常见错误
- 使用**旧名称** `LineChartView`/`PieChartView`……（已重命名）或 **`withSlice`**（现在是 `slice`）。
- 传入颜色 `0x00…` 却期望得到黑色：`0` 是“自动”，而 alpha `00` 是不可见的——请使用 `0xFF000000`。
- 期望 `onClick`：交互是通过由选择/悬停触发的 `onAction` 实现的。

## 另见
- [`ui/`](/docs/ui) · [`cookbook/`](/docs/cookbook) · [`whiteboard`](/docs/ui/widgets/whiteboard)
