# `Drafter.Widget.PieChart`
[🔗](https://github.com/jaman/drafter/blob/main/lib/drafter/widget/pie_chart.ex#L1)

Renders a circular pie chart using Unicode block and braille characters.

Each slice is proportional to its value relative to the total. The chart uses
quarter-block and half-block Unicode characters for sub-cell resolution rendering,
and braille characters where finer detail is needed.

## Component tag

Tag `:pie_chart`, built by `Drafter.App` as `{:pie_chart, data, opts}`:

    pie_chart(data, opts)

The positional argument becomes `:data` when it is a non-empty list that is not
a keyword list; otherwise `:data` is read from `opts`.

## Options

  * `:data` - `[{label, value} | {label, value, rgb}]`. Default `[]`. A slice
    without an explicit colour takes the palette entry at its index, cycling.
    A total of zero gives every slice a percentage of `0.0`.
  * `:show_legend` - `t:boolean/0`, draw labels down the right-hand side. Default
    `true`. The legend takes `min(longest_entry + 4, 30)` columns and the pie
    takes the rest, with at least one column.
  * `:show_percentages` - `t:boolean/0`, append `(12.5%)` to each legend label.
    Default `true`. Only read when the legend is drawn.
  * `:colors` - `[{r, g, b}]` palette. Default
    `[{100, 180, 255}, {255, 130, 80}, {100, 220, 140}, {220, 100, 220},
    {255, 220, 80}, {120, 220, 220}, {255, 100, 100}, {180, 140, 255}]`.
  * `:renderer` - `:text` (default) draws block and braille cells. Any other atom
    is treated as a terminal graphics protocol and passed to
    `Drafter.Widget.Chart.Pixel`, falling back to cells when that protocol is
    unavailable.
  * `:style` - `t:map/0` of style overrides passed to the theme computation.
    Default `%{}`.
  * `:class` - theme class atom or list of them, normalised by
    `Drafter.Style.normalize_classes/1` and reaching `mount/1` as `:classes`.
    Default `[]`.
  * `:height` - `t:pos_integer/0` read only by `preferred_height/2`, never by
    `mount/1`. Default `10`.

Every option except `:height` is live-updatable: `update_props_from_mount/3`
passes the full mount props through.

## Usage

    pie_chart([{"Elixir", 45}, {"Rust", 30}, {"Go", 25}])
    pie_chart([{"A", 60, {255, 100, 100}}, {"B", 40, {100, 100, 255}}])
    pie_chart([{"X", 10}, {"Y", 20}], show_legend: false)

# `entry`

```elixir
@type entry() :: {String.t(), number()} | {String.t(), number(), rgb()}
```

# `rgb`

```elixir
@type rgb() :: {0..255, 0..255, 0..255}
```

# `t`

```elixir
@type t() :: %Drafter.Widget.PieChart{
  app_module: module() | nil,
  classes: [atom()],
  colors: [rgb()],
  data: [entry()],
  renderer: atom(),
  show_legend: boolean(),
  show_percentages: boolean(),
  style: map()
}
```

# `apply_data_buffer`

```elixir
@spec apply_data_buffer(t(), [entry() | term()], Drafter.Widget.rect() | nil) :: t()
```

Replaces `:data` with a non-empty list of slice entries.

Unlike the other data-driven widgets this expects a plain list rather than a
`Drafter.RingBuffer`: `{label, value}` and `{label, value, color}` tuples pass
through, and anything else becomes `{"", term}`. An empty list or a value that is
not a list returns `state` unchanged.

    iex> state = Drafter.Widget.PieChart.mount(%{})
    iex> Drafter.Widget.PieChart.apply_data_buffer(state, [{"A", 1}, 7], nil).data
    [{"A", 1}, {"", 7}]

    iex> state = Drafter.Widget.PieChart.mount(%{data: [{"A", 1}]})
    iex> Drafter.Widget.PieChart.apply_data_buffer(state, [], nil).data
    [{"A", 1}]

# `component_tag`

```elixir
@spec component_tag() :: :pie_chart
```

The component tag this widget registers under.

    iex> Drafter.Widget.PieChart.component_tag()
    :pie_chart

# `focused`

# `from_component_opts`

```elixir
@spec from_component_opts(
  term(),
  keyword()
) :: Drafter.Widget.props()
```

Builds the props map for a `{:pie_chart, data, opts}` element.

`data` becomes `:data` when it is a non-empty list that is not a keyword list;
otherwise `opts[:data]` is used, defaulting to `[]`. `:class` is normalised into
`:classes` and `:__app_module__` becomes `:app_module`.

    iex> props = Drafter.Widget.PieChart.from_component_opts([{"A", 1}], show_legend: false)
    iex> {props.data, props.show_legend, props.renderer}
    {[{"A", 1}], false, :text}

    iex> Drafter.Widget.PieChart.from_component_opts(nil, data: [{"B", 2}]).data
    [{"B", 2}]

# `handle_event`

```elixir
@spec handle_event(Drafter.Event.t(), t()) :: {:bubble, t()}
```

Ignores every event and returns `{:bubble, state}`, letting it continue to the
parent widget and then to the app.

# `image_active?`

```elixir
@spec image_active?(t()) :: boolean()
```

Whether this pie chart is drawing a transmitted image rather than cells.

# `mount`

```elixir
@spec mount(Drafter.Widget.props()) :: t()
```

Builds the widget state from `props`.

Every option listed in the module doc is read here with the default stated there.

    iex> state = Drafter.Widget.PieChart.mount(%{data: [{"A", 60}, {"B", 40}]})
    iex> {state.data, state.show_legend, state.show_percentages, state.renderer}
    {[{"A", 60}, {"B", 40}], true, true, :text}

    iex> Drafter.Widget.PieChart.mount(%{}).colors |> length()
    8

# `preferred_height`

```elixir
@spec preferred_height(
  term(),
  keyword()
) :: pos_integer()
```

The number of rows the element asks for: `opts[:height]`, default `10`.

    iex> Drafter.Widget.PieChart.preferred_height(nil, [])
    10

    iex> Drafter.Widget.PieChart.preferred_height(nil, height: 20)
    20

# `render`

```elixir
@spec render(t() | Drafter.Widget.props(), Drafter.Widget.rect()) :: [
  Drafter.Draw.Strip.t()
]
```

Draws the chart into `rect`, always returning exactly `rect.height` strips.

`state` may be a plain props map, in which case it is passed through `mount/1`
first. Slices are laid out clockwise starting at twelve o'clock. This is the cell
renderer and is used whatever `:renderer` says; `image/3` is the graphics path.

# `unmount`

# `update`

```elixir
@spec update(Drafter.Widget.props(), t()) :: t()
```

Replaces the state fields named in `props`, keeping the current value for any key
that is absent.

Accepts `:data`, `:show_legend`, `:show_percentages`, `:colors`, `:style`,
`:classes`, `:app_module` and `:renderer`.

    iex> state = Drafter.Widget.PieChart.mount(%{data: [{"A", 1}]})
    iex> updated = Drafter.Widget.PieChart.update(%{show_legend: false}, state)
    iex> {updated.data, updated.show_legend}
    {[{"A", 1}], false}

# `update_props_from_mount`

```elixir
@spec update_props_from_mount(Drafter.Widget.props(), term(), keyword()) ::
  Drafter.Widget.props()
```

Passes the mount props through unchanged, so every option is live-updatable
through the component tree.

    iex> props = Drafter.Widget.PieChart.from_component_opts([{"A", 1}], [])
    iex> Drafter.Widget.PieChart.update_props_from_mount(props, %{}, []) == props
    true

---

*Consult [api-reference.md](api-reference.md) for complete listing*
