Pie Charts

Pie chart examples: donut, labels, legend, stacked rings and more.

Each example is an iv-card with a chart inside. Copy the code under it. See Chart for the parts and the API.

import { IV_CHART_IMPORTS } from '@inlaylab/ivorie/chart';

Interactive

Pie Chart - InteractiveJanuary - June 2024
186 Visitors
import { ChangeDetectionStrategy, Component, computed, signal } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_SELECT_IMPORTS } from '@inlaylab/ivorie/select';
import { IV_CHART_IMPORTS, IvChartConfig, IvSectorShape, ivArc } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-interactive',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, IV_SELECT_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="flex-row items-start space-y-0 pb-0">
        <div class="grid gap-1">
          <iv-card-title>Pie Chart - Interactive</iv-card-title>
          <iv-card-description>January - June 2024</iv-card-description>
        </div>
        <iv-select [(value)]="month">
          <iv-select-trigger
            class="ml-auto h-7 w-[130px] rounded-lg pl-2.5"
            aria-label="Select a value"
          />
          <iv-select-content class="rounded-xl">
            @for (key of months; track key) {
              <iv-select-item [value]="key" class="rounded-lg">
                <div class="flex items-center gap-2 text-xs">
                  <span
                    class="flex h-3 w-3 shrink-0 rounded-xs"
                    [style.background-color]="config[key].color"
                  ></span>
                  {{ config[key].label }}
                </div>
              </iv-select-item>
            }
          </iv-select-content>
        </iv-select>
      </iv-card-header>
      <iv-card-content class="flex flex-1 justify-center pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square w-full max-w-[300px]">
          <svg ivPieChart>
            <g
              ivPie
              [data]="data"
              dataKey="desktop"
              nameKey="month"
              [innerRadius]="60"
              [strokeWidth]="5"
              [activeIndex]="activeIndex()"
            >
              <ng-template ivActiveShape let-s>
                <svg:path [attr.d]="grow(s)" [attr.fill]="s.fill" />
                <svg:path [attr.d]="ring(s)" [attr.fill]="s.fill" />
              </ng-template>
              <ng-template ivChartLabel let-cx="cx" let-cy="cy">
                <svg:text
                  [attr.x]="cx"
                  [attr.y]="cy"
                  text-anchor="middle"
                  dominant-baseline="middle"
                >
                  <svg:tspan [attr.x]="cx" [attr.y]="cy" class="fill-foreground text-3xl font-bold">
                    {{ data[activeIndex()].desktop.toLocaleString() }}
                  </svg:tspan>
                  <svg:tspan [attr.x]="cx" [attr.y]="cy + 24" class="fill-muted-foreground">
                    Visitors
                  </svg:tspan>
                </svg:text>
              </ng-template>
            </g>
          </svg>
          <iv-chart-tooltip [cursor]="false" hideLabel />
        </iv-chart>
      </iv-card-content>
    </iv-card>
  `,
})
export default class ChartPieInteractive {
  protected readonly data = [
    { month: 'january', desktop: 186, fill: 'var(--color-january)' },
    { month: 'february', desktop: 305, fill: 'var(--color-february)' },
    { month: 'march', desktop: 237, fill: 'var(--color-march)' },
    { month: 'april', desktop: 173, fill: 'var(--color-april)' },
    { month: 'may', desktop: 209, fill: 'var(--color-may)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    desktop: { label: 'Desktop' },
    mobile: { label: 'Mobile' },
    january: { label: 'January', color: 'var(--chart-1)' },
    february: { label: 'February', color: 'var(--chart-2)' },
    march: { label: 'March', color: 'var(--chart-3)' },
    april: { label: 'April', color: 'var(--chart-4)' },
    may: { label: 'May', color: 'var(--chart-5)' },
  };

  protected readonly months = this.data.map((row) => row.month);
  protected readonly month = signal<string | null>(this.months[0]);
  protected readonly activeIndex = computed(() =>
    Math.max(
      0,
      this.data.findIndex((row) => row.month === this.month()),
    ),
  );

  /** The active sector, 10px larger, and a ring around it. */
  protected readonly grow = (s: IvSectorShape) => ivArc({ ...s, outerRadius: s.outerRadius + 10 });
  protected readonly ring = (s: IvSectorShape) =>
    ivArc({ ...s, innerRadius: s.outerRadius + 12, outerRadius: s.outerRadius + 25 });
}

Simple

Pie ChartJanuary - June 2024
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-simple',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px]">
          <svg ivPieChart>
            <g ivPie [data]="data" dataKey="visitors" nameKey="browser" />
          </svg>
          <iv-chart-tooltip [cursor]="false" hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieSimple {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;
}

Separator None

Pie Chart - Separator NoneJanuary - June 2024
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-separator-none',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Separator None</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px]">
          <svg ivPieChart>
            <g ivPie [data]="data" dataKey="visitors" nameKey="browser" stroke="0" />
          </svg>
          <iv-chart-tooltip [cursor]="false" hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieSeparatorNone {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;
}

Label

Pie Chart - LabelJanuary - June 2024 275 200 187 173 90
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-label',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Label</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart
          [config]="config"
          class="mx-auto aspect-square max-h-[250px] pb-0 [&_[data-slot=chart-pie-label]]:fill-foreground"
        >
          <svg ivPieChart>
            <g ivPie [data]="data" dataKey="visitors" label nameKey="browser" />
          </svg>
          <iv-chart-tooltip hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieLabel {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;
}

Custom Label

Pie Chart - Custom LabelJanuary - June 2024 275 200 187 173 90
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-label-custom',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Custom Label</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px] px-0">
          <svg ivPieChart>
            <g
              ivPie
              [data]="data"
              dataKey="visitors"
              [labelLine]="false"
              [label]="label"
              nameKey="browser"
            >
              <ng-template #label let-l>
                <svg:text
                  [attr.x]="l.x"
                  [attr.y]="l.y"
                  [attr.text-anchor]="l.textAnchor"
                  [attr.dominant-baseline]="l.dominantBaseline"
                  fill="var(--foreground)"
                >
                  {{ l.value }}
                </svg:text>
              </ng-template>
            </g>
          </svg>
          <iv-chart-tooltip nameKey="visitors" hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieLabelCustom {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;
}

Label List

Pie Chart - Label ListJanuary - June 2024 Chrome Safari Firefox Edge Other
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-label-list',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Label List</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px]">
          <svg ivPieChart>
            <g ivPie [data]="data" dataKey="visitors">
              <g
                ivLabelList
                dataKey="browser"
                class="fill-background text-xs"
                [formatter]="label"
              />
            </g>
          </svg>
          <iv-chart-tooltip nameKey="visitors" hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieLabelList {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;

  /** The config label of a browser key. */
  protected readonly label = (browser: string) => this.config[browser]?.label ?? browser;
}

Legend

Pie Chart - LegendJanuary - June 2024
Chrome
Safari
Firefox
Edge
Other
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-legend',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Legend</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[300px]">
          <svg ivPieChart>
            <g ivPie [data]="data" dataKey="visitors" />
          </svg>
          <iv-chart-legend
            nameKey="browser"
            class="-translate-y-2 flex-wrap gap-2 *:basis-1/4 *:justify-center"
          />
        </iv-chart>
      </iv-card-content>
    </iv-card>
  `,
})
export default class ChartPieLegend {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };
}

Donut

Pie Chart - DonutJanuary - June 2024
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-donut',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Donut</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px]">
          <svg ivPieChart>
            <g ivPie [data]="data" dataKey="visitors" nameKey="browser" [innerRadius]="60" />
          </svg>
          <iv-chart-tooltip [cursor]="false" hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieDonut {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;
}

Donut Active

Pie Chart - Donut ActiveJanuary - June 2024
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig, IvSectorShape, ivArc } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-donut-active',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Donut Active</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px]">
          <svg ivPieChart>
            <g
              ivPie
              [data]="data"
              dataKey="visitors"
              nameKey="browser"
              [innerRadius]="60"
              [strokeWidth]="5"
              [activeIndex]="0"
            >
              <ng-template ivActiveShape let-s>
                <svg:path [attr.d]="grow(s)" [attr.fill]="s.fill" />
              </ng-template>
            </g>
          </svg>
          <iv-chart-tooltip [cursor]="false" hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieDonutActive {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 187, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 90, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;

  /** The active sector, 10px larger. */
  protected readonly grow = (s: IvSectorShape) => ivArc({ ...s, outerRadius: s.outerRadius + 10 });
}

Donut with Text

Pie Chart - Donut with TextJanuary - June 2024 1,125 Visitors
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-donut-text',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Donut with Text</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px]">
          <svg ivPieChart>
            <g
              ivPie
              [data]="data"
              dataKey="visitors"
              nameKey="browser"
              [innerRadius]="60"
              [strokeWidth]="5"
            >
              <ng-template ivChartLabel let-cx="cx" let-cy="cy">
                <svg:text
                  [attr.x]="cx"
                  [attr.y]="cy"
                  text-anchor="middle"
                  dominant-baseline="middle"
                >
                  <svg:tspan [attr.x]="cx" [attr.y]="cy" class="fill-foreground text-3xl font-bold">
                    {{ total.toLocaleString() }}
                  </svg:tspan>
                  <svg:tspan [attr.x]="cx" [attr.y]="cy + 24" class="fill-muted-foreground">
                    Visitors
                  </svg:tspan>
                </svg:text>
              </ng-template>
            </g>
          </svg>
          <iv-chart-tooltip [cursor]="false" hideLabel />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieDonutText {
  protected readonly data = [
    { browser: 'chrome', visitors: 275, fill: 'var(--color-chrome)' },
    { browser: 'safari', visitors: 200, fill: 'var(--color-safari)' },
    { browser: 'firefox', visitors: 287, fill: 'var(--color-firefox)' },
    { browser: 'edge', visitors: 173, fill: 'var(--color-edge)' },
    { browser: 'other', visitors: 190, fill: 'var(--color-other)' },
  ];

  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    chrome: { label: 'Chrome', color: 'var(--chart-1)' },
    safari: { label: 'Safari', color: 'var(--chart-2)' },
    firefox: { label: 'Firefox', color: 'var(--chart-3)' },
    edge: { label: 'Edge', color: 'var(--chart-4)' },
    other: { label: 'Other', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;

  protected readonly total = this.data.reduce((sum, row) => sum + row.visitors, 0);
}

Stacked

Pie Chart - StackedJanuary - June 2024
Trending up by 5.2% this month
Showing total visitors for the last 6 months
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { NgIcon } from '@ng-icons/core';
import { lucideTrendingUp } from '@ng-icons/lucide';
import { IV_CARD_IMPORTS } from '@inlaylab/ivorie/card';
import { IV_CHART_IMPORTS, IvChartConfig, IvChartPayload } from '@inlaylab/ivorie/chart';

@Component({
  selector: 'demo-chart-pie-stacked',
  imports: [IV_CARD_IMPORTS, IV_CHART_IMPORTS, NgIcon],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-card class="w-full max-w-md flex flex-col">
      <iv-card-header class="items-center pb-0">
        <iv-card-title>Pie Chart - Stacked</iv-card-title>
        <iv-card-description>January - June 2024</iv-card-description>
      </iv-card-header>
      <iv-card-content class="flex-1 pb-0">
        <iv-chart [config]="config" class="mx-auto aspect-square max-h-[250px]">
          <svg ivPieChart>
            <g ivPie [data]="desktop" dataKey="desktop" [outerRadius]="60" />
            <g ivPie [data]="mobile" dataKey="mobile" [innerRadius]="70" [outerRadius]="90" />
          </svg>
          <iv-chart-tooltip
            labelKey="visitors"
            nameKey="month"
            indicator="line"
            [labelFormatter]="series"
          />
        </iv-chart>
      </iv-card-content>
      <iv-card-footer class="flex-col gap-2 text-sm">
        <div class="flex items-center gap-2 leading-none font-medium">
          Trending up by 5.2% this month <ng-icon [svg]="trendingUp" size="16" />
        </div>
        <div class="text-muted-foreground leading-none">
          Showing total visitors for the last 6 months
        </div>
      </iv-card-footer>
    </iv-card>
  `,
})
export default class ChartPieStacked {
  protected readonly config: IvChartConfig = {
    visitors: { label: 'Visitors' },
    desktop: { label: 'Desktop' },
    mobile: { label: 'Mobile' },
    january: { label: 'January', color: 'var(--chart-1)' },
    february: { label: 'February', color: 'var(--chart-2)' },
    march: { label: 'March', color: 'var(--chart-3)' },
    april: { label: 'April', color: 'var(--chart-4)' },
    may: { label: 'May', color: 'var(--chart-5)' },
  };

  protected readonly trendingUp = lucideTrendingUp;

  protected readonly desktop = [
    { month: 'january', desktop: 186, fill: 'var(--color-january)' },
    { month: 'february', desktop: 305, fill: 'var(--color-february)' },
    { month: 'march', desktop: 237, fill: 'var(--color-march)' },
    { month: 'april', desktop: 173, fill: 'var(--color-april)' },
    { month: 'may', desktop: 209, fill: 'var(--color-may)' },
  ];

  protected readonly mobile = [
    { month: 'january', mobile: 80, fill: 'var(--color-january)' },
    { month: 'february', mobile: 200, fill: 'var(--color-february)' },
    { month: 'march', mobile: 120, fill: 'var(--color-march)' },
    { month: 'april', mobile: 190, fill: 'var(--color-april)' },
    { month: 'may', mobile: 130, fill: 'var(--color-may)' },
  ];

  /** The label names the ring: Desktop or Mobile. */
  protected readonly series = (_: unknown, payload: IvChartPayload[]) =>
    String(this.config[payload[0]?.key]?.label ?? '');
}