From fcbd9f9e5c565c738da76d2e6541f0a7a64253b9 Mon Sep 17 00:00:00 2001 From: Simon Martens Date: Tue, 23 Sep 2025 05:12:42 +0200 Subject: [PATCH] Zoom mode --- views/assets/scripts.js | 649 +++++++++++++++----------- views/assets/style.css | 2 +- views/transform/single-page-viewer.js | 319 ++++++++++++- 3 files changed, 685 insertions(+), 285 deletions(-) diff --git a/views/assets/scripts.js b/views/assets/scripts.js index 871a0e0..cea8dcf 100644 --- a/views/assets/scripts.js +++ b/views/assets/scripts.js @@ -1,4 +1,4 @@ -class H extends HTMLElement { +class T extends HTMLElement { constructor() { super(), this.scrollHandler = null, this.scrollTimeout = null, this.clickHandlers = [], this.manualNavigation = !1; } @@ -25,8 +25,8 @@ class H extends HTMLElement { this.updateActiveLink(), this.updateSidebarScrollToTopButton(); }, 50); }, window.addEventListener("scroll", this.scrollHandler), this.navLinks.forEach((e) => { - const t = (i) => { - i.preventDefault(); + const i = (t) => { + t.preventDefault(); const n = e.getAttribute("data-target"), o = document.getElementById(n); o && (this.updateActiveLinkImmediate(n), this.manualNavigation = !0, o.scrollIntoView({ behavior: "smooth", @@ -35,23 +35,23 @@ class H extends HTMLElement { this.manualNavigation = !1, this.ensureMarkerVisibility(); }, 1e3)); }; - this.clickHandlers.push({ link: e, handler: t }), e.addEventListener("click", t); + this.clickHandlers.push({ link: e, handler: i }), e.addEventListener("click", i); }), this.updateActiveLink(), this.updateSidebarScrollToTopButton(); } ensureMarkerVisibility() { - const e = document.getElementById("scrollspy-slider"), t = document.getElementById("scrollspy-nav"); - if (!e || !t || e.style.opacity === "0") + const e = document.getElementById("scrollspy-slider"), i = document.getElementById("scrollspy-nav"); + if (!e || !i || e.style.opacity === "0") return; - const i = t.getBoundingClientRect(), n = parseFloat(e.style.top), o = parseFloat(e.style.height), s = n + o, a = t.scrollTop, l = a + i.height; - if (s > l) { - const c = s - i.height + 20; - t.scrollTo({ + const t = i.getBoundingClientRect(), n = parseFloat(e.style.top), o = parseFloat(e.style.height), r = n + o, a = i.scrollTop, l = a + t.height; + if (r > l) { + const c = r - t.height + 20; + i.scrollTo({ top: c, behavior: "smooth" }); } else if (n < a) { const c = n - 20; - t.scrollTo({ + i.scrollTo({ top: Math.max(0, c), behavior: "smooth" }); @@ -64,17 +64,17 @@ class H extends HTMLElement { try { this.sections.forEach((n) => { if (!n || !n.getAttribute) return; - const o = n.getAttribute("id"), s = n.querySelector(".akteur-werke-section"), a = n.querySelector(".akteur-beitraege-section"); + const o = n.getAttribute("id"), r = n.querySelector(".akteur-werke-section"), a = n.querySelector(".akteur-beitraege-section"); let l = !1; - if (s) { - const c = s.getBoundingClientRect(), d = c.top < window.innerHeight, g = c.bottom > 0; + if (r) { + const c = r.getBoundingClientRect(), d = c.top < window.innerHeight, g = c.bottom > 0; d && g && (l = !0); } if (a && !l) { const c = a.getBoundingClientRect(), d = c.top < window.innerHeight, g = c.bottom > 0; d && g && (l = !0); } - if (!s && !a) { + if (!r && !a) { const c = n.querySelector("div:first-child"); if (c) { const d = c.getBoundingClientRect(), g = d.top >= 0, u = d.bottom <= window.innerHeight; @@ -86,26 +86,26 @@ class H extends HTMLElement { } catch { return; } - const t = [], i = document.getElementById("scrollspy-slider"); + const i = [], t = document.getElementById("scrollspy-slider"); if (this.navLinks.forEach((n) => { n.classList.remove("font-medium"); const o = n.getAttribute("data-target"); - e.includes(o) && (n.classList.add("font-medium"), t.push(n)); - }), t.length > 0 && i) { + e.includes(o) && (n.classList.add("font-medium"), i.push(n)); + }), i.length > 0 && t) { const n = document.getElementById("scrollspy-nav"), o = n.getBoundingClientRect(); - let s = 1 / 0, a = -1 / 0; - t.forEach((c) => { + let r = 1 / 0, a = -1 / 0; + i.forEach((c) => { const d = c.getBoundingClientRect(), g = d.top - o.top + n.scrollTop, u = g + d.height; - s = Math.min(s, g), a = Math.max(a, u); + r = Math.min(r, g), a = Math.max(a, u); }); - let l = a - s; - i.style.top = `${s}px`, i.style.height = `${l}px`, i.style.opacity = "1", setTimeout(() => this.ensureMarkerVisibility(), 100); - } else i && (i.style.opacity = "0"); - t.length > 0 && this.updateSidebarScroll(t); + let l = a - r; + t.style.top = `${r}px`, t.style.height = `${l}px`, t.style.opacity = "1", setTimeout(() => this.ensureMarkerVisibility(), 100); + } else t && (t.style.opacity = "0"); + i.length > 0 && this.updateSidebarScroll(i); } updateActiveLinkImmediate(e) { if (!this.navLinks) return; - const t = document.getElementById("scrollspy-slider"); + const i = document.getElementById("scrollspy-slider"); try { this.navLinks.forEach((n) => { n && n.classList && n.classList.remove("font-medium"); @@ -113,29 +113,29 @@ class H extends HTMLElement { } catch { return; } - const i = document.querySelector(`[data-target="${e}"]`); - if (i && (i.classList.add("font-medium"), t)) { + const t = document.querySelector(`[data-target="${e}"]`); + if (t && (t.classList.add("font-medium"), i)) { const n = document.getElementById("scrollspy-nav"); if (n) { - const o = n.getBoundingClientRect(), s = i.getBoundingClientRect(), a = s.top - o.top + n.scrollTop; - t.style.top = `${a}px`, t.style.height = `${s.height}px`, t.style.opacity = "1"; + const o = n.getBoundingClientRect(), r = t.getBoundingClientRect(), a = r.top - o.top + n.scrollTop; + i.style.top = `${a}px`, i.style.height = `${r.height}px`, i.style.opacity = "1"; } } } updateSidebarScroll(e) { if (this.manualNavigation) return; - const t = document.getElementById("scrollspy-nav"); - if (!t) return; - const i = e[0], n = Math.max( + const i = document.getElementById("scrollspy-nav"); + if (!i) return; + const t = e[0], n = Math.max( document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight - ), o = window.innerHeight, s = n - o, a = s > 0 ? window.scrollY / s : 0, l = t.clientHeight, d = t.scrollHeight - l; + ), o = window.innerHeight, r = n - o, a = r > 0 ? window.scrollY / r : 0, l = i.clientHeight, d = i.scrollHeight - l; if (d > 0) { - const g = a * d, u = i.getBoundingClientRect(), p = t.getBoundingClientRect(), f = u.top - p.top + t.scrollTop, m = l / 2, L = f - m, y = 0.7, I = y * g + (1 - y) * L, x = Math.max(0, Math.min(d, I)), T = t.scrollTop; - Math.abs(x - T) > 10 && t.scrollTo({ + const g = a * d, u = t.getBoundingClientRect(), p = i.getBoundingClientRect(), f = u.top - p.top + i.scrollTop, m = l / 2, E = f - m, y = 0.7, H = y * g + (1 - y) * E, x = Math.max(0, Math.min(d, H)), I = i.scrollTop; + Math.abs(x - I) > 10 && i.scrollTo({ top: x, behavior: "smooth" }); @@ -144,21 +144,21 @@ class H extends HTMLElement { updateSidebarScrollToTopButton() { const e = document.getElementById("sidebar-scroll-to-top"); if (!e) return; - const t = window.pageYOffset || document.documentElement.scrollTop, i = window.innerHeight; - t > i * 0.5 ? (e.classList.remove("opacity-0"), e.classList.add("opacity-100")) : (e.classList.remove("opacity-100"), e.classList.add("opacity-0")); + const i = window.pageYOffset || document.documentElement.scrollTop, t = window.innerHeight; + i > t * 0.5 ? (e.classList.remove("opacity-0"), e.classList.add("opacity-100")) : (e.classList.remove("opacity-100"), e.classList.add("opacity-0")); } cleanup() { - this.scrollHandler && (window.removeEventListener("scroll", this.scrollHandler), this.scrollHandler = null), this.scrollTimeout && (clearTimeout(this.scrollTimeout), this.scrollTimeout = null), this.clickHandlers && this.clickHandlers.length > 0 && this.clickHandlers.forEach(({ link: t, handler: i }) => { - t && i && t.removeEventListener("click", i); + this.scrollHandler && (window.removeEventListener("scroll", this.scrollHandler), this.scrollHandler = null), this.scrollTimeout && (clearTimeout(this.scrollTimeout), this.scrollTimeout = null), this.clickHandlers && this.clickHandlers.length > 0 && this.clickHandlers.forEach(({ link: i, handler: t }) => { + i && t && i.removeEventListener("click", t); }); const e = document.getElementById("scrollspy-slider"); e && (e.style.opacity = "0", e.style.height = "0"), this.sections = null, this.navLinks = null, this.clickHandlers = [], this.manualNavigation = !1; } } -customElements.define("akteure-scrollspy", H); +customElements.define("akteure-scrollspy", T); class A extends HTMLElement { constructor() { - super(), this.resizeObserver = null; + super(), this.resizeObserver = null, this.zoomLevel = 1, this.minZoom = 1, this.maxZoom = 4, this.panX = 0, this.panY = 0, this.isDragging = !1, this.lastMouseX = 0, this.lastMouseY = 0; } // Dynamically detect sidebar width in pixels detectSidebarWidth() { @@ -167,8 +167,8 @@ class A extends HTMLElement { const n = e.getBoundingClientRect().width; return console.log("Detected sidebar width:", n, "px"), `${n}px`; } - const t = window.innerWidth; - return t < 1024 ? "0px" : t < 1280 ? `${Math.floor(t * 0.25)}px` : `${Math.floor(t * 0.2)}px`; + const i = window.innerWidth; + return i < 1024 ? "0px" : i < 1280 ? `${Math.floor(i * 0.25)}px` : `${Math.floor(i * 0.2)}px`; } connectedCallback() { const e = this.detectSidebarWidth(); @@ -223,6 +223,23 @@ class A extends HTMLElement {
+ +
+ Strg + Mausrad oder +/- für Zoom +
+ + + + + +
+ + + +
+