fix(web): lecteurs CBZ/CBR et PDF — assouplir le suivi de page en vertical: commit initial après stabilisation de l'ancrage et ré-ancrage si la page change sans scroll utilisateur (4e correctif bug #39)
This commit is contained in:
@ -31,6 +31,7 @@ export function CbzReader({
|
||||
const pendingVerticalAnchorRef = useRef(false);
|
||||
const verticalTrackingReadyRef = useRef(false);
|
||||
const verticalUserScrollRef = useRef(false);
|
||||
const verticalAnchorTargetPageRef = useRef<number | null>(null);
|
||||
const verticalAnchorFrameRef = useRef<number | null>(null);
|
||||
const verticalAnchorAttemptRef = useRef(0);
|
||||
const verticalAnchorStableFramesRef = useRef(0);
|
||||
@ -82,6 +83,23 @@ export function CbzReader({
|
||||
if (verticalAnchorFrameRef.current !== null) cancelAnimationFrame(verticalAnchorFrameRef.current);
|
||||
verticalAnchorFrameRef.current = null;
|
||||
}, []);
|
||||
const commitVisiblePage = useCallback(
|
||||
(stage: HTMLElement, allowInitialCommit = false) => {
|
||||
if (!pages || !verticalTrackingReadyRef.current) return;
|
||||
if (!allowInitialCommit && !verticalUserScrollRef.current) return;
|
||||
const stageRect = stage.getBoundingClientRect();
|
||||
const visiblePage = majorityVisiblePage(
|
||||
Array.from(stage.querySelectorAll<HTMLElement>("[data-reader-page]")).map((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return { page: Number(element.dataset.readerPage), top: rect.top, bottom: rect.bottom };
|
||||
}),
|
||||
stageRect.top,
|
||||
stageRect.bottom
|
||||
);
|
||||
if (visiblePage && visiblePage !== currentPage) onPageCommit(clampReaderPage(visiblePage, pages.pageCount), pages.pageCount, 1, "queued");
|
||||
},
|
||||
[currentPage, onPageCommit, pages]
|
||||
);
|
||||
const stabilizeVerticalAnchor = useCallback(
|
||||
(targetPage: number) => {
|
||||
clearVerticalAnchorFrame();
|
||||
@ -106,6 +124,7 @@ export function CbzReader({
|
||||
|
||||
if (verticalAnchorStableFramesRef.current >= VERTICAL_ANCHOR_STABLE_FRAMES) {
|
||||
verticalTrackingReadyRef.current = true;
|
||||
commitVisiblePage(stage, true);
|
||||
return;
|
||||
}
|
||||
verticalAnchorAttemptRef.current += 1;
|
||||
@ -116,7 +135,7 @@ export function CbzReader({
|
||||
|
||||
verticalAnchorFrameRef.current = requestAnimationFrame(measure);
|
||||
},
|
||||
[clearVerticalAnchorFrame]
|
||||
[clearVerticalAnchorFrame, commitVisiblePage]
|
||||
);
|
||||
|
||||
const go = useCallback(
|
||||
@ -178,10 +197,11 @@ export function CbzReader({
|
||||
pendingVerticalAnchorRef.current = false;
|
||||
verticalTrackingReadyRef.current = false;
|
||||
verticalUserScrollRef.current = false;
|
||||
verticalAnchorTargetPageRef.current = null;
|
||||
clearVerticalAnchorFrame();
|
||||
return;
|
||||
}
|
||||
if (previousModeRef.current !== "vertical") {
|
||||
if (previousModeRef.current !== "vertical" || (!verticalUserScrollRef.current && verticalAnchorTargetPageRef.current !== currentPage)) {
|
||||
pendingVerticalAnchorRef.current = true;
|
||||
verticalTrackingReadyRef.current = false;
|
||||
verticalUserScrollRef.current = false;
|
||||
@ -194,6 +214,7 @@ export function CbzReader({
|
||||
return;
|
||||
}
|
||||
pendingVerticalAnchorRef.current = false;
|
||||
verticalAnchorTargetPageRef.current = currentPage;
|
||||
stabilizeVerticalAnchor(currentPage);
|
||||
}
|
||||
previousModeRef.current = mode;
|
||||
@ -213,17 +234,7 @@ export function CbzReader({
|
||||
const keyTarget = typeof window === "undefined" ? null : window;
|
||||
const updateVisiblePage = () => {
|
||||
frameId = 0;
|
||||
if (!verticalTrackingReadyRef.current || !verticalUserScrollRef.current) return;
|
||||
const stageRect = stage.getBoundingClientRect();
|
||||
const visiblePage = majorityVisiblePage(
|
||||
Array.from(stage.querySelectorAll<HTMLElement>("[data-reader-page]")).map((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return { page: Number(element.dataset.readerPage), top: rect.top, bottom: rect.bottom };
|
||||
}),
|
||||
stageRect.top,
|
||||
stageRect.bottom
|
||||
);
|
||||
if (visiblePage && visiblePage !== currentPage) onPageCommit(clampReaderPage(visiblePage, pages.pageCount), pages.pageCount, 1, "queued");
|
||||
commitVisiblePage(stage);
|
||||
};
|
||||
const onScroll = () => {
|
||||
if (frameId) return;
|
||||
@ -243,7 +254,7 @@ export function CbzReader({
|
||||
keyTarget?.removeEventListener("keydown", markUserScrollKey);
|
||||
stage.removeEventListener("scroll", onScroll);
|
||||
};
|
||||
}, [currentPage, mode, onPageCommit, pages]);
|
||||
}, [commitVisiblePage, mode, pages]);
|
||||
|
||||
useEffect(() => () => clearVerticalAnchorFrame(), [clearVerticalAnchorFrame]);
|
||||
|
||||
|
||||
@ -157,6 +157,7 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
const pendingVerticalAnchorRef = useRef(false);
|
||||
const verticalTrackingReadyRef = useRef(false);
|
||||
const verticalUserScrollRef = useRef(false);
|
||||
const verticalAnchorTargetPageRef = useRef<number | null>(null);
|
||||
const verticalAnchorFrameRef = useRef<number | null>(null);
|
||||
const verticalAnchorAttemptRef = useRef(0);
|
||||
const verticalAnchorStableFramesRef = useRef(0);
|
||||
@ -178,6 +179,23 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
if (verticalAnchorFrameRef.current !== null) cancelAnimationFrame(verticalAnchorFrameRef.current);
|
||||
verticalAnchorFrameRef.current = null;
|
||||
}, []);
|
||||
const commitVisiblePage = useCallback(
|
||||
(stage: HTMLElement, allowInitialCommit = false) => {
|
||||
if (!verticalTrackingReadyRef.current) return;
|
||||
if (!allowInitialCommit && !verticalUserScrollRef.current) return;
|
||||
const stageRect = stage.getBoundingClientRect();
|
||||
const visiblePage = majorityVisiblePage(
|
||||
Array.from(stage.querySelectorAll<HTMLElement>("[data-reader-page]")).map((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return { page: Number(element.dataset.readerPage), top: rect.top, bottom: rect.bottom };
|
||||
}),
|
||||
stageRect.top,
|
||||
stageRect.bottom
|
||||
);
|
||||
if (visiblePage && visiblePage !== currentPage) onPageCommit(clampReaderPage(visiblePage, pages), pages, 1, "queued");
|
||||
},
|
||||
[currentPage, onPageCommit, pages]
|
||||
);
|
||||
const stabilizeVerticalAnchor = useCallback(
|
||||
(targetPage: number) => {
|
||||
clearVerticalAnchorFrame();
|
||||
@ -202,6 +220,7 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
|
||||
if (verticalAnchorStableFramesRef.current >= VERTICAL_ANCHOR_STABLE_FRAMES) {
|
||||
verticalTrackingReadyRef.current = true;
|
||||
commitVisiblePage(stage, true);
|
||||
return;
|
||||
}
|
||||
verticalAnchorAttemptRef.current += 1;
|
||||
@ -212,7 +231,7 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
|
||||
verticalAnchorFrameRef.current = requestAnimationFrame(measure);
|
||||
},
|
||||
[clearVerticalAnchorFrame]
|
||||
[clearVerticalAnchorFrame, commitVisiblePage]
|
||||
);
|
||||
|
||||
const go = useCallback(
|
||||
@ -244,10 +263,11 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
pendingVerticalAnchorRef.current = false;
|
||||
verticalTrackingReadyRef.current = false;
|
||||
verticalUserScrollRef.current = false;
|
||||
verticalAnchorTargetPageRef.current = null;
|
||||
clearVerticalAnchorFrame();
|
||||
return;
|
||||
}
|
||||
if (previousModeRef.current !== "vertical") {
|
||||
if (previousModeRef.current !== "vertical" || (!verticalUserScrollRef.current && verticalAnchorTargetPageRef.current !== currentPage)) {
|
||||
pendingVerticalAnchorRef.current = true;
|
||||
verticalTrackingReadyRef.current = false;
|
||||
verticalUserScrollRef.current = false;
|
||||
@ -260,6 +280,7 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
return;
|
||||
}
|
||||
pendingVerticalAnchorRef.current = false;
|
||||
verticalAnchorTargetPageRef.current = currentPage;
|
||||
stabilizeVerticalAnchor(currentPage);
|
||||
}
|
||||
previousModeRef.current = mode;
|
||||
@ -279,17 +300,7 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
const keyTarget = typeof window === "undefined" ? null : window;
|
||||
const updateVisiblePage = () => {
|
||||
frameId = 0;
|
||||
if (!verticalTrackingReadyRef.current || !verticalUserScrollRef.current) return;
|
||||
const stageRect = stage.getBoundingClientRect();
|
||||
const visiblePage = majorityVisiblePage(
|
||||
Array.from(stage.querySelectorAll<HTMLElement>("[data-reader-page]")).map((element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
return { page: Number(element.dataset.readerPage), top: rect.top, bottom: rect.bottom };
|
||||
}),
|
||||
stageRect.top,
|
||||
stageRect.bottom
|
||||
);
|
||||
if (visiblePage && visiblePage !== currentPage) onPageCommit(clampReaderPage(visiblePage, pages), pages, 1, "queued");
|
||||
commitVisiblePage(stage);
|
||||
};
|
||||
const onScroll = () => {
|
||||
if (frameId) return;
|
||||
@ -309,7 +320,7 @@ export function PdfReader({ url, page, backHref, zoom, mode, onPageCommit, onCon
|
||||
keyTarget?.removeEventListener("keydown", markUserScrollKey);
|
||||
stage.removeEventListener("scroll", onScroll);
|
||||
};
|
||||
}, [currentPage, mode, onPageCommit, pages]);
|
||||
}, [commitVisiblePage, mode, pages]);
|
||||
|
||||
useEffect(() => () => clearVerticalAnchorFrame(), [clearVerticalAnchorFrame]);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user