| 1 | "use client" |
| 2 | |
| 3 | import { type ReactNode, useEffect } from "react" |
| 4 | import { |
| 5 | type AreaVariant, |
| 6 | type SeriesKind, |
| 7 | type StrokeVariant, |
| 8 | useChartPart, |
| 9 | } from "./chart-context" |
| 10 | import { SeriesContext } |
| 11 | |
| 12 | export type SeriesProps |
| 13 | dataKey: string |
| 14 | variant?: AreaVariant |
| 15 | strokeVariant?: StrokeVariant |
| 16 | isClickable?: boolean |
| 17 | children?: ReactNode |
| 18 | } |
| 19 | |
| 20 | /** |
| 21 | * Shared implementation for the continuous series (`<Area>`, `<Line>`). The |
| 22 | * dithered fill/line is painted on the canvas; this registers the series so the |
| 23 | * canvas knows how to draw it, wires click-to-select via a transparent band |
| 24 | * polygon, and exposes the series to child `<Dot>`/`<ActiveDot>` markers. |
| 25 | */ |
| 26 | function CartesianSeries({ |
| 27 | part, |
| 28 | kind, |
| 29 | dataKey, |
| 30 | variant = "gradient" |
| 31 | strokeVariant = "solid" |
| 32 | isClickable = false, |
| 33 | children, |
| 34 | }: SeriesProps |
| 35 | const ctx = |
| 36 | const { registerSeries, |
| 37 | |
| 38 | if (process.env |
| 39 | console.warn( |
| 40 | `<${part} dataKey="${ |
| 41 | ) |
| 42 | } |
| 43 | |
| 44 | useEffect(() => |
| 45 | registerSeries({ dataKey, |
| 46 | return () => |
| 47 | }, [dataKey, |
| 48 | |
| 49 | const band = |
| 50 | if (!ctx.ready |
| 51 | |
| 52 | const seed = |
| 53 | const emphasis = |
| 54 | const dimmed = |
| 55 | const onClick = |
| 56 | ? () => ctx |
| 57 | : undefined |
| 58 | |
| 59 | // Transparent hit polygon tracing the series' own band, so clicking a series |
| 60 | // selects *that* series. The Legend offers the same toggle accessibly. |
| 61 | // One pass out along the top edge, one pass back along the floor. |
| 62 | let hitPath: |
| 63 | if (isClickable) { |
| 64 | const parts: |
| 65 | band.forEach((b |
| 66 | parts.push(`${ |
| 67 | }) |
| 68 | for (let i |
| 69 | parts.push(`L |
| 70 | } |
| 71 | hitPath = `${parts |
| 72 | } |
| 73 | |
| 74 | return ( |
| 75 | <> |
| 76 | {hitPath && ( |
| 77 | // biome-ignore lint/a11y/noStaticElementInteractions: progressive enhancement; the Legend offers the same toggle accessibly |
| 78 | <path |
| 79 | d={hitPath} |
| 80 | fill="transparent" |
| 81 | style={{ cursor: |
| 82 | onClick={onClick} |
| 83 | /> |
| 84 | )} |
| 85 | <SeriesContext value={ |
| 86 | {children} |
| 87 | </SeriesContext> |
| 88 | </> |
| 89 | ) |
| 90 | } |
| 91 | |
| 92 | export type AreaProps |
| 93 | |
| 94 | /** One area series - dithered fill from the value line down to its floor. */ |
| 95 | export function Area(props |
| 96 | return <CartesianSeries part |
| 97 | } |
| 98 | |
| 99 | /** One line series - bright line with a thin dither glow hugging it. */ |
| 100 | export function Line(props |
| 101 | return <CartesianSeries part |
| 102 | } |