/** * Projection between time, slot index and pixel offset along the timeline. * * Two implementations sit behind this interface and the choice is purely a * performance trade, invisible to callers: * * - {@link UniformAxis} — closed-form arithmetic, **zero allocation**. Used when * slots are equal in both duration and width. Ten years at minute granularity * is 5.26 million slots and costs nothing; a materialised edge array for the * same range would be ~42 MB. * - {@link PrefixAxis} — two `Float64Array` edge tables with binary search. Used * when slots are unequal: months (28–31 days), quarters, years, proportional * widths, or day/week slots across a DST transition. Ten years of days is * ~58 KB, which is negligible — the array only becomes untenable at sub-hour * granularity, which is exactly where the uniform path applies. * * All methods are hot: they run per visible slot per frame. None allocates. */ export interface SlotAxis { /** Number of slots. */ readonly count: number; /** Total width of all slots, in pixels. */ readonly totalPx: number; /** Time at the very start of the axis. */ readonly startMs: number; /** Time at the very end of the axis (exclusive). */ readonly endMs: number; /** Left edge of slot `i`, in pixels from the axis origin. */ offsetOf(index: number): number; /** Width of slot `i`, in pixels. */ widthOf(index: number): number; /** Start time of slot `i`. */ timeOf(index: number): number; /** Slot containing pixel `px`, clamped to `[0, count - 1]`. */ indexAt(px: number): number; /** Pixel offset of time `t`. Interpolates within a slot; may fall outside the axis. */ pxAt(t: number): number; /** Time at pixel `px`. Inverse of {@link pxAt}. */ timeAt(px: number): number; } /** * Equal-duration, equal-width slots. Every operation is closed-form. * * The absence of any backing array is the point — it is what makes a decade of * minute slots feasible. */ export declare class UniformAxis implements SlotAxis { readonly startMs: number; private readonly slotMs; private readonly slotPx; readonly count: number; readonly totalPx: number; readonly endMs: number; /** * @param startMs - Time at slot 0. * @param slotMs - Duration of one slot. Must be > 0. * @param slotPx - Width of one slot. Must be > 0. * @param count - Number of slots. */ constructor(startMs: number, slotMs: number, slotPx: number, count: number); offsetOf(index: number): number; widthOf(): number; timeOf(index: number): number; indexAt(px: number): number; pxAt(t: number): number; timeAt(px: number): number; } /** * Unequal slots, backed by edge tables. * * `edgesMs` comes straight from `ticksBetween`'s fence posts and `edgesPx` is * its prefix sum, so both have `count + 1` entries and slot `i` spans * `[edgesMs[i], edgesMs[i+1])` / `[edgesPx[i], edgesPx[i+1])`. Storing widths * explicitly means equal-width and proportional-width modes share one * implementation — the difference is only how `edgesPx` was built. */ export declare class PrefixAxis implements SlotAxis { private readonly edgesMs; private readonly edgesPx; readonly count: number; readonly totalPx: number; readonly startMs: number; readonly endMs: number; /** * @param edgesMs - Fence posts, strictly ascending, length `count + 1`. * @param edgesPx - Cumulative pixel offsets, ascending, length `count + 1`. */ constructor(edgesMs: Float64Array, edgesPx: Float64Array); offsetOf(index: number): number; widthOf(index: number): number; timeOf(index: number): number; indexAt(px: number): number; pxAt(t: number): number; timeAt(px: number): number; } /** * Builds a {@link PrefixAxis} from fence posts. * * @param ticks - Ascending fence posts from `ticksBetween` (`count + 1` entries). * @param slotPx - Fixed width per slot, for `'equal'` mode. * @param proportional - When `true`, slot widths scale with duration, so a * 31-day month is wider than a 28-day one. Reads as a Gantt/duration view. * When `false`, every slot gets `slotPx` and the timeline reads as columns. */ export declare function buildPrefixAxis(ticks: readonly number[], slotPx: number, proportional: boolean): PrefixAxis; /** The slot window to render, in slot indices. */ export interface SlotWindow { /** First slot to render, inclusive. */ readonly start: number; /** Last slot to render, exclusive. */ readonly end: number; } /** * Computes the visible slot range for a horizontal scroll position. * * @param buffer - Extra slots rendered either side, so a scroll of a few pixels * does not expose an unpainted edge. Defaults to 2, matching the grid's own * `COL_BUFFER`, so the timeline header and the grid's column virtualization * shift on the same frames. */ export declare function visibleSlotWindow(axis: SlotAxis, scrollLeft: number, viewportWidth: number, buffer?: number): SlotWindow; /** * Time range to query events for, given a scroll position. * * Deliberately **not** derived from {@link visibleSlotWindow}: a slot buffer is * the wrong unit for events. At minute granularity two slots is two minutes, so * a bar wider than the viewport would pop in and out at its edges. This instead * pads by half a viewport on each side, in pixels, which is scale-invariant. * * Long events that begin far to the left are *not* handled here — that is the * job of the event index's max-end augmentation, which finds them regardless of * how far back they start. */ export declare function visibleTimeRange(axis: SlotAxis, scrollLeft: number, viewportWidth: number): { start: number; end: number; }; //# sourceMappingURL=slot-axis.d.ts.map