KQ-728 · COMPARE/LINES

Compare Lines

Two assets on one plate, each series normalised to its own first point so the lines share a scale of percent-since-start and a dashed baseline at zero. On mount both traces draw in together — pathLength from 0 to 1 on one durations.page tween with the enter ease — so they finish on the same frame and the eye reads the divergence as it happens. The legend is two toggles: hiding a series fades its line and area on the exit ease with no redraw, and the vertical domain is fixed across both series so a toggle never re-scales the plate. Pointing at the plate sets a cursor at the nearest sample — a hairline, a dot per visible series, a bar between them and a readout chip that prints both values and the gap in percentage points — and the chip moves on snap while keeping inside the plate; the plate is a focusable group where Left and Right step the cursor, Home and End jump to the ends and Escape clears it.

KQ-728 · COMPARE/LINES
Basin BSN against Fernwork FRN

Basin BSN up 8.41 percent and Fernwork FRN up 3.11 percent over 24 sessions.

BSN +8.41% · FRN +3.11% · hover for the gap

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/compare-lines

Props

series
[CompareSeries, CompareSeries]
default
{ id, label, points: number[] }, closes oldest first; both series share the same sample count.
labels
string[]
default
Already-formatted x labels, one per sample, for the readout.
hidden / defaultHidden
string[]
default []
Controlled or initial set of hidden series ids.
onHiddenChange
(hidden: string[]) => void
default
Fires from the toggle that changed it.
onCursorChange
(index: number | null) => void
default
Fires from the pointer or key that moved the cursor.
format
(value: number) => string
default Intl.NumberFormat("en-US", { style: "currency", currency: "USD" })
Prints a raw close in the readout. The default pins an explicit locale so server and client agree.
label
React.ReactNode
default
Visible heading. Omit it and pass aria-label.
height
number
default 140
Plate height in px; the width is fluid and measured.
aria-label
string
default
Invisible label when label is omitted.