mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-11-16 01:21:16 +01:00
Merge 4093ded628 into 5c9e590856
This commit is contained in:
commit
d7032ec143
@ -191,7 +191,6 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, onSignatur
|
|||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
overflow: 'hidden',
|
|
||||||
flex: 1,
|
flex: 1,
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
@ -287,8 +286,6 @@ export function LocalEmbedPDF({ file, url, enableAnnotations = false, onSignatur
|
|||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
minWidth: 0,
|
minWidth: 0,
|
||||||
contain: 'strict',
|
contain: 'strict',
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Scroller
|
<Scroller
|
||||||
|
|||||||
@ -7,9 +7,7 @@ import {
|
|||||||
determineAutoZoom,
|
determineAutoZoom,
|
||||||
DEFAULT_FALLBACK_ZOOM,
|
DEFAULT_FALLBACK_ZOOM,
|
||||||
DEFAULT_VISIBILITY_THRESHOLD,
|
DEFAULT_VISIBILITY_THRESHOLD,
|
||||||
measureRenderedPageRect,
|
|
||||||
useFitWidthResize,
|
useFitWidthResize,
|
||||||
ZoomViewport,
|
|
||||||
} from '@app/utils/viewerZoom';
|
} from '@app/utils/viewerZoom';
|
||||||
import { getFirstPageAspectRatioFromStub } from '@app/utils/pageMetadata';
|
import { getFirstPageAspectRatioFromStub } from '@app/utils/pageMetadata';
|
||||||
|
|
||||||
@ -73,18 +71,6 @@ export function ZoomAPIBridge() {
|
|||||||
}
|
}
|
||||||
}, [spreadMode, zoomState?.zoomLevel, scheduleAutoZoom, requestFitWidth]);
|
}, [spreadMode, zoomState?.zoomLevel, scheduleAutoZoom, requestFitWidth]);
|
||||||
|
|
||||||
const getViewportSnapshot = useCallback((): ZoomViewport | null => {
|
|
||||||
if (!zoomState || typeof zoomState !== 'object') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ('viewport' in zoomState) {
|
|
||||||
const candidate = (zoomState as { viewport?: ZoomViewport | null }).viewport;
|
|
||||||
return candidate ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}, [zoomState]);
|
|
||||||
|
|
||||||
const isManagedZoom =
|
const isManagedZoom =
|
||||||
!!zoom &&
|
!!zoom &&
|
||||||
@ -119,7 +105,7 @@ export function ZoomAPIBridge() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fitWidthZoom = zoomState.currentZoomLevel;
|
const fitWidthZoom = zoomState.currentZoomLevel;
|
||||||
if (!fitWidthZoom || fitWidthZoom <= 0) {
|
if (!fitWidthZoom || fitWidthZoom <= 0 || fitWidthZoom === 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,37 +123,23 @@ export function ZoomAPIBridge() {
|
|||||||
const pagesPerSpread = currentSpreadMode !== SpreadMode.None ? 2 : 1;
|
const pagesPerSpread = currentSpreadMode !== SpreadMode.None ? 2 : 1;
|
||||||
const metadataAspectRatio = getFirstPageAspectRatioFromStub(firstFileStub);
|
const metadataAspectRatio = getFirstPageAspectRatioFromStub(firstFileStub);
|
||||||
|
|
||||||
const viewport = getViewportSnapshot();
|
|
||||||
|
|
||||||
if (cancelled) {
|
if (cancelled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const metrics = viewport ?? {};
|
const viewportWidth = window.innerWidth ?? 0;
|
||||||
const viewportWidth =
|
const viewportHeight = window.innerHeight ?? 0;
|
||||||
metrics.clientWidth ?? metrics.width ?? window.innerWidth ?? 0;
|
|
||||||
const viewportHeight =
|
|
||||||
metrics.clientHeight ?? metrics.height ?? window.innerHeight ?? 0;
|
|
||||||
|
|
||||||
if (viewportWidth <= 0 || viewportHeight <= 0) {
|
if (viewportWidth <= 0 || viewportHeight <= 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageRect = await measureRenderedPageRect({
|
|
||||||
shouldCancel: () => cancelled,
|
|
||||||
});
|
|
||||||
if (cancelled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const decision = determineAutoZoom({
|
const decision = determineAutoZoom({
|
||||||
viewportWidth,
|
viewportWidth,
|
||||||
viewportHeight,
|
viewportHeight,
|
||||||
fitWidthZoom,
|
fitWidthZoom,
|
||||||
pagesPerSpread,
|
pagesPerSpread,
|
||||||
pageRect: pageRect
|
pageRect: undefined,
|
||||||
? { width: pageRect.width, height: pageRect.height }
|
|
||||||
: undefined,
|
|
||||||
metadataAspectRatio: metadataAspectRatio ?? null,
|
metadataAspectRatio: metadataAspectRatio ?? null,
|
||||||
visibilityThreshold: DEFAULT_VISIBILITY_THRESHOLD,
|
visibilityThreshold: DEFAULT_VISIBILITY_THRESHOLD,
|
||||||
fallbackZoom: DEFAULT_FALLBACK_ZOOM,
|
fallbackZoom: DEFAULT_FALLBACK_ZOOM,
|
||||||
@ -197,7 +169,6 @@ export function ZoomAPIBridge() {
|
|||||||
firstFileId,
|
firstFileId,
|
||||||
firstFileStub,
|
firstFileStub,
|
||||||
requestFitWidth,
|
requestFitWidth,
|
||||||
getViewportSnapshot,
|
|
||||||
autoZoomTick,
|
autoZoomTick,
|
||||||
spreadMode,
|
spreadMode,
|
||||||
triggerImmediateZoomUpdate,
|
triggerImmediateZoomUpdate,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
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 const DEFAULT_FALLBACK_ZOOM = 1.44; // 144% fallback when no reliable metadata is present
|
||||||
|
|
||||||
export interface ZoomViewport {
|
export interface ZoomViewport {
|
||||||
@ -36,47 +36,33 @@ export function determineAutoZoom({
|
|||||||
visibilityThreshold = DEFAULT_VISIBILITY_THRESHOLD,
|
visibilityThreshold = DEFAULT_VISIBILITY_THRESHOLD,
|
||||||
fallbackZoom = DEFAULT_FALLBACK_ZOOM,
|
fallbackZoom = DEFAULT_FALLBACK_ZOOM,
|
||||||
}: AutoZoomParams): AutoZoomDecision {
|
}: AutoZoomParams): AutoZoomDecision {
|
||||||
|
// Get aspect ratio from pageRect or metadata
|
||||||
const rectWidth = pageRect?.width ?? 0;
|
const rectWidth = pageRect?.width ?? 0;
|
||||||
const rectHeight = pageRect?.height ?? 0;
|
const rectHeight = pageRect?.height ?? 0;
|
||||||
|
|
||||||
const aspectRatio: number | null =
|
const aspectRatio: number | null =
|
||||||
rectWidth > 0 ? rectHeight / rectWidth : metadataAspectRatio ?? null;
|
rectWidth > 0 ? rectHeight / rectWidth : metadataAspectRatio ?? null;
|
||||||
|
|
||||||
let renderedHeight: number | null = rectHeight > 0 ? rectHeight : null;
|
// Need aspect ratio to proceed
|
||||||
|
if (!aspectRatio || aspectRatio <= 0) {
|
||||||
if (!renderedHeight || renderedHeight <= 0) {
|
return { type: 'fallback', zoom: Math.min(fitWidthZoom, fallbackZoom) };
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!renderedHeight || renderedHeight <= 0) {
|
// Landscape pages need 100% visibility, portrait need the specified threshold
|
||||||
return { type: 'fitWidth' };
|
const isLandscape = aspectRatio < 1;
|
||||||
}
|
|
||||||
|
|
||||||
const isLandscape = aspectRatio !== null && aspectRatio < 1;
|
|
||||||
const targetVisibility = isLandscape ? 100 : visibilityThreshold;
|
const targetVisibility = isLandscape ? 100 : visibilityThreshold;
|
||||||
|
|
||||||
const visiblePercent = (viewportHeight / renderedHeight) * 100;
|
// Calculate zoom level that shows targetVisibility% of page height
|
||||||
|
const pageHeightAtFitWidth = (viewportWidth / pagesPerSpread) * aspectRatio;
|
||||||
|
const heightBasedZoom = fitWidthZoom * (viewportHeight / pageHeightAtFitWidth) / (targetVisibility / 100);
|
||||||
|
|
||||||
if (visiblePercent >= targetVisibility) {
|
// Use whichever zoom is smaller (more zoomed out) to satisfy both width and height constraints
|
||||||
|
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' };
|
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 {
|
export interface MeasurePageRectOptions {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user