/** * Layout for the Timeline's track view: one horizontal lane per layer on a * shared time axis. * * The list answers "what happened, in what order, to whom". It cannot show * concurrency or rhythm — which layers fire together, how a click lines up * with the update tick it caused, how long a tick is next to its neighbours. * This module turns the same {@link TimelineSpan}s into lanes and rows, and * owns the arithmetic between milliseconds and pixels, so the element that * draws them (`panel/timeline-tracks.ts`) is only DOM. * * Pure and dependency-free, like `derive.ts`, so it is unit-tested without a * browser. */ import type { TimelineSpan } from './derive.js'; /** * Spans in one row of a lane, sorted by start and never overlapping, so * {@link visibleRange} can binary-search them. */ export type TrackRow = TimelineSpan[]; /** One lane: every span of one layer, packed into non-overlapping rows. */ export interface Track { layerId: string; rows: TrackRow[]; } /** * Groups spans into one track per layer, in `layers` order, then any layer * the spans mention that `layers` does not (a custom layer announced after the * last `get-meta`), in first-seen order. A layer with no spans still gets an * empty track, so a lane does not appear and vanish as events arrive. * * Within a track, spans are packed greedily: each goes into the first row * whose last span has ended by the time it starts. Lit's lifecycle phases * nest, so one update tick lands as `performUpdate` on row 0 and * `willUpdate` / `update` / `updated` side by side on row 1 — the flame shape * falls out of the packing without modelling it. */ export declare const buildTracks: (spans: readonly TimelineSpan[], layers: readonly { id: string; }[]) => Track[]; /** * The recording's time bounds over `spans`: the earliest start, and the * latest instant anything is known to have happened (an end, or the start of * a span with none). The origin is the earliest start rather than zero * because the panel's buffer is capped and rolls its oldest events off; a * long recording would otherwise open on an empty stretch. */ export declare const timeBounds: (spans: readonly TimelineSpan[]) => { origin: number; extent: number; }; /** Deepest zoom, in multiples of "fit": about a microsecond per pixel on a * second-long recording, past which there is nothing left to separate. */ export declare const MAX_ZOOM = 100000; /** Mapping between recording time and pixels for the current zoom and pan. */ export interface TimeScale { pxPerMs: number; /** First and last millisecond inside the plot. */ start: number; end: number; toX(ms: number): number; toMs(x: number): number; } /** * Builds the scale for a plot `width` pixels wide showing a recording that * begins at `originMs` and runs for `extentMs`. * * `zoom` is a multiple of "fit" (1 shows the whole recording); `pan` is how * many milliseconds past the origin the left edge sits. Both are clamped, so * callers can apply a raw wheel or drag delta and read back where it landed. */ export declare const timeScale: (originMs: number, extentMs: number, width: number, zoom?: number, pan?: number) => TimeScale; export declare const clampZoom: (zoom: number) => number; /** Keeps the visible window inside the recording. */ export declare const clampPan: (pan: number, extentMs: number, zoom: number) => number; /** The pan that puts the live edge (the end of the recording) at the right * of the plot, for following a recording in progress. */ export declare const livePan: (extentMs: number, zoom: number) => number; /** * Zooms by `factor` while keeping the millisecond under pixel `x` where it * is, which is what a wheel over a timeline is expected to do. */ export declare const zoomAt: (originMs: number, extentMs: number, width: number, zoom: number, pan: number, x: number, factor: number) => { zoom: number; pan: number; }; /** * Index range `[from, to)` of the spans in `row` that intersect the window * `[start, end]`, found by binary search so a zoomed-in lane renders a * handful of marks rather than walking thousands. * * Only the span just before the first one starting inside the window can * reach into it, because a row's spans never overlap. */ export declare const visibleRange: (row: TrackRow, start: number, end: number) => [number, number]; /** * A round tick interval (1, 2 or 5 times a power of ten, in milliseconds) at * least `minMs` long, for axis labels that land on readable numbers. */ export declare const niceStep: (minMs: number) => number; //# sourceMappingURL=tracks.d.ts.map