---
title: "Chart Card"
description: "Panel grafiklerinin çerçevesi: başlık, dönen ana değer, değişim rozeti, zaman aralığı seçimi ve grafik."
---

<Callout type="info" title="Ne zaman kullanılır">
Panelde tek başına duran her grafik. Aralık değişince ana değer döner, grafik yumuşakça yeniden çizilir.
</Callout>

## Kurulum

```bash
npx shadcn@latest add @ikas/chart-card
```

Registry tanımı yoksa önce [Kurulum](https://builders.ikas.com/tr/docs/app-development/ui-kit/installation) adımlarını tamamlayın.

## Örnekler

### Gelir

7G / 30G / 90G arasında geçin: toplam yön duyarlı döner, alan grafiği soldan sağa yeniden açılır.

**Örnek: Gelir** (`chart-card/revenue`) · [Canlı önizleme](https://builders.ikas.com/ui-preview/demo/chart-card/revenue?align=stretch)

```tsx
import * as React from "react"
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from "recharts"

import { ChartContainer, ChartTooltip } from "@/components/ui/chart"
import { ChartCard } from "@/components/ikas/chart-card"
import { ChartFillDefs, ChartTooltipCard, RevealMask, chartFill, compactNumberFormat } from "@/components/ikas/chart-kit"

type Range = "7" | "30" | "90"

const money = new Intl.NumberFormat("tr-TR", { style: "currency", currency: "TRY", maximumFractionDigits: 0 }).format
const day = new Intl.DateTimeFormat("tr-TR", { day: "numeric", month: "short" }).format

/** Deterministic, gently rising revenue so ranges look like the same store. */
function revenue(days: number) {
  const end = new Date(2026, 9, 6)
  return Array.from({ length: days }, (_, i) => {
    const date = new Date(end)
    date.setDate(end.getDate() - (days - 1 - i))
    const trend = 4200 + i * (5200 / days)
    const wave = Math.sin(i * 0.9) * 900 + Math.cos(i * 0.37) * 650
    const weekend = date.getDay() % 6 === 0 ? 1400 : 0
    return { date: day(date), revenue: Math.round(trend + wave + weekend) }
  })
}

const data: Record<Range, ReturnType<typeof revenue>> = { "7": revenue(7), "30": revenue(30), "90": revenue(90) }
const changes: Record<Range, number> = { "7": 8.4, "30": 12.4, "90": 31.2 }

export default function ChartCardRevenue() {
  const [range, setRange] = React.useState<Range>("30")
  const rows = data[range]
  const total = rows.reduce((sum, r) => sum + r.revenue, 0)
  const id = React.useId().replace(/:/g, "")

  return (
    <ChartCard
      className="w-full"
      title="Gelir"
      value={total}
      valueFormat={money}
      change={changes[range]}
      changeLabel="önceki döneme göre"
      ranges={[
        { value: "7", label: "7G" },
        { value: "30", label: "30G" },
        { value: "90", label: "90G" },
      ]}
      range={range}
      onRangeChange={setRange}
      footer="Kargo ve vergiler hariç. Veriler her saat güncellenir."
    >
      <ChartContainer config={{ revenue: { label: "Gelir", color: "var(--chart-ink)" } }} className="aspect-auto h-56 w-full">
        <AreaChart data={rows} margin={{ top: 4, right: 4, bottom: 0, left: 0 }}>
          <defs>
            <ChartFillDefs id={`${id}-fill`} color="var(--chart-ink)" variant="gradient" />
            <RevealMask id={`${id}-reveal`} />
          </defs>
          <CartesianGrid vertical={false} stroke="var(--border)" />
          <XAxis dataKey="date" tickLine={false} axisLine={false} tickMargin={8} minTickGap={28} />
          <YAxis width={44} tickLine={false} axisLine={false} tickFormatter={compactNumberFormat} />
          <ChartTooltip
            cursor={{ stroke: "var(--border-strong)" }}
            content={({ active, payload, label }) =>
              active && payload?.length ? (
                <ChartTooltipCard title={label} format={money} rows={[{ key: "revenue", label: "Gelir", color: "var(--chart-ink)", value: payload[0].value as number }]} />
              ) : null
            }
          />
          <Area
            type="monotone"
            dataKey="revenue"
            stroke="var(--chart-ink)"
            strokeWidth={2}
            fill={chartFill(`${id}-fill`, "var(--chart-ink)", "gradient")}
            isAnimationActive={false}
            activeDot={{ r: 4, strokeWidth: 2, stroke: "var(--card)" }}
            style={{ mask: `url(#${id}-reveal)` }}
          />
        </AreaChart>
      </ChartContainer>
    </ChartCard>
  )
}
```

### Donut ile

Gövdeye herhangi bir grafik konabilir.

**Örnek: Donut ile** (`chart-card/donut`) · [Canlı önizleme](https://builders.ikas.com/ui-preview/demo/chart-card/donut)

```tsx
import * as React from "react"

import { ChartCard } from "@/components/ikas/chart-card"
import { DonutChart } from "@/components/ikas/donut-chart"
import { channels } from "@/demos/_data"

type Range = "month" | "quarter"

const data: Record<Range, { key: string; label: string; value: number }[]> = {
  month: [
    { key: "web", label: channels.web, value: 412 },
    { key: "marketplaceA", label: channels.marketplaceA, value: 296 },
    { key: "marketplaceB", label: channels.marketplaceB, value: 158 },
    { key: "social", label: channels.social, value: 87 },
  ],
  quarter: [
    { key: "web", label: channels.web, value: 1184 },
    { key: "marketplaceA", label: channels.marketplaceA, value: 1042 },
    { key: "marketplaceB", label: channels.marketplaceB, value: 391 },
    { key: "social", label: channels.social, value: 312 },
  ],
}

export default function ChartCardDonut() {
  const [range, setRange] = React.useState<Range>("month")
  const total = data[range].reduce((sum, d) => sum + d.value, 0)

  return (
    <ChartCard
      className="w-full max-w-xl"
      title="Kanal bazında sipariş"
      value={total}
      change={range === "month" ? -3.1 : 9.6}
      ranges={[
        { value: "month", label: "Bu ay" },
        { value: "quarter", label: "Çeyrek" },
      ]}
      range={range}
      onRangeChange={setRange}
    >
      <DonutChart height={170} centerLabel="Sipariş" data={data[range]} />
    </ChartCard>
  )
}
```

## Kullanım ilkeleri

**Yapın:**

- Ana değer ile grafik aynı aralığı göstersin.
- Aralık seçeneklerini 2–4 ile sınırlayın: 7G, 30G, 90G.

**Yapmayın:**

- Kart içine ikinci bir ana değer koymayın; iki metrik iki kart demektir.
- İki farklı ölçeği tek grafikte iki eksenle göstermeyin.

## API

### `ChartCard<T>`

| Prop | Tip | Varsayılan | Açıklama |
| --- | --- | --- | --- |
| `title` (zorunlu) | `React.ReactNode` | - | Ne ölçüldüğü. Kısa isim: “Gelir”, “İade oranı”. |
| `description` | `React.ReactNode` | - | Değerin altında bir satır bağlam. |
| `value` | `number` | - | Seçili aralığın ana değeri. AnimatedNumber ile döner. |
| `valueFormat` | `(value: number) => string` | `defaultNumberFormat` | Ana değerin biçimi. Varsayılan tr-TR sayı biçimi. |
| `change` | `number` | - | Önceki döneme göre yüzde değişim. Yöne göre yeşil/kırmızı rozet. |
| `invertChange` | `boolean` | `false` | Düşüşün iyi olduğu metrikler (iade, hata, süre). |
| `changeLabel` | `React.ReactNode` | - | Karşılaştırılan dönem. |
| `ranges` | `ChartCardRange<T>[]` | - | Sağ üstteki zaman aralığı seçimi. Değişince gövde yeniden mount edilip fade ile gelir. |
| `range` | `T` | - | Sağ üstteki zaman aralığı seçimi. Değişince gövde yeniden mount edilip fade ile gelir. |
| `onRangeChange` | `(range: T) => void` | - | Sağ üstteki zaman aralığı seçimi. Değişince gövde yeniden mount edilip fade ile gelir. |
| `footer` | `React.ReactNode` | - | Kaynak, güncellenme sıklığı gibi küçük notlar. |
| `className` | `string` | - |  |
| `children` (zorunlu) | `React.ReactNode` | - | The chart, usually AreaChart or BarChart. |
