Langue

Me contacter

Application Android · depuis 2025

ClearLap

Chronomètre Android avec temps de tour, conçu comme une seule page web hors ligne dans une enveloppe Cordova.

Sortie
Autorisations d'exécution
Aucune
Publicités
Aucune
Prix
Gratuit
  • HTML
  • CSS
  • JavaScript
  • Apache Cordova (Android)
  • Web Audio API
  • Screen Wake Lock API
  • Vibration API
Google Play play.google.com

À propos

ClearLap est un chronomètre avec tours, mise en évidence du meilleur et du pire tour, sons de clic, vibration lorsque la WebView la prend en charge, et une présentation sombre en plein écran. Il n'a ni publicités, ni comptes, ni utilisation du réseau, ni plugins : toute l'application tient dans un seul fichier HTML d'environ 8 KB avec CSS et JavaScript en ligne.

Le travail d'ingénierie consiste à faire correctement les bases dans une WebView : un temps qui ne dérive pas lorsque des images sont perdues ou que l'application est en arrière-plan, des tours dont la somme égale toujours le total, un verrou d'éveil de l'écran demandé là où la WebView le prend en charge, et des sons de retour synthétisés sans fichiers audio.

ClearLap · chronomètre

ce qui a été résolu

EN LIGNEdepuis 2025

Cœur de mesure du temps

dans le produit

Ce que cela apporteLe temps reste exact lorsque le téléphone masque l'application, une pause ne fait jamais perdre ni gagner de temps, les tours s'additionnent au total et les chiffres ne sautent pas.

Problème
Un chronomètre dans une WebView ne peut pas se fier aux minuteurs ni aux callbacks d'image pour compter le temps : ils sont ralentis, sautés ou suspendus lorsque l'application est en arrière-plan.
Solution

Le temps est toujours calculé à partir d'horodatages ; la boucle d'images ne fait que dessiner. La pause, la reprise et les tours sont de l'arithmétique sur des horodatages stockés.

Stack
  • JavaScript
  • requestAnimationFrame
Tâches · 5
Les compteurs à intervalle dérivent et s'arrêtent pendant que l'application est masquéeLe temps écoulé est Date.now() moins un horodatage de départ, recalculé à chaque image

tick() n'incrémente jamais un compteur. Il définit elapsed = Date.now() - startTs et redessine. Si des images sont perdues ou si la WebView suspend requestAnimationFrame en arrière-plan, l'image suivante affiche le bon temps, car rien n'a été accumulé.

La pause et la reprise ne doivent ni faire perdre ni ajouter du tempsÀ la reprise, on rebase le départ : startTs = Date.now() - elapsed

La pause annule l'image d'animation et conserve elapsed tel quel. La reprise recule startTs de la durée déjà écoulée, de sorte que la formule de tick() repart de la même valeur sans variable distincte de « durée de pause ».

La remise à zéro annule la boucle d'images, réinitialise l'état et désactive le bouton Tour ; doLap() retourne aussi immédiatement lorsque le chronomètre ne tourne pas.

Les durées des tours doivent s'additionner exactement au temps totalChaque tour est le temps écoulé moins la marque du tour précédent, donc les tours se télescopent jusqu'au total

doLap() stocke le numéro du tour, sa durée (elapsed - lapElapsed) et le total cumulé, puis déplace lapElapsed sur elapsed. Comme chaque tour commence là où le précédent s'est terminé, la somme des durées des tours égale le total par construction, sans écart d'arrondi.

Le compteur du tour en cours sous le temps principal utilise la même marque : elapsed - lapElapsed.

Marquer le meilleur et le pire tour n'a aucun sens avec un seul tourCalculer le minimum et le maximum sur tous les tours à chaque affichage ; ne mettre en évidence que s'il y en a 2 ou plus

renderLaps() reconstruit la liste en commençant par le plus récent, trouve les durées la plus courte et la plus longue et n'ajoute les classes best/worst que s'il existe plus d'un tour.

Les chiffres se décalent latéralement quand le temps changePolice à chasse fixe plus font-variant-numeric: tabular-nums sur chaque affichage du temps

Tous les champs de temps utilisent des chiffres de largeur fixe, de sorte que l'affichage à 16vw ne bouge pas quand les centièmes changent. fmt() affiche toujours mm:ss.cc avec des zéros de remplissage.

Comportement de l'appareil sans plugins

dans le produit

Ce que cela apporteL'écran reste allumé pendant les longues séances, l'application occupe tout l'écran, et les appuis donnent un bip et une vibration, sans jamais perturber la mesure du temps.

Problème
L'écran allumé, le plein écran, le son et le retour haptique viennent d'ordinaire de plugins Cordova, et les navigateurs n'en autorisent certains qu'après un geste de l'utilisateur.
Solution

Utiliser les API de la plateforme web depuis la WebView là où elles existent, les demander au bon moment, et rendre chacune facultative pour qu'une API manquante ne perturbe jamais la mesure du temps.

Stack
  • Screen Wake Lock API
  • Fullscreen API
  • Web Audio API
  • Vibration API
  • Cordova config.xml
Tâches · 4
L'écran s'éteint pendant une longue séance de mesureDemander un verrou d'éveil de l'écran là où la WebView le prend en charge, et de nouveau chaque fois que la page redevient visible

Le système libère un verrou d'éveil lorsque la page est masquée. requestWakeLock() s'exécute au chargement de la page et à chaque visibilitychange vers visible, et l'écouteur de libération efface la référence. L'appel est ignoré lorsque navigator.wakeLock est absent et les erreurs sont absorbées, de sorte que le chronomètre fonctionne de la même façon dans les deux cas.

Le plein écran ne peut être demandé que depuis un geste de l'utilisateurLe demander au premier toucher, avec un repli webkit, puis retirer l'écouteur

Un écouteur touchstart à usage unique appelle requestFullscreen ou webkitRequestFullscreen et se retire lui-même. config.xml définit aussi la préférence Cordova Fullscreen pour la build Android.

Des sons de clic sans fichiers audio et sans claquements ni craquementsSynthétiser de courts bips sinusoïdaux avec Web Audio et un fondu de gain exponentiel

beep() crée un oscillateur et un nœud de gain à chaque appui et ramène le gain de façon exponentielle à 0.001 sur la durée du bip, ce qui évite le claquement d'un arrêt brutal. Le démarrage, le tour et la remise à zéro utilisent des hauteurs et des durées différentes (880, 1100 et 440 Hz).

L'AudioContext est créé à la demande dans le premier gestionnaire de bouton, ce qui satisfait la règle de lecture automatique selon laquelle l'audio doit démarrer depuis un geste de l'utilisateur.

Les échecs du retour sensoriel ne doivent jamais interrompre la mesure du tempsLe son et la vibration s'exécutent avant les changements d'état, seulement là où l'API existe, et dans un try/catch

beep() et vibe() interceptent toutes les exceptions, et vibe() n'appelle navigator.vibrate que là où il est disponible. Le démarrage, le tour et la remise à zéro demandent des durées de vibration différentes (25, 15 et 40 ms).

config.xml ne déclare aucun plugin et la page n'effectue aucun appel réseau, de sorte que le cœur de mesure du temps ne dépend que de la WebView.

Chiffres

du produit
  • Fonctionne sur Android 5.0 et versions ultérieures
  • Code de l'application environ 8 KB Un seul fichier HTML, aucun framework.
  • Précision 1/100 s