diff --git a/ui/library/src/components/thumbnails/Thumbnail.tsx b/ui/library/src/components/thumbnails/Thumbnail.tsx index c750ad3..147479a 100644 --- a/ui/library/src/components/thumbnails/Thumbnail.tsx +++ b/ui/library/src/components/thumbnails/Thumbnail.tsx @@ -11,8 +11,7 @@ type Props = { }; export const Thumbnail: React.FunctionComponent = ({ pageNumber }: Props) => { - const { pageRenderStates, buildObjectURLForPage, getObjectURLForPage } = - React.useContext(PageRenderContext); + const { getObjectURLForPage } = React.useContext(PageRenderContext); const { isPageVisible, scrollToPage, visiblePageRatios } = React.useContext(ScrollContext); const [maxVisiblePageNumber, setMaxVisiblePageNumber] = React.useState>(null); const objectURL = getObjectURLForPage({ pageNumber }); @@ -31,10 +30,6 @@ export const Thumbnail: React.FunctionComponent = ({ pageNumber }: Props) parseInt(maxVisiblePageNumber) === pageNumber && isPageVisible({ pageNumber }); - React.useEffect(() => { - buildObjectURLForPage({ pageNumber }); - }, [pageRenderStates]); - const onClick = React.useCallback( event => { event.preventDefault(); diff --git a/ui/library/src/context/PageRenderContext.ts b/ui/library/src/context/PageRenderContext.ts index 5cf1a81..be6b5fb 100644 --- a/ui/library/src/context/PageRenderContext.ts +++ b/ui/library/src/context/PageRenderContext.ts @@ -16,6 +16,7 @@ export interface IPageRenderContext { pageRenderStates: PageNumberToRenderStateMap; getObjectURLForPage: (pageNumber: PageNumber) => Nullable; isBuildingObjectURLForPage: (pageNumber: PageNumber) => boolean; + isFinishedBuildingAllPagesObjectURLs: () => boolean; buildObjectURLForPage: (pageNumber: PageNumber) => Promise; } @@ -29,6 +30,10 @@ export const PageRenderContext = React.createContext({ logProviderWarning(`isBuildingObjectURLForPage(${JSON.stringify(args)})`, 'PageRenderContext'); return false; }, + isFinishedBuildingAllPagesObjectURLs: () => { + logProviderWarning(`isFinishedBuildingAllPagesObjectURLs()`, 'PageRenderContext'); + return false; + }, buildObjectURLForPage: args => { logProviderWarning(`buildObjectURLForPage(${JSON.stringify(args)})`, 'PageRenderContext'); return Promise.resolve(''); @@ -82,6 +87,16 @@ export function usePageRenderContextProps({ [pageRenderStates] ); + const isFinishedBuildingAllPagesObjectURLs = React.useCallback((): boolean => { + if (!pdfDocProxy) return false; + for (let pageNumber = 1; pageNumber <= pdfDocProxy.numPages; pageNumber++) { + if (!pageRenderStates.get(pageNumber)?.objectURL) { + return false; + } + } + return true; + }, [pdfDocProxy, pageRenderStates]); + const getObjectURLForPage = React.useCallback( ({ pageNumber, pageIndex }: PageNumber): Nullable => { if (typeof pageIndex === 'number') { @@ -139,13 +154,20 @@ export function usePageRenderContextProps({ ); React.useEffect(() => { - for (const pageNumber of visiblePageRatios.keys()) { - if (pageRenderStates.has(pageNumber)) { - continue; - } + const visiblePages = [...visiblePageRatios.keys()]; + if ( + !pdfDocProxy || + [...pageRenderStates.keys()].length === pdfDocProxy.numPages || + visiblePages.length === 0 + ) { + return; + } + + const priorityQueue = getPriorityQueue(visiblePages, pdfDocProxy.numPages); + for (const pageNumber of priorityQueue) { buildObjectURLForPage({ pageNumber }); } - }, [pageRenderStates, visiblePageRatios]); + }, [pageRenderStates, pdfDocProxy, visiblePageRatios]); // Flush page render states when scale changes React.useEffect(() => { @@ -166,10 +188,22 @@ export function usePageRenderContextProps({ pageRenderStates, getObjectURLForPage, isBuildingObjectURLForPage, + isFinishedBuildingAllPagesObjectURLs, buildObjectURLForPage, }; } +export function getNeighboringPages(pages: number[], numPages: number): number[] { + return [Math.max(1, pages[0] - 1), Math.min(numPages, pages[pages.length - 1] + 1)]; +} + +export function getPriorityQueue(visiblePages: number[], numPages: number): number[] { + const visiblePagesNeighbors = getNeighboringPages(visiblePages, numPages); + const allPages = Array.from({ length: numPages }, (_, i) => i + 1); + const priorityQueue = new Set([...visiblePages, ...visiblePagesNeighbors, ...allPages]); // put into set to remove duplicats + return Array.from(priorityQueue); // convert set to array +} + // This boost causes the rendered image to be scaled up by this amount const SCALE_BOOST = 2;