Projet du troisième volet : Développement centré sur les données - Code Institute.
Ce projet a été construit à l'aide du Flask Microframework et pourrait être utilisé comme chronomètre manuel pour chronométrer plusieurs athlètes en natation et en piste. Le but de cette application est d'améliorer l'efficacité du chronométrage sportif en réduisant le nombre de personnes chronométrant séparément et en stockant directement les temps, plutôt que de conserver une documentation écrite.
CETTE DEMANDE EST À USAGE ÉDUCATIF UNIQUEMENT. CETTE APPLICATION N'EST PAS DESTINÉE À UN USAGE COMMERCIAL.
Une démo en direct de ce projet peut être trouvée ici. Cette application est hébergée sur Heroku. Les heures sont stockées dans MongoDB.
L’idée de cette application Timing Assistant est venue de mon exposition à la natation tout au long de mon enfance. J'ai remarqué qu'il fallait qu'un certain nombre de personnes soient impliquées dans le processus de chronométrage, car les pavés tactiles de la piscine ne produisent pas toujours des heures précises ou lisibles pour diverses raisons. De plus, l'entraîneur et les athlètes ne peuvent pas voir les temps finaux ou les temps intermédiaires avant la fin de la compétition, à moins que plusieurs personnes ne chronométrent sur le pont pour chaque couloir et notent les temps dans un presse-papiers.
J'ai vu cette opportunité de créer une application qui réduirait le nombre de personnes impliquées dans le processus de chronométrage, dans l'espoir d'améliorer l'efficacité des compétitions et le retour d'informations aux athlètes et aux entraîneurs. Cette application pourrait être optimisée pour n'importe quel sport chronométré, et cette version fonctionne à la fois avec la natation et la piste.
Les entraîneurs et les chronométreurs peuvent choisir un sport, une compétition, un événement, une série et des numéros de couloir qui les aident tous à suivre ce qui se passe lors d'une compétition. Cela leur permet également de donner à leurs athlètes un retour instantané après une course, puisque les temps s'affichent une fois que vous les avez enregistrés, puis que vous avez cliqué sur « Afficher les temps ». Je voulais également m'assurer qu'ils pouvaient voir les résultats cumulatifs de la compétition, au lieu d'un seul événement à la fois.
Aucun thème n'a été utilisé pour cette conception, le design moderne a été choisi car avec beaucoup de minuteries et de données sur une page, elle peut paraître désordonnée et désorganisée. Je ne voulais pas cela, alors même si je voulais les minuteries, les heures et les options d'événements sur une seule page, j'ai pensé que diviser la page en tiers verticalement serait la meilleure façon de le faire, créant une différence notable entre chaque tiers.
Timing Assistant a été construit à l'aide du Flask Microframework en Python avec une base de données NoSQL (MongoDB) sur le backend, avec HTML, CSS, Javascript et jQuery sur le frontend et pour la fonctionnalité chronomètre, connecté au backend avec AJAX.
Sur la page d'accueil de l'application, l'utilisateur saisit le sport pour lequel il souhaite chronométrer, le nom de son équipe, son nom d'utilisateur et le nom de la compétition. Cette action les amène à la page du chronomètre, où ils peuvent ensuite choisir l'événement et la manche pour lesquels ils souhaitent chronométrer. L'utilisateur peut chronométrer jusqu'à trois voies et effectuer des fractionnements pour les trois voies. L'utilisateur devra arrêter manuellement la minuterie principale une fois les trois petites minuteries arrêtées, car elles sont réglées individuellement. Cela pourrait cependant être particulièrement utile si l'entraîneur voulait savoir combien de temps durait la course et comparer les temps de ses nageurs avec le temps du finaliste. L'heure du minuteur principal ne sera pas enregistrée dans la base de données.
Une fois qu'ils auront cliqué sur « soumettre », l'événement et la série apparaîtront. Ils peuvent ensuite commencer à chronométrer jusqu'à trois couloirs en appuyant sur « START » sur le chronomètre principal. Cela démarrera les quatre chronomètres, cependant, seuls les trois derniers seront enregistrés dans la base de données. Il existe la possibilité de collecter les temps intermédiaires pour chaque piste individuellement avec le bouton « SPLIT ». Chaque chronomètre peut être arrêté et démarré individuellement, le chronomètre principal contrôlant tous les chronomètres (démarrage, arrêt et réinitialisation).
En cliquant sur « ENREGISTRER LES TEMPS », les heures seront enregistrées en utilisant l'appel AJAX dans le fichier Javascript pour transmettre les heures à Flask, avec Flask connecté à MongoDB. Une fois les temps enregistrés, en cliquant sur « AFFICHER LES TEMPS », les temps apparaîtront sous les chronomètres.
Les données seront également sauvegardées sans événement ou manche spécifié (ces champs seront vides lorsque les temps seront consultés). Cela pourrait être utile si un entraîneur souhaitait utiliser les chronomètres à l’entraînement et non dans le cadre d’une compétition.
J'aimerais pouvoir donner aux entraîneurs la possibilité de télécharger les données au format PDF ou dans un autre format de fichier. À long terme, cela leur permettrait de conserver tous les chronométrages manuels pour leurs records sans avoir à s'appuyer sur des données manuscrites ou à s'appuyer sur ce site chaque fois qu'ils souhaitent revenir en arrière et consulter d'anciennes compétitions.
J'aimerais également permettre à l'entraîneur de sélectionner le nombre de chronomètres qu'il souhaite visualiser en fonction du nombre d'athlètes dans chaque manche. Actuellement, vous ne pouvez chronométrer que 3 athlètes à la fois, et vous ne pouvez pas choisir de chronométrer moins de 3.
J'aimerais également mettre en œuvre un « mode entraînement » et un « mode rencontre » qui permettraient un timing plus sophistiqué pour les rencontres et les entraînements. Le mode Meet créerait plus de restrictions sur le choix d'un événement ou d'une manche, et permettrait à l'entraîneur de choisir le nombre de couloirs pour lesquels il souhaite chronométrer. Le mode entraînement permettrait à l'entraîneur de prendre des notes sur les temps qu'il économise (pour un exercice spécifique, etc.), sans avoir à spécifier un événement ou une manche.
Tous les tests pour ce projet ont été effectués manuellement. Le formulaire sur la page de destination nécessite des attributs sur les balises d'entrée pour empêcher l'utilisateur de ne pas remplir un champ du formulaire, car cela entraînerait une erreur 400, car l'itinéraire de l'application Flask dépend de ces entrées.
La fonction Ajax et le bouton Save Times ont été testés via la console et vérifié que les données apparaissaient correctement formatées dans MongoDB. Les données collectées à partir des minuteries et la structure de données prévue ont également été testées.
Gain de temps individuel avec un document par piste :
Horaires des voies affichées dans le même document (remarque : à des fins de tests, seules deux voies ont été enregistrées ici pour garantir que deux d'entre elles apparaîtraient dans le même document.) :
Structure de données correcte :
Les tests des chronomètres ont également été effectués manuellement pour s'assurer que le bouton de réinitialisation principal réinitialisait le chronomètre et effaçait les temps intermédiaires de tous les chronomètres, tandis que chaque chronomètre individuel n'effaçait que son propre temps et ses temps intermédiaires. En outre, cela a également été testé pour la fonction marche/arrêt, car le chronomètre principal contrôle tous les chronomètres, tandis que les chronomètres individuels ne doivent contrôler que leurs propres fonctions marche/arrêt.
Tous les chemins Flask ont également été testés pour s'assurer que tous les liens fonctionnaient et qu'il pouvait gérer toutes les valeurs inhabituelles dans l'entrée, et qu'il afficherait correctement les entrées via Jinja dans le fichier HTML.
Au cours du processus de test, j'ai réalisé qu'il serait possible pour deux utilisateurs d'avoir le même nom de compétition ou le même nom de club, permettant ainsi à l'utilisateur d'accéder aux données de quelqu'un d'autre. Ainsi, pour afficher les heures dans le modèle, j'ai inclus les éléments suivants pour m'assurer que trois champs de saisie sur la page de destination doivent correspondre afin d'afficher les heures correspondantes. Cela nécessite que le nom de l'équipe, le nom d'utilisateur et le nom de la rencontre soient corrects pour éviter la sauvegarde ou la visualisation croisée des temps.
{% if time.team == team %}
{% if time.username == username %}
{% if time.meet == meets %}
Les répartitions pour chaque voie apparaissaient à l'origine dans le format suivant :
split: ["00:02.2300:01.45"]
Cependant, je voulais qu'ils apparaissent dans une liste comme celle-ci :
split: ["00:02.23", "00:01.45"]
J'ai donc dû implémenter une compréhension de liste pour séparer cette chaîne en plusieurs chaînes dans une liste (si plus d'une division était prise pour une voie) tous les 9 caractères.
Dans le HTML timer_page.html, le formulaire qui envoie des données pour la fonction AJAX semble avoir une balise de fin parasite, mais il est nécessaire d'englober toutes les données de temps final, de fractionnement et de voie afin de sauvegarder les temps dans MongoDB. . En raison du style et d'autres éléments devant être affichés, il semble que le formulaire ne soit pas en ordre avec les autres éléments. De plus, en regardant le HTML, il y a des balises vides, cependant, c'est là que les temps intermédiaires sont insérés dans le HTML à l'aide de jQuery.
Lors de la sauvegarde des temps, si vous choisissez le même couloir pour chaque chronomètre (piste 1 par exemple), une seule des fois du couloir 1 apparaîtra dans la visualisation des temps. Mais vous devez choisir une voie, car vous ne pouvez pas visualiser les temps que vous avez enregistrés sans elle en raison de la nature de la structure des données. La liste déroulante des voies est configurée pour enregistrer par défaut les voies 1, 2 et 3 au cas où l'utilisateur ne spécifie pas de voie. J'espère mettre en œuvre une validation qui empêchera l'enregistrement des temps si l'utilisateur choisit le même numéro de couloir pour deux couloirs dans une manche.
Les fonctions Javascript exécutant le chronomètre sont modifiées à partir du didacticiel Coding with Sara pour cette application. Une partie du HTML a également été calquée sur son exemple, mais modifiée pour s'adapter au style, à plusieurs boutons, divisions et voies.
Pour le JavaScript, les fonctions de réinitialisation ont été modifiées pour que le bouton de réinitialisation réinitialise tous les chronomètres au lieu d'actualiser la page, et les boutons de réinitialisation individuels pour chaque petit chronomètre ont été supprimés car il s'agissait d'une fonctionnalité inutile pour l'UX de ce projet. Des fonctions de partage ont également été ajoutées. Les fonctions Start/Stop ont été modifiées pour un changement de style des boutons à l'aide de jQuery. Un chronomètre principal a été ajouté pour l'UX afin que l'entraîneur puisse voir le temps total écoulé ainsi que les temps individuels, à la manière d'un tableau d'affichage de natation. Le bouton Enregistrer pour transmettre les valeurs à Flask et à MongoDB a été ajouté à l'aide d'Ajax.
La fonction Ajax a été calquée sur cet article de Stack Overflow et modifiée pour s'adapter à ce projet en examinant les modèles d'autres utilisations et syntaxes d'Ajax. Un PreventDefault a été ajouté pour empêcher le rechargement de la page lorsque l'appel AJAX est effectué.
La récursivité dans Jinja a été utilisée pour parcourir les dictionnaires imbriqués en Python afin de restituer correctement les heures et de répondre aux données en garantissant que toutes les voies étaient parcourues et affichées en boucle. Cette méthode de Stack Overflow a été suivie à titre indicatif et modifiée en fonction de la nature de ma structure de données.
La fonction javascript pour les chronomètres a été tentée d'être remaniée afin que l'utilisateur puisse décider du nombre de chronomètres qu'il souhaite afficher à l'écran en fonction du nombre de voies choisies.
var stopwatches = [ ] ;
var i ;
for ( i = 0 ; i <= 1 ; i ++ ) {
var stopwatch = new timing ( "timerLabel" + i , "start" + i , "splitLabel" + i ) ;
stopwatches . push ( stopwatch ) ;
console . log ( i ) ;
document . getElementById ( "start" + i ) . onclick = function ( ) {
stopwatches [ i ] . start ( ) ;
}
document . getElementById ( "reset" + i ) . onclick = function ( ) {
stopwatches [ i ] . reset ( ) ;
}
document . getElementById ( "split" + i ) . onclick = function ( ) {
stopwatches [ i ] . split ( ) ;
}
console . log ( stopwatches ) ;
}
En essayant de les écrire dans une boucle for comme celle-ci, les chronomètres[i].start() ne liraient pas i
comme une variable susceptible de changer. Cependant, lorsqu'elle était codée en dur, il n'y avait aucun problème :
document . getElementById ( "reset" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . reset ( ) ;
}
document . getElementById ( "split" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . split ( ) ;
}
J'ai essayé de l'aborder d'une manière différente, ce qui impliquait des instructions if pour faire apparaître les chronomètres correspondants.
J'ai tenté de transmettre le i
via une fonction à la place en tant qu'argument tiré de la boucle for ci-dessus, mais sans succès :
function chooseNumberOfStopwatches ( i ) {
if ( i == 1 ) {
stopwatches_one . start ( ) ;
}
else if ( i == 2 ) {
stopwatches_one . start ( ) ;
stopwatches_two . start ( ) ;
} else {
console . log ( 'else' ) ;
}
}
Si vous souhaitez cloner ce référentiel, pour configurer et installer tout ce qui se trouve dans le fichier requirejs.txt, exécutez la commande suivante dans le terminal :
$ sudo pip3 -r install requirements.txt
Veuillez noter que j'ai utilisé Cloud9 pour ce projet, donc si vous utilisez un autre éditeur, les commandes du terminal peuvent différer. Veuillez consulter la documentation de l'éditeur que vous utilisez pour plus d'informations sur les commandes de terminal spécifiques à l'éditeur. Toutes les clés secrètes de MongoDB devront être obtenues individuellement, car elles me sont cachées et spécifiques.