Интерактивная таблица результатов

Глядя на таблицу результатов футбольного сезона, я часто задаюсь вопросами:

  • Лидировала ли команда с начала сезона или совершила героический рывок в конце?
  • Как зимнее трансферное окно повлияло на результаты?
  • Доигрывали ли сезон команды в середине таблицы или играли в полную силу?

Статичная таблица не даёт ответов.

Поиски удачной визуализации сезона на просторах интернета закончились безуспешно, поэтому я начал экспериментировать сам.

Графики или быстро теряли читаемость с ростом количеством команд, или требовали нетривиальной концентрации при первом контакте. В итоге, всё закончилось тем, с чего началось — таблицей. Точнее, скриптом, который преобразовывает результаты сезона в интерактивную таблицу. Можно посмотреть результаты после любого тура или просто нажать на replay и наблюдать, как команды плавают вверх и вниз по таблице:

image

Живая демонстрация

Входные данные


Найти результаты любого хоть сколь-нибудь популярного чемпионата не проблема, спасибо огромной букмекерской индустрии. Для демонстрации я возьму результаты матчей английской Премьер-лиги на Football Data:
Date Home Team Score Away Team Score
August 8, 2015 Bournemouth 0 Aston Villa 1
August 8, 2015 Chelsea 2 Swansea 2
August 8, 2015 Everton 2 Watford 2
... ... ... ... ...

Скрипт парсит csv-файл, преобразовывает данные в удобные для представления javascript-объекты и добавляет дополнительную информацию —например, количество побед, ничей и поражений после каждого тура.

Использование


  1. Подключаем стили в head:

    <link rel="stylesheet" type="text/css" href="cdn.jsdelivr.net/replay-table/latest/replay-table.css">

  2. Добавляем скрипт в конец body:

    <script type="text/javascript" src="//cdn.jsdelivr.net/replay-table/latest/replay-table.min.js"></script>

  3. Помещаем на страницу div с классом replayTable и ссылкой на csv-файл в атрибуте data-csv:

    <div class="replayTable" data-csv="https://s3-us-west-2.amazonaws.com/replay-table/csv/football/england/premier-league/2015-2016.csv" data-table-name="Premier League" data-input-type="listOfMatches" data-item-name="Team" data-use-rounds-numbers="true" </div>

Готово:

image

Настройка


Внимательный читатель уже заметил data- атрибуты. С их помощью таблица адаптируется под разные виды спорта, локализируется и меняет внешний вид. Подробная документация есть на Гитхабе.

Я постарался сделать так, чтобы скрипт без доработки можно было использовать для как можно большего числа видов спорта. На сайте таблиц есть примеры вместе с исходным кодом:


Лицензия


Используйте таблицы на любых сайтах, в том числе коммерческих.

Код на Гитхабе.

Спасибо Даше за красоту.

Обновление. Скрипт вырос в полноценную библиотеку.
Поделиться публикацией
Похожие публикации
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама
Комментарии 25
  • +8
    Мне нравится очень информативная графика изменения позиций пилотов на протяжении гонки в той же F1. Легко проследить динамику конкретного пилота.

    • 0
      Тут важный нюанс, что у гонщика есть стартовая позиция, да и в ходе гонки она определяется физическим положением болида. В футбольном чемпионате физических ограничений нет, в начальной стадии точно будет беспрерывная чехарда.
      • 0
        Чехарды в начале меньше, если расставить команды по результатам прошлого сезона. Но всё равно «обгонов» будет в разы больше, чем в любой формульной гонке.
        • 0
          Можно сделать побольше горизонтальный масштаб (расстояние между турами) и читаемость значительно повысится.
          Да и брать за отсечку не обязательно начало чемпионата. Расставить можно сразу по результатам 1-го тура, там даже будет правильнее.
      • 0
        Идея хорошая, но я запомнил положение участников, потом они «сбрасываются» вниз и… я не помню кто куда переместился. Сделать бы изменения только тех позиций, которые реально менялись.
        • 0
          Не совсем понял. Можете привести пример или прикрепить гифку, пожалуйста?
          Сортировка в таблицах устойчивая, команды перемещаются только при изменении позиции.
        • 0
          Отлично. Недавно понадобилось сделать такую же анимацию, нашелся только старенький jquery-плагин.
          Единственное пожелание: добавьте файл лицензии (MIT или другую), чтобы можно было спокойно использовать в коммерческих проектах.
        • 0
          Идея хорошая. На мой взгляд, интерактивность должна подразумевать большую вовлеченность пользователя в процесс взаимодействия. Еще было бы интересно, если бы таблица позволяла делать прогноз на следующий тур.
          • 0
            Полезная штука.
            Хорошо бы добавить опцию, чтобы подсветка не исчезала, а оставалась бы до обновления таблицы или принудительного сброса на стартовое значение. Так легче отслеживать динамику.
            • 0
              Такие таблицы очень легко делаются с помощью d3.js, если вдруг кому понадобится.
              • 0
                Вполне вероятно, что и я перепишу анимацию на d3.js вместо React Flip Move.
              • 0
                Добавите статистику по динамике кэфов от букмекеров для каждой из команд(в чемпионате) и будет Супер. Видеть надёжность команд в отрабатывании ожиданий, это ценно.
                • 0
                  Движения для всех команд тяжело для восприятия. Лучше показать движение одной команды.
                  • 0
                    Можно сфокусироваться на одной или нескольких командах через параметр data-focused-items.
                  • +1
                    Получается довольно любопытный виджет, спасибо. Благодатная тема для исследования и совершенствования, поскольку в каждом чемпионате свои нюансы при равенстве очков. Вижу естественным развитием вынесение конфигурации чемпионата в файл с данными. Причём, в формате JSON, а не CSV, всё-таки.

                    В самой анимации смущает изменение номера места до перемещения. Может, лучше разбить на три этапа? Начисление очков, сортировка, обновление номера.
                    • 0
                      Всё так. Скорее всего, для начала добавлю параметр data-tie-breaking с заготовками для дополнительных показателей количество побед, забитые голы и т.п. Если будет не хватать, добавлю опцию конфигурационного JSON-файла.

                      Я пробовал сделать обновление в несколько этапов — интуитивно казалось, что так хуже.
                    • 0
                      Неплохо было бы разделать css на тот что относится именно к таблице и общий, относящийся к странице. Потому что если подключить все по инструкции в существующий сайт будет конфликт определения заголовков h2 и некоторых других общеупотребимых тегов.
                      Так же идет ссылка на локально расположенные шрифты, про которых в инструкции ничего нет, что выдает ошибку валидатора.
                      • 0
                        Это очень хорошие замечания, спасибо.

                        Мы сделали ошибку, не разделив скрипт и демонстрационный сайт, из-за чего вылезли проблемы с CSS и шрифтами. Сайт в новогоднюю ночь сел на Jekyll и переехал в отдельный репозиторий: https://github.com/TargetProcess/replayTable.com. В ближайшее время вычистим лишнее из файлов самого скрипта — и всё станет хорошо.
                      • 0
                        Такая задача как раз для OLAP кубов… Вот либа есть для отображения на js
                        • 0
                          сформировал вот такой файлик исходных данных — чо-то не работает.
                          2 Дивизион Центр
                          Date,HomeTeam,FTHG,AwayTeam,FTAG
                          20.07.2016, Арсенал-2,0, Зенит Пз,0
                          20.07.2016, Торпедо М,2, Чертаново,1
                          20.07.2016, Авангард К,2, Энергомаш,0
                          20.07.2016, Сатурн,1, Металлург Лп,1
                          20.07.2016, Орёл,1, Калуга,0
                          20.07.2016, Витязь,1, Рязань,0
                          28.07.2016, Торпедо М,2, Витязь,1
                          28.07.2016, Зенит Пз,0, Орёл,0
                          28.07.2016, Металлург Лп,2, Рязань,2
                          28.07.2016, Сатурн,1, Авангард К,1
                          28.07.2016, Энергомаш,1, Динамо Бр,0
                          29.07.2016, Калуга,2, Чертаново,0
                          04.08.2016, Арсенал-2,0, Энергомаш,6
                          04.08.2016, Чертаново,1, Зенит Пз,1
                          04.08.2016, Авангард К,1, Металлург Лп,0
                          04.08.2016, Динамо Бр,0, Сатурн,1
                          04.08.2016, Рязань,2, Торпедо М,1
                          04.08.2016, Витязь,1, Калуга,0
                          11.08.2016, Зенит Пз,0, Витязь,5
                          11.08.2016, Металлург Лп,0, Торпедо М,2
                          11.08.2016, Авангард К,1, Динамо Бр,0
                          11.08.2016, Сатурн,1, Арсенал-2,1
                          11.08.2016, Энергомаш,4, Орёл,0
                          12.08.2016, Калуга,1, Рязань,0
                          18.08.2016, Арсенал-2,1, Авангард К,2
                          18.08.2016, Орёл,1, Сатурн,0
                          18.08.2016, Чертаново,1, Энергомаш,4
                          18.08.2016, Торпедо М,1, Калуга,1
                          18.08.2016, Динамо Бр,1, Металлург Лп,0
                          18.08.2016, Рязань,2, Зенит Пз,0
                          25.08.2016, Авангард К,0, Орёл,0
                          25.08.2016, Динамо Бр,5, Арсенал-2,0
                          25.08.2016, Сатурн,1, Чертаново,2
                          28.08.2016, Металлург Лп,1, Калуга,0
                          28.08.2016, Зенит Пз,1, Торпедо М,1
                          28.08.2016, Энергомаш,2, Витязь,0
                          02.09.2016, Чертаново,0, Авангард К,1
                          02.09.2016, Арсенал-2,1, Металлург Лп,3
                          02.09.2016, Орёл,0, Динамо Бр,1
                          02.09.2016, Рязань,1, Энергомаш,3
                          02.09.2016, Витязь,2, Сатурн,1
                          03.09.2016, Калуга,2, Зенит Пз,2
                          09.09.2016, Арсенал-2,2, Орёл,2
                          10.09.2016, Энергомаш,0, Торпедо М,0
                          10.09.2016, Сатурн,1, Рязань,0
                          10.09.2016, Динамо Бр,0, Чертаново,2
                          10.09.2016, Металлург Лп,2, Зенит Пз,4
                          11.09.2016, Авангард К,3, Витязь,0
                          16.09.2016, Чертаново,0, Арсенал-2,1
                          17.09.2016, Калуга,1, Энергомаш,1
                          17.09.2016, Орёл,0, Металлург Лп,1
                          17.09.2016, Витязь,1, Динамо Бр,0
                          17.09.2016, Рязань,1, Авангард К,1
                          18.09.2016, Торпедо М,1, Сатурн,2
                          25.09.2016, Сатурн,1, Калуга,1
                          25.09.2016, Динамо Бр,0, Рязань,0
                          25.09.2016, Арсенал-2,1, Витязь,2
                          25.09.2016, Орёл,1, Чертаново,3
                          25.09.2016, Авангард К,0, Торпедо М,1
                          26.09.2016, Энергомаш,5, Зенит Пз,1
                          01.10.2016, Калуга,2, Авангард К,0
                          01.10.2016, Торпедо М,1, Динамо Бр,1
                          02.10.2016, Витязь,3, Орёл,2
                          02.10.2016, Зенит Пз,0, Сатурн,1
                          02.10.2016, Чертаново,1, Металлург Лп,2
                          02.10.2016, Рязань,2, Арсенал-2,1
                          09.10.2016, Арсенал-2,1, Торпедо М,2
                          09.10.2016, Чертаново,3, Витязь,3
                          09.10.2016, Динамо Бр,0, Калуга,0
                          09.10.2016, Орёл,1, Рязань,1
                          09.10.2016, Металлург Лп,0, Энергомаш,4
                          09.10.2016, Авангард К,1, Зенит Пз,0
                          15.10.2016, Калуга,1, Арсенал-2,0
                          16.10.2016, Торпедо М,1, Орёл,1
                          16.10.2016, Зенит Пз,1, Динамо Бр,3
                          16.10.2016, Металлург Лп,0, Витязь,0
                          16.10.2016, Рязань,2, Чертаново,2
                          16.10.2016, Энергомаш,0, Сатурн,1
                          23.10.2016, Чертаново,4, Калуга,0
                          23.10.2016, Динамо Бр,1, Энергомаш,0
                          23.10.2016, Авангард К,2, Сатурн,2
                          23.10.2016, Витязь,1, Торпедо М,3
                          23.10.2016, Орёл,3, Зенит Пз,1
                          23.10.2016, Рязань,1, Металлург Лп,1
                          29.10.2016, Калуга,2, Витязь,1
                          30.10.2016, Торпедо М,1, Рязань,1
                          30.10.2016, Металлург Лп,1, Авангард К,0
                          30.10.2016, Энергомаш,4, Арсенал-2,0
                          30.10.2016, Зенит Пз,3, Чертаново,0
                          30.10.2016, Сатурн,1, Динамо Бр,0
                          06.11.2016, Витязь,3, Зенит Пз,1
                          06.11.2016, Арсенал-2,1, Сатурн,3
                          06.11.2016, Динамо Бр,0, Авангард К,1
                          06.11.2016, Торпедо М,1, Металлург Лп,0
                          06.11.2016, Рязань,1, Калуга,2
                          06.11.2016, Орёл,1, Энергомаш,1
                          • 0
                            И вправду, был баг, при котором таблица не работала, если команды сыграли разное количество туров.

                            Выпустил новый релиз с фиксом и протестировал вашу таблицу: https://replaytable.com/tables/requests/2016/1ax-russian-second-division-centre.html. Кстати, локализировал её и добавил общее количество туров, чтобы прогресс-бар показывал правду — загляните в исходный код.

                            В следующем релизе поправим стили, про которые вы писали сверху.
                          • 0
                            да, заработало. но появились другие проблемы
                            добавил еще 2 игры, для полного соответствия реальности — выявилась еще одна проблема (а может 2), в исходных данных Чертаново сыграло 14 игр, а табличка генерит что 15, это идет из 4 тура, который Чертаново пропускало, таблица добавляет проигранную игру, видимо из следующего тура (кстати, проверил — такая ситуация во всех случаях пропуска тура, то есть динамика неверно отражена, в каждом туре присутствует результат из другого тура). А вот откуда берет лишнюю игру в итоге — непонятно, в разбивке В/П/Н идет верно 4/7/3=14

                            2 Дивизион Центр
                            Date,HomeTeam,FTHG,AwayTeam,FTAG
                            20.07.2016, Арсенал-2,0, Зенит Пз,0
                            20.07.2016, Торпедо М,2, Чертаново,1
                            20.07.2016, Авангард К,2, Энергомаш,0
                            20.07.2016, Сатурн,1, Металлург Лп,1
                            20.07.2016, Орёл,1, Калуга,0
                            20.07.2016, Витязь,1, Рязань,0
                            28.07.2016, Торпедо М,2, Витязь,1
                            28.07.2016, Зенит Пз,0, Орёл,0
                            28.07.2016, Металлург Лп,2, Рязань,2
                            28.07.2016, Сатурн,1, Авангард К,1
                            28.07.2016, Энергомаш,1, Динамо Бр,0
                            29.07.2016, Калуга,2, Чертаново,0
                            04.08.2016, Арсенал-2,0, Энергомаш,6
                            04.08.2016, Чертаново,1, Зенит Пз,1
                            04.08.2016, Авангард К,1, Металлург Лп,0
                            04.08.2016, Динамо Бр,0, Сатурн,1
                            04.08.2016, Рязань,2, Торпедо М,1
                            04.08.2016, Витязь,1, Калуга,0
                            11.08.2016, Зенит Пз,0, Витязь,5
                            11.08.2016, Металлург Лп,0, Торпедо М,2
                            11.08.2016, Авангард К,1, Динамо Бр,0
                            11.08.2016, Сатурн,1, Арсенал-2,1
                            11.08.2016, Энергомаш,4, Орёл,0
                            12.08.2016, Калуга,1, Рязань,0
                            18.08.2016, Арсенал-2,1, Авангард К,2
                            18.08.2016, Орёл,1, Сатурн,0
                            18.08.2016, Чертаново,1, Энергомаш,4
                            18.08.2016, Торпедо М,1, Калуга,1
                            18.08.2016, Динамо Бр,1, Металлург Лп,0
                            18.08.2016, Рязань,2, Зенит Пз,0
                            25.08.2016, Авангард К,0, Орёл,0
                            25.08.2016, Динамо Бр,5, Арсенал-2,0
                            25.08.2016, Сатурн,1, Чертаново,2
                            28.08.2016, Металлург Лп,1, Калуга,0
                            28.08.2016, Зенит Пз,1, Торпедо М,1
                            28.08.2016, Энергомаш,2, Витязь,0
                            02.09.2016, Чертаново,0, Авангард К,1
                            02.09.2016, Арсенал-2,1, Металлург Лп,3
                            02.09.2016, Орёл,0, Динамо Бр,1
                            02.09.2016, Рязань,1, Энергомаш,3
                            02.09.2016, Витязь,2, Сатурн,1
                            03.09.2016, Калуга,2, Зенит Пз,2
                            09.09.2016, Арсенал-2,2, Орёл,2
                            10.09.2016, Энергомаш,0, Торпедо М,0
                            10.09.2016, Сатурн,1, Рязань,0
                            10.09.2016, Динамо Бр,0, Чертаново,2
                            10.09.2016, Металлург Лп,2, Зенит Пз,4
                            11.09.2016, Авангард К,3, Витязь,0
                            16.09.2016, Чертаново,0, Арсенал-2,1
                            17.09.2016, Калуга,1, Энергомаш,1
                            17.09.2016, Орёл,0, Металлург Лп,1
                            17.09.2016, Витязь,1, Динамо Бр,0
                            17.09.2016, Рязань,1, Авангард К,1
                            18.09.2016, Торпедо М,1, Сатурн,2
                            25.09.2016, Сатурн,1, Калуга,1
                            25.09.2016, Динамо Бр,0, Рязань,0
                            25.09.2016, Арсенал-2,1, Витязь,2
                            25.09.2016, Орёл,1, Чертаново,3
                            25.09.2016, Авангард К,0, Торпедо М,1
                            26.09.2016, Энергомаш,5, Зенит Пз,1
                            01.10.2016, Калуга,2, Авангард К,0
                            01.10.2016, Торпедо М,1, Динамо Бр,1
                            02.10.2016, Витязь,3, Орёл,2
                            02.10.2016, Зенит Пз,0, Сатурн,1
                            02.10.2016, Чертаново,1, Металлург Лп,2
                            02.10.2016, Рязань,2, Арсенал-2,1
                            09.10.2016, Арсенал-2,1, Торпедо М,2
                            09.10.2016, Чертаново,3, Витязь,3
                            09.10.2016, Динамо Бр,0, Калуга,0
                            09.10.2016, Орёл,1, Рязань,1
                            09.10.2016, Металлург Лп,0, Энергомаш,4
                            09.10.2016, Авангард К,1, Зенит Пз,0
                            15.10.2016, Калуга,1, Арсенал-2,0
                            16.10.2016, Торпедо М,1, Орёл,1
                            16.10.2016, Зенит Пз,1, Динамо Бр,3
                            16.10.2016, Металлург Лп,0, Витязь,0
                            16.10.2016, Рязань,2, Чертаново,2
                            16.10.2016, Энергомаш,0, Сатурн,1
                            23.10.2016, Чертаново,4, Калуга,0
                            23.10.2016, Динамо Бр,1, Энергомаш,0
                            23.10.2016, Авангард К,2, Сатурн,2
                            23.10.2016, Витязь,1, Торпедо М,3
                            23.10.2016, Орёл,3, Зенит Пз,1
                            23.10.2016, Рязань,1, Металлург Лп,1
                            29.10.2016, Калуга,2, Витязь,1
                            30.10.2016, Торпедо М,1, Рязань,1
                            30.10.2016, Металлург Лп,1, Авангард К,0
                            30.10.2016, Энергомаш,4, Арсенал-2,0
                            30.10.2016, Зенит Пз,3, Чертаново,0
                            30.10.2016, Сатурн,1, Динамо Бр,0
                            06.11.2016, Витязь,3, Зенит Пз,1
                            06.11.2016, Арсенал-2,1, Сатурн,3
                            06.11.2016, Динамо Бр,0, Авангард К,1
                            06.11.2016, Торпедо М,1, Металлург Лп,0
                            06.11.2016, Рязань,1, Калуга,2
                            06.11.2016, Орёл,1, Энергомаш,1
                            12.11.2016, Сатурн,5, Орёл,0
                            12.11.2016, Авангард К,2, Арсенал-2,0
                            • 0
                              Интересно. Обновил csv из вашего комментария — Replay Table показывает у Чертаново 14 игр (таблица):
                              image.
                              • 0
                                В 15 туре действительно 14, но есть уже 1 игра из 16 тура.
                                И хотя его Чертаново не играло, +1 игру оно получает.
                                самый первый тур с этой проблемой — 4, там где Чертаново пропускает тур.
                                Или можно взять любой тур, найти команду которая его пропускает и там будет проблема влияние результатов игры из следующего тура, просто все остальные команды потом выравниваются, а Чертаново еще и на 1 игру больше.

                            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.