Preview preload pages count
This commit is contained in:
@ -13,7 +13,6 @@
|
||||
// ── Общие состояния оверлея ──
|
||||
/** @type {FileEntry | null} */
|
||||
let activeFile = $state(null);
|
||||
|
||||
/** Режим просмотра: 'gallery' (выбор страниц) или 'preview' (чтение) */
|
||||
let viewMode = $state(/** @type {'gallery' | 'preview'} */ ('gallery'));
|
||||
|
||||
@ -39,18 +38,23 @@
|
||||
{ id: 'color', label: 'Цвет' }
|
||||
];
|
||||
|
||||
// ── PDF.js Core (Остается в родителе для управления памятью) ──
|
||||
// ── PDF.js Core ──
|
||||
async function loadPdfDocument(entry) {
|
||||
if (entry.pdfDoc) return entry.pdfDoc;
|
||||
try {
|
||||
const pdfjsLib = await import('https://mozilla.github.io/pdf.js/build/pdf.mjs');
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://mozilla.github.io/pdf.js/build/pdf.worker.mjs';
|
||||
|
||||
const arrayBuffer = await entry.file.arrayBuffer();
|
||||
const loadingTask = pdfjsLib.getDocument({ data: arrayBuffer });
|
||||
const pdf = await loadingTask.promise;
|
||||
|
||||
entry.pdfDoc = pdf;
|
||||
entry.totalPages = pdf.numPages;
|
||||
// Инициализируем выбранные страницы только если они еще не заданы
|
||||
if (!entry.selectedPages || entry.selectedPages.size === 0) {
|
||||
entry.selectedPages = new Set(Array.from({ length: pdf.numPages }, (_, i) => i + 1));
|
||||
}
|
||||
return pdf;
|
||||
} catch (err) {
|
||||
console.error('PDF load error:', err);
|
||||
@ -64,11 +68,10 @@
|
||||
const viewport = page.getViewport({ scale });
|
||||
const canvas = document.createElement('canvas');
|
||||
const context = canvas.getContext('2d');
|
||||
|
||||
const outputScale = window.devicePixelRatio || 1;
|
||||
|
||||
canvas.width = Math.floor(viewport.width * outputScale);
|
||||
canvas.height = Math.floor(viewport.height * outputScale);
|
||||
|
||||
canvas.style.width = `${Math.floor(viewport.width)}px`;
|
||||
canvas.style.height = `${Math.floor(viewport.height)}px`;
|
||||
|
||||
@ -92,6 +95,8 @@
|
||||
previewPagesCache = {};
|
||||
|
||||
await tick();
|
||||
|
||||
// Используем уже загруженный документ или загружаем при необходимости
|
||||
if (!entry.pdfDoc) await loadPdfDocument(entry);
|
||||
|
||||
if (!entry.pdfDoc || entry.totalPages === 0) {
|
||||
@ -123,17 +128,22 @@
|
||||
await tick();
|
||||
|
||||
if (entry.fileType === 'pdf') {
|
||||
// Документ должен быть уже загружен при добавлении файла,
|
||||
// но на всякий случай проверяем
|
||||
if (!entry.pdfDoc) await loadPdfDocument(entry);
|
||||
|
||||
// Берем totalPages из entry, которое было получено при добавлении файла
|
||||
if (entry.totalPages > 0) {
|
||||
preloadPreviewPages(entry, 1, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function preloadPreviewPages(entry, startPage, count, direction = 'forward') {
|
||||
if (!entry.pdfDoc || isPreviewRendering) return;
|
||||
isPreviewRendering = true;
|
||||
|
||||
let pagesToLoad = [];
|
||||
|
||||
if (direction === 'around') {
|
||||
const half = Math.floor(count / 2);
|
||||
const from = Math.max(1, startPage - half);
|
||||
@ -148,7 +158,6 @@
|
||||
|
||||
if (pagesToLoad.length > 0) {
|
||||
const newCacheEntries = {};
|
||||
|
||||
for (const pageNum of pagesToLoad) {
|
||||
try {
|
||||
const url = await renderPageToImage(entry.pdfDoc, pageNum, 1.5);
|
||||
@ -157,16 +166,13 @@
|
||||
console.error(`Failed to render preview page ${pageNum}`, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(newCacheEntries).length > 0) {
|
||||
previewPagesCache = { ...previewPagesCache, ...newCacheEntries };
|
||||
}
|
||||
}
|
||||
|
||||
isPreviewRendering = false;
|
||||
}
|
||||
|
||||
// Обработчик запроса страниц от дочернего PreviewPage
|
||||
function handlePreviewRequestPages(start, count, direction) {
|
||||
if (activeFile) preloadPreviewPages(activeFile, start, count, direction);
|
||||
}
|
||||
@ -240,8 +246,13 @@
|
||||
selectedPages: fType === 'image' ? new Set([1]) : new Set(),
|
||||
pdfDoc: null,
|
||||
};
|
||||
|
||||
files.push(entry);
|
||||
if (fType === 'pdf') loadPdfDocument(entry);
|
||||
|
||||
// ВАЖНО: Загружаем PDF сразу при добавлении, чтобы сохранить totalPages
|
||||
if (fType === 'pdf') {
|
||||
loadPdfDocument(entry);
|
||||
}
|
||||
}
|
||||
input.value = '';
|
||||
}
|
||||
@ -252,6 +263,7 @@
|
||||
}
|
||||
|
||||
function toggleExpanded(file) { file.expanded = !file.expanded; }
|
||||
|
||||
function removeFile(file) {
|
||||
if (file.previewUrl) URL.revokeObjectURL(file.previewUrl);
|
||||
files = files.filter((f) => f.id !== file.id);
|
||||
@ -363,6 +375,7 @@
|
||||
{/if}
|
||||
</section>
|
||||
{/each}
|
||||
|
||||
<button type="button" class="add-file-btn" onclick={triggerFileInput}>+ Добавить файлы</button>
|
||||
{/if}
|
||||
</main>
|
||||
@ -389,9 +402,7 @@
|
||||
<!-- ═══════════════════════════════════════════════════════════ -->
|
||||
{#if activeFile}
|
||||
<div class="overlay-backdrop" onclick={closeOverlay} role="dialog" aria-modal="true">
|
||||
<!-- stopPropagation чтобы клики внутри окна не закрывали его -->
|
||||
<div class="overlay-window-wrapper" onclick={(e) => e.stopPropagation()}>
|
||||
|
||||
{#if viewMode === 'gallery'}
|
||||
<SelectionPage
|
||||
file={activeFile}
|
||||
@ -411,13 +422,11 @@
|
||||
onClose={closeOverlay}
|
||||
/>
|
||||
{/if}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
/* Стили основного меню остались без изменений */
|
||||
.page-container { width: 100%; min-height: 100dvh; display: flex; flex-direction: column; background: radial-gradient(120% 60% at 50% -10%, rgba(99, 102, 241, 0.18) 0%, transparent 60%); font-family: system-ui, -apple-system, sans-serif; color: #f5f7fa; }
|
||||
.header { padding: 24px 20px 8px; }
|
||||
.back-btn { background: none; border: none; color: #6366f1; font-size: 15px; font-weight: 600; cursor: pointer; padding: 8px 4px; margin-bottom: 12px; }
|
||||
@ -464,25 +473,22 @@
|
||||
.summary-itogo { font-size: 30px; font-weight: 700; color: #8b93a1; }
|
||||
.summary-price { font-size: 38px; font-weight: 800; color: #fff; }
|
||||
|
||||
/* Обертка оверлея */
|
||||
.overlay-backdrop {
|
||||
position: fixed; inset: 0; z-index: 1000;
|
||||
background: rgba(10, 12, 18, 0.92); backdrop-filter: blur(12px);
|
||||
display: flex; align-items: center; justify-content: center; padding: 0;
|
||||
}
|
||||
|
||||
.overlay-window-wrapper {
|
||||
width: 100%; height: 100%;
|
||||
display: flex; flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.overlay-window-wrapper {
|
||||
max-width: 800px; max-height: 90vh;
|
||||
border-radius: 20px; height: auto;
|
||||
border: 1px solid rgba(255,255,255,0.1);
|
||||
background: #13151b; /* Fallback bg for wrapper on desktop */
|
||||
background: #13151b;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user