Aller au contenu
← 1001 Widgets
N° 035 · ●●○

Chronomètre avec tours

Un chronomètre au centième, avec une liste de tours où le plus rapide et le plus lent ressortent. Le bon exercice pour mesurer le temps avec précision plutôt que de compter des intervalles.

JS
Ce qu'on apprend
  • Mesurer le temps avec performance.now
  • Mettre en pause sans perdre le temps écoulé
  • Comparer une série pour trouver le minimum et le maximum
Pourquoi ce langage

Pourquoi un chronomètre avec tours ? Pour une séance de course, des longueurs à la piscine ou un entraînement par intervalles, on veut le temps total et le temps de chaque tour.

L'erreur classique serait d'ajouter dix millisecondes à chaque tic d'un setInterval. Les navigateurs retardent ces tics, et le chrono dérive. On note plutôt l'heure exacte du départ avec performance.now, et on calcule la différence à chaque image. La pause ajoute le temps déjà écoulé dans un cumul.

Pourquoi en JavaScript simple ? Deux nombres, une soustraction, et requestAnimationFrame pour l'affichage. La barre d'espace lance et arrête.

Comment ça marche
  1. L'ÉTAT

    cumul garde le temps des périodes précédentes, depart le début de la période en cours.

    let depart = 0, cumul = 0, enCours = false, raf = 0;
    const tours = [];
    let dernierTour = 0;
  2. LE TEMPS ÉCOULÉ

    performance.now est précis et ne recule pas si l'horloge de l'ordinateur change.

    const ecoule = () => enCours ? cumul + performance.now() - depart : cumul;
  3. FORMATER

    83456 ms devient « 01:23,45 ».

    function format(ms) {
      const p = n => String(n).padStart(2, '0');
      return p(Math.floor(ms / 60000)) + ':' + p(Math.floor(ms / 1000) % 60) + ',' + p(Math.floor(ms / 10) % 100);
    }
  4. DÉMARRER ET ARRÊTER

    function basculer() {
      if (enCours) { cumul = ecoule(); enCours = false; cancelAnimationFrame(raf); }
      else { depart = performance.now(); enCours = true; boucle(); }
    }
    function boucle() {
      document.getElementById('temps').textContent = format(ecoule());
      raf = requestAnimationFrame(boucle);
    }
  5. LES TOURS

    Un tour = le temps depuis le tour précédent. On repère le meilleur et le plus lent.

    function tour() {
      const t = ecoule();
      tours.push({ duree: t - dernierTour, total: t });
      dernierTour = t;
      const durees = tours.map(x => x.duree);
      const meilleur = Math.min(...durees), pire = Math.max(...durees);
      // on marque ensuite chaque ligne selon qu'elle vaut meilleur ou pire
    }
Pièges

PIÈGE 1 : Compter les tics

Piège

Mauvais : setInterval(() => ms += 10, 10). Les tics arrivent en retard, surtout dans un onglet en arrière-plan, et le chrono perd des secondes.

Fix

Correct : noter l'heure de départ et calculer la différence à chaque affichage.

PIÈGE 2 : Utiliser Date.now

Piège

Mauvais : Date.now pour mesurer une durée. Si l'ordinateur ajuste son heure pendant la course, le temps fait un saut.

Fix

Correct : performance.now, une horloge qui avance toujours régulièrement.

PIÈGE 3 : Remettre à zéro pendant la course

Piège

Mauvais : laisser le bouton actif quand le chrono tourne. Un doigt qui glisse et la séance est perdue.

Fix

Correct : désactiver la remise à zéro tant que le chrono n'est pas arrêté.

PERSONNALISER
  • Un mode intervalles : 30 secondes d'effort, 15 de repos, avec un signal sonore.
  • L'export des tours en CSV pour les reprendre dans un tableur.
  • Une vibration au téléphone à chaque tour avec navigator.vibrate.
OPTIMISATION
  • Quand l'onglet est caché, requestAnimationFrame s'arrête tout seul : le temps continue d'être juste grâce au calcul par différence.
  • Mettez le temps dans un élément role="timer" mais sans aria-live, pour ne pas saturer les lecteurs d'écran.
VERS REACT

Le départ et le cumul vivent dans des useRef : ils changent sans avoir besoin d'un nouveau rendu.

Le temps affiché est un useState mis à jour dans la boucle, ou mieux, écrit directement dans le DOM par une ref.

Les tours sont un useState tableau ; le meilleur et le pire se calculent au rendu.

Commentaires
0/1000

Chargement des commentaires…