From 12bc1c4123fa1227715d2c7dc8254bb8bd449fd8 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 2 Aug 2026 03:28:57 +0900 Subject: fix(slides): fix flickering --- services/nuldoc/public/slides/slide.js | 63 ++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'services/nuldoc/public/slides/slide.js') diff --git a/services/nuldoc/public/slides/slide.js b/services/nuldoc/public/slides/slide.js index 8d6ba52d..a90fda7a 100644 --- a/services/nuldoc/public/slides/slide.js +++ b/services/nuldoc/public/slides/slide.js @@ -8,13 +8,22 @@ async function init() { const url = canvas.dataset.slideLink; let pageNum = 1; - let pageNumPending = null; - let pageRendering = false; let doc = null; + let renderTask = null; + let renderToken = 0; + + const backCanvas = document.createElement("canvas"); + const backCtx = backCanvas.getContext("2d"); const renderPage = async (num) => { - pageRendering = true; + const token = ++renderToken; + if (renderTask !== null) { + renderTask.cancel(); + renderTask = null; + } + const page = await doc.getPage(num); + if (token !== renderToken) return; const baseViewport = page.getViewport({ scale: 1.0 }); const containerWidth = canvas.parentElement.clientWidth; @@ -22,65 +31,69 @@ async function init() { const viewport = page.getViewport({ scale }); const outputScale = globalThis.devicePixelRatio || 1; - canvas.height = Math.floor(viewport.height * outputScale); - canvas.width = Math.floor(viewport.width * outputScale); - canvas.style.width = Math.floor(viewport.width) + "px"; - canvas.style.height = Math.floor(viewport.height) + "px"; + const cssWidth = Math.floor(viewport.width); + const cssHeight = Math.floor(viewport.height); + backCanvas.width = Math.floor(viewport.width * outputScale); + backCanvas.height = Math.floor(viewport.height * outputScale); const transform = outputScale !== 1 ? [outputScale, 0, 0, outputScale, 0, 0] : null; // TODO: error handling - await page.render({ - canvasContext: ctx, + const task = page.render({ + canvasContext: backCtx, viewport, transform, }); - - pageRendering = false; - if (pageNumPending !== null) { - renderPage(pageNumPending); - pageNumPending = null; + renderTask = task; + try { + await task.promise; + } catch (e) { + if (e?.name === "RenderingCancelledException") return; + throw e; + } finally { + if (renderTask === task) renderTask = null; } - }; + if (token !== renderToken) return; - const queueRenderPage = (num) => { - if (pageRendering) { - pageNumPending = num; - } else { - renderPage(num); + if (canvas.width !== backCanvas.width || canvas.height !== backCanvas.height) { + canvas.width = backCanvas.width; + canvas.height = backCanvas.height; + canvas.style.width = cssWidth + "px"; + canvas.style.height = cssHeight + "px"; } + ctx.drawImage(backCanvas, 0, 0); }; const prev = document.getElementById("prev"); prev.addEventListener("click", () => { if (pageNum <= 1) return; pageNum--; - queueRenderPage(pageNum); + renderPage(pageNum); }); const next = document.getElementById("next"); next.addEventListener("click", () => { if (pageNum >= doc.numPages) return; pageNum++; - queueRenderPage(pageNum); + renderPage(pageNum); }); document.addEventListener("keydown", (e) => { if (e.key === "ArrowLeft" || e.key === "h") { if (pageNum <= 1) return; pageNum--; - queueRenderPage(pageNum); + renderPage(pageNum); } else if (e.key === "ArrowRight" || e.key === "l") { if (pageNum >= doc.numPages) return; pageNum++; - queueRenderPage(pageNum); + renderPage(pageNum); } }); // TODO: error handling doc = await getDocument(url).promise; - queueRenderPage(pageNum); + renderPage(pageNum); } document.addEventListener("DOMContentLoaded", init); -- cgit v1.3.1