Simplify reader visible page detection

This commit is contained in:
schroda
2025-11-17 02:11:05 +01:00
parent 36477d1c95
commit 48b57c4a74
2 changed files with 21 additions and 21 deletions

View File

@@ -494,22 +494,8 @@ export class ReaderControls {
type: PageInViewportType, type: PageInViewportType,
readingDirection: ReadingDirection, readingDirection: ReadingDirection,
) { ) {
const themeDirectionForReadingDirection = READING_DIRECTION_TO_THEME_DIRECTION[readingDirection];
const firstVisibleImageIndex = imageRefs.current.findIndex( const firstVisibleImageIndex = imageRefs.current.findIndex(
(image) => (image) => image && isPageInViewport(image, type, { truncateValues: true }),
image &&
isPageInViewport(
image,
type,
// the pages aren't always properly scrolled to the top which results in the leading page to still be slightly
// visible (e.g. 0.0123px) breaking the "first visible image" detection
{
bottom: 1,
left: getOptionForDirection(0, 1, themeDirectionForReadingDirection),
right: getOptionForDirection(1, 0, themeDirectionForReadingDirection),
},
),
); );
const lastPage = imageRefs.current?.[imageRefs.current.length - 1]; const lastPage = imageRefs.current?.[imageRefs.current.length - 1];
const isEndReached = lastPage && isEndOfPageInViewport(lastPage, type, readingDirection); const isEndReached = lastPage && isEndOfPageInViewport(lastPage, type, readingDirection);

View File

@@ -333,13 +333,21 @@ type InViewportThresholds = {
left?: number; left?: number;
right?: number; right?: number;
}; };
const getIsPageInViewportInfo = ( type InViewportOptions = {
element: HTMLElement, /**
* The pages aren't always properly scrolled to the start/end (e.g., via scrollIntoView) which results in a side to be slightly
* visible (e.g. 0.0123px) breaking the visibility detection
*/
truncateValues?: boolean;
/** /**
* Thresholds are not considered for the detection of an image filling the whole viewport. * Thresholds are not considered for the detection of an image filling the whole viewport.
* They are only used for detecting if a specific side of an image is inside the viewport * They are only used for detecting if a specific side of an image is inside the viewport
*/ */
argThresholds?: InViewportThresholds, thresholds?: InViewportThresholds;
};
const getIsPageInViewportInfo = (
element: HTMLElement,
{ truncateValues, thresholds: argThresholds }: InViewportOptions = { truncateValues: false, thresholds: {} },
): { ): {
isLeftInViewport: boolean; isLeftInViewport: boolean;
isRightInViewport: boolean; isRightInViewport: boolean;
@@ -348,7 +356,13 @@ const getIsPageInViewportInfo = (
isBottomInViewport: boolean; isBottomInViewport: boolean;
isFillingHeightViewportCompletely: boolean; isFillingHeightViewportCompletely: boolean;
} => { } => {
const { top, bottom, left, right } = element.getBoundingClientRect(); const { top: topRaw, bottom: bottomRaw, left: leftRaw, right: rightRaw } = element.getBoundingClientRect();
const maybeTruncateValue = (value: number): number => (truncateValues ? Math.trunc(value) : value);
const top = maybeTruncateValue(topRaw);
const bottom = maybeTruncateValue(bottomRaw);
const left = maybeTruncateValue(leftRaw);
const right = maybeTruncateValue(rightRaw);
const thresholds = { const thresholds = {
top: 0, top: 0,
@@ -379,7 +393,7 @@ const getIsPageInViewportInfo = (
export const isPageInViewport = ( export const isPageInViewport = (
element: HTMLElement, element: HTMLElement,
type: PageInViewportType, type: PageInViewportType,
thresholds?: InViewportThresholds, options?: InViewportOptions,
): boolean => { ): boolean => {
const { const {
isLeftInViewport, isLeftInViewport,
@@ -388,7 +402,7 @@ export const isPageInViewport = (
isTopInViewport, isTopInViewport,
isBottomInViewport, isBottomInViewport,
isFillingHeightViewportCompletely, isFillingHeightViewportCompletely,
} = getIsPageInViewportInfo(element, thresholds); } = getIsPageInViewportInfo(element, options);
const isInViewportX = isLeftInViewport || isRightInViewport || isFillingWidthViewportCompletely; const isInViewportX = isLeftInViewport || isRightInViewport || isFillingWidthViewportCompletely;
const isInViewportY = isTopInViewport || isBottomInViewport || isFillingHeightViewportCompletely; const isInViewportY = isTopInViewport || isBottomInViewport || isFillingHeightViewportCompletely;