# Charts (ChartView)

> Gráficos — linha, área, barra, barra/área empilhada, pizza, rosca e combo — com um núcleo de render compartilhado.

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

# Charts (ChartView + subclasses)

O módulo `dev.crossfly.ui.chart` tem um **núcleo de render compartilhado** (`ChartView`, que estende
`Component`) e **8 subclasses concretas** que são os pontos de entrada recomendados — cada uma
pré-configura o tipo e expõe métodos fluentes ergonômicos:

| Classe | Tipo | Como adiciona dados |
|---|---|---|
| `LineChart` | linha | `.withSeries(nome, valores[, cor])` |
| `AreaChart` | linha com área preenchida (estende `LineChart`) | `.withSeries(...)` · `.areaOpacity(int)` |
| `BarChart` | barras agrupadas | `.withSeries(...)` |
| `StackedBarChart` | barras empilhadas | `.series(nome, valores[, cor])` |
| `StackedAreaChart` | áreas empilhadas (gradiente) | `.series(...)` · `.areaOpacity(int)` |
| `PieChart` | pizza | `.slice(nome, valor[, cor])` |
| `DonutChart` | rosca | `.slice(...)` · `.hole(float)` |
| `ComboChart` | barras + linha (eixo Y secundário) | `.addBarSeries(...)` · `.addLineSeries(...)` |

> 🟡 · **Pacote:** `dev.crossfly.ui.chart` · **Estende:** `Component` · **Estilo:** `ComponentStyle`
>
> ⚠️ **Renomeação 2026:** as classes antigas `LineChartView`/`BarChartView`/`PieChartView`/
> `DonutChartView`/`ComboChartView` foram **renomeadas** para `LineChart`/`BarChart`/`PieChart`/
> `DonutChart`/`ComboChart` (sufixo `View` removido). E pie/rosca agora usam **`slice(...)`** (não
> `withSlice`).

## Quando usar
- Tendências por categoria (linha/área), magnitudes (barra), composição ao longo do tempo (empilhado),
  proporção de um todo (pizza/rosca), ou magnitude + taxa juntas (combo).

## Quando NÃO usar
- Dispersão XY com X arbitrário, 3D ou velocímetro → não suportados. Desenho livre → [`whiteboard`](/docs/ui/widgets/whiteboard).

## Exemplo completo (copiar, colar e rodar)
No CrossFly você escreve **uma classe `Window`** (a tela principal) — o `Main` e o launcher são
**boilerplate da plataforma**. Aponte o launcher para esta classe (parâmetro `classname`) e rode
`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…

/**
 * Tela principal executável. Aponte o launcher para esta classe (classname)
 * e rode: 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);         // faixa Y fixa (ou autoYAxis())

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

> Os trechos abaixo mostram **só o miolo** (o que vai dentro de `onShow()`), para focar no recurso.
> Para rodar, coloque o miolo dentro do esqueleto `MainWindow` acima.

## Uso básico (por subclasse — recomendado)
```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);                    // faixa Y fixa (ou autoYAxis())
add(LAY_FILL, line);
```

### Barra e barra empilhada
```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);
```

### Área e área empilhada
```java
AreaChart area = new AreaChart();
area.withSeries("Load", new double[]{180, 260, 210, 300, 280}, 0xFF26C6DA);
area.areaOpacity(110);                    // alpha 0–255 do preenchimento

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;                        // campos públicos para ajuste fino
```

### Pizza e rosca
```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);                          // raio do furo [0..0.95]
```

### Combo (barras + linha em eixo secundário)
```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);  // eixo Y direito
combo.title("Conversão x Sessões").yAxis(0, 1600, 8);
```

## Modelo de dados
- **`ChartView.Series`** (cartesiano): `new Series(nome, double[] valores[, cor])`; fluentes `.line()` /
  `.bar()` definem o `renderMode` (usado no combo).
- **`ChartView.PieSlice`** (radial): `new PieSlice(nome, double valor[, cor])`.
- **Cor `0` = automática** (paleta `DEFAULT_COLORS`, 9 cores). Para cor fixa use ARGB **com alpha** (`0xFF…`).

## Configuração (campos públicos + fluentes)
| Membro | Tipo | Padrão | O que faz |
|---|---|---|---|
| `title(String)` · `categories(String[])` | fluente | — | título / rótulos do eixo X |
| `yAxis(min, max, steps)` · `autoYAxis()` | fluente | auto | faixa do eixo Y |
| `smooth(bool)` / `smoothLines` | fluente/campo | `false` | interpolação Catmull-Rom |
| `area(bool)` / `showArea` | fluente/campo | `false` | preenche a área sob a linha |
| `areaOpacity(int)` / `areaAlpha` | fluente/campo | `0x55` | alpha (0–255) do preenchimento |
| `showLegend`/`showGrid`/`showTitle`/`showPoints`/`showValues` | campo | `true` | flags de exibição |
| `decimals` | campo | `2` | casas decimais em rótulos/tooltips |
| `axisColor`/`axisTextColor`/`legendTextColor`/`gridColor` | campo | tema | cores (ARGB) |
| `pointRadius`/`lineThickness`/`barInnerGap`/`splineSteps` | campo | — | ajuste fino do desenho |
| `donutHoleRatio` / `hole(float)` | campo/fluente | `0.56` | furo da rosca |
| `enableHoverSelection`/`enableInteractionAnimations` | campo | `true` | seleção por hover / animação de realce |

> Após alterar **campos públicos** fora de um método fluente, chame `repaint()`.

## Callbacks e estados
- **`onAction(Action)`** dispara ao **mudar a seleção** (ponto/barra/fatia) — via `runActions()`.
  Leia `selectedSeries`+`selectedIndex` (cartesiano) ou `selectedSlice` (radial); `-1` = nada.
- Interação por `onTouchUp` (seleciona o mais próximo) e `onHover` (realça sob o cursor). Não há `onClick`.

## Estilo
Como qualquer `Component`: `chart.getStyle().backColor(...)`/`borderColor(...)`; use `.copy()` para
derivar sem mutar o compartilhado:
```java
chart.style(chart.getStyle().copy().backColor(0xFFFFFFFF).borderColor(0xFFE0E0E0));
```

## Boas práticas
- Prefira a **subclasse concreta** (`LineChart`, `BarChart`…) ao `ChartView` cru — os métodos fluentes
  são mais claros.
- Cartesiano usa `series`/`withSeries`; radial usa `slices`/`slice` — não misture no mesmo tipo.
- Fixe `yAxis(min,max,steps)` para eixos estáveis (o modo automático inclui o zero e pode "achatar").

## Erros comuns
- Usar os **nomes antigos** `LineChartView`/`PieChartView`… (renomeados) ou **`withSlice`** (agora `slice`).
- Passar cor `0x00…` esperando preto: `0` é "automática" e alpha `00` é invisível — use `0xFF000000`.
- Esperar `onClick`: a interação é via `onAction` disparado por seleção/hover.

## Veja também
- [`ui/`](/docs/ui) · [`cookbook/`](/docs/cookbook) · [`whiteboard`](/docs/ui/widgets/whiteboard)
