PDF-Zoom neu: Pinch zoomt um die Fingermitte und zeichnet scharf neu (Scrollen: an Ort und Stelle, die Stelle bleibt; Seiten: vergrößerte Seite mit einem Finger verschiebbar, am Rand weiterwischen blättert); pdfSmartZoomPage gab es nicht mehr; Seiten werden auf eigener Canvas gezeichnet und erst fertig eingesetzt (sw CACHE v169)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0d712a7f21
commit
1e36d8600b
6 changed files with 251 additions and 52 deletions
|
|
@ -1851,8 +1851,10 @@ html.nui-tts-on body.reader-immersive .reader-overlay { bottom: var(--bar-h); }
|
|||
/* Page by page the page fills the whole reading area, without its padding: 66-pdf-paginated.js
|
||||
measures the area and places the page by its text box itself. */
|
||||
.reader-content.pdf-paginated { overflow:hidden !important; display:block; padding:0 !important; }
|
||||
/* The pages are as wide as they're drawn, not the text column's line length (--reader-max-width). */
|
||||
/* The pages are as wide as they're drawn, not the text column's line length (--reader-max-width);
|
||||
zoomed wider than the screen, scrolling reaches their left edge too (not centred past it). */
|
||||
.reader-content > #pdf-viewport { max-width:none; }
|
||||
.reader-content:not(.pdf-paginated) > #pdf-viewport { width:max-content; min-width:100%; }
|
||||
.reader-content.pdf-paginated > #pdf-viewport { width:100%; height:100%; max-width:none; margin:0; }
|
||||
.pdf-paginated .pdf-page-wrapper { margin:0; }
|
||||
.pdf-paginated .pdf-page-wrapper { position:relative; }
|
||||
|
|
|
|||
|
|
@ -45,9 +45,6 @@ function _readerScrollTick() {
|
|||
_readerScrollLastTs = now;
|
||||
$('reader-content')?.scrollBy({top: Math.round(_readerScrollDir * READER_SCROLL_SPEED * dt / 1000)});
|
||||
}
|
||||
let _pinchStartDist = 0;
|
||||
let _pinchStartZoom = 100;
|
||||
let _isPinching = false;
|
||||
|
||||
if (typeof pdfjsLib !== 'undefined') {
|
||||
pdfjsLib.GlobalWorkerOptions.workerSrc = '/static/js/pdf.worker.min.js';
|
||||
|
|
|
|||
|
|
@ -439,26 +439,38 @@ async function _pdfDrawNow(e, page, cssScale) {
|
|||
let ratio = window.devicePixelRatio || 1;
|
||||
const area = viewport.width * viewport.height;
|
||||
if (area * ratio * ratio > PDF_MAX_PIXELS) ratio = Math.max(0.5, Math.sqrt(PDF_MAX_PIXELS / area));
|
||||
e.canvas.width = Math.round(viewport.width * ratio);
|
||||
e.canvas.height = Math.round(viewport.height * ratio);
|
||||
e.canvas.style.width = viewport.width + 'px';
|
||||
e.canvas.style.height = viewport.height + 'px';
|
||||
// Drawn on a canvas of its own and put in place when it's done: the page shown so far stays
|
||||
// until then (after a zoom larger or smaller and blurred for a moment, never blank).
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.className = 'pdf-page';
|
||||
canvas.width = Math.round(viewport.width * ratio);
|
||||
canvas.height = Math.round(viewport.height * ratio);
|
||||
canvas.style.width = viewport.width + 'px';
|
||||
canvas.style.height = viewport.height + 'px';
|
||||
const task = page.render({
|
||||
canvasContext: e.canvas.getContext('2d'),
|
||||
canvasContext: canvas.getContext('2d'),
|
||||
viewport,
|
||||
transform: ratio !== 1 ? [ratio, 0, 0, ratio, 0, 0] : null,
|
||||
});
|
||||
e.task = task;
|
||||
const discard = () => { canvas.width = 0; canvas.height = 0; };
|
||||
try {
|
||||
await task.promise;
|
||||
} catch (err) {
|
||||
if (e.task === task) e.task = null;
|
||||
discard();
|
||||
if (err && err.name !== 'RenderingCancelledException') console.warn('PDF page', e.num, err);
|
||||
return false;
|
||||
}
|
||||
if (e.task === task) e.task = null;
|
||||
if (e.token !== token) return false;
|
||||
if (e.token !== token) { discard(); return false; }
|
||||
const old = e.canvas;
|
||||
if (old.parentNode) old.parentNode.replaceChild(canvas, old);
|
||||
old.width = 0;
|
||||
old.height = 0;
|
||||
e.canvas = canvas;
|
||||
e.drawn = cssScale;
|
||||
e.stale = false;
|
||||
const recolor = _pdfColorFilter();
|
||||
e.canvas.classList.toggle('pdf-recolored', recolor);
|
||||
if (recolor) _pdfImageLayer(e, page, viewport, ratio, token).catch(err => console.warn('PDF page pictures', e.num, err));
|
||||
|
|
@ -478,6 +490,56 @@ function _pdfLetGo(e, pdf) {
|
|||
if (pdf) pdf.getPage(e.num).then(p => { if (!e.task) p.cleanup(); }, () => {});
|
||||
}
|
||||
|
||||
/**
|
||||
* What of which page is at (x, y) on the screen (client pixels): {e, x, y, rx, ry}, rx/ry the
|
||||
* place on the page as a share of its width and height.
|
||||
*/
|
||||
function _pdfPointAt(x, y) {
|
||||
const v = _pdfView;
|
||||
if (!v || !v.entries.length) return null;
|
||||
let lo = 0, hi = v.entries.length - 1;
|
||||
while (lo < hi) {
|
||||
const mid = (lo + hi) >> 1;
|
||||
if (v.entries[mid].wrapper.getBoundingClientRect().bottom > y) hi = mid; else lo = mid + 1;
|
||||
}
|
||||
const e = v.entries[lo];
|
||||
const r = e.canvas.getBoundingClientRect();
|
||||
return {e, x, y, rx: r.width ? (x - r.left) / r.width : 0, ry: r.height ? (y - r.top) / r.height : 0};
|
||||
}
|
||||
|
||||
/**
|
||||
* Scrolling, zoomed by [f]: every page's place grows or shrinks at once (the ones drawn are
|
||||
* shown larger or smaller until drawn anew, those near the view first), and [anchor]'s point
|
||||
* (_pdfPointAt) stays where it is on the screen. false when there's no scrolling view.
|
||||
*/
|
||||
function _pdfRezoomScroll(f, anchor) {
|
||||
const v = _pdfView;
|
||||
if (!v || v.stopped || readerSettings.pdfPaginated || !v.work) return false;
|
||||
for (const e of v.entries) {
|
||||
e.canvas.style.width = (parseFloat(e.canvas.style.width) || 0) * f + 'px';
|
||||
e.canvas.style.height = (parseFloat(e.canvas.style.height) || 0) * f + 'px';
|
||||
if (e.task) {
|
||||
e.token++;
|
||||
e.drawing = null;
|
||||
try { e.task.cancel(); } catch (err) {}
|
||||
}
|
||||
if (e.drawn || e.task) {
|
||||
_pdfDropLayers(e);
|
||||
e.stale = true;
|
||||
}
|
||||
if (e.near) v.queue.add(e);
|
||||
}
|
||||
if (anchor) {
|
||||
const contentEl = v.contentEl;
|
||||
const r = anchor.e.canvas.getBoundingClientRect();
|
||||
if (typeof _suppressScrollJumpDetect === 'function') _suppressScrollJumpDetect();
|
||||
contentEl.scrollLeft += r.left + anchor.rx * r.width - anchor.x;
|
||||
contentEl.scrollTop += r.top + anchor.ry * r.height - anchor.y;
|
||||
}
|
||||
v.work();
|
||||
return true;
|
||||
}
|
||||
|
||||
/** The page shown at the top of the scrolling view (binary search, the pages are in order). */
|
||||
function _pdfTopPage(contentEl) {
|
||||
const v = _pdfView;
|
||||
|
|
@ -596,13 +658,15 @@ async function renderPdf(arrayBuffer, contentEl, scaleOverride, pivotPage) {
|
|||
const cur = _pdfTopPage(contentEl);
|
||||
const next = Array.from(view.queue).sort((a, b) => Math.abs(a.num - cur) - Math.abs(b.num - cur))[0];
|
||||
view.queue.delete(next);
|
||||
if (next.near && !next.drawn) await draw(next);
|
||||
if (next.near && (!next.drawn || next.stale)) await draw(next);
|
||||
}
|
||||
} finally {
|
||||
view.working = false;
|
||||
}
|
||||
}
|
||||
|
||||
view.work = work;
|
||||
|
||||
// Turning the device, a narrower window, the bars coming or going: laid out again at the same page.
|
||||
let lastW = contentEl.clientWidth, lastH = contentEl.clientHeight;
|
||||
if (typeof ResizeObserver === 'function') {
|
||||
|
|
|
|||
|
|
@ -384,18 +384,29 @@ function toggleSettingsPanel() {
|
|||
}
|
||||
}
|
||||
|
||||
async function applyPdfZoom(newZoom) {
|
||||
/**
|
||||
* The PDF at another zoom (%). Scrolling, [anchor] (_pdfPointAt: where the fingers were) stays
|
||||
* in place, else the middle of the screen; page by page, the page is fitted anew (_pdfFitPage).
|
||||
*/
|
||||
async function applyPdfZoom(newZoom, anchor) {
|
||||
const old = readerSettings.pdfZoom;
|
||||
readerSettings.pdfZoom = newZoom;
|
||||
const zoomRange = document.getElementById('rs-zoom');
|
||||
const zoomVal = document.getElementById('rs-zoom-val');
|
||||
if (zoomRange) zoomRange.value = newZoom;
|
||||
if (zoomVal) zoomVal.textContent = newZoom + '%';
|
||||
saveReaderSettings();
|
||||
if (!currentPdfDoc) return;
|
||||
if (readerSettings.pdfPaginated) {
|
||||
pdfSmartZoomPage(pdfCurrentPage);
|
||||
} else {
|
||||
await reRenderPdf();
|
||||
await _pdfShowPage(pdfCurrentPage);
|
||||
return;
|
||||
}
|
||||
if (newZoom === old) return;
|
||||
if (!anchor) {
|
||||
const r = $('reader-content').getBoundingClientRect();
|
||||
anchor = _pdfPointAt(r.left + r.width / 2, r.top + r.height / 2);
|
||||
}
|
||||
if (!_pdfRezoomScroll(newZoom / old, anchor)) await reRenderPdf();
|
||||
}
|
||||
|
||||
// The page at the top of the view (scrolling) — 58-pdf.js keeps the pages in order.
|
||||
|
|
|
|||
|
|
@ -13,11 +13,17 @@
|
|||
// at most this many times the size the whole page would have.
|
||||
const PDF_CROP_MAX = 2.5;
|
||||
const PDF_CROP_PAD = 12;
|
||||
// Zoom (readerSettings.pdfZoom, %): the PDF panel's slider and pinching.
|
||||
const PDF_ZOOM_MIN = 50;
|
||||
const PDF_ZOOM_MAX = 200;
|
||||
|
||||
let _pdfTurnSaveTimer = 0;
|
||||
let _pdfWheelSum = 0;
|
||||
let _pdfWheelAt = 0;
|
||||
let _touchStartY = 0;
|
||||
// A touch gesture under way: {kind: 'pinch' | 'pan' | 'after'} (_pdfTouchStart).
|
||||
let _pdfGesture = null;
|
||||
let _pdfPanAt = 0; // when a page was last moved by a finger (that touch is no tap)
|
||||
|
||||
function enterPdfPaginatedMode() {
|
||||
const contentEl = $('reader-content');
|
||||
|
|
@ -25,7 +31,7 @@ function enterPdfPaginatedMode() {
|
|||
contentEl.classList.add('pdf-paginated');
|
||||
contentEl.style.overflow = 'hidden';
|
||||
const pdfVp = document.getElementById('pdf-viewport');
|
||||
if (pdfVp) pdfVp.style.zoom = '';
|
||||
if (pdfVp) { pdfVp.style.transform = ''; pdfVp.style.transformOrigin = ''; }
|
||||
// From scrolling: the drawing near the view stops, the pages are this mode's now.
|
||||
const v = _pdfView;
|
||||
if (v && v.observer) { v.observer.disconnect(); v.observer = null; v.queue.clear(); }
|
||||
|
|
@ -47,6 +53,8 @@ function exitPdfPaginatedMode(page) {
|
|||
|
||||
function _pdfPaginatedClick(e) {
|
||||
if (e.target.closest('a, button, input')) return;
|
||||
// The page was just moved with a finger: no tap.
|
||||
if (Date.now() - _pdfPanAt < 400) return;
|
||||
// Text just selected (the text layer): that tap wasn't a turn.
|
||||
const sel = window.getSelection();
|
||||
if (sel && !sel.isCollapsed) return;
|
||||
|
|
@ -62,6 +70,18 @@ function _pdfPaginatedClick(e) {
|
|||
function _pdfPaginatedWheel(e) {
|
||||
if (e.ctrlKey) return; // the browser's zoom
|
||||
e.preventDefault();
|
||||
// A page taller than the screen (zoomed in) is moved first; at its end the wheel turns.
|
||||
const pe = _pdfView && _pdfView.entries[pdfCurrentPage - 1];
|
||||
if (pe && pe.place && pe.place.minY < pe.place.maxY) {
|
||||
const y = Math.max(pe.place.minY, Math.min(pe.place.maxY, pe.pos.y - e.deltaY));
|
||||
if (Math.abs(y - pe.pos.y) > 0.5) {
|
||||
_pdfPlace(pe, pe.pos.x, y);
|
||||
_pdfKeepFocus(pe);
|
||||
_pdfWheelSum = 0;
|
||||
_pdfWheelAt = Date.now();
|
||||
return;
|
||||
}
|
||||
}
|
||||
const now = Date.now();
|
||||
if (now - _pdfWheelAt > 400) _pdfWheelSum = 0;
|
||||
_pdfWheelAt = now;
|
||||
|
|
@ -73,48 +93,123 @@ function _pdfPaginatedWheel(e) {
|
|||
pdfGoToPage(pdfCurrentPage + dir);
|
||||
}
|
||||
|
||||
// Touch (62-reader.js listens for every book; only a PDF's are handled here):
|
||||
// - two fingers zoom around the point between them: a preview while they move (a CSS
|
||||
// transform, the layout stays as it is), then drawn anew at the new size with that point
|
||||
// where it was (scrolling: _pdfRezoomScroll; page by page: _pdfFitPage and v.focus);
|
||||
// - page by page, a page larger than the screen moves with one finger, and pushed on past
|
||||
// its edge sideways it turns; otherwise a swipe turns.
|
||||
function _pdfTouchStart(e) {
|
||||
const v = _pdfView;
|
||||
if (!currentPdfDoc || !v) return;
|
||||
const contentEl = $('reader-content');
|
||||
if (e.touches.length === 2) {
|
||||
const dx = e.touches[0].clientX - e.touches[1].clientX;
|
||||
const dy = e.touches[0].clientY - e.touches[1].clientY;
|
||||
_pinchStartDist = Math.hypot(dx, dy);
|
||||
_pinchStartZoom = readerSettings.pdfZoom;
|
||||
_isPinching = true;
|
||||
const ce = $('reader-content');
|
||||
if (ce) ce.classList.add('pinch-active');
|
||||
} else {
|
||||
_touchStartX = e.touches[0].clientX;
|
||||
_touchStartY = e.touches[0].clientY;
|
||||
_isPinching = false;
|
||||
const a = e.touches[0], b = e.touches[1];
|
||||
const x = (a.clientX + b.clientX) / 2, y = (a.clientY + b.clientY) / 2;
|
||||
const r = contentEl.getBoundingClientRect();
|
||||
const g = {kind: 'pinch', dist: Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY) || 1,
|
||||
zoom: readerSettings.pdfZoom, f: 1, cx: x - r.left, cy: y - r.top};
|
||||
if (readerSettings.pdfPaginated) {
|
||||
g.entry = v.entries[pdfCurrentPage - 1];
|
||||
if (!g.entry || !g.entry.pos) return;
|
||||
g.pos = {x: g.entry.pos.x, y: g.entry.pos.y};
|
||||
} else {
|
||||
const vp = document.getElementById('pdf-viewport');
|
||||
if (!vp) return;
|
||||
const vr = vp.getBoundingClientRect();
|
||||
g.vp = vp;
|
||||
g.ox = x - vr.left;
|
||||
g.oy = y - vr.top;
|
||||
g.anchor = _pdfPointAt(x, y);
|
||||
}
|
||||
_pdfGesture = g;
|
||||
contentEl.classList.add('pinch-active');
|
||||
return;
|
||||
}
|
||||
if (e.touches.length !== 1) return;
|
||||
const t = e.touches[0];
|
||||
_touchStartX = t.clientX;
|
||||
_touchStartY = t.clientY;
|
||||
_pdfGesture = null;
|
||||
const pe = readerSettings.pdfPaginated && v.entries[pdfCurrentPage - 1];
|
||||
if (pe && pe.place && (pe.place.minX < pe.place.maxX || pe.place.minY < pe.place.maxY)) {
|
||||
_pdfGesture = {kind: 'pan', entry: pe, x: t.clientX, y: t.clientY, ox: pe.pos.x, oy: pe.pos.y,
|
||||
dx: 0, dy: 0, moved: false};
|
||||
}
|
||||
}
|
||||
|
||||
function _pdfTouchMove(e) {
|
||||
if (e.touches.length !== 2 || !_isPinching) return;
|
||||
e.preventDefault();
|
||||
const dx = e.touches[0].clientX - e.touches[1].clientX;
|
||||
const dy = e.touches[0].clientY - e.touches[1].clientY;
|
||||
const dist = Math.hypot(dx, dy);
|
||||
if (_pinchStartDist === 0) return;
|
||||
const liveZoom = Math.max(50, Math.min(200, _pinchStartZoom * (dist / _pinchStartDist)));
|
||||
const vp = document.getElementById('pdf-viewport');
|
||||
if (vp) vp.style.zoom = liveZoom / 100;
|
||||
const g = _pdfGesture;
|
||||
if (!g) return;
|
||||
if (g.kind === 'pinch') {
|
||||
if (e.touches.length !== 2) return;
|
||||
e.preventDefault();
|
||||
const a = e.touches[0], b = e.touches[1];
|
||||
const dist = Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);
|
||||
const zoom = Math.max(PDF_ZOOM_MIN, Math.min(PDF_ZOOM_MAX, g.zoom * dist / g.dist));
|
||||
g.f = zoom / g.zoom;
|
||||
if (g.entry) {
|
||||
// The page grows around the point between the fingers (its transform's origin is 0 0).
|
||||
const x = g.cx - g.f * (g.cx - g.pos.x), y = g.cy - g.f * (g.cy - g.pos.y);
|
||||
g.entry.inner.style.transform = `translate(${x}px, ${y}px) scale(${g.f})`;
|
||||
} else {
|
||||
g.vp.style.transformOrigin = `${g.ox}px ${g.oy}px`;
|
||||
g.vp.style.transform = `scale(${g.f})`;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (g.kind === 'pan' && e.touches.length === 1) {
|
||||
const t = e.touches[0];
|
||||
g.dx = t.clientX - g.x;
|
||||
g.dy = t.clientY - g.y;
|
||||
if (!g.moved && Math.hypot(g.dx, g.dy) < 8) return;
|
||||
g.moved = true;
|
||||
e.preventDefault();
|
||||
_pdfPlace(g.entry, g.ox + g.dx, g.oy + g.dy);
|
||||
}
|
||||
}
|
||||
|
||||
function _pdfTouchEnd(e) {
|
||||
if (_isPinching) {
|
||||
_isPinching = false;
|
||||
const ce = $('reader-content');
|
||||
if (ce) ce.classList.remove('pinch-active');
|
||||
const vp = document.getElementById('pdf-viewport');
|
||||
const liveZoom = vp && vp.style.zoom ? parseFloat(vp.style.zoom) * 100 : readerSettings.pdfZoom;
|
||||
// The live zoom was only a preview: the page is drawn anew at the new size.
|
||||
if (vp) vp.style.zoom = '';
|
||||
const snapped = Math.max(50, Math.min(200, Math.round(liveZoom / 10) * 10));
|
||||
applyPdfZoom(snapped);
|
||||
const g = _pdfGesture;
|
||||
if (g && g.kind === 'pinch') {
|
||||
// The other finger may stay down a moment: it's no swipe.
|
||||
_pdfGesture = {kind: 'after'};
|
||||
const contentEl = $('reader-content');
|
||||
if (contentEl) contentEl.classList.remove('pinch-active');
|
||||
const zoom = Math.max(PDF_ZOOM_MIN, Math.min(PDF_ZOOM_MAX, Math.round(g.zoom * g.f / 10) * 10));
|
||||
if (g.entry) {
|
||||
const pe = g.entry, s = pe.drawn, p = pe.place;
|
||||
// The page's point between the fingers stays there (_pdfFitPage); the preview stays
|
||||
// until the page is drawn at its new size.
|
||||
if (s && p) {
|
||||
_pdfView.focus = {x: (g.cx - g.pos.x) / s, y: (g.cy - g.pos.y) / s, sx: g.cx / p.W, sy: g.cy / p.H};
|
||||
_pdfView.focusPage = pe.num;
|
||||
}
|
||||
if (zoom === readerSettings.pdfZoom) _pdfPlace(pe, g.pos.x, g.pos.y);
|
||||
} else {
|
||||
g.vp.style.transform = '';
|
||||
g.vp.style.transformOrigin = '';
|
||||
}
|
||||
if (zoom !== readerSettings.pdfZoom) applyPdfZoom(zoom, g.anchor);
|
||||
return;
|
||||
}
|
||||
if (!readerSettings.pdfPaginated || !e.changedTouches.length) return;
|
||||
if (g && g.kind === 'after') {
|
||||
if (!e.touches || !e.touches.length) _pdfGesture = null;
|
||||
return;
|
||||
}
|
||||
if (g && g.kind === 'pan') {
|
||||
_pdfGesture = null;
|
||||
if (!g.moved) return; // a tap: the click turns or shows the bars
|
||||
_pdfPanAt = Date.now();
|
||||
_pdfKeepFocus(g.entry);
|
||||
// Already at its edge and pushed on sideways: the next or previous page (a move that only
|
||||
// reaches the edge doesn't turn as well).
|
||||
const p = g.entry.place;
|
||||
const atEdge = g.dx < 0 ? g.ox <= p.minX + 1 : g.ox >= p.maxX - 1;
|
||||
if (atEdge && Math.abs(g.dx) > 50 && Math.abs(g.dx) > Math.abs(g.dy) * 1.5) pdfGoToPage(pdfCurrentPage + (g.dx > 0 ? -1 : 1));
|
||||
return;
|
||||
}
|
||||
if (!currentPdfDoc || !readerSettings.pdfPaginated || !e.changedTouches.length) return;
|
||||
const dx = e.changedTouches[0].clientX - _touchStartX;
|
||||
const dy = e.changedTouches[0].clientY - _touchStartY;
|
||||
// Sideways, clearly: a slanted scroll is not a turn.
|
||||
|
|
@ -217,18 +312,48 @@ async function _pdfFitPage(v, e, ahead) {
|
|||
if (!e.drawn || Math.abs(scale - e.drawn) / e.drawn > 0.05) {
|
||||
if (!await _pdfDraw(e, page, scale)) return;
|
||||
}
|
||||
// Centre the text box (at the scale it was drawn with).
|
||||
// The text box centred where it fits (at the scale it was drawn with); larger than the
|
||||
// screen (zoomed in), it can be moved up to its edges and starts at its top left — or
|
||||
// where it was looked at (v.focus: a pinch, a move, the screen turned).
|
||||
const s = e.drawn;
|
||||
const offsetX = (W - s * bw) / 2 - s * box.x1;
|
||||
const offsetY = (H - s * bh) / 2 - s * box.y1;
|
||||
e.inner.style.transform = `translate(${offsetX}px, ${offsetY}px)`;
|
||||
const range = (size, lo, hi) => {
|
||||
if (hi - lo + PDF_CROP_PAD * 2 <= size + 1) {
|
||||
const c = (size - (hi - lo)) / 2 - lo;
|
||||
return [c, c];
|
||||
}
|
||||
return [size - PDF_CROP_PAD - hi, PDF_CROP_PAD - lo];
|
||||
};
|
||||
const [minX, maxX] = range(W, s * box.x1, s * box.x2);
|
||||
const [minY, maxY] = range(H, s * box.y1, s * box.y2);
|
||||
e.place = {minX, maxX, minY, maxY, W, H};
|
||||
const f = v.focusPage === e.num ? v.focus : null;
|
||||
e.inner.style.transformOrigin = '0 0';
|
||||
_pdfPlace(e, f ? W * f.sx - s * f.x : maxX, f ? H * f.sy - s * f.y : maxY);
|
||||
e.wrapper.style.overflow = 'hidden';
|
||||
e.wrapper.style.width = W + 'px';
|
||||
e.wrapper.style.height = H + 'px';
|
||||
if (!ahead && v.shown === e.num) e.wrapper.style.display = '';
|
||||
}
|
||||
|
||||
/** Page [e] moved to (x, y) (its offset in the reading area), kept within its edges (e.place). */
|
||||
function _pdfPlace(e, x, y) {
|
||||
const p = e.place;
|
||||
if (p) {
|
||||
x = Math.max(p.minX, Math.min(p.maxX, x));
|
||||
y = Math.max(p.minY, Math.min(p.maxY, y));
|
||||
}
|
||||
e.pos = {x, y};
|
||||
e.inner.style.transform = `translate(${x}px, ${y}px)`;
|
||||
}
|
||||
|
||||
/** Page [e] moved: that part of it stays in view when it's laid out again (another zoom, turned). */
|
||||
function _pdfKeepFocus(e) {
|
||||
const v = _pdfView, p = e.place;
|
||||
if (!v || !p || !e.drawn) return;
|
||||
v.focus = {x: (p.W / 2 - e.pos.x) / e.drawn, y: (p.H / 2 - e.pos.y) / e.drawn, sx: 0.5, sy: 0.5};
|
||||
v.focusPage = e.num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Where the page's content is, in the page's own top-down coordinates at scale 1 (as
|
||||
* getViewport gives them, so turned pages and odd media boxes come out right): its text,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* diora service worker — caches the app shell for offline use.
|
||||
*/
|
||||
|
||||
const CACHE = 'diora-v168';
|
||||
const CACHE = 'diora-v169';
|
||||
const SHELL = [
|
||||
'/static/css/app.css',
|
||||
'/static/js/app/01-core.js',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue