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

Выбор инструментов был прост:
В итоге выбор естественным образом пал на связку SVG+JavaScript (что, правда, исключило IE из списка поддерживаемых браузеров).
Итак поехали.
Первым делом в JavaScript-секции определяем параметры турнира и внешнего вида таблицы:
Ура. Теперь можно рисовать — для начала турнирную сетку. Определяем команды и координаты (M — MoveTo, H — Horizontal line, V — Vertical line, маленькие буквы означают, что координаты относительные):
Теперь с этими координатами надо что-то делать. Все очень просто — создаем объект «path», определяемый этой строкой, и добавляем его в документ:
Теперь с наполнением. Что делать с данными? Запихать в массив. Сколько элементов в массиве? По числу команд. Что представляет из себя каждый элемент массива? Имя команды, цвет команды и дальше по порядку — место в соответствующем туре, например:
И теперь обходим все элементы массива, сначала проставляя метки с названиями команд, потом рисуя график продвижения:
В какой момент рисовать? Да в момент загрузки — весь этот код заносим в функцию makeShape, вызываемую при загрузке документа:

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

Получилось. :) Результат можно посмотреть здесь, а код взять здесь. :)

Выбор инструментов был прост:
- табличка для браузера — значит, что-нибудь из вэб-технологий;
- нужна векторная графика;
- никаких закрытых либо сложных приложений при создании — я все-таки не вэб-дизайнер.
В итоге выбор естественным образом пал на связку 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">

Неплохо. Но сложновато отследить продвижение одной команды. Было бы здорово по клику мышки выделять один график. Захотели — сделали:
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 + ")");

Получилось. :) Результат можно посмотреть здесь, а код взять здесь. :)