diff --git a/frontend/src/core/components/viewer/LocalEmbedPDF.tsx b/frontend/src/core/components/viewer/LocalEmbedPDF.tsx index 62d60e14f..f20b68b9a 100644 --- a/frontend/src/core/components/viewer/LocalEmbedPDF.tsx +++ b/frontend/src/core/components/viewer/LocalEmbedPDF.tsx @@ -191,7 +191,6 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, onSignatur height: '100%', width: '100%', position: 'relative', - overflow: 'hidden', flex: 1, minHeight: 0, minWidth: 0, @@ -287,8 +286,6 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, onSignatur minHeight: 0, minWidth: 0, contain: 'strict', - display: 'flex', - justifyContent: 'center', }} > cancelled, - }); - if (cancelled) { - return; - } - const decision = determineAutoZoom({ viewportWidth, viewportHeight, fitWidthZoom, pagesPerSpread, - pageRect: pageRect - ? { width: pageRect.width, height: pageRect.height } - : undefined, + pageRect: undefined, metadataAspectRatio: metadataAspectRatio ?? null, visibilityThreshold: DEFAULT_VISIBILITY_THRESHOLD, fallbackZoom: DEFAULT_FALLBACK_ZOOM, diff --git a/frontend/src/core/utils/viewerZoom.ts b/frontend/src/core/utils/viewerZoom.ts index 1fa1fb492..80775cfbe 100644 --- a/frontend/src/core/utils/viewerZoom.ts +++ b/frontend/src/core/utils/viewerZoom.ts @@ -1,6 +1,6 @@ import { useEffect, useRef } from 'react'; -export const DEFAULT_VISIBILITY_THRESHOLD = 80; // Require at least 80% of the page height to be visible +export const DEFAULT_VISIBILITY_THRESHOLD = 70; // Require at least 70% of the page height to be visible export const DEFAULT_FALLBACK_ZOOM = 1.44; // 144% fallback when no reliable metadata is present export interface ZoomViewport { @@ -36,47 +36,48 @@ export function determineAutoZoom({ visibilityThreshold = DEFAULT_VISIBILITY_THRESHOLD, fallbackZoom = DEFAULT_FALLBACK_ZOOM, }: AutoZoomParams): AutoZoomDecision { + // Get aspect ratio from pageRect or metadata const rectWidth = pageRect?.width ?? 0; const rectHeight = pageRect?.height ?? 0; - const aspectRatio: number | null = rectWidth > 0 ? rectHeight / rectWidth : metadataAspectRatio ?? null; - let renderedHeight: number | null = rectHeight > 0 ? rectHeight : null; - - if (!renderedHeight || renderedHeight <= 0) { - if (aspectRatio == null || aspectRatio <= 0) { - return { type: 'fallback', zoom: Math.min(fitWidthZoom, fallbackZoom) }; - } - - const pageWidth = viewportWidth / (fitWidthZoom * pagesPerSpread); - const pageHeight = pageWidth * aspectRatio; - renderedHeight = pageHeight * fitWidthZoom; + // Need aspect ratio to proceed + if (!aspectRatio || aspectRatio <= 0) { + return { type: 'fallback', zoom: Math.min(fitWidthZoom, fallbackZoom) }; } - if (!renderedHeight || renderedHeight <= 0) { - return { type: 'fitWidth' }; - } - - const isLandscape = aspectRatio !== null && aspectRatio < 1; + // Landscape pages need 100% visibility, portrait need 80% + const isLandscape = aspectRatio < 1; const targetVisibility = isLandscape ? 100 : visibilityThreshold; - const visiblePercent = (viewportHeight / renderedHeight) * 100; + // Step 1: Calculate what zoom level shows targetVisibility% (80%) of page height + // + // At fitWidth, page dimensions are: + // pageHeightAtFitWidth = (viewportWidth / pagesPerSpread) * aspectRatio + // + // For 80% of page to be visible: + // viewportHeight / pageHeightAtZoom = targetVisibility / 100 + // viewportHeight / (pageHeightAtFitWidth * zoomRatio) = targetVisibility / 100 + // + // Where zoomRatio = heightBasedZoom / fitWidthZoom + // + // Solving: + // heightBasedZoom = fitWidthZoom * viewportHeight / (pageHeightAtFitWidth * targetVisibility / 100) + // heightBasedZoom = fitWidthZoom * (viewportHeight / pageHeightAtFitWidth) * (100 / targetVisibility) - if (visiblePercent >= targetVisibility) { + const pageHeightAtFitWidth = (viewportWidth / pagesPerSpread) * aspectRatio; + const heightBasedZoom = fitWidthZoom * (viewportHeight / pageHeightAtFitWidth) / (targetVisibility / 100); + + // Step 2: Compare with fitWidth + // Use whichever is smaller (more zoomed out) to ensure both constraints are met + if (heightBasedZoom < fitWidthZoom) { + // Need to zoom out from fitWidth to show enough height + return { type: 'adjust', zoom: heightBasedZoom }; + } else { + // fitWidth already shows enough return { type: 'fitWidth' }; } - - const allowableHeightRatio = targetVisibility / 100; - const zoomScale = - viewportHeight / (allowableHeightRatio * renderedHeight); - const targetZoom = Math.min(fitWidthZoom, fitWidthZoom * zoomScale); - - if (Math.abs(targetZoom - fitWidthZoom) < 0.001) { - return { type: 'fitWidth' }; - } - - return { type: 'adjust', zoom: targetZoom }; } export interface MeasurePageRectOptions {