From c59a4728534b333502a0db4b800dfa8c91013340 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Thu, 16 Oct 2025 14:18:13 +0200 Subject: [PATCH] refactor: remove zoom and pan functionality from BookReader and ReaderContent components, replacing SinglePage with ZoomablePage for enhanced zoom capabilities --- src/components/reader/BookReader.tsx | 6 -- .../reader/components/ReaderContent.tsx | 18 +--- .../reader/components/ZoomablePage.tsx | 77 +++++++++++++ .../reader/hooks/usePageNavigation.ts | 102 ++++-------------- 4 files changed, 103 insertions(+), 100 deletions(-) create mode 100644 src/components/reader/components/ZoomablePage.tsx diff --git a/src/components/reader/BookReader.tsx b/src/components/reader/BookReader.tsx index c9c8752..a1a4781 100644 --- a/src/components/reader/BookReader.tsx +++ b/src/components/reader/BookReader.tsx @@ -35,9 +35,6 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps) handlePreviousPage, handleNextPage, shouldShowDoublePage, - zoomLevel, - panPosition, - handleDoubleClick, showEndMessage, } = usePageNavigation({ book, @@ -141,9 +138,6 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps) shouldShowDoublePage={shouldShowDoublePage} isRTL={isRTL} onThumbnailLoad={handleThumbnailLoad} - zoomLevel={zoomLevel} - panPosition={panPosition} - onDoubleClick={handleDoubleClick} /> boolean; isRTL: boolean; onThumbnailLoad: (pageNumber: number) => void; - zoomLevel: number; - panPosition: { x: number; y: number }; - onDoubleClick: () => void; } export const ReaderContent = ({ @@ -25,14 +22,11 @@ export const ReaderContent = ({ shouldShowDoublePage, isRTL, onThumbnailLoad, - zoomLevel, - panPosition, - onDoubleClick, }: ReaderContentProps) => { return (
- {isDoublePage && shouldShowDoublePage(currentPage) && ( - )}
diff --git a/src/components/reader/components/ZoomablePage.tsx b/src/components/reader/components/ZoomablePage.tsx new file mode 100644 index 0000000..d6ea046 --- /dev/null +++ b/src/components/reader/components/ZoomablePage.tsx @@ -0,0 +1,77 @@ +import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch"; +import { cn } from "@/lib/utils"; + +interface ZoomablePageProps { + pageUrl: string | null; + pageNumber: number; + isLoading: boolean; + onLoad: (pageNumber: number) => void; + isDoublePage?: boolean; + isRTL?: boolean; + order?: "first" | "second"; +} + +export const ZoomablePage = ({ + pageUrl, + pageNumber, + isLoading, + onLoad, + isDoublePage = false, + isRTL = false, + order = "first", +}: ZoomablePageProps) => { + return ( +
+ {isLoading && ( +
+
+
+ )} + + {pageUrl && ( + + + {`Page onLoad(pageNumber)} + /> + + + )} +
+ ); +}; diff --git a/src/components/reader/hooks/usePageNavigation.ts b/src/components/reader/hooks/usePageNavigation.ts index b3419e7..95f0e7b 100644 --- a/src/components/reader/hooks/usePageNavigation.ts +++ b/src/components/reader/hooks/usePageNavigation.ts @@ -25,17 +25,12 @@ export const usePageNavigation = ({ const [currentPage, setCurrentPage] = useState(cPage < 1 ? 1 : cPage); const [isLoading, setIsLoading] = useState(true); const [secondPageLoading, setSecondPageLoading] = useState(true); - const [zoomLevel, setZoomLevel] = useState(1); - const [panPosition, setPanPosition] = useState({ x: 0, y: 0 }); const [showEndMessage, setShowEndMessage] = useState(false); const timeoutRef = useRef(null); const touchStartXRef = useRef(null); const touchStartYRef = useRef(null); - const lastPanPositionRef = useRef({ x: 0, y: 0 }); const currentPageRef = useRef(currentPage); const isRTL = direction === "rtl"; - const initialDistanceRef = useRef(null); - const DEFAULT_ZOOM_LEVEL = 2; useEffect(() => { currentPageRef.current = currentPage; @@ -136,59 +131,17 @@ export const usePageNavigation = ({ router, ]); - const calculateDistance = (touch1: Touch, touch2: Touch) => { - const dx = touch2.clientX - touch1.clientX; - const dy = touch2.clientY - touch1.clientY; - return Math.sqrt(dx * dx + dy * dy); - }; - - const handleTouchMove = useCallback( - (event: TouchEvent) => { - if (event.touches.length === 2) { - const distance = calculateDistance(event.touches[0], event.touches[1]); - if (initialDistanceRef.current !== null) { - const scale = distance / initialDistanceRef.current; - const zoomFactor = 0.3; - setZoomLevel((prevZoomLevel) => - Math.min(3, Math.max(1, prevZoomLevel + (scale - 1) * zoomFactor)) - ); - } - } else if (event.touches.length === 1 && zoomLevel > 1) { - // Gestion du pan uniquement quand on est zoomé - if (touchStartXRef.current !== null && touchStartYRef.current !== null) { - const deltaX = event.touches[0].clientX - touchStartXRef.current; - const deltaY = event.touches[0].clientY - touchStartYRef.current; - - setPanPosition({ - x: lastPanPositionRef.current.x + deltaX, - y: lastPanPositionRef.current.y + deltaY, - }); - } - event.preventDefault(); // Empêcher le scroll de la page - } - }, - [zoomLevel] - ); - const handleTouchStart = useCallback( (event: TouchEvent) => { - if (event.touches.length === 2) { - initialDistanceRef.current = calculateDistance(event.touches[0], event.touches[1]); - } else { - touchStartXRef.current = event.touches[0].clientX; - touchStartYRef.current = event.touches[0].clientY; - lastPanPositionRef.current = panPosition; - currentPageRef.current = currentPage; - } + touchStartXRef.current = event.touches[0].clientX; + touchStartYRef.current = event.touches[0].clientY; + currentPageRef.current = currentPage; }, - [currentPage, panPosition] + [currentPage] ); const handleTouchEnd = useCallback( (event: TouchEvent) => { - if (event.touches.length < 2) { - initialDistanceRef.current = null; - } if (touchStartXRef.current === null || touchStartYRef.current === null) return; const touchEndX = event.changedTouches[0].clientX; @@ -196,15 +149,6 @@ export const usePageNavigation = ({ const deltaX = touchEndX - touchStartXRef.current; const deltaY = touchEndY - touchStartYRef.current; - // Si on est zoomé, on met à jour la position finale du pan - if (zoomLevel > 1) { - lastPanPositionRef.current = { - x: lastPanPositionRef.current.x + deltaX, - y: lastPanPositionRef.current.y + deltaY, - }; - return; - } - // Si le déplacement vertical est plus important que le déplacement horizontal, // on ne fait rien (pour éviter de confondre avec un scroll) if (Math.abs(deltaY) > Math.abs(deltaX)) return; @@ -231,16 +175,9 @@ export const usePageNavigation = ({ touchStartXRef.current = null; touchStartYRef.current = null; }, - [handleNextPage, handlePreviousPage, isRTL, zoomLevel] + [handleNextPage, handlePreviousPage, isRTL] ); - // Reset du pan quand on change de page ou dezoom - useEffect(() => { - if (zoomLevel === 1) { - setPanPosition({ x: 0, y: 0 }); - lastPanPositionRef.current = { x: 0, y: 0 }; - } - }, [zoomLevel, currentPage]); useEffect(() => { setIsLoading(true); @@ -272,13 +209,11 @@ export const usePageNavigation = ({ window.addEventListener("keydown", handleKeyDown); window.addEventListener("touchstart", handleTouchStart); window.addEventListener("touchend", handleTouchEnd); - window.addEventListener("touchmove", handleTouchMove); return () => { window.removeEventListener("keydown", handleKeyDown); window.removeEventListener("touchstart", handleTouchStart); window.removeEventListener("touchend", handleTouchEnd); - window.removeEventListener("touchmove", handleTouchMove); }; }, [ handleNextPage, @@ -287,7 +222,7 @@ export const usePageNavigation = ({ handleTouchEnd, onClose, isRTL, - handleTouchMove, + currentPage, ]); useEffect(() => { @@ -300,13 +235,24 @@ export const usePageNavigation = ({ }; }, [syncReadProgress, book]); - const handleDoubleClick = useCallback(() => { - setZoomLevel((prevZoom) => { - if (prevZoom === 1) { - return DEFAULT_ZOOM_LEVEL; + const handleDoubleClick = useCallback((transformRef?: any) => { + if (transformRef?.current) { + try { + // Utiliser setTransform au lieu de zoomIn pour éviter les NaN + const transform = transformRef.current; + const currentScale = transform.instance?.state?.scale || 1; + + if (currentScale <= 1.1) { + // Zoom à 2x + transform.setTransform(0, 0, 2); + } else { + // Reset à 1x + transform.setTransform(0, 0, 1); + } + } catch (error) { + console.error("Error in handleDoubleClick:", error); } - return 1; - }); + } }, []); return { @@ -319,8 +265,6 @@ export const usePageNavigation = ({ handlePreviousPage, handleNextPage, shouldShowDoublePage, - zoomLevel, - panPosition, handleDoubleClick, showEndMessage, };