import { Layout } from '../../contracts/src/index.js'; /** * Configuration for page geometry calculations. */ export interface PageGeometryConfig { /** The layout containing page data */ layout: Layout; /** Gap between pages in pixels (defaults to layout.pageGap ?? 0) */ pageGap?: number; } /** * PageGeometryHelper provides efficient, cached access to page positions and heights. * * This class: * - Computes cumulative Y positions for each page (accounting for per-page heights and gaps) * - Caches calculations for O(1) lookup performance * - Invalidates cache when layout changes * - Handles mixed page sizes correctly * * **Why This Exists:** * Selection overlays were drifting because geometry calculations used different * assumptions about page spacing than the DOM painter. This helper ensures all * code uses the same page positions by providing a single source of truth. * * **Performance:** * - Initial calculation: O(n) where n = number of pages * - Subsequent lookups: O(1) via cached arrays * - Cache invalidation: O(1) version check * * **Usage:** * ```typescript * const helper = new PageGeometryHelper({ layout, pageGap: 24 }); * * // Get cumulative Y position for page 5 * const y = helper.getPageTop(5); * * // Get height of page 5 * const height = helper.getPageHeight(5); * * // Get gap between pages * const gap = helper.getPageGap(); * * // Update when layout changes * helper.updateLayout(newLayout); * ``` */ export declare class PageGeometryHelper { private config; private cache; /** * Creates a new PageGeometryHelper instance. * * @param config - Page geometry configuration */ constructor(config: PageGeometryConfig); /** * Updates the layout and invalidates the cache. * * Call this whenever the layout changes (new pages, different heights, etc.) * * @param layout - New layout data * @param pageGap - Optional new page gap (if not provided, uses current gap) */ updateLayout(layout: Layout, pageGap?: number): void; /** * Updates the page gap and invalidates the cache. * * @param pageGap - New gap between pages in pixels */ updatePageGap(pageGap: number): void; /** * Gets the cumulative Y position (top edge) of a page in container space. * * The returned value is the distance from the top of the container to the * top of the specified page, accounting for all previous pages and gaps. * * @param pageIndex - Zero-based page index * @returns Y position in pixels, or 0 if page index is invalid * * @example * ```typescript * // Get Y position of page 0 (first page) * const y0 = helper.getPageTop(0); // Returns 0 * * // Get Y position of page 2 (third page) * // Assumes page 0 height = 1000, page 1 height = 1200, gap = 24 * const y2 = helper.getPageTop(2); // Returns 1000 + 24 + 1200 + 24 = 2248 * ``` */ getPageTop(pageIndex: number): number; /** * Gets the height of a specific page. * * Uses per-page height if available (from layout.pages[i].size?.h), * otherwise falls back to layout.pageSize.h. * * @param pageIndex - Zero-based page index * @returns Page height in pixels, or 0 if page index is invalid * * @example * ```typescript * const height = helper.getPageHeight(0); // Returns page-specific height * ``` */ getPageHeight(pageIndex: number): number; /** * Gets the gap between pages. * * @returns Gap in pixels * * @example * ```typescript * const gap = helper.getPageGap(); // Returns 24 * ``` */ getPageGap(): number; /** * Gets the total height of all pages including gaps. * * Total height = sum of all page heights + (pageCount - 1) * gap * * @returns Total height in pixels * * @example * ```typescript * // 3 pages: heights [1000, 1200, 1000], gap = 24 * const total = helper.getTotalHeight(); * // Returns 1000 + 24 + 1200 + 24 + 1000 = 3248 * ``` */ getTotalHeight(): number; /** * Gets the number of pages in the layout. * * @returns Page count */ getPageCount(): number; /** * Finds the page index containing a given Y coordinate. * * This performs a linear search through cached cumulative positions. * For large documents, consider adding binary search optimization. * * @param containerY - Y coordinate in container space * @returns Page index, or null if Y is outside all pages * * @example * ```typescript * // Find which page contains Y = 1500 * const pageIndex = helper.getPageIndexAtY(1500); * // Returns 1 (second page) if first page ends at Y=1024 * ``` */ getPageIndexAtY(containerY: number): number | null; /** * Finds the nearest page index to a given Y coordinate (snap-to-nearest). * * Returns the page containing Y when inside a page; otherwise returns the * closest page based on distance to page center. Useful for dragging through * page gaps where getPageIndexAtY would return null. * * @param containerY - Y coordinate in container space * @returns Nearest page index, or null if there are no pages */ getNearestPageIndex(containerY: number): number | null; /** * Ensures the cache is built and up-to-date. * Validates cache state and rebuilds if needed. * @private * @throws Never throws - handles errors gracefully with fallback values */ private ensureCache; /** * Builds the geometry cache from current layout data. * Handles errors gracefully by providing fallback values. * @private * @throws Never throws - catches all errors and provides safe defaults */ private buildCache; /** * Clears the cache, forcing recalculation on next access. * Useful for testing or manual cache invalidation. */ clearCache(): void; /** * Gets debug information about the current cache state. * @internal */ getDebugInfo(): { isCached: boolean; pageCount: number; pageGap: number; totalHeight: number; cumulativeY: number[]; pageHeights: number[]; }; } //# sourceMappingURL=page-geometry-helper.d.ts.map