Proyecto Stream Three: Desarrollo centrado en datos - Code Institute.
Este proyecto se construyó utilizando Flask Microframework y podría usarse como un cronómetro manual para cronometrar a varios atletas en natación y atletismo. El objetivo de esta aplicación es mejorar la eficiencia en el cronometraje deportivo al disminuir el número de personas que cronometran por separado y almacenar los tiempos directamente, en lugar de mantener una documentación escrita.
ESTA APLICACIÓN ES SÓLO PARA USO EDUCATIVO. ESTA APLICACIÓN NO ES PARA USO COMERCIAL.
Puede encontrar una demostración en vivo de este proyecto aquí. Esta aplicación está alojada en Heroku. Los tiempos se almacenan en MongoDB.
La idea de esta aplicación Timing Assistant surgió de mi exposición a la natación durante mi infancia. Me di cuenta de que era necesario que hubiera varias personas involucradas en el proceso de cronometraje, ya que los paneles táctiles del grupo no siempre producen tiempos precisos o legibles debido a varias razones. Además, el entrenador y los atletas no pueden ver los tiempos finales ni las divisiones hasta que termine la competencia, a menos que haya varias personas en cubierta para cada carril anotando los tiempos en un portapapeles.
Vi esta oportunidad de crear una aplicación que reduciría la cantidad de personas involucradas en el proceso de cronometraje, con la esperanza de mejorar la eficiencia de las competencias y la retroalimentación a los atletas y entrenadores. Esta aplicación podría optimizarse para cualquier deporte cronometrado y esta versión funciona tanto con natación como con pista.
Tanto los entrenadores como los cronometradores pueden elegir un deporte, competencia, evento, serie y números de carril, lo que les ayuda a realizar un seguimiento de lo que sucede en una competencia. También les permite brindarles a sus atletas retroalimentación instantánea después de una carrera, ya que los tiempos aparecen después de que los hayas guardado y luego presiones "ver tiempos". También quería asegurarme de que pudieran ver los resultados acumulativos de la competencia, en lugar de solo un evento a la vez.
No se utilizó ningún tema para este diseño, se eligió el diseño moderno porque con muchos temporizadores y datos en una página, puede parecer desordenada y desorganizada. No quería esto, así que aunque quería los temporizadores, las horas y las opciones de eventos en una página, pensé que dividir la página en tercios verticalmente sería la mejor manera de hacerlo, creando una diferencia notable entre cada tercio.
Timing Assistant se creó utilizando Flask Microframework en Python con una base de datos NoSQL (MongoDB) en el backend, con HTML, CSS, Javascript y jQuery en el frontend y para la funcionalidad de cronómetro, conectado al backend con AJAX.
En la página de inicio de la aplicación, el usuario ingresa el deporte que desea cronometrar, el nombre de su equipo, su nombre de usuario y el nombre de la competencia. Esta acción los lleva a la página del cronómetro, donde luego pueden elegir el evento y la serie que les gustaría cronometrar. El usuario puede cronometrar hasta tres carriles y dividirse en los tres carriles. El usuario tendrá que detener el temporizador principal manualmente después de detener los tres temporizadores pequeños, ya que se configuran individualmente. Sin embargo, esto podría ser particularmente útil si el entrenador quisiera saber cuánto duró la carrera y comparar los tiempos de sus nadadores con los del finalista. El tiempo del cronómetro principal no se guardará en la base de datos.
Una vez que hagan clic en "enviar", aparecerán el evento y la eliminatoria. Luego pueden comenzar a cronometrar hasta tres carriles presionando 'INICIAR' en el cronómetro principal. Esto iniciará los cuatro cronómetros; sin embargo, solo los tres últimos se guardarán en la base de datos. Existe la opción de recopilar tiempos parciales para cada carril individualmente con el botón 'DIVIDIR'. Cada temporizador se puede detener e iniciar individualmente, y el temporizador principal controla todos los cronómetros (iniciar, detener y restablecer).
Al hacer clic en 'GUARDAR TIEMPOS', los tiempos se guardarán utilizando la llamada AJAX en el archivo Javascript para enviar los tiempos a Flask, con Flask conectado a MongoDB. Una vez guardados los tiempos, al hacer clic en 'VER TIEMPOS', los tiempos aparecerán debajo de los cronómetros.
Los datos también se guardarán sin un evento o serie especificada (estos campos estarán en blanco cuando se vean los tiempos). Esto podría ser útil si un entrenador quisiera usar los cronómetros en la práctica y no en un encuentro.
Me gustaría poder darles a los entrenadores la oportunidad de descargar los datos en formato PDF u otro formato de archivo. A largo plazo, les permitiría mantener todo el cronometraje manual para sus registros sin tener que depender de datos escritos a mano o de este sitio cada vez que quieran volver y ver competiciones antiguas.
También me gustaría permitir que el entrenador seleccione la cantidad de cronómetros que desea ver en función de la cantidad de atletas en cada serie. Actualmente, solo puedes cronometrar a 3 atletas a la vez y no puedes elegir cronometrar a menos de 3.
También me gustaría implementar un 'modo de práctica' y un 'modo de encuentro' que permitirían una sincronización más sofisticada para los encuentros y las prácticas. El modo Meet crearía más restricciones a la hora de elegir un evento o una serie y permitiría al entrenador elegir en cuántos carriles le gustaría cronometrar. El modo de práctica permitiría al entrenador tomar notas sobre los tiempos que está guardando (para un ejercicio específico, etc.), sin tener que especificar un evento o una serie.
Todas las pruebas para este proyecto se realizaron manualmente. El formulario en la página de destino tiene atributos obligatorios en las etiquetas de entrada para evitar que el usuario no complete un campo en el formulario, ya que esto resultará en un error 400, ya que la ruta de la aplicación Flask depende de estas entradas.
Se probó la función Ajax y el botón Save Times a través de la consola y verificando que los datos habían aparecido correctamente formateados en MongoDB. También se probaron los datos recopilados de los temporizadores y la estructura de datos prevista.
Ahorro de tiempos individualmente con un documento por carril:

Tiempos para los carriles que se muestran en el mismo documento (nota: para fines de prueba, aquí solo se guardaron dos carriles para garantizar que dos de ellos aparecieran en el mismo documento):

Estructura de datos correcta:

Las pruebas de los cronómetros también se realizaron manualmente para garantizar que el botón de reinicio principal reiniciara el cronómetro y borrara las divisiones de todos los cronómetros, mientras que cada cronómetro individual solo borrara su propio tiempo y divisiones. Además, esto también se probó para la función de inicio/parada, ya que el cronómetro principal controla todos los cronómetros, mientras que los individuales solo deben controlar sus propias funciones de inicio/parada.
También se probaron todas las rutas de Flask para garantizar que todos los enlaces funcionaran y que pudieran manejar cualquier valor poco común en la entrada, y que mostrara las entradas correctamente a través de Jinja en el archivo HTML.
Durante el proceso de prueba, me di cuenta de que sería posible que dos usuarios tuvieran el mismo nombre de reunión o el mismo nombre de club, por lo que era posible que el usuario se encontrara con los datos de otra persona. Entonces, para ver los tiempos en la plantilla, he incluido lo siguiente para asegurarme de que tres campos de entrada en la página de destino deben coincidir para mostrar los tiempos correspondientes. Esto requiere que el nombre del equipo, el nombre de usuario y el nombre de la reunión correctos coincidan para evitar que se guarden o se visualicen los tiempos.
{% if time.team == team %}
{% if time.username == username %}
{% if time.meet == meets %}
Las divisiones para cada carril aparecían originalmente en el siguiente formato:
split: ["00:02.2300:01.45"]
Sin embargo, quería que aparecieran en una lista como esta:
split: ["00:02.23", "00:01.45"]
Entonces tuve que implementar una lista por comprensión para separar esta cadena en varias cadenas en una lista (si se tomó más de una división para un carril) cada 9 caracteres.
En HTML timer_page.html, el formulario que envía datos para la función AJAX parece tener una etiqueta final perdida, pero es necesario abarcar todos los tiempos finales, datos de división y carriles para guardar los tiempos en MongoDB. . Debido al estilo y a otros elementos que deben mostrarse, parece que el formulario no está en orden con los otros elementos. Además, al mirar el HTML hay etiquetas vacías; sin embargo, aquí es donde los tiempos parciales se insertan en el HTML usando jQuery.
Al guardar los tiempos, si elige el mismo carril para cada cronómetro (carril 1, por ejemplo), solo uno de los tiempos del carril 1 aparecerá en la vista de tiempos. Pero debe elegir un carril, ya que no puede ver los tiempos que ha guardado sin él debido a la naturaleza de la estructura de datos. El menú desplegable de carril está configurado para guardar en el carril 1, el terreno 2 y el terreno 3 de forma predeterminada en caso de que el usuario no especifique un carril. Espero implementar una validación que prohíba que los tiempos se guarden si el usuario elige el mismo número de carril para dos carriles en una serie.
Las funciones de Javascript que ejecutan el cronómetro se modifican del tutorial de cronómetro Codificación con Sara para esta aplicación. Parte del HTML también se modeló según su ejemplo, pero se modificó para adaptarse al estilo, múltiples botones, divisiones y carriles.
Para JavaScript, se modificaron las funciones de reinicio del botón de reinicio para restablecer todos los cronómetros en lugar de actualizar la página, y se eliminaron los botones de reinicio individuales para cada cronómetro pequeño, ya que era una característica innecesaria para la UX de este proyecto. También se agregaron funciones divididas. Se modificaron las funciones Start/Stop para un cambio de estilo en los botones usando jQuery. Se agregó un cronómetro principal para UX para que el entrenador pudiera ver el tiempo total transcurrido junto con los tiempos individuales, similar a un marcador de natación. El botón Guardar para pasar valores a Flask y a MongoDB se agregó usando Ajax.
La función Ajax se modeló a partir de esta publicación de Stack Overflow y se modificó para adaptarse a este proyecto observando patrones de otros usos y sintaxis de Ajax. Se agregó preventDefault para evitar que la página se recargue cuando se realiza la llamada AJAX.
La recursividad en Jinja se utilizó para iterar sobre los diccionarios anidados en Python para representar los tiempos y cumplir con los datos correctamente, asegurando que todos los carriles se recorrieran y mostraran. Este método de Stack Overflow se siguió como guía y se modificó según la naturaleza de mi estructura de datos.
Se intentó refactorizar la función de JavaScript para los cronómetros para que el usuario pudiera decidir cuántos cronómetros quería que se mostraran en la pantalla en función del número de carriles elegidos.
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 ) ;
} Al intentar escribirlos en un bucle for como este, los cronómetros[i].start() no leían i como una variable que podía cambiar; sin embargo, cuando estaba codificado, no había ningún problema:
document . getElementById ( "reset" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . reset ( ) ;
}
document . getElementById ( "split" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . split ( ) ;
}Intenté abordarlo de una manera diferente, lo que implicaba declaraciones if para que aparecieran los cronómetros correspondientes.
Intenté pasar i a través de una función como un argumento tomado del bucle for anterior, pero no tuve éxito:
function chooseNumberOfStopwatches ( i ) {
if ( i == 1 ) {
stopwatches_one . start ( ) ;
}
else if ( i == 2 ) {
stopwatches_one . start ( ) ;
stopwatches_two . start ( ) ;
} else {
console . log ( 'else' ) ;
}
}Si está interesado en clonar este repositorio, para configurar e instalar todo en el archivo require.txt, ejecute el siguiente comando en la terminal:
$ sudo pip3 -r install requirements.txt
Tenga en cuenta que utilicé Cloud9 para este proyecto, por lo que si utiliza un editor diferente, los comandos del terminal pueden diferir. Consulte los documentos del editor que está utilizando para obtener más información sobre los comandos de terminal específicos del editor. Todas las claves secretas de MongoDB deberán obtenerse individualmente, ya que están ocultas y son específicas para mí.