Проект третьего потока: Разработка, ориентированная на данные — Институт кода.
Этот проект был создан с использованием микрофреймворка Flask, и его можно использовать в качестве ручного секундомера для измерения времени нескольких спортсменов в плавании и легкой атлетике. Целью этого приложения является повышение эффективности спортивного хронометража за счет уменьшения количества людей, фиксирующих время отдельно, и непосредственного сохранения времени, а не ведения письменной документации.
ЭТО ПРИЛОЖЕНИЕ ПРЕДНАЗНАЧЕНО ТОЛЬКО ДЛЯ ОБРАЗОВАТЕЛЬНОГО ИСПОЛЬЗОВАНИЯ. ЭТО ПРИЛОЖЕНИЕ НЕ ПРЕДНАЗНАЧЕНО ДЛЯ КОММЕРЧЕСКОГО ИСПОЛЬЗОВАНИЯ.
Живую демонстрацию этого проекта можно найти здесь. Это приложение размещено на Heroku. Время хранится в MongoDB.
Идея создания этого приложения Timing Assistant возникла у меня в детстве, когда я занимался плаванием. Я заметил, что в процессе отсчета времени должно участвовать несколько человек, поскольку сенсорные панели в пуле не всегда выдают точное или читаемое время по разным причинам. Кроме того, тренер и спортсмены не могут видеть окончательное время или разделение до тех пор, пока соревнования не закончатся, если только у вас нет нескольких человек, определяющих время на каждой дорожке и записывающих время в буфер обмена.
Я увидел в этом возможность создать приложение, которое сократило бы количество людей, участвующих в процессе определения времени, в надежде повысить эффективность соревнований и обратную связь со спортсменами и тренерами. Это приложение можно оптимизировать для любого вида спорта на время, и эта версия работает как с плаванием, так и с легкой атлетикой.
Тренеры и таймеры могут выбирать вид спорта, соревнование, событие, забег и номера дорожек, которые помогают им отслеживать, что происходит на соревнованиях. Это также позволяет им мгновенно оставлять отзывы своим спортсменам после гонки, поскольку время отображается после того, как вы их сохранили, а затем нажали «Просмотреть время». Я также хотел убедиться, что они смогут видеть совокупные результаты соревнований, а не только одно событие за раз.
Для этого дизайна не использовалась никакая тема, был выбран современный дизайн, потому что при большом количестве таймеров и данных на странице она может выглядеть беспорядочной и неорганизованной. Я этого не хотел, поэтому, хотя мне хотелось, чтобы таймеры, время и параметры событий были на одной странице, я подумал, что лучшим способом сделать это будет разделение страницы на трети по вертикали, создавая заметную разницу между каждой третью.
Помощник по времени был создан с использованием микрофреймворка Flask на Python с базой данных NoSQL (MongoDB) на внутреннем интерфейсе, с HTML, CSS, Javascript и jQuery на внешнем интерфейсе, а также для функций секундомера, подключенных к серверной части с помощью AJAX.
На главной странице приложения пользователь вводит вид спорта, для которого он хочет зарезервировать время, название своей команды, свое имя пользователя и название соревнования. Это действие приведет их на страницу секундомера, где они смогут выбрать событие и забег, на который они хотят засечь время. Пользователь может засечь время до трех полос и разделить движение на все три полосы. Пользователю придется вручную остановить основной таймер после остановки всех трех малых таймеров, поскольку они настраиваются индивидуально. Однако это может быть особенно полезно, если тренер хочет узнать, как долго длилась гонка, и сравнить время своих пловцов со временем финишера. Время основного таймера не сохраняется в базе данных.
Как только они нажмут «отправить», появятся событие и забег. Затем они могут начать отсчет времени для трех полос движения, нажав кнопку «СТАРТ» на главном секундомере. При этом запустятся все четыре секундомера, однако в базе данных сохранятся только три нижних. Существует возможность собирать данные о промежуточном времени для каждой полосы индивидуально с помощью кнопки «SPLIT». Каждый таймер можно останавливать и запускать индивидуально, при этом основной таймер управляет всеми секундомерами (запуском, остановкой и сбросом).
Нажав кнопку «СОХРАНИТЬ ВРЕМЯ», время будет сохранено с помощью вызова AJAX в файле Javascript, чтобы передать время в Flask, при этом Flask будет подключен к MongoDB. После сохранения времени нажмите «ПРОСМОТР ВРЕМЕНИ», и оно появится под секундомерами.
Данные также будут сохранены без указания события или забега (эти поля будут пустыми при просмотре времени). Это может быть полезно, если тренер захочет использовать секундомеры на практике, а не на соревнованиях.
Я хотел бы предоставить тренерам возможность загружать данные в формате PDF или другом формате. В долгосрочной перспективе это позволит им вести все свои записи вручную, не полагаясь на рукописные данные или на этот сайт каждый раз, когда они захотят вернуться и посмотреть на старые встречи.
Я также хотел бы позволить тренеру выбирать количество секундомеров, которые он хочет просматривать, в зависимости от количества спортсменов в каждом забеге. В настоящее время вы можете одновременно фиксировать время только для 3 спортсменов, и вы не можете выбрать хронометраж для менее чем 3 спортсменов.
Я также хотел бы реализовать «режим тренировок» и «режим встреч», которые позволили бы более точно рассчитывать время для встреч и тренировок. Режим Meet создаст больше ограничений на выбор соревнования или забега и позволит тренеру выбирать, на сколько дорожек он хочет выделить время. Режим тренировки позволит тренеру делать заметки о времени, которое он сохраняет (для конкретного упражнения и т. д.), без необходимости указывать событие или забег.
Все тестирование этого проекта проводилось вручную. Форма на целевой странице имеет обязательные атрибуты в тегах ввода, чтобы пользователь не мог не заполнить поле в форме, поскольку это приведет к ошибке 400, поскольку маршрут приложения Flask зависит от этих входных данных.
Функция Ajax и кнопка «Сохранить время» были протестированы через консоль и проверялось, что данные отображаются в правильном формате в MongoDB. Также были протестированы данные, собранные с таймеров, и предполагаемая структура данных.
Экономия времени индивидуально с одним документом на полосу:
Время отображения дорожек в одном документе (примечание: в целях тестирования здесь были сохранены только две полосы, чтобы гарантировать, что две полосы будут отображаться в одном документе):
Правильная структура данных:
Тестирование секундомеров также проводилось вручную, чтобы убедиться, что основная кнопка сброса сбрасывает секундомер и очищает все таймеры, в то время как каждый отдельный секундомер очищает только свое собственное время и разделение. Кроме того, это также было протестировано для функции запуска/остановки, поскольку основной секундомер управляет всеми секундомерами, в то время как отдельные из них должны управлять только своими собственными функциями запуска/остановки.
Все пути Flask также были протестированы, чтобы убедиться, что все ссылки работают и что он может обрабатывать любые необычные значения во входных данных, а также правильно отображать входные данные через Jinja в HTML-файле.
В процессе тестирования я понял, что два пользователя могут иметь одно и то же имя соревнования или одно и то же название клуба, что позволит пользователю столкнуться с чужими данными. Итак, чтобы просмотреть время в шаблоне, я включил следующее, чтобы убедиться, что три поля ввода на целевой странице должны совпадать, чтобы отображать соответствующие значения времени. Для этого необходимо, чтобы правильное название команды, имя пользователя и название соревнования совпадали, чтобы предотвратить перекрестное сохранение или перекрестный просмотр времени.
{% if time.team == team %}
{% if time.username == username %}
{% if time.meet == meets %}
Разделения для каждой полосы изначально отображались в следующем формате:
split: ["00:02.2300:01.45"]
Однако я хотел, чтобы они отображались в следующем списке:
split: ["00:02.23", "00:01.45"]
Поэтому мне пришлось реализовать понимание списка, чтобы разделить эту строку на несколько строк в списке (если для полосы было выполнено более одного разделения) каждые 9 символов.
В HTML-файле timer_page.html форма, отправляющая данные для функции AJAX, выглядит так, как будто у нее есть случайный закрывающий тег, но необходимо охватить все данные о конечном времени, разделении и полосе, чтобы сохранить время в MongoDB. . Из-за необходимости отображения стилей и других элементов создается впечатление, что форма не соответствует другим элементам. Кроме того, если посмотреть на HTML, есть пустые теги, однако именно здесь время разделения вставляется в HTML с помощью jQuery.
Если при сохранении времени вы выберете одну и ту же полосу для каждого таймера (например, дорожка 1), во времени просмотра будет отображаться только одно из времен дорожки 1. Но вам придется выбрать полосу, так как вы не сможете просмотреть сэкономленное время без нее из-за особенностей структуры данных. В раскрывающемся списке полос по умолчанию сохраняется полоса 1, площадка 2 и площадка 3, если пользователь не указывает полосу движения. Я надеюсь реализовать проверку, которая запретит сохранение времени, если пользователь выберет один и тот же номер полосы для двух полос во время забега.
Функции Javascript, запускающие секундомер, взяты из руководства Сары по кодированию секундомера для этого приложения. Некоторый HTML-код также был смоделирован по ее примеру, но изменен, чтобы соответствовать стилю, множеству кнопок, разделениям и полосам.
Для JavaScript были изменены функции сброса: кнопка сброса позволяла сбрасывать все секундомеры вместо обновления страницы, а отдельные кнопки сброса для каждого маленького секундомера были удалены, поскольку это была ненужная функция для пользовательского интерфейса этого проекта. Также были добавлены функции разделения. Функции Start/Stop были изменены для изменения стиля кнопок с помощью jQuery. Для удобства работы был добавлен основной секундомер, чтобы тренер мог видеть общее прошедшее время, а также индивидуальное время, аналогично табло по плаванию. Кнопка «Сохранить» для передачи значений в Flask и MongoDB была добавлена с помощью Ajax.
Функция Ajax была смоделирована по образцу этой публикации из Stack Overflow и изменена в соответствии с этим проектом с учетом шаблонов и синтаксиса других вариантов использования Ajax. Был добавлен параметр PreventDefault, чтобы предотвратить перезагрузку страницы при выполнении вызова AJAX.
Рекурсия в Jinja использовалась для перебора вложенных словарей в Python для правильного отображения времени и соответствия данным, обеспечивая циклическое прохождение и отображение всех полос. Этот метод из Stack Overflow использовался в качестве руководства и был изменен с учетом особенностей моей структуры данных.
Функцию Javascript для секундомеров попытались реорганизовать, чтобы пользователь мог решить, сколько секундомеров он хочет отображать на экране, в зависимости от количества выбранных полос движения.
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 ) ;
}
При попытке записать их в цикл for, подобный этому, секундомеры[i].start() не считывали i
как переменную, которая могла измениться, однако, когда она была жестко запрограммирована, проблем не возникало:
document . getElementById ( "reset" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . reset ( ) ;
}
document . getElementById ( "split" + i ) . onclick = function ( ) {
stopwatches [ 0 ] . split ( ) ;
}
Я попытался подойти к этому по-другому: операторы if вызывали появление соответствующих секундомеров.
Попытка передать i
через функцию вместо аргумента, взятого из приведенного выше цикла for, но безуспешно:
function chooseNumberOfStopwatches ( i ) {
if ( i == 1 ) {
stopwatches_one . start ( ) ;
}
else if ( i == 2 ) {
stopwatches_one . start ( ) ;
stopwatches_two . start ( ) ;
} else {
console . log ( 'else' ) ;
}
}
Если вы заинтересованы в клонировании этого репозитория, чтобы настроить и установить все, что есть в файле require.txt, выполните в терминале следующую команду:
$ sudo pip3 -r install requirements.txt
Обратите внимание, что для этого проекта я использовал Cloud9, поэтому, если вы используете другой редактор, команды терминала могут отличаться. Пожалуйста, обратитесь к документации редактора, который вы используете, для получения дополнительной информации о командах терминала, специфичных для редактора. Все секретные ключи для MongoDB нужно будет получать индивидуально, так как они скрыты и специфичны для меня.