- 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:
@@ -264,6 +264,9 @@ Damit es nicht ruppig wirkt:
|
|||||||
Oberkante geht in die Höhenabfrage ein (`walkHeight` in `main.ts`,
|
Oberkante geht in die Höhenabfrage ein (`walkHeight` in `main.ts`,
|
||||||
`treppeTritte` in `structures.ts`). Ob man hinaufkommt, entscheidet nur die
|
`treppeTritte` in `structures.ts`). Ob man hinaufkommt, entscheidet nur die
|
||||||
Stufenhöhe (45 cm). Holz-, Lamellen- und Betonwände bleiben Hindernisse.
|
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
|
- Das **Gartentor** öffnet sich, wenn man darauf zugeht, und schliesst sich
|
||||||
hinter einem wieder; `E` übersteuert das von Hand. Im Durchgang selbst
|
hinter einem wieder; `E` übersteuert das von Hand. Im Durchgang selbst
|
||||||
schliesst es nie.
|
schliesst es nie.
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ export class Walker {
|
|||||||
let last = { x: 0, y: 0 };
|
let last = { x: 0, y: 0 };
|
||||||
let start = { x: 0, y: 0, t: 0 };
|
let start = { x: 0, y: 0, t: 0 };
|
||||||
dom.addEventListener('touchstart', (e) => {
|
dom.addEventListener('touchstart', (e) => {
|
||||||
|
if (!this.enabled) return;
|
||||||
for (const t of Array.from(e.changedTouches)) {
|
for (const t of Array.from(e.changedTouches)) {
|
||||||
if (touchId === null && t.clientX > window.innerWidth * 0.35) {
|
if (touchId === null && t.clientX > window.innerWidth * 0.35) {
|
||||||
touchId = t.identifier;
|
touchId = t.identifier;
|
||||||
@@ -154,6 +155,7 @@ export class Walker {
|
|||||||
}
|
}
|
||||||
}, { passive: true });
|
}, { passive: true });
|
||||||
dom.addEventListener('touchmove', (e) => {
|
dom.addEventListener('touchmove', (e) => {
|
||||||
|
if (!this.enabled) { touchId = null; return; }
|
||||||
for (const t of Array.from(e.changedTouches)) {
|
for (const t of Array.from(e.changedTouches)) {
|
||||||
if (t.identifier !== touchId) continue;
|
if (t.identifier !== touchId) continue;
|
||||||
this.lookDelta.x += (t.clientX - last.x) * 0.006;
|
this.lookDelta.x += (t.clientX - last.x) * 0.006;
|
||||||
|
|||||||
+56
-6
@@ -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 dragging = false;
|
||||||
let lastPointer = { x: 0, y: 0 };
|
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) => {
|
canvas.addEventListener('pointerdown', (e) => {
|
||||||
if (!orbit.active) return;
|
if (!orbit.active) return;
|
||||||
dragging = true;
|
zeiger.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
||||||
lastPointer = { x: e.clientX, y: e.clientY };
|
|
||||||
canvas.setPointerCapture(e.pointerId);
|
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.addEventListener('pointermove', (e) => {
|
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.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));
|
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 };
|
lastPointer = { x: e.clientX, y: e.clientY };
|
||||||
orbit.apply();
|
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) => {
|
canvas.addEventListener('wheel', (e) => {
|
||||||
if (!orbit.active) return;
|
if (!orbit.active) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
orbit.distance = Math.max(14, Math.min(110, orbit.distance * (1 + Math.sign(e.deltaY) * 0.12)));
|
const schritt = Math.max(-1, Math.min(1, e.deltaY / (e.deltaMode === 1 ? 3 : 120)));
|
||||||
orbit.apply();
|
zoome(1 + schritt * 0.14);
|
||||||
}, { passive: false });
|
}, { passive: false });
|
||||||
|
|
||||||
// -- Umschalten zwischen den Darstellungen --------------------------------
|
// -- Umschalten zwischen den Darstellungen --------------------------------
|
||||||
|
|||||||
+2
-1
@@ -178,7 +178,8 @@ export function setupHud(opts: HudOptions): Hud {
|
|||||||
<li>Treppen, Stufen und Sitzmauern sind begehbar. Das Gartentor öffnet sich,
|
<li>Treppen, Stufen und Sitzmauern sind begehbar. Das Gartentor öffnet sich,
|
||||||
wenn man darauf zugeht; <kbd>E</kbd> öffnet oder schliesst es von Hand.</li>
|
wenn man darauf zugeht; <kbd>E</kbd> öffnet oder schliesst es von Hand.</li>
|
||||||
<li>Am Handy: auf den Boden tippen, links der Joystick, rechts wischen zum Umsehen</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>
|
<li>Die Sonne steht für Abtwil SG astronomisch korrekt</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p id="sun-readout"></p>
|
<p id="sun-readout"></p>
|
||||||
|
|||||||
Reference in New Issue
Block a user