Zum Inhalt springen
UI Kit
Accent

Flächendiagramm

Eine Linie mit ruhiger Fläche darunter, als Tönung, Verlauf oder gestapelte Bänder mit Lücke in Flächenfarbe.

Eine von 7 Components in Charts

3 Variants

Variants

Einfach

Tageswerte mit gleichmäßiger Tönung im Akzent, die Wochenenden fallen von selbst auf.

Verlauf

Die Tönung läuft zur Grundlinie aus, die Linie bleibt oben klar.

Gestapelt

Drei Kanäle gestapelt zur Wochensumme, der Tooltip rechnet sie zusammen.

Details

Was Flächendiagramm mitbringt, aus Registry und Quellcode gelesen.

Kategorie
Charts
Bereich
Elements
Variants
3
Version
1.0.0 · seit 1.0.0
Datei
components/ui/area-chart.tsx
Bringt mit
utilskitchart
npm-Pakete
Keine
Sprachen
Texte kommen über Props
Studio
Im Code anpassen

Props

Die Schnittstelle AreaChartProps aus components/ui/area-chart.tsx. Beschreibungen stammen aus den Kommentaren im Code und sind auf Englisch. Nimmt außerdem alle Props von ChartA11y an.

  • dataPflicht
    Datum[]

    Rows, one per x value, e.g. { day: '2026-09-14', visits: 412 }

  • xKeyPflicht
    string

    Key of the x value. "2026-03" and "2026-03-14" are read as dates and formatted per language.

  • seriesPflicht
    ChartSeries[]

    One area per series, in slot order (accent, grey, two accent tones)

  • formatoptional
    Intl.NumberFormatOptions

    Value format, e.g. { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 }

  • xFormatoptional
    Intl.DateTimeFormatOptions
  • tooltipXFormatoptional
    Intl.DateTimeFormatOptions
  • stackedoptional
    boolean

    Stack the series to a total. Each band gets a tint and a top line in its series color.

  • filloptional
    'wash' | 'gradient'

    wash: an even, quiet tint. gradient: the tint fades towards the baseline.

  • curveoptional
    'smooth' | 'linear'
  • heightoptional
    number

    Plot height in px, axis labels included

  • legendoptional
    boolean

    Legend above the plot. Default: for two series and more.

  • xLabeloptional
    string

    Header of the first table column

Barrierefreiheit

Aus dem Quellcode der Component abgeleitet.

  • Kommt ohne Client-State aus. Der Server schreibt sie vollständig, sie ist auch ohne JavaScript lesbar.

Bewegung

  • Ohne Animationen, sie steht sofort ruhig da.

Quellcode

Die Datei, die aiw add in dein Projekt legt. Sie gehört danach dir.

Datei anzeigen, 134 Zeilen
components/ui/area-chart.tsx
'use client';

import { useId } from 'react';
import { CartesianFrame, GlideDot, linePath, seriesColor, seriesOpacity, type ChartA11y, type ChartSeries, type Datum } from '@/components/ui/chart';

export interface AreaChartProps extends ChartA11y {
  /** Rows, one per x value, e.g. { day: '2026-09-14', visits: 412 } */
  data: Datum[];
  /** Key of the x value. "2026-03" and "2026-03-14" are read as dates and formatted per language. */
  xKey: string;
  /** One area per series, in slot order (accent, grey, two accent tones) */
  series: ChartSeries[];
  /** Value format, e.g. { style: 'currency', currency: 'EUR', maximumFractionDigits: 0 } */
  format?: Intl.NumberFormatOptions;
  xFormat?: Intl.DateTimeFormatOptions;
  tooltipXFormat?: Intl.DateTimeFormatOptions;
  /** Stack the series to a total. Each band gets a tint and a top line in its series color. */
  stacked?: boolean;
  /** wash: an even, quiet tint. gradient: the tint fades towards the baseline. */
  fill?: 'wash' | 'gradient';
  curve?: 'smooth' | 'linear';
  /** Plot height in px, axis labels included */
  height?: number;
  /** Legend above the plot. Default: for two series and more. */
  legend?: boolean;
  /** Header of the first table column */
  xLabel?: string;
  className?: string;
}

/**
 * Areas over time: a single tinted area, a gradient, or stacked bands.
 *   <AreaChart data={rows} xKey="day" series={[{ key: 'visits', label: 'Visits' }]} fill="gradient" />
 */
export function AreaChart({ data, xKey, series, format, xFormat, tooltipXFormat, stacked = false, fill = 'wash', curve = 'smooth', height = 260, legend, xLabel, label, summary, labels, animate, className }: AreaChartProps) {
  const uid = useId().replace(/[^a-zA-Z0-9]/g, '');
  const num = (d: Datum, k: string) => (typeof d[k] === 'number' ? (d[k] as number) : null);
  // Cumulative tops per series when stacked
  const tops = series.map((_, si) => data.map((d) => series.slice(0, si + 1).reduce((a, s) => a + Math.max(0, num(d, s.key) ?? 0), 0)));
  const all = stacked ? tops[tops.length - 1] ?? [] : data.flatMap((d) => series.map((s) => num(d, s.key))).filter((v): v is number => v !== null);
  const extent: [number, number] = [Math.min(0, ...all), Math.max(0, ...all)];
  const smooth = curve === 'smooth';

  return (
    <CartesianFrame
      data={data}
      xKey={xKey}
      series={series}
      format={format}
      xFormat={xFormat}
      tooltipXFormat={tooltipXFormat}
      height={height}
      scale="point"
      extent={extent}
      legend={legend}
      legendShape={stacked ? 'rect' : 'line'}
      crosshair
      total={stacked}
      xLabel={xLabel}
      label={label}
      summary={summary}
      labels={labels}
      animate={animate}
      className={className}
      marks={({ cat, val, animated, focus }) => (
        <>
          <defs>
            {series.map((s, si) => (
              <linearGradient key={s.key} id={`${uid}-g${si}`} x1="0" x2="0" y1="0" y2="1">
                <stop offset="0" stopColor={seriesColor(si, s.color)} stopOpacity={stacked ? 0.55 : 0.3} />
                <stop offset="1" stopColor={seriesColor(si, s.color)} stopOpacity={stacked ? 0.22 : 0} />
              </linearGradient>
            ))}
          </defs>
          {/* Draw from the last series down, so the first sits in front when not stacked */}
          {[...series.keys()].reverse().map((si) => {
            const s = series[si];
            const color = seriesColor(si, s.color);
            const style = animated ? ({ '--kitch-d': `${si * 120}ms` } as React.CSSProperties) : undefined;
            const op = seriesOpacity(si, focus);
            if (stacked) {
              const upper: [number, number][] = data.map((_, i) => [cat(i), val(tops[si][i])]);
              const lower: [number, number][] = data.map((_, i) => [cat(i), val(si ? tops[si - 1][i] : 0)]).reverse() as [number, number][];
              const top = linePath(upper, smooth);
              const bottom = linePath(lower, smooth).replace(/^M/, 'L');
              return (
                <g key={s.key} className="kitch-series" opacity={op}>
                  <path d={`${top} ${bottom} Z`} fill={fill === 'gradient' ? `url(#${uid}-g${si})` : color} fillOpacity={fill === 'gradient' ? 1 : 0.4} className={animated ? 'kitch-clip' : undefined} style={style} />
                  {/* Each band ends in a crisp line of its own color */}
                  <path d={top} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" pathLength={1} className={animated ? 'kitch-draw' : undefined} style={style} />
                </g>
              );
            }
            const segments: [number, number][][] = [[]];
            data.forEach((d, i) => {
              const v = num(d, s.key);
              if (v !== null) segments[segments.length - 1].push([cat(i), val(v)]);
              else if (segments[segments.length - 1].length) segments.push([]);
            });
            return (
              <g key={s.key} className="kitch-series" opacity={op}>
                {segments
                  .filter((seg) => seg.length > 1)
                  .map((seg, k) => {
                    const top = linePath(seg, smooth);
                    const base = val(Math.max(extent[0], 0));
                    return (
                      <g key={k}>
                        <path
                          d={`${top} L${seg[seg.length - 1][0]} ${base} L${seg[0][0]} ${base} Z`}
                          fill={fill === 'gradient' ? `url(#${uid}-g${si})` : color}
                          fillOpacity={fill === 'gradient' ? 1 : si === 0 ? 0.12 : 0.1}
                          className={animated ? 'kitch-clip' : undefined}
                          style={style}
                        />
                        <path d={top} fill="none" stroke={color} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" strokeDasharray={s.dashed ? '4 5' : undefined} pathLength={s.dashed ? undefined : 1} className={animated ? (s.dashed ? 'kitch-clip' : 'kitch-draw') : undefined} style={style} />
                      </g>
                    );
                  })}
              </g>
            );
          })}
        </>
      )}
      overlay={({ cat, val, shown, open, jump, focus }) =>
        shown !== null &&
        series.map((s, si) => {
          const v = stacked ? tops[si][shown] : num(data[shown], s.key);
          return v !== null && v !== undefined ? <GlideDot key={s.key} x={cat(shown)} y={val(v)} open={open} jump={jump} color={seriesColor(si, s.color)} opacity={seriesOpacity(si, focus)} /> : null;
        })
      }
    />
  );
}

Häufige Fragen

Wie installiere ich Flächendiagramm?

Mit aiw add @ai-website/area-chart. Der Befehl legt die Datei components/ui/area-chart.tsx in dein Projekt, der Code gehört danach dir. Mit dabei sind chart. Weitere npm-Pakete braucht sie nicht.

Welche Varianten hat Flächendiagramm?

3 Varianten, Einfach, Verlauf und Gestapelt.

Kann ein KI-Assistent Flächendiagramm einbauen?

Ja. Über den MCP-Server der aiw CLI finden Claude, Cursor, GitHub Copilot, Windsurf, Codex und Gemini Flächendiagramm mit aiw_components und installieren sie mit aiw_add @ai-website/area-chart.

Oft gesucht

Direkt zu

In die Zwischenablage kopiert