Der Regler gehörte der Uhr, nicht dem Finger
`zeitAuffrischen` schrieb `zeitleiste.value` bei jedem `timeupdate` neu — viermal je Sekunde, auch mitten im Ziehen. Das hatte zwei Gesichter, und nur das harmlosere war zu sehen: der Knopf sprang unter dem Finger an die laufende Stelle zurück, und nach dem Loslassen noch einmal, weil ein Sprung einen Augenblick braucht und der Spieler in dem weiter die alte Stelle meldet. Das andere ist schlimmer. Gemessen an einer Nachbildung mit 20-ms-Takt: gezogen auf 113, und `onchange` las 7 — der Takt hatte `value` überschrieben, bevor der Browser den Zug festschreiben konnte. Es sprang also nicht nur zurück, es sprang an die falsche Stelle. Genau deshalb half Festhalten: es schiebt den letzten `input` näher an den `change`. Jetzt gehört der Regler dem Zeiger, solange einer darauf liegt, und danach dem Sprungziel, bis der Spieler dort angekommen ist. Mit Notbremse nach dreissig Sekunden, damit eine Leiste nie stehen bleibt, wenn ein neu gebauter Strom woanders herauskommt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0186087051
commit
d152ac3795
+46
-4
@@ -763,17 +763,59 @@ export function spieler(anfrage: Spieleranfrage): void {
|
||||
zeigeFehler(videofehler());
|
||||
};
|
||||
|
||||
zeitleiste.oninput = () => { stand.textContent = dauer(Number(zeitleiste.value)); };
|
||||
zeitleiste.onchange = () => void springen(Number(zeitleiste.value));
|
||||
/** Ob der Regler gerade dem Zeiger gehört und nicht der Uhr. */
|
||||
let amRegler = false;
|
||||
/** Wohin gesprungen wurde — bis der Spieler dort angekommen ist. */
|
||||
let sprungziel: number | null = null;
|
||||
let sprungAb = 0;
|
||||
|
||||
zeitleiste.oninput = () => {
|
||||
// Auch Tastatur und Finger kommen hier an, nicht nur die Maus.
|
||||
amRegler = true;
|
||||
stand.textContent = dauer(Number(zeitleiste.value));
|
||||
};
|
||||
zeitleiste.onchange = () => {
|
||||
amRegler = false;
|
||||
const ziel = Number(zeitleiste.value);
|
||||
sprungziel = ziel;
|
||||
sprungAb = performance.now();
|
||||
void springen(ziel);
|
||||
};
|
||||
// Ein abgebrochener Zeiger meldet kein `change`. Ohne das bliebe der
|
||||
// Regler stehen, bis jemand ihn wieder anfasst.
|
||||
zeitleiste.onpointercancel = () => { amRegler = false; };
|
||||
|
||||
/** Die Gesamtlänge des Films — nicht die des Stroms. */
|
||||
const gesamt = anfrage.laenge ?? 0;
|
||||
|
||||
function zeitAuffrischen(): void {
|
||||
const jetzt = filmzeit();
|
||||
let jetzt = filmzeit();
|
||||
|
||||
// **Der Regler gehört dem Zeiger, nicht der Uhr.**
|
||||
//
|
||||
// `timeupdate` kommt viermal je Sekunde und schrieb `value` jedes Mal
|
||||
// neu — auch mitten im Ziehen. Der Knopf sprang dadurch unter dem
|
||||
// Finger an die laufende Stelle zurück, und nur wer festhielt und
|
||||
// gegenhielt, kam irgendwo an. Gleich danach dasselbe noch einmal: ein
|
||||
// Sprung braucht einen Augenblick, und in dem meldet der Spieler
|
||||
// weiter die alte Stelle. Ungeprüft übernommen zieht das den Regler
|
||||
// zurück, kurz bevor er nach vorn springt.
|
||||
if (amRegler) {
|
||||
jetzt = Number(zeitleiste.value);
|
||||
} else if (sprungziel !== null) {
|
||||
// Die Notbremse: landet der Sprung nie — weil der Strom neu gebaut
|
||||
// wird und woanders herauskommt —, bliebe die Leiste sonst für
|
||||
// immer stehen.
|
||||
if (Math.abs(jetzt - sprungziel) < 1.5 || performance.now() - sprungAb > 30_000) {
|
||||
sprungziel = null;
|
||||
} else {
|
||||
jetzt = sprungziel;
|
||||
}
|
||||
}
|
||||
|
||||
const laenge = gesamt > 0 ? gesamt : vorlauf + (Number.isFinite(video.duration) ? video.duration : 0);
|
||||
zeitleiste.max = String(Math.max(1, laenge));
|
||||
zeitleiste.value = String(jetzt);
|
||||
if (!amRegler) zeitleiste.value = String(jetzt);
|
||||
stand.textContent = dauer(jetzt);
|
||||
rest.textContent = laenge > jetzt ? `−${dauer(laenge - jetzt)}` : '';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user