Files
ReadaBook/apps/web/src/reader/readerLayout.ts

81 lines
2.7 KiB
TypeScript

export type ReaderSize = {
width: number;
height: number;
};
export const READER_ZOOM_MIN = 50;
export const READER_ZOOM_MAX = 300;
export const READER_ZOOM_STEP = 25;
export const READER_ZOOM_DEFAULT = 100;
export function clampReaderZoom(zoom: number) {
const steppedZoom = Math.round(zoom / READER_ZOOM_STEP) * READER_ZOOM_STEP;
return Math.max(READER_ZOOM_MIN, Math.min(steppedZoom, READER_ZOOM_MAX));
}
export function readerZoomLabel(zoom: number) {
return `${clampReaderZoom(zoom)} %`;
}
export function readerZoomFactor(zoom: number) {
return clampReaderZoom(zoom) / 100;
}
export function clampReaderPage(page: number, pageCount: number) {
const safePageCount = Math.max(1, Math.floor(pageCount));
return Math.max(1, Math.min(Math.floor(page), safePageCount));
}
export function previousReaderPage(page: number, pageCount: number) {
return clampReaderPage(page - 1, pageCount);
}
export function nextReaderPage(page: number, pageCount: number) {
return clampReaderPage(page + 1, pageCount);
}
export function readerPositionLabel(page: number, pageCount: number) {
return `Page ${clampReaderPage(page, pageCount)} / ${Math.max(1, Math.floor(pageCount))}`;
}
export function containPageSize(viewport: ReaderSize, page: ReaderSize): ReaderSize {
if (viewport.width <= 0 || viewport.height <= 0 || page.width <= 0 || page.height <= 0) {
return { width: 0, height: 0 };
}
const scale = Math.min(viewport.width / page.width, viewport.height / page.height);
return {
width: Math.max(1, Math.floor(page.width * scale)),
height: Math.max(1, Math.floor(page.height * scale))
};
}
export function orientedContainPageSize(viewport: ReaderSize, page: ReaderSize): ReaderSize {
if (viewport.width <= 0 || viewport.height <= 0 || page.width <= 0 || page.height <= 0) {
return { width: 0, height: 0 };
}
const fitByHeight = page.height >= page.width;
const primaryScale = fitByHeight ? viewport.height / page.height : viewport.width / page.width;
const crossScale = fitByHeight ? viewport.width / page.width : viewport.height / page.height;
const scale = Math.min(primaryScale, crossScale);
return {
width: Math.max(1, Math.floor(page.width * scale)),
height: Math.max(1, Math.floor(page.height * scale))
};
}
export function zoomReaderSize(size: ReaderSize, zoom: number): ReaderSize {
const factor = readerZoomFactor(zoom);
return {
width: Math.max(1, Math.floor(size.width * factor)),
height: Math.max(1, Math.floor(size.height * factor))
};
}
export function readableViewportSize(size: ReaderSize): ReaderSize | null {
if (size.width < 32 || size.height < 32) return null;
return {
width: Math.floor(size.width),
height: Math.floor(size.height)
};
}