diff --git a/ts_web/elements/viewer.ts b/ts_web/elements/viewer.ts index 49f98a2..915a358 100644 --- a/ts_web/elements/viewer.ts +++ b/ts_web/elements/viewer.ts @@ -13,7 +13,7 @@ import { import { demoFunc } from "./viewer.demo.js"; import { DeDocument } from "./document.js"; -import * as deesCatalog from "@design.estate/dees-catalog"; +import "@design.estate/dees-catalog"; declare global { interface HTMLElementTagNameMap { @@ -65,6 +65,14 @@ export class DeDocumentViewer extends DeesElement { }) accessor documentSettings: plugins.shared.interfaces.IDocumentSettings; + // External configuration properties + @property({ type: Number }) + accessor initialZoom: number = null; // Initial zoom % (null = auto) + + @property({ type: Number }) + accessor initialPageGap: number = 16; // Initial page gap in pixels + + // Internal state @state() accessor zoomMode: TZoomPreset = "auto"; @@ -387,8 +395,6 @@ export class DeDocumentViewer extends DeesElement { `, ]; - private documentRef: DeDocument | null = null; - public render(): TemplateResult { return html`
@@ -728,8 +734,19 @@ export class DeDocumentViewer extends DeesElement { } public firstUpdated(): void { - // Update display zoom initially - setTimeout(() => this.updateDisplayZoom(), 200); + // Apply initial settings if provided + if (this.initialPageGap !== 16) { + this.pageGap = this.initialPageGap; + } + + if (this.initialZoom !== null) { + this.zoomLevel = this.initialZoom; + this.displayZoom = this.initialZoom; + this.zoomMode = this.initialZoom; + } else { + // Update display zoom initially for auto mode + setTimeout(() => this.updateDisplayZoom(), 200); + } // Handle viewport resize to update display zoom in auto mode const viewport = this.shadowRoot?.querySelector(".viewport"); @@ -743,4 +760,120 @@ export class DeDocumentViewer extends DeesElement { this.registerGarbageFunction(() => resizeObserver.disconnect()); } } + + // ============================================ + // PUBLIC API METHODS + // ============================================ + + /** + * Set the zoom level programmatically + * @param level - Zoom percentage (25-400), or 'auto', 'fit-width', 'fit-page' + */ + public setZoom(level: number | "auto" | "fit-width" | "fit-page"): void { + if (level === "auto") { + this.handleZoomPreset("auto"); + } else if (level === "fit-width") { + this.handleZoomPreset("fit-width"); + } else if (level === "fit-page") { + this.handleZoomPreset("fit-page"); + } else { + const clampedZoom = Math.min(400, Math.max(25, level)); + this.zoomLevel = clampedZoom; + this.displayZoom = clampedZoom; + this.zoomMode = clampedZoom; + } + } + + /** + * Get the current zoom percentage + */ + public getZoom(): number { + return this.displayZoom; + } + + /** + * Set the page gap (spacing between pages) + * @param gap - Gap in pixels (0-64) + */ + public setPageGap(gap: number): void { + this.pageGap = Math.min(64, Math.max(0, gap)); + } + + /** + * Get the current page gap in pixels + */ + public getPageGap(): number { + return this.pageGap; + } + + /** + * Get the total number of pages in the document + */ + public getPageCount(): number { + const doc = this.shadowRoot?.querySelector("dedocument-dedocument"); + if (!doc) return 0; + const pages = doc.shadowRoot?.querySelectorAll("dedocument-page"); + return pages?.length ?? 0; + } + + /** + * Get the currently visible page number (1-indexed) + */ + public getCurrentPage(): number { + const viewport = this.shadowRoot?.querySelector(".viewport"); + const doc = this.shadowRoot?.querySelector("dedocument-dedocument"); + if (!viewport || !doc) return 1; + + const pages = doc.shadowRoot?.querySelectorAll("dedocument-page"); + if (!pages || pages.length === 0) return 1; + + const viewportRect = viewport.getBoundingClientRect(); + const viewportCenter = viewportRect.top + viewportRect.height / 2; + + let currentPage = 1; + for (let i = 0; i < pages.length; i++) { + const pageRect = pages[i].getBoundingClientRect(); + if (pageRect.top <= viewportCenter && pageRect.bottom >= viewportCenter) { + currentPage = i + 1; + break; + } + if (pageRect.top > viewportCenter) { + currentPage = Math.max(1, i); + break; + } + currentPage = i + 1; + } + + return currentPage; + } + + /** + * Scroll to a specific page + * @param pageNumber - Page number (1-indexed) + * @param smooth - Whether to use smooth scrolling (default: true) + */ + public scrollToPage(pageNumber: number, smooth: boolean = true): void { + const doc = this.shadowRoot?.querySelector("dedocument-dedocument"); + if (!doc) return; + + const pages = doc.shadowRoot?.querySelectorAll("dedocument-page"); + if (!pages || pages.length === 0) return; + + const targetIndex = Math.min(Math.max(0, pageNumber - 1), pages.length - 1); + const targetPage = pages[targetIndex]; + + if (targetPage) { + targetPage.scrollIntoView({ + behavior: smooth ? "smooth" : "instant", + block: "start", + }); + } + } + + /** + * Trigger the print dialog + */ + public async print(): Promise { + await this.handlePrint(); + } }