Uebersicht: kein Zoom mehr, nur noch scrollen
Zwei Zoom-Ebenen lagen uebereinander, und beide waren falsch. Aussen ein Rad-Zoom, der nur die iframes skaliert hat -- Beschriftung, Abstaende und Polster stehen ausserhalb der Transformation und blieben stehen, also standen beim Herauszoomen riesige Ueberschriften ueber winzigen Streifen. Und innen reagierte die Post-Seite im iframe weiter auf ihr eigenes Mausrad, weil sie ihren Canvas mitbringt. Jetzt: jeder Streifen wird auf die Fensterbreite eingepasst, gescrollt wird nur hoch und runter. Die iframes bekommen pointer-events: none -- die Uebersicht ist zum Ansehen da, bedient wird im Projekt selbst. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
16b85a285a
commit
79821775b0
2 files changed
+24
-80
No files matched your search
@@ -30,7 +30,8 @@ nach: jedes Projekt kommt als `iframe` mit `?nur=streifen`, und in diesem Modus
|
||||
blendet die Post-Seite ihre Bedienoberfläche aus, zeigt den Streifen in
|
||||
natürlicher Größe und **speichert nichts** — drei Kacheln, die beim Schließen
|
||||
ihren Stand zurückschreiben, wären genau die Falle aus [`POST-2.md`](./POST-2.md) §6.
|
||||
Skaliert wird außen; ziehen schiebt, das Rad zoomt, `Fit` passt ein.
|
||||
Jeder Streifen ist auf die Fensterbreite eingepasst, gescrollt wird nur
|
||||
hoch und runter — kein Zoom, weder außen noch im Streifen.
|
||||
|
||||
**Post 2 gibt es zweimal, in zwei Themes.** Projekt und Theme sind zwei
|
||||
verschiedene Dinge: das Projekt sagt, welcher Beitrag, das Theme, wie er
|
||||
|
||||
+22
-79
@@ -50,14 +50,17 @@
|
||||
.menu .liste button:hover { background: #262A34; color: #FFFFFF; }
|
||||
.menu .liste hr { border: 0; border-top: 1px solid #2E313B; margin: 5px 2px; }
|
||||
|
||||
/* Dieselbe Fläche wie im Generator: gepunkteter Grund, ziehbar, Rad zoomt. */
|
||||
/* Derselbe gepunktete Grund wie im Generator, aber ohne dessen Canvas:
|
||||
hier wird nur gescrollt. */
|
||||
.stage { position: absolute; inset: 34px 0 0; overflow: hidden;
|
||||
background-color: #101116;
|
||||
background-image: radial-gradient(circle, #282B35 1.6px, transparent 1.6px);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.scroller { position: absolute; inset: 0; overflow: auto; overscroll-behavior: contain; }
|
||||
.scroller.panning { cursor: grabbing; }
|
||||
/* Nur hoch und runter. Die Streifen sind auf die Breite eingepasst,
|
||||
also gibt es waagerecht nichts zu holen. */
|
||||
.scroller { position: absolute; inset: 0; overflow-y: auto; overflow-x: hidden;
|
||||
overscroll-behavior: contain; }
|
||||
.flaeche {
|
||||
width: max-content; min-width: 100%; height: max-content; min-height: 100%;
|
||||
padding: 54px; display: flex; flex-direction: column; gap: 46px;
|
||||
@@ -74,8 +77,12 @@
|
||||
bleibt in Originalgröße und wird nur transformiert. Ohne den Rahmen
|
||||
würde das ungeskalierte iframe die Fläche aufblähen. */
|
||||
.rahmen { overflow: hidden; background: #FFFFFF; border: 1px solid #2E313B; }
|
||||
/* pointer-events: none -- sonst zoomt das Mausrad im Streifen die
|
||||
Post-Seite darin, die ja ihren eigenen Canvas mitbringt. Die Uebersicht
|
||||
ist zum Ansehen da, bedient wird im Projekt selbst. */
|
||||
.rahmen iframe {
|
||||
display: block; border: 0; transform-origin: 0 0; background: #FFFFFF;
|
||||
pointer-events: none;
|
||||
}
|
||||
.reihe.fehlt .rahmen { display: grid; place-items: center; width: 420px; height: 90px;
|
||||
background: #16181F; color: #6E7480; font-size: 13px; }
|
||||
@@ -87,13 +94,6 @@
|
||||
border-top: 1px solid #23262F;
|
||||
}
|
||||
.hud p { margin: 0; font-size: 12px; color: #6E7480; letter-spacing: .04em; }
|
||||
.zoom { margin-left: auto; display: flex; gap: 4px; }
|
||||
.zoom button {
|
||||
font: inherit; font-size: 13px; font-weight: 700; cursor: pointer;
|
||||
background: #1D1F26; color: #C7CCD6; border: 1px solid #2E313B;
|
||||
border-radius: 7px; padding: 6px 10px; min-width: 32px;
|
||||
}
|
||||
.zoom button:hover { background: #262A34; color: #FFFFFF; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -118,11 +118,6 @@
|
||||
</div>
|
||||
<div class="hud">
|
||||
<p id="meta">Lade Streifen ...</p>
|
||||
<div class="zoom">
|
||||
<button id="zoom-out" title="Auszoomen">−</button>
|
||||
<button id="zoom-fit" title="Einpassen">Fit</button>
|
||||
<button id="zoom-in" title="Einzoomen">+</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -140,10 +135,12 @@
|
||||
const scroller = document.getElementById("scroller");
|
||||
const meta = document.getElementById("meta");
|
||||
|
||||
/* Ein Streifen ist bis zu 6480 px breit. Der Maßstab ist deshalb nicht
|
||||
frei, sondern immer relativ zu "passt in die Fläche" -- sonst müsste man
|
||||
bei jedem Öffnen erst herauszoomen. zoom === null heißt eingepasst. */
|
||||
let zoom = null;
|
||||
/* Kein Zoom. Ein Streifen ist bis zu 6480 px breit und wird immer auf die
|
||||
Fensterbreite eingepasst; gescrollt wird nur hoch und runter. Ein
|
||||
Zwischenstand hatte Rad-Zoom und Zoomknöpfe -- das war doppelt gemoppelt,
|
||||
weil die Post-Seite im iframe ihren eigenen Canvas mitbringt, und die
|
||||
Beschriftungen skalierten nicht mit, standen beim Herauszoomen also
|
||||
riesig über winzigen Streifen. */
|
||||
const reihen = [];
|
||||
|
||||
function bauen() {
|
||||
@@ -178,22 +175,15 @@
|
||||
legen();
|
||||
});
|
||||
|
||||
/* Beschriftung, Abstände und Polster skalieren NICHT mit -- sie stehen
|
||||
außerhalb des transformierten iframes. Ein einfaches
|
||||
"verfügbar / Gesamthöhe" ließ die letzte Reihe deshalb unten
|
||||
hinauslaufen. Die feste Höhe muss vorher abgezogen werden. */
|
||||
const POLSTER = 54 * 2, LUECKE = 46, KOPFZEILE = 32;
|
||||
// Eingepasst wird nur in die Breite, die Höhe ergibt sich und wird gescrollt.
|
||||
const POLSTER = 54 * 2;
|
||||
function passend() {
|
||||
const n = reihen.length;
|
||||
const breit = Math.max(...reihen.map(r => r.w), 1080);
|
||||
const hoch = reihen.reduce((s, r) => s + r.h, 0);
|
||||
const fest = POLSTER + (n - 1) * LUECKE + n * KOPFZEILE;
|
||||
return Math.min((scroller.clientWidth - POLSTER) / breit,
|
||||
Math.max(0.02, (scroller.clientHeight - fest) / hoch), 0.5);
|
||||
return Math.min((scroller.clientWidth - POLSTER) / breit, 0.5);
|
||||
}
|
||||
|
||||
function legen() {
|
||||
const k = zoom || passend();
|
||||
const k = passend();
|
||||
reihen.forEach(r => {
|
||||
r.ram.style.width = r.w + "px";
|
||||
r.ram.style.height = r.h + "px";
|
||||
@@ -201,57 +191,14 @@
|
||||
r.rahmen.style.width = Math.round(r.w * k) + "px";
|
||||
r.rahmen.style.height = Math.round(r.h * k) + "px";
|
||||
});
|
||||
document.getElementById("zoom-fit").textContent = zoom ? Math.round(k * 100) + " %" : "Fit";
|
||||
const offen = reihen.filter(r => r.da).length;
|
||||
meta.textContent = offen < reihen.length
|
||||
? "Lade Streifen ... " + offen + " von " + reihen.length
|
||||
: reihen.length + " Projekte · " + reihen.map(r => Math.round(r.w / 1080) + " Slides").join(" · ");
|
||||
}
|
||||
|
||||
function zoomAuf(k, anker) {
|
||||
const vor = zoom || passend();
|
||||
const ax = anker ? anker.x : scroller.clientWidth / 2;
|
||||
const ay = anker ? anker.y : scroller.clientHeight / 2;
|
||||
const s0 = scroller.getBoundingClientRect();
|
||||
const f0 = flaeche.getBoundingClientRect();
|
||||
const u = (s0.left + ax - f0.left) / vor;
|
||||
const v = (s0.top + ay - f0.top) / vor;
|
||||
zoom = Math.min(1, Math.max(0.02, k));
|
||||
legen();
|
||||
const f1 = flaeche.getBoundingClientRect();
|
||||
scroller.scrollLeft += (f1.left + u * zoom) - (s0.left + ax);
|
||||
scroller.scrollTop += (f1.top + v * zoom) - (s0.top + ay);
|
||||
}
|
||||
|
||||
// ─── Bedienung: ziehen, Rad zoomt, Umschalt+Rad schiebt waagerecht ───────
|
||||
let zieht = null;
|
||||
scroller.addEventListener("pointerdown", e => {
|
||||
if (e.button !== 0 && e.button !== 1) return;
|
||||
zieht = { x: e.clientX, y: e.clientY, l: scroller.scrollLeft, t: scroller.scrollTop };
|
||||
scroller.classList.add("panning");
|
||||
scroller.setPointerCapture(e.pointerId);
|
||||
});
|
||||
scroller.addEventListener("pointermove", e => {
|
||||
if (!zieht) return;
|
||||
scroller.scrollLeft = zieht.l - (e.clientX - zieht.x);
|
||||
scroller.scrollTop = zieht.t - (e.clientY - zieht.y);
|
||||
});
|
||||
const losen = () => { zieht = null; scroller.classList.remove("panning"); };
|
||||
scroller.addEventListener("pointerup", losen);
|
||||
scroller.addEventListener("pointercancel", losen);
|
||||
|
||||
scroller.addEventListener("wheel", e => {
|
||||
if (e.shiftKey) return; // waagerecht schieben
|
||||
e.preventDefault();
|
||||
const r = scroller.getBoundingClientRect();
|
||||
zoomAuf((zoom || passend()) * (e.deltaY < 0 ? 1.12 : 1 / 1.12),
|
||||
{ x: e.clientX - r.left, y: e.clientY - r.top });
|
||||
}, { passive: false });
|
||||
|
||||
document.getElementById("zoom-in").addEventListener("click", () => zoomAuf((zoom || passend()) * 1.2));
|
||||
document.getElementById("zoom-out").addEventListener("click", () => zoomAuf((zoom || passend()) / 1.2));
|
||||
document.getElementById("zoom-fit").addEventListener("click", () => { zoom = null; legen(); });
|
||||
window.addEventListener("resize", () => { if (!zoom) legen(); });
|
||||
// Kein Ziehen, kein Rad-Zoom: die Seite scrollt wie eine gewoehnliche Seite.
|
||||
window.addEventListener("resize", legen);
|
||||
|
||||
// ─── Menü ────────────────────────────────────────────────────────────────
|
||||
document.querySelectorAll(".menu").forEach(m => {
|
||||
@@ -269,10 +216,6 @@
|
||||
if (b.dataset.gehe) { location.href = b.dataset.gehe; return; }
|
||||
if (b.dataset.klick === "neu") { bauen(); legen(); }
|
||||
});
|
||||
document.addEventListener("keydown", e => {
|
||||
if (e.key === "0") { zoom = null; legen(); }
|
||||
});
|
||||
|
||||
bauen();
|
||||
legen();
|
||||
})();
|
||||
|
||||
Reference in new issue
Block a user