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();
+ }
}