pie-chart

PreviousNext

pie-chart

Docs
intentuiui

Preview

Loading preview…
components/ui/pie-chart.tsx
"use client"

import type { ComponentProps } from "react"
import { Cell, Pie, PieChart as PieChartPrimitive } from "recharts"
import type { NameType, ValueType } from "recharts/types/component/DefaultTooltipContent"
import {
  type BaseChartProps,
  Chart,
  ChartTooltip,
  ChartTooltipContent,
  DEFAULT_COLORS,
  getColorValue,
} from "./chart"

const sumNumericArray = (arr: number[]): number => arr.reduce((sum, num) => sum + num, 0)

const calculateDefaultLabel = (data: any[], valueKey: string): number =>
  sumNumericArray(data.map((dataPoint) => dataPoint[valueKey]))

const parseLabelInput = (
  labelInput: string | undefined,
  valueFormatter: (value: number) => string,
  data: any[],
  valueKey: string,
): string => labelInput || valueFormatter(calculateDefaultLabel(data, valueKey))

interface PieChartProps<TValue extends ValueType, TName extends NameType>
  extends Omit<
    BaseChartProps<TValue, TName>,
    | "hideGridLines"
    | "hideXAxis"
    | "hideYAxis"
    | "xAxisProps"
    | "yAxisProps"
    | "displayEdgeLabelsOnly"
    | "legend"
    | "legendProps"
  > {
  variant?: "pie" | "donut"
  nameKey?: string

  chartProps?: Omit<ComponentProps<typeof PieChartPrimitive>, "data" | "stackOffset">

  label?: string
  showLabel?: boolean
  pieProps?: Omit<ComponentProps<typeof Pie>, "data" | "dataKey" | "name">
}

const PieChart = <TValue extends ValueType, TName extends NameType>({
  data = [],
  dataKey,
  colors = DEFAULT_COLORS,
  config,
  children,
  label,
  showLabel,

  // Components
  tooltip = true,
  tooltipProps,

  variant = "pie",
  nameKey,

  chartProps,

  valueFormatter = (value: number) => value.toString(),
  pieProps,
  ...props
}: PieChartProps<TValue, TName>) => {
  const parsedLabelInput = parseLabelInput(label, valueFormatter, data, dataKey)

  return (
    <Chart config={config} data={data} layout="radial" dataKey={dataKey} {...props}>
      {({ onLegendSelect }) => (
        <PieChartPrimitive
          data={data}
          onClick={() => {
            onLegendSelect(null)
          }}
          margin={{
            bottom: 0,
            left: 0,
            right: 0,
            top: 0,
          }}
          {...chartProps}
        >
          {showLabel && variant === "donut" && (
            <text
              className="fill-fg font-semibold"
              x="50%"
              data-slot="label"
              y="50%"
              textAnchor="middle"
              dominantBaseline="middle"
            >
              {parsedLabelInput}
            </text>
          )}

          {!children ? (
            <Pie
              name={nameKey}
              dataKey={dataKey}
              data={data}
              cx={pieProps?.cx ?? "50%"}
              cy={pieProps?.cy ?? "50%"}
              startAngle={pieProps?.startAngle ?? 90}
              endAngle={pieProps?.endAngle ?? -270}
              strokeLinejoin="round"
              innerRadius={variant === "donut" ? "50%" : "0%"}
              isAnimationActive
              {...pieProps}
            >
              {data.map((_, index) => (
                <Cell
                  key={`cell-${index}`}
                  fill={getColorValue(
                    config?.[data[index]?.code || data[index]?.name]?.color ??
                      colors[index % colors.length],
                  )}
                />
              ))}
            </Pie>
          ) : (
            children
          )}

          {tooltip && (
            <ChartTooltip
              content={
                typeof tooltip === "boolean" ? (
                  <ChartTooltipContent hideLabel labelSeparator={false} accessibilityLayer />
                ) : (
                  tooltip
                )
              }
              {...tooltipProps}
            />
          )}
        </PieChartPrimitive>
      )}
    </Chart>
  )
}

export type { PieChartProps }
export { PieChart }

Installation

npx shadcn@latest add @intentui/pie-chart

Usage

import { PieChart } from "@/components/ui/pie-chart"
<PieChart />