Stoppuhr
Misst auf die Hundertstelsekunde genau, nimmt beliebig viele Rundenzeiten auf und zeigt die schnellste und langsamste Runde.
Eine Stoppuhr braucht man öfter, als man denkt: beim Training, beim Backen, beim Vortragüben, beim Messen, wie lange etwas dauert, das gefühlt ewig dauert. Diese hier läuft auf die Hundertstelsekunde genau und nimmt Rundenzeiten auf — so viele, wie ihr wollt.
Der große Knopf startet und hält an, der zweite nimmt eine Runde auf, der dritte setzt zurück. Jede Runde erscheint in der Liste mit ihrer eigenen Zeit und der Gesamtzeit bis dahin; die schnellste und die langsamste werden gekennzeichnet. Unter der Liste steht die Durchschnittszeit aller Runden.
Zur Genauigkeit ein ehrliches Wort: Angezeigt werden Hundertstel, verlässlich sind sie nur bedingt. Nicht wegen der Uhr im Rechner — die ist genau genug —, sondern wegen der Reaktionszeit beim Drücken, die typischerweise bei zwei bis drei Zehntelsekunden liegt. Bei Handmessungen liegt der Fehler also beim Menschen, nicht beim Programm. Für Zeitmessungen im Zehntel- und Hundertstelbereich benutzt der Sport deshalb Lichtschranken.
Verwandtes im Archiv: Sekundencountdown zählt rückwärts statt vorwärts, Reaktionstest misst genau jene Reaktionszeit, die hier den Fehler ausmacht, und Onlinezeit misst die Verweildauer auf der Seite.
Gemessen wird mit der Zeitrechnung des Browsers; die Reaktionszeit beim Drücken bleibt der größere Fehler.
So funktioniert das Script
Eine Stoppuhr sieht einfach aus und hat zwei Fallen: Womit misst man die Zeit, und wie übersteht die Messung ein Anhalten und Weiterlaufen? Beides ist hier gelöst — und beides wird in selbstgebauten Stoppuhren regelmäßig falsch gemacht.
function jetzt() {
return performance.now();
}
Gemessen wird mit performance.now() und nicht mit Date.now(). Der Unterschied ist entscheidend: Date.now() liefert die Systemuhr, und die kann sich während der Messung ändern — durch einen Abgleich mit einem Zeitserver, durch die Sommerzeitumstellung oder weil jemand die Uhr verstellt. Eine Stoppuhr, die dabei rückwärts springt, wäre unbrauchbar. performance.now() zählt dagegen monoton seit dem Laden der Seite und ist genau dafür gemacht. Als Zugabe liefert es Bruchteile von Millisekunden.
function verstrichen() {
return angesammelt + (laeuft ? jetzt() - startzeit : 0);
}
Das ist der Kern der Anhalten-und-weiter-Logik. Statt einen Zähler hochzuzählen, merkt sich das Script zwei Werte: die Summe aller früheren Laufabschnitte (angesammelt) und den Zeitpunkt des letzten Starts. Läuft die Uhr, kommt die Zeit seit dem letzten Start dazu; steht sie, gilt nur die angesammelte Zeit. Beim Anhalten wird der aktuelle Stand in angesammelt übernommen.
Der Vorteil gegenüber einem hochzählenden Zähler: Die angezeigte Zeit ist immer die tatsächlich vergangene, unabhängig davon, wie oft und wie pünktlich die Anzeige aktualisiert wurde. Ein Zähler, der bei jedem Intervall um 10 erhöht wird, geht dagegen nach — Intervalle sind nie exakt, und im Hintergrundreiter bremst der Browser sie stark aus.
uhr = setInterval(zeichnen, 31);
Die Anzeige wird etwa dreißigmal je Sekunde neu gezeichnet. Das ist schnell genug, dass die Hundertstel flimmerfrei durchlaufen, und deutlich sparsamer als eine Aktualisierung bei jedem Bild. Wichtig ist, dass hier nur gezeichnet und nicht gezählt wird — die Zeitmessung selbst hängt nicht an diesem Takt.
runden.push({ dauer: gesamt - letzteRunde, gesamt: gesamt });
letzteRunde = gesamt;
Jede Runde speichert zwei Zeiten: die eigene Dauer und den Gesamtstand. Die Rundenzeit ergibt sich als Abstand zur vorigen Rundenmarke — deshalb muss letzteRunde danach sofort nachgezogen werden. Beide Werte zu speichern, statt einen aus dem anderen zu berechnen, macht die Anzeige und die spätere Auswertung einfacher.
for (let i = 1; i < runden.length; i++) {
if (runden[i].dauer < runden[schnellste].dauer) schnellste = i;
…
}
Schnellste und langsamste Runde werden in einem einzigen Durchlauf gesucht. Gemerkt wird dabei nicht der Wert, sondern die Position — so lässt sich die betreffende Zeile später kennzeichnen. Die Schleife beginnt bei 1, weil die nullte Runde als Startwert für beide Merker dient.
Zum Anpassen: Für Tastenbedienung fangt ihr keydown ab — Leertaste für Start und Stopp, Eingabetaste für die Runde. Wollt ihr die Rundenzeiten weiterverwenden, könnt ihr sie mit runden.map(r => alsZeit(r.dauer)).join("\n") als Text ausgeben und in die Zwischenablage kopieren.
Script für die eigene Homepage
Kopiert euch den kompletten Code und fügt ihn an der Stelle eurer Seite ein, an der das Script erscheinen soll. Er läuft ohne weitere Dateien und ohne fremde Server.