Uebersicht zoomen: zwei Finger und Strg+Mausrad
Deploy App / deploy (push) Successful in 42s

- Zwei Finger auf- und zuziehen zoomt die Uebersicht. Beide Zeiger werden
  mitgefuehrt; laesst man einen Finger los, geht es nahtlos ins Drehen
  ueber.
- Mausrad zoomt weiterhin, jetzt auch mit gedrueckter Strg-Taste - der
  Seitenzoom des Browsers wird dabei unterdrueckt. Die Schrittweite kommt
  aus dem Betrag des Radwegs, damit Trackpads feiner dosieren koennen.
- Zoombereich 9 bis 120 m statt 14 bis 110 m.
- Das Wischen des Rundgangs wird im Uebersichtsmodus nicht mehr
  ausgewertet; sonst sammelte sich dort eine Blickdrehung an, die beim
  Zurueckwechseln sprang.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 12:41:24 +02:00
co-authored by Claude Opus 5
parent 76185e8ba8
commit 53a67444a3
4 changed files with 63 additions and 7 deletions
+3
View File
@@ -264,6 +264,9 @@ Damit es nicht ruppig wirkt:
Oberkante geht in die Höhenabfrage ein (`walkHeight` in `main.ts`,
`treppeTritte` in `structures.ts`). Ob man hinaufkommt, entscheidet nur die
Stufenhöhe (45 cm). Holz-, Lamellen- und Betonwände bleiben Hindernisse.
- In der **Übersicht** dreht Ziehen die Ansicht; gezoomt wird mit dem Mausrad
(auch mit `Strg`, wobei der Seitenzoom des Browsers unterdrückt wird) und am
Handy mit zwei Fingern. Abstand 9 bis 120 m.
- Das **Gartentor** öffnet sich, wenn man darauf zugeht, und schliesst sich
hinter einem wieder; `E` übersteuert das von Hand. Im Durchgang selbst
schliesst es nie.
+2
View File
@@ -145,6 +145,7 @@ export class Walker {
let last = { x: 0, y: 0 };
let start = { x: 0, y: 0, t: 0 };
dom.addEventListener('touchstart', (e) => {
if (!this.enabled) return;
for (const t of Array.from(e.changedTouches)) {
if (touchId === null && t.clientX > window.innerWidth * 0.35) {
touchId = t.identifier;
@@ -154,6 +155,7 @@ export class Walker {
}
}, { passive: true });
dom.addEventListener('touchmove', (e) => {
if (!this.enabled) { touchId = null; return; }
for (const t of Array.from(e.changedTouches)) {
if (t.identifier !== touchId) continue;
this.lookDelta.x += (t.clientX - last.x) * 0.006;
+55 -5
View File
@@ -336,27 +336,77 @@ async function main() {
},
};
const ABSTAND = { nah: 9, fern: 120 };
const zoome = (faktor: number) => {
orbit.distance = Math.max(ABSTAND.nah, Math.min(ABSTAND.fern, orbit.distance * faktor));
orbit.apply();
};
// Ziehen dreht, zwei Finger zoomen. Beide Zeiger werden mitgefuehrt, damit
// beim Loslassen eines Fingers nahtlos weitergedreht wird.
let dragging = false;
let lastPointer = { x: 0, y: 0 };
const zeiger = new Map<number, { x: number; y: number }>();
let kneifStart = 0;
let kneifAbstand = 0;
const kneifSpanne = () => {
const [a, b] = [...zeiger.values()];
return Math.hypot(a.x - b.x, a.y - b.y);
};
canvas.addEventListener('pointerdown', (e) => {
if (!orbit.active) return;
zeiger.set(e.pointerId, { x: e.clientX, y: e.clientY });
canvas.setPointerCapture(e.pointerId);
if (zeiger.size === 2) {
dragging = false;
kneifAbstand = kneifSpanne();
kneifStart = orbit.distance;
} else if (zeiger.size === 1) {
dragging = true;
lastPointer = { x: e.clientX, y: e.clientY };
canvas.setPointerCapture(e.pointerId);
}
});
canvas.addEventListener('pointermove', (e) => {
if (!orbit.active || !dragging) return;
if (!orbit.active || !zeiger.has(e.pointerId)) return;
zeiger.set(e.pointerId, { x: e.clientX, y: e.clientY });
if (zeiger.size >= 2) {
// Finger auseinander = naeher heran
const jetzt = kneifSpanne();
if (jetzt > 1 && kneifAbstand > 1) {
orbit.distance = Math.max(ABSTAND.nah, Math.min(ABSTAND.fern, kneifStart * (kneifAbstand / jetzt)));
orbit.apply();
}
return;
}
if (!dragging) return;
orbit.yaw -= (e.clientX - lastPointer.x) * 0.006;
orbit.pitch = Math.max(0.12, Math.min(1.45, orbit.pitch + (e.clientY - lastPointer.y) * 0.004));
lastPointer = { x: e.clientX, y: e.clientY };
orbit.apply();
});
canvas.addEventListener('pointerup', () => { dragging = false; });
const zeigerWeg = (e: PointerEvent) => {
zeiger.delete(e.pointerId);
if (zeiger.size === 1) {
// Vom Zoomen zurueck aufs Drehen, ohne Sprung
const [rest] = [...zeiger.values()];
lastPointer = { ...rest };
dragging = true;
} else if (zeiger.size === 0) {
dragging = false;
}
};
canvas.addEventListener('pointerup', zeigerWeg);
canvas.addEventListener('pointercancel', zeigerWeg);
// Mausrad zoomt - auch mit Strg, wo der Browser sonst die Seite vergroessern
// wuerde. Trackpads melden feine Schritte, deshalb wird die Staerke aus dem
// Betrag abgeleitet statt nur aus der Richtung.
canvas.addEventListener('wheel', (e) => {
if (!orbit.active) return;
e.preventDefault();
orbit.distance = Math.max(14, Math.min(110, orbit.distance * (1 + Math.sign(e.deltaY) * 0.12)));
orbit.apply();
const schritt = Math.max(-1, Math.min(1, e.deltaY / (e.deltaMode === 1 ? 3 : 120)));
zoome(1 + schritt * 0.14);
}, { passive: false });
// -- Umschalten zwischen den Darstellungen --------------------------------
+2 -1
View File
@@ -178,7 +178,8 @@ export function setupHud(opts: HudOptions): Hud {
<li>Treppen, Stufen und Sitzmauern sind begehbar. Das Gartentor &ouml;ffnet sich,
wenn man darauf zugeht; <kbd>E</kbd> &ouml;ffnet oder schliesst es von Hand.</li>
<li>Am Handy: auf den Boden tippen, links der Joystick, rechts wischen zum Umsehen</li>
<li>Übersicht: ziehen zum Drehen, Mausrad zum Zoomen</li>
<li>Übersicht: ziehen zum Drehen; zoomen mit dem Mausrad (auch mit <kbd>Strg</kbd>),
am Handy mit zwei Fingern auf- und zuziehen</li>
<li>Die Sonne steht für Abtwil SG astronomisch korrekt</li>
</ul>
<p id="sun-readout"></p>