diff --git a/src/views/common/DocumentSearch.vue b/src/views/common/DocumentSearch.vue index dd87665..6bc268b 100644 --- a/src/views/common/DocumentSearch.vue +++ b/src/views/common/DocumentSearch.vue @@ -61,7 +61,7 @@ if (resolvedWorkerSrc) { pdfjsLib.GlobalWorkerOptions.workerSrc = null } -const DEFAULT_SCALE = 0.95 +const DEFAULT_SCALE = 1 export default { name: 'DocumentSearch', @@ -107,6 +107,7 @@ export default { standardFontDataUrl: '', pdfAssetsBase: '', fontsReady: new Set(), + renderingSet: new Set(), } }, mounted() { @@ -267,6 +268,8 @@ export default { const viewport = page.getViewport({ scale: this.scale }) this.ensureContainerDimensions(pageNumber, viewport) + container.classList.add('is-loading') + this.renderingSet.add(pageNumber) const oldCanvas = container.querySelector('.pdf-canvas') if (oldCanvas) { @@ -276,7 +279,7 @@ export default { const canvas = document.createElement('canvas') canvas.className = 'pdf-canvas' const deviceScale = window.devicePixelRatio || 1 - const outputScale = Math.min(deviceScale, 1.25) + const outputScale = deviceScale > 1 ? deviceScale : 1 canvas.width = viewport.width * outputScale canvas.height = viewport.height * outputScale canvas.style.width = `${viewport.width}px` @@ -284,6 +287,9 @@ export default { container.appendChild(canvas) const canvasContext = canvas.getContext('2d') + if (canvasContext && 'imageSmoothingEnabled' in canvasContext) { + canvasContext.imageSmoothingEnabled = false + } const renderContext = { canvasContext, viewport, @@ -302,6 +308,8 @@ export default { } this.renderedPages.set(pageNumber, { container, viewport }) + container.classList.remove('is-loading') + this.renderingSet.delete(pageNumber) return { page, viewport, container } }, @@ -318,7 +326,7 @@ export default { const existing = container.querySelector('.textLayer') if (existing && !force && this.pageTextDivs[index]?.length) { - existing.style.display = visible ? '' : 'none' + existing.style.display = '' return } if (existing) { @@ -329,7 +337,7 @@ export default { textLayerDiv.className = 'textLayer' textLayerDiv.style.width = `${viewport.width}px` textLayerDiv.style.height = `${viewport.height}px` - textLayerDiv.style.display = visible ? '' : 'none' + textLayerDiv.style.display = '' container.appendChild(textLayerDiv) const textLayer = new TextLayerBuilder({ textLayerDiv, @@ -485,6 +493,8 @@ export default { textLayer.style.display = 'none' } + container.classList.remove('is-loading') + this.renderingSet.delete(pageNumber) container.dataset.status = this.pageTextDivs[index]?.length ? 'text-ready' : 'prefetched' container.classList.add('prefetched') this.renderedPages.delete(pageNumber) @@ -647,11 +657,11 @@ export default { this.observer = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { - const page = Number(entry.target.dataset.page) - if (page) { - this.renderTextLayer(page, { visible: true, force: true }) - this.scheduleRender(page, { priority: true }) - } + const page = Number(entry.target.dataset.page) + if (page) { + this.renderTextLayer(page, { visible: true, force: true }) + this.scheduleRender(page, { priority: true }) + } } else { const page = Number(entry.target.dataset.page) if (page) { @@ -841,6 +851,39 @@ export default { -webkit-user-select: text; } +.pdf-page.is-loading::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 48px; + height: 48px; + margin: -24px 0 0 -24px; + border-radius: 50%; + border: 4px solid rgba(86, 119, 196, 0.25); + border-top-color: rgba(86, 119, 196, 0.9); + animation: pdf-page-spin 0.9s linear infinite; + z-index: 5; +} + +.pdf-page.is-loading::after { + opacity: 0.5; +} + +.pdf-page.is-loading .textLayer, +.pdf-page.is-loading .pdf-canvas { + opacity: 0.35; +} + +@keyframes pdf-page-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + .pdf-page > canvas.pdf-canvas { position: relative; top: 0;