From fa790c2abbeb7baeb152848a62e24a539556b923 Mon Sep 17 00:00:00 2001 From: John O'Keefe Date: Sat, 18 Apr 2026 23:04:48 -0400 Subject: [PATCH] Fix zoom percentage to track relative to fit-page scale The zoom percentage display had two bugs: 1. Scroll-zoom never updated the status bar percentage because the 'zoom' event listener was registered inside the magnifier-toggle click handler (only added on click, and re-added on each click). 2. After reset (fit-page), the status bar showed '100%' but the zoom-in button treated the current scale as 1.0 (absolute), not the fit-page scale (e.g. 0.3). This caused a wild zoom jump from '100%' to '120%' that was actually a 4x visual change. Fix by introducing a #baseScale field that captures the fit-page or fit-width scale whenever the component renders in auto-fit mode. The new currentScale getter exposes the actual transform scale, and zoomPercent expresses it as a percentage of baseScale. All zoom-in/ zoom-out handlers (buttons and keyboard) now use currentScale instead of getAttribute('zoom') || 1, and all percentage displays use zoomPercent. The zoom event listener is registered once at setup rather than inside the magnifier toggle handler. Also removes all diagnostic console.log statements from fixed-layout.js and reader.js. --- fixed-layout.js | 44 ++++++-------------- reader.js | 104 ++++++++---------------------------------------- 2 files changed, 30 insertions(+), 118 deletions(-) diff --git a/fixed-layout.js b/fixed-layout.js index 7013d38..60a5c26 100644 --- a/fixed-layout.js +++ b/fixed-layout.js @@ -40,6 +40,7 @@ export class FixedLayout extends HTMLElement { #interactionMode = "select"; #wrapper; #transform = { x: 0, y: 0, scale: 1 }; + #baseScale = 1; #zoomState = { minScale: 0.1, maxScale: 10, @@ -132,6 +133,14 @@ export class FixedLayout extends HTMLElement { return this.#magnifier.enabled; } + get currentScale() { + return this.#transform.scale; + } + + get zoomPercent() { + return Math.round((this.#transform.scale / this.#baseScale) * 100); + } + resetZoom() { this.#zoom = undefined; this.#render(); @@ -395,14 +404,6 @@ export class FixedLayout extends HTMLElement { } #zoomByRatio(cx, cy, ratio) { - console.log("[FXL] zoomByRatio:", { - cx, - cy, - ratio, - oldScale: this.#transform.scale, - oldX: this.#transform.x, - oldY: this.#transform.y, - }); const oldScale = this.#transform.scale; const newScale = Math.min( this.#zoomState.maxScale, @@ -421,12 +422,6 @@ export class FixedLayout extends HTMLElement { this.dispatchEvent( new CustomEvent("zoom", { detail: { scale: newScale } }), ); - console.log("[FXL] zoomByRatio result:", { - newX: this.#transform.x, - newY: this.#transform.y, - newScale: this.#transform.scale, - actualRatio, - }); } #handleWheel(event) { @@ -442,16 +437,6 @@ export class FixedLayout extends HTMLElement { event.deltaY > 0 ? 1 - this.#zoomState.zoomStep : 1 + this.#zoomState.zoomStep; - console.log("[FXL] wheel:", { - cx, - cy, - transformX: this.#transform.x, - transformY: this.#transform.y, - transformScale: this.#transform.scale, - zoom: this.#zoom, - side: this.#side, - hostWidth: rect.width, - }); this.#zoomByRatio(cx, cy, ratio); } @@ -656,13 +641,6 @@ export class FixedLayout extends HTMLElement { } #render(side = this.#side) { - console.log("[FXL] render:", { - side, - zoom: this.#zoom, - transformScale: this.#transform.scale, - isNumericZoom: typeof this.#zoom === "number" && !isNaN(this.#zoom), - hasDualFrames: !this.#center && !this.#left?.blank && !this.#right?.blank, - }); if (!side) return; const left = this.#left ?? {}; const right = this.#center ?? this.#right ?? {}; @@ -699,6 +677,10 @@ export class FixedLayout extends HTMLElement { this.#transform.scale = scale; + if (typeof this.#zoom !== "number" || isNaN(this.#zoom)) { + this.#baseScale = scale; + } + this.#updateFrameScales(scale); const { contentWidth, contentHeight } = this.#getContentSize(); diff --git a/reader.js b/reader.js index 3c11452..418a8fd 100644 --- a/reader.js +++ b/reader.js @@ -120,19 +120,8 @@ class Reader { const { book } = this.view; - // DEBUG: Log book and renderer info - console.log("[Reader Debug] 📖 Book opened:", { - title: book.metadata?.title, - type: file.name, - rendition: book.rendition, - isFixedLayout: this.view.isFixedLayout, - renderer: this.view.renderer?.localName, - rendererClass: this.view.renderer?.constructor.name, - isFixedLayoutInstance: this.view.renderer instanceof FixedLayout, - }); book.transformTarget?.addEventListener("data", ({ detail }) => { - detail.data = Promise.resolve(detail.data).catch((e) => { - console.error(new Error(`Failed to load ${detail.name}`, { cause: e })); + detail.data = Promise.resolve(detail.data).catch(() => { return ""; }); }); @@ -156,83 +145,44 @@ class Reader { } document.addEventListener("keydown", this.#handleKeydown.bind(this)); - console.log("[Reader Debug] 🔧 Setting up zoom control listeners..."); // Add zoom control listeners $("#zoom-in").addEventListener("click", () => { - console.log("[Reader Debug] 🔍 Zoom in button clicked"); const renderer = this.view.renderer; - console.log( - "[Reader Debug] Renderer:", - renderer?.localName, - renderer?.constructor.name, - ); - console.log( - "[Reader Debug] Is FixedLayout?", - renderer instanceof FixedLayout, - ); if (renderer instanceof FixedLayout) { - const current = renderer.getAttribute("zoom") || 1; - const newZoom = Math.min(10, parseFloat(current) * 1.2); - renderer.setAttribute("zoom", newZoom); - $("#zoom-reset").textContent = `${Math.round(newZoom * 100)}%`; - console.log("[Reader Debug] ✅ Zoom applied:", current, "->", newZoom); - } else { - console.log("[Reader Debug] ❌ Not a FixedLayout renderer, ignoring"); + const newScale = Math.min(10, renderer.currentScale * 1.2); + renderer.setAttribute("zoom", newScale); + $("#zoom-reset").textContent = `${renderer.zoomPercent}%`; } }); $("#zoom-out").addEventListener("click", () => { - console.log("[Reader Debug] 🔍 Zoom out button clicked"); const renderer = this.view.renderer; - console.log( - "[Reader Debug] Is FixedLayout?", - renderer instanceof FixedLayout, - ); if (renderer instanceof FixedLayout) { - const current = renderer.getAttribute("zoom") || 1; - const newZoom = Math.max(0.1, parseFloat(current) / 1.2); - renderer.setAttribute("zoom", newZoom); - $("#zoom-reset").textContent = `${Math.round(newZoom * 100)}%`; - console.log("[Reader Debug] ✅ Zoom applied:", current, "->", newZoom); - } else { - console.log("[Reader Debug] ❌ Not a FixedLayout renderer, ignoring"); + const newScale = Math.max(0.1, renderer.currentScale / 1.2); + renderer.setAttribute("zoom", newScale); + $("#zoom-reset").textContent = `${renderer.zoomPercent}%`; } }); $("#zoom-reset").addEventListener("click", () => { - console.log("[Reader Debug] 🔄 Reset zoom button clicked"); const renderer = this.view.renderer; - console.log( - "[Reader Debug] Is FixedLayout?", - renderer instanceof FixedLayout, - ); if (renderer instanceof FixedLayout) { renderer.resetZoom(); renderer.dragOffset = { x: 0, y: 0 }; $("#zoom-reset").textContent = "100%"; - console.log("[Reader Debug] ✅ Zoom reset"); - } else { - console.log("[Reader Debug] ❌ Not a FixedLayout renderer, ignoring"); } }); + const renderer = this.view.renderer; + renderer.addEventListener("zoom", () => { + $("#zoom-reset").textContent = `${renderer.zoomPercent}%`; + }); $("#magnifier-toggle").addEventListener("click", () => { - console.log("[Reader Debug] 🔍 Magnifier toggle button clicked"); const renderer = this.view.renderer; - renderer.addEventListener("zoom", (e) => { - $("#zoom-reset").textContent = `${Math.round(e.detail.scale * 100)}%`; - }); - console.log( - "[Reader Debug] Is FixedLayout?", - renderer instanceof FixedLayout, - ); if (renderer instanceof FixedLayout) { renderer.toggleMagnifier(); - console.log("[Reader Debug] ✅ Magnifier toggled"); - } else { - console.log("[Reader Debug] ❌ Not a FixedLayout renderer, ignoring"); } }); const modeToggle = $("#interaction-mode-toggle"); @@ -255,7 +205,6 @@ class Reader { modeToggle.style.display = ""; } }); - console.log("[Reader Debug] ✅ Zoom control listeners configured"); const title = formatLanguageMap(book.metadata?.title) || "Untitled Book"; document.title = title; @@ -309,47 +258,28 @@ class Reader { } #handleKeydown(event) { const k = event.key; - console.log("[Reader Debug] ⌨️ Key pressed:", k); if (k === "ArrowLeft" || k === "h") this.view.goLeft(); else if (k === "ArrowRight" || k === "l") this.view.goRight(); else if (k === "+" || k === "=") { - console.log("[Reader Debug] 🔍 Zoom in via keyboard"); const renderer = this.view.renderer; if (renderer instanceof FixedLayout) { - const current = renderer.getAttribute("zoom") || 1; - const newZoom = Math.min(10, parseFloat(current) * 1.2); - renderer.setAttribute("zoom", newZoom); - $("#zoom-reset").textContent = `${Math.round(newZoom * 100)}%`; - console.log( - "[Reader Debug] ✅ Keyboard zoom applied:", - current, - "->", - newZoom, - ); + const newScale = Math.min(10, renderer.currentScale * 1.2); + renderer.setAttribute("zoom", newScale); + $("#zoom-reset").textContent = `${renderer.zoomPercent}%`; } } else if (k === "-" || k === "_") { - console.log("[Reader Debug] 🔍 Zoom out via keyboard"); const renderer = this.view.renderer; if (renderer instanceof FixedLayout) { - const current = renderer.getAttribute("zoom") || 1; - const newZoom = Math.max(0.1, parseFloat(current) / 1.2); - renderer.setAttribute("zoom", newZoom); - $("#zoom-reset").textContent = `${Math.round(newZoom * 100)}%`; - console.log( - "[Reader Debug] ✅ Keyboard zoom applied:", - current, - "->", - newZoom, - ); + const newScale = Math.max(0.1, renderer.currentScale / 1.2); + renderer.setAttribute("zoom", newScale); + $("#zoom-reset").textContent = `${renderer.zoomPercent}%`; } } else if (k === "0") { - console.log("[Reader Debug] 🔄 Reset zoom via keyboard"); const renderer = this.view.renderer; if (renderer instanceof FixedLayout) { renderer.resetZoom(); renderer.dragOffset = { x: 0, y: 0 }; $("#zoom-reset").textContent = "100%"; - console.log("[Reader Debug] ✅ Keyboard zoom reset"); } } else if (k === "Escape") { const renderer = this.view.renderer;