# Charts (ChartView)

> Charts — line, area, bar, stacked bar/area, pie, donut and combo — with a shared render core.

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

# Charts (ChartView + subclasses)

The `dev.crossfly.ui.chart` module has a **shared render core** (`ChartView`, which extends
`Component`) and **8 concrete subclasses** that are the recommended entry points — each one
pre-configures the type and exposes ergonomic fluent methods:

| Class | Type | How it adds data |
|---|---|---|
| `LineChart` | line | `.withSeries(name, values[, color])` |
| `AreaChart` | line with filled area (extends `LineChart`) | `.withSeries(...)` · `.areaOpacity(int)` |
| `BarChart` | grouped bars | `.withSeries(...)` |
| `StackedBarChart` | stacked bars | `.series(name, values[, color])` |
| `StackedAreaChart` | stacked areas (gradient) | `.series(...)` · `.areaOpacity(int)` |
| `PieChart` | pie | `.slice(name, value[, color])` |
| `DonutChart` | donut | `.slice(...)` · `.hole(float)` |
| `ComboChart` | bars + line (secondary Y axis) | `.addBarSeries(...)` · `.addLineSeries(...)` |

> 🟡 · **Package:** `dev.crossfly.ui.chart` · **Extends:** `Component` · **Style:** `ComponentStyle`
>
> ⚠️ **2026 rename:** the old classes `LineChartView`/`BarChartView`/`PieChartView`/
> `DonutChartView`/`ComboChartView` were **renamed** to `LineChart`/`BarChart`/`PieChart`/
> `DonutChart`/`ComboChart` (the `View` suffix was removed). And pie/donut now use **`slice(...)`** (not
> `withSlice`).

## When to use
- Trends by category (line/area), magnitudes (bar), composition over time (stacked),
  proportion of a whole (pie/donut), or magnitude + rate together (combo).

## When NOT to use
- XY scatter with arbitrary X, 3D or gauge → not supported. Free-hand drawing → [`whiteboard`](/docs/ui/widgets/whiteboard).

## Complete example (copy, paste and run)
In CrossFly you write **a single `Window` class** (the main screen) — the `Main` and the launcher are
**platform boilerplate**. Point the launcher at this class (`classname` parameter) and run
`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…

/**
 * Main runnable screen. Point the launcher to this class (classname)
 * and run: 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);         // fixed Y range (or autoYAxis())

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

> The snippets below show **only the core** (what goes inside `onShow()`), to focus on the feature.
> To run them, place the core inside the `MainWindow` skeleton above.

## Basic usage (per subclass — recommended)
```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);                    // fixed Y range (or autoYAxis())
add(LAY_FILL, line);
```

### Bar and stacked bar
```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);
```

### Area and stacked area
```java
AreaChart area = new AreaChart();
area.withSeries("Load", new double[]{180, 260, 210, 300, 280}, 0xFF26C6DA);
area.areaOpacity(110);                    // fill 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;                        // public fields for fine-tuning
```

### Pie and donut
```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);                          // hole radius [0..0.95]
```

### Combo (bars + line on secondary axis)
```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);  // right Y axis
combo.title("Conversão x Sessões").yAxis(0, 1600, 8);
```

## Data model
- **`ChartView.Series`** (cartesian): `new Series(name, double[] values[, color])`; the fluent `.line()` /
  `.bar()` set the `renderMode` (used in the combo).
- **`ChartView.PieSlice`** (radial): `new PieSlice(name, double value[, color])`.
- **Color `0` = automatic** (`DEFAULT_COLORS` palette, 9 colors). For a fixed color use ARGB **with alpha** (`0xFF…`).

## Configuration (public fields + fluent)
| Member | Type | Default | What it does |
|---|---|---|---|
| `title(String)` · `categories(String[])` | fluent | — | title / X-axis labels |
| `yAxis(min, max, steps)` · `autoYAxis()` | fluent | auto | Y-axis range |
| `smooth(bool)` / `smoothLines` | fluent/field | `false` | Catmull-Rom interpolation |
| `area(bool)` / `showArea` | fluent/field | `false` | fills the area under the line |
| `areaOpacity(int)` / `areaAlpha` | fluent/field | `0x55` | alpha (0–255) of the fill |
| `showLegend`/`showGrid`/`showTitle`/`showPoints`/`showValues` | field | `true` | display flags |
| `decimals` | field | `2` | decimal places in labels/tooltips |
| `axisColor`/`axisTextColor`/`legendTextColor`/`gridColor` | field | theme | colors (ARGB) |
| `pointRadius`/`lineThickness`/`barInnerGap`/`splineSteps` | field | — | fine-tuning the drawing |
| `donutHoleRatio` / `hole(float)` | field/fluent | `0.56` | donut hole |
| `enableHoverSelection`/`enableInteractionAnimations` | field | `true` | hover selection / highlight animation |

> After changing **public fields** outside a fluent method, call `repaint()`.

## Callbacks and states
- **`onAction(Action)`** fires when the **selection changes** (point/bar/slice) — via `runActions()`.
  Read `selectedSeries`+`selectedIndex` (cartesian) or `selectedSlice` (radial); `-1` = nothing.
- Interaction via `onTouchUp` (selects the nearest) and `onHover` (highlights under the cursor). There is no `onClick`.

## Style
Like any `Component`: `chart.getStyle().backColor(...)`/`borderColor(...)`; use `.copy()` to
derive without mutating the shared one:
```java
chart.style(chart.getStyle().copy().backColor(0xFFFFFFFF).borderColor(0xFFE0E0E0));
```

## Best practices
- Prefer the **concrete subclass** (`LineChart`, `BarChart`…) over the raw `ChartView` — the fluent methods
  are clearer.
- Cartesian uses `series`/`withSeries`; radial uses `slices`/`slice` — do not mix them within the same type.
- Fix `yAxis(min,max,steps)` for stable axes (the automatic mode includes zero and can "flatten").

## Common mistakes
- Using the **old names** `LineChartView`/`PieChartView`… (renamed) or **`withSlice`** (now `slice`).
- Passing color `0x00…` expecting black: `0` is "automatic" and alpha `00` is invisible — use `0xFF000000`.
- Expecting `onClick`: interaction is via `onAction` fired by selection/hover.

## See also
- [`ui/`](/docs/ui) · [`cookbook/`](/docs/cookbook) · [`whiteboard`](/docs/ui/widgets/whiteboard)
