Турнирная таблица на SVG

    Решил сделать интерактивную турнирную таблицу-график для футболного чемпионата России. Вот такую:

    image

    Выбор инструментов был прост:
    • табличка для браузера — значит, что-нибудь из вэб-технологий;
    • нужна векторная графика;
    • никаких закрытых либо сложных приложений при создании — я все-таки не вэб-дизайнер.

    В итоге выбор естественным образом пал на связку SVG+JavaScript (что, правда, исключило IE из списка поддерживаемых браузеров).

    Итак поехали.

    Первым делом в JavaScript-секции определяем параметры турнира и внешнего вида таблицы:

    var nTeams = 16, nTours = (nTeams - 1) * 2, nToursPlayed = nTours;
    var vPad = 30, vIndent = 0, hPad = 20, hIndent = 65;


    Ура. Теперь можно рисовать — для начала турнирную сетку. Определяем команды и координаты (M — MoveTo, H — Horizontal line, V — Vertical line, маленькие буквы означают, что координаты относительные):

    // Grid - horizontal lines
    path = "M " + (hPad + hIndent) + " " + (vPad + vIndent);
    for (i = 0; i < nTeams; i++)
    {
      path += "h " + width + " m -" + width + " " + vPad;
    }

    // Grid path - vertical lines
    path += " M " + (hPad*2 + hIndent) + " " + (vPad + vIndent);
    for (i = 0; i < nTours; i++)
    {
      path += "v " + height + " m " + hPad + " -" + height;
    }


    Теперь с этими координатами надо что-то делать. Все очень просто — создаем объект «path», определяемый этой строкой, и добавляем его в документ:

    grid = svgDocument.createElementNS(svgns, "path");
    grid.setAttributeNS(null, "d", path);
    grid.setAttributeNS(null, "class", "grid");
    svgDocument.documentElement.appendChild(grid);


    Теперь с наполнением. Что делать с данными? Запихать в массив. Сколько элементов в массиве? По числу команд. Что представляет из себя каждый элемент массива? Имя команды, цвет команды и дальше по порядку — место в соответствующем туре, например:

    ["Кр.Советов", "#1E90FF", 4, 2, 4, 2, 3, 1, 4, 5, 3, 3, 3, 4, 6, 7, 7, 8, 11, 9, 9, 9, 9, 9, 10, 10, 12, 9, 9, 9, 10, 10]

    И теперь обходим все элементы массива, сначала проставляя метки с названиями команд, потом рисуя график продвижения:

    // Create text labels - teams
    for (i = 0; i < nTeams; i++)
    {
      label = svgDocument.createElementNS(svgns, "text");
      label.setAttributeNS(null, "x", 0);
      label.setAttributeNS(null, "y", vPad * (i + 1) + 4 + vIndent);
      label.appendChild(document.createTextNode(tournamentData[i][0]));
      svgDocument.documentElement.appendChild(label);
    }

    // Create team tracks
    for (i = 0; i < nTeams; i++)
    {
      path = "M " + (hPad + hIndent) + " " + (vPad * (i + 1) + vIndent);

      for (j = 0; j < nToursPlayed; j++)
      {
        path += " L " + (hPad * (j + 2) + hIndent) + " " + (vPad * tournamentData[i][j+2] + vIndent);
      }
      path += " L " + (hPad * (nTours + 1) + hIndent) + " " + (vPad * tournamentData[i][nToursPlayed+1] + vIndent);

      teamTrack = svgDocument.createElementNS(svgns, "path");
      teamTrack.setAttributeNS(null, "d", path);
      teamTrack.setAttributeNS(null, "fill", "none");
      teamTrack.setAttributeNS(null, "stroke", tournamentData[i][1]);
      teamTrack.setAttributeNS(null, "stroke-width", 2);
      teamTrack.setAttributeNS(null, "stroke-linejoin", "round");
      teamTrack.setAttributeNS(null, "stroke-linecap", "round");
      svgDocument.documentElement.appendChild(teamTrack);
    }


    В какой момент рисовать? Да в момент загрузки — весь этот код заносим в функцию makeShape, вызываемую при загрузке документа:

    <svg onload="makeShape(evt)" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">

    image

    Неплохо. Но сложновато отследить продвижение одной команды. Было бы здорово по клику мышки выделять один график. Захотели — сделали:

    function highlight(evt, i)
    {
      var svgDocument = evt.target.ownerDocument;
      var element = svgDocument.getElementById("track" + i);

      // Trigger highligtning
      if (element.getAttributeNS(null, "stroke-width") == "2")
        element.setAttributeNS(null, "stroke-width", 10);
      else
        element.setAttributeNS(null, "stroke-width", 2);
    }


    Теперь добавляем вызов этой функции по клику на график (а заодно и присваиваем id графику):

    teamTrack.setAttributeNS(null, "id", "track" + i);
    teamTrack.setAttributeNS(null, "onclick", "highlight(evt, " + i + ")");


    image

    Получилось. :) Результат можно посмотреть здесь, а код взять здесь.  :)
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 33

      +1
      А можно расшифровку таблицу (как её читать?), пожалуйста. А то вроде понял, что все это означает, но ощущение — что что-то не понял)
      Спасибо_
        0
        Места по турам. :) Например, выделенные Крылья Советов в первом туре были на четвертом месте, во втором — на втором, в третьем туре — опять на четвертом, в четвертом туре — опять на втором и так далее, до десятого места после 30го тура.

        Он, конечно, больше не информативен, а нагляден.
          +1
          Ни слова не понял

          Откуда видно, что «Крылья Советов в первом туре были на четвертом месте»?
            –1
            Тур — это вертикальная линия. Номер тура сверху. Положение команды в определенном туре — это позиция соответствующей линии на вертикали с номером тура. По итогам пятого тура КС были третьими — их линия третья сверху на вертикали пятого тура.

            Это выглядит несколько путано, но графически дает неплохое представление о турнирном пути команды. Если выделить, например, Рубин, то видно, что у него было несколько скачков в начале чемпионата, но потом он стабильно шел на первом месте. В то же время борьба за четвертое место шла почти до самого конца чемпионата.
              0
              Я правильно понял, что ответ попросту «места считаются сверху вниз»?
      0
      Справа цифры с местом бы не помешали ;-)
        0
        Ага, я думал об этом. С одной стороны, добавить их проще простого — дополнительные текстовые метки в цикле «Create text labels — teams», а с другой стороны, боюсь перегружать график. Он больше для чисто визуального восприятия движения команд по турниру.

        В любом случае, код открыт, лицензия свободная — если нужно, меняйте и используйте. :)
        0
        а для эксплореров vml писать не будете?
          +5
          Даже как-то не задумывался. Но вряд ли — читать что-то по технологии, ориентированной на одно семейство браузеров (пусть даже доминирующее), мне попросту лень. Я не вэб-разработчик, это больше как мини-развлечение было. :)
            0
            Развлечением пусть станет XSLT фильтр, который преобразует SVG в VML — там всё довольно просто, плюс есть готовые реализации. В конце концов VML — это папа SVG.
          0
          было бы классно это все визуализировать, и добавит некторые параметры столбцы: кол-во голов, очков и т.п.
            0
            Это сложно даже не в техническом плане, а с точки зрения юзабилити — как добавить все это и не перегрузить график.
              0
              я как раз имел ввиду, что сделать не график, а визуальный ряд
                0
                Пожалуй, это можно сделать в виде всплывающих по удержанию фокуса подсказках.
                0
                Кстати, насчет допинформации на графиках — на самом деле, было бы интересно добавить в график ключевые события типа тренерских отставок, переходов игроков и каких-либо скандалов. :)
                0
                По-моему места не всегда отображают всю соль борьбы, вот набранные очки более явно всё показывают.
                Скажем сделать так: в разрезе каждого тура определять максимум и минимум очков, и соответственно ранжировать значения очков команды относительно этой шкалы, более наглядно будет смотреться гонки команд друг за другом и напряжение борьбы.
                  0
                  Можно, но есть один минус: например, Химки в 2009 году набрали ничтожно мало очков, в то время, как наверху шла довольно плотная борьба. В итоге сверху граф превратился бы в месиво.

                  Хотя попробовать можно, конечно. :)
                    0
                    Если в реальности у команд было месиво, то график это должен как-то показывать это ведь отражает действительность, попробуйте обязательно.
                  +3
                  Посмотрите в сторону raphaeljs.com. Возможно пригодится.
                    0
                    Пробовал использовать — работает хорошо (в опере глючило, но причина так и не установлено).
                    Посмотрите тут: spokoino.ru/filter Если прокрутить до конца вниз произойдёт дозагрузка контента и логотип анимируется)
                    –2
                    автор забыл добавить: «сине-бело-голубые хэй хэй» :)
                      +1
                      >> табличка для браузера — значит, что-нибудь из вэб-технологий;
                      Хороший вывод :)
                        0
                        Вам нехватает слева от участников квадратика с их цветом, а то неясно в конечно итоге кто же там лидирует.
                          0
                          Тут я сделал несколько иначе — раскрасил в цвета названия команд.
                            0
                            Начальное расположение команд должно соответствовать итогам прошлого сезона, а то такая чехарда в первых турах.
                              0
                              В графике по прошлому сезону была маленькая хитрость: начальное расположение команд соответствовало их положению в первом туре. В графике текущего сезона я расположил их по алфавиту, но, думаю, стоит сделать так же — чуть меньше путаницы будет в первых турах.
                                0
                                Ещё хорошо бы подобрать хороший шрифт без засечек.
                          0
                          Достаточно просто и удобно, спасибо))
                            0
                            если ваш проект не коммерческий я бы воспользовался highcharts.com/ и не исключал IE, а так интересно было почитать про работу с svg
                              0
                              Это вообще не проект — так, в рамках хобби. :) Но за ссылку спасибо, если вдруг где понадобится — учту.
                              +1
                              С точки зрения практики использования SVG — отлично. Но такое месиво разноцветных колбас читать просто невозможно.
                              Почитайте Артема Горбунова, он один из лучших дизайнеров инфографики на постсоветском пространстве и дает много дельных советов на вопросы читателей. Более-менее по вашей теме: тыц, тыц.
                              На вскидку:
                              — убрать жир с линий.
                              — добавить чекбоксы, которые включают-выключают отображение определенных линий. Сомневаюсь, что кому-то необходимо видеть их сразу. Скорее всего в область интересов входит 2-3-5 команд.
                              — подпишите оси, в первую очередь вертикальную. Я не футбольный болельщик и я совсем не понимаю этот график, но думаю что и для тех, кто в теме тут не все доступно сразу.
                                0
                                Спасибо большое за ссылку.

                                Насчет мессива — согласен, особенно в первых турах (в начале графика). Кое-что удается исправить сортировкой команд по позиции в первом туре, но не всегда это работает, так что я по-прежнему в размышлениях. :)

                                По поводу остальных изменений — это график больше для меня самого и еще какого-то круга людей, которые знают, о чем идет речь. Я попробую и эти вещи, и некоторые другие, понравится — оставлю. А для того, чтоб остальные тоже тоже могли свободно пробовать и при желании использовать — выложен исходный код. :)

                              Only users with full accounts can post comments. Log in, please.