> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Donut

> Donut chart implementation for @servicetitan/anvil2-rn-charts-kit.

A donut chart shows part-to-whole relationships. Each slice is a variable, so `variant` assigns color per datum. Use `monochrome` for four or fewer slices, and `categorical` for five or more, grouping the remainder into an "Other" slice. Donut charts do not use the semantic palette.

* Design rules: [Donut charts](/docs/web/data-visualization/donut-charts)
* Shared API / tooltips / palettes: [Chart component](/docs/kits/charts-react-native/chart)

***

## Minimal option

A donut is a pie series with an inner radius. The `padAngle` and slice corner radius come from `variant`.

```tsx theme={null}
const option: EChartsOption = {
  legend: { orient: "vertical", right: 8, top: "middle" },
  series: [
    {
      type: "pie",
      radius: ["40%", "70%"],
      data: [
        { name: "Organic", value: 48 },
        { name: "Paid", value: 32 },
        { name: "Referral", value: 14 },
        { name: "Other", value: 6 },
      ],
    },
  ],
};

<Chart
  option={option}
  variant="monochrome"
  width={480}
  height={300}
  accessibilityLabel="Donut chart. Revenue by channel."
/>;
```

***

## Variant styling

`variant` applies the following treatment:

| Concern       | Behavior                                            |
| ------------- | --------------------------------------------------- |
| Color         | Monochrome steps or categorical hues by slice index |
| Gaps          | `padAngle` of roughly 4px between slices            |
| Slice corners | `borderRadius` on slices                            |
| Hover         | Series focus and blur                               |

Avoid hand-authoring slice gaps or palette hex values to reproduce this treatment.

***

## Labels inside slices

Direct labels follow the same pattern as bar end labels. The chart theme styles `pie.label` with a font, a translucent background, and padding, and leaves it at `show: false`. Enable it with `position: "inside"`.

Use percent of total for part-to-whole, which ECharts writes as `{d}%`. Raw values through `{c}` also work. Categorical donut charts require direct labels, because the slice colors do not all reach a 3:1 contrast ratio against each other. Leave `renderTooltip` unset when the in-slice labels carry enough information. Small slices clip their labels, so group them into an "Other" slice.

```tsx theme={null}
series: [
  {
    type: "pie",
    radius: ["40%", "70%"],
    data: [
      { name: "Organic", value: 48 },
      { name: "Paid", value: 32 },
      { name: "Referral", value: 14 },
      { name: "Other", value: 6 },
    ],
    // Theme supplies font / background / padding; show + position (+ formatter) are required.
    label: {
      show: true,
      position: "inside",
      formatter: "{d}%", // percent of total; use "{c}" for the raw value
    },
  },
];
```

***

## Labels outside with a leader line

Outside labels suit charts where in-slice text would clutter or clip. Set `position: "outside"` and `labelLine: { show: true }`. Add the category to the formatter through `{b}` when the chart has no legend, and leave room in the plot by reducing `radius` or dropping the side legend so the labels do not collide.

```tsx theme={null}
series: [
  {
    type: "pie",
    radius: ["35%", "55%"],
    data: [
      { name: "Organic", value: 48 },
      { name: "Paid", value: 32 },
      { name: "Referral", value: 14 },
      { name: "Other", value: 6 },
    ],
    label: {
      show: true,
      position: "outside",
      formatter: "{b}\\n{d}%", // name + percent
    },
    labelLine: { show: true },
  },
];
```

***

## Mixed labels by slice size

The series defaults to inside labels, and slices below a percentage threshold override to outside labels with a `labelLine`. ECharts merges per-slice `label` and `labelLine` values onto the series defaults. The threshold is a product decision: the 20% cutoff in this example is not a design system constant.

```tsx theme={null}
const MIN_PERCENT = 20; // product choice
const total = data.reduce((sum, d) => sum + d.value, 0);

const slices = data.map((d) => {
  const pct = (d.value / total) * 100;
  if (pct >= MIN_PERCENT) return d;
  return {
    ...d,
    label: { position: "outside", formatter: "{b}\\n{d}%" },
    labelLine: { show: true },
  };
});

series: [
  {
    type: "pie",
    radius: ["35%", "55%"],
    data: slices,
    label: { show: true, position: "inside", formatter: "{d}%" },
    labelLine: { show: false },
  },
];
```

***

## Tooltips

Pass `renderTooltip` for richer tooltip content. See [Chart component](/docs/kits/charts-react-native/chart#tooltips).

```tsx theme={null}
import { Chart } from "@servicetitan/anvil2-rn-charts-kit";
import { TooltipSurface } from "@servicetitan/anvil2-rn";
import type { ChartTooltipInfo } from "@servicetitan/anvil2-rn-charts-kit";
import type { EChartsOption } from "@servicetitan/anvil2-rn-charts-kit";
import { Text, View } from "react-native";

function renderTooltip({ name, points }: ChartTooltipInfo) {
  return (
    <TooltipSurface
      accessibilityLabel={name}
      content={
        <View>
          <Text>{name}</Text>
          {points.map((point) => (
            <Text key={point.seriesIndex}>
              {point.seriesName ? `${point.seriesName}: ` : ""}
              {String(point.value)}
            </Text>
          ))}
        </View>
      }
    />
  );
}

const option: EChartsOption = {
  legend: { orient: "vertical", right: 8, top: "middle" },
  series: [
    {
      type: "pie",
      radius: ["40%", "70%"],
      data: [
        { name: "Organic", value: 48 },
        { name: "Paid", value: 32 },
        { name: "Referral", value: 14 },
        { name: "Other", value: 6 },
      ],
    },
  ],
};

<Chart
  option={option}
  variant="monochrome"
  renderTooltip={renderTooltip}
  width={480}
  height={300}
  accessibilityLabel="Donut chart. Revenue by channel."
/>;
```
