# Multi-level Pie Example



This example shows how to create a multi-level (sunburst) pie chart by nesting `PieSlice` components with different `stack` values. Click a slice to see its breakdown in the secondary legend.

```tsx
import { Svg } from "cx/svg";
import { PieChart, PieSlice, Legend, ColorMap } from "cx/charts";
import { createModel } from "cx/data";
import { Controller, Repeater, KeySelection, expr } from "cx/ui";

interface SubSlice {
  name: string;
  value: number;
}

interface Slice {
  id: number;
  name: string;
  value: number;
  active: boolean;
  slices: SubSlice[];
}

interface Model {
  data: Slice[];
  $record: Slice;
  $index: number;
  $slice: SubSlice;
  $sliceIndex: number;
  selection: number | null;
}

const m = createModel<Model>();

const regions: Record<string, string[]> = {
  "North America": ["USA", "Canada", "Mexico"],
  Europe: ["Germany", "France", "UK", "Italy"],
  "Asia Pacific": ["China", "Japan", "India", "Australia"],
  "Latin America": ["Brazil", "Argentina", "Chile"],
  "Middle East": ["UAE", "Saudi Arabia", "Israel"],
  Africa: ["South Africa", "Nigeria", "Egypt"],
};

class PageController extends Controller {
  onInit() {
    this.store.set(
      m.data,
      Object.entries(regions).map(([name, countries], i) => {
        let slices = countries.map((country) => ({
          name: country,
          value: 5 + Math.random() * 25,
        }));
        return {
          id: i,
          name,
          value: slices.reduce((sum, s) => sum + s.value, 0),
          active: true,
          slices,
        };
      }),
    );
  }
}

export default (
  <div controller={PageController}>
    <Legend />
    <div style="display: flex; gap: 16px">
      <Svg style="flex: 1; height: 350px">
        <ColorMap />
        <PieChart gap={2}>
          <Repeater records={m.data}>
            <PieSlice
              value={m.$record.value}
              active={m.$record.active}
              colorMap="pie"
              r={55}
              r0={20}
              borderRadius={3}
              name={m.$record.name}
              selection={{
                type: KeySelection,
                bind: m.selection,
                record: m.$record,
                index: m.$index,
                keyField: "id",
              }}
            />
            <Repeater
              records={m.$record.slices}
              recordAlias="$slice"
              indexAlias="$sliceIndex"
            >
              <PieSlice
                value={m.$slice.value}
                active={m.$record.active}
                colorMap="pie"
                colorName={m.$record.name}
                r={90}
                r0={58}
                offset={3}
                borderRadius={3}
                name={m.$slice.name}
                legend={expr(m.selection, m.$record.id, (sel, id) =>
                  sel === id ? "slice" : false,
                )}
                stack="outer"
                style={{
                  fillOpacity: expr(m.$sliceIndex, (i) => 0.4 + 0.6 * (i / 3)),
                }}
                selection={{
                  type: KeySelection,
                  bind: m.selection,
                  record: m.$record,
                  index: m.$index,
                  keyField: "id",
                }}
              />
            </Repeater>
          </Repeater>
        </PieChart>
      </Svg>
      <Legend name="slice" vertical class="w-32" />
    </div>
  </div>
);

```

## How It Works

1. **Inner ring** - Main slices using the default stack
2. **Outer ring** - Sub-slices using `stack="outer"` to form a separate ring
3. **Shared selection** - Both rings share the same `KeySelection` to highlight related slices
4. **Dynamic legend** - The `legend` prop uses `expr` to show sub-slice legend only when parent is selected
5. **Opacity variation** - Sub-slices use varying `fillOpacity` to show hierarchy within the same color

## Configuration

| Property      | Type     | Default | Description                                           |
| ------------- | -------- | ------- | ----------------------------------------------------- |
| `stack`       | `string` | `stack` | Stack name. Use different values for separate rings.  |
| `r` / `r0`    | `number` |         | Outer/inner radius. Adjust to create ring separation. |
| `offset`      | `number` | `0`     | Gap between rings when using different stacks.        |
| `fillOpacity` | `number` |         | Use in `style` to vary opacity within a color.        |