Flot — рисуем графики в jQuery

18 августа 2010

Flot — это JavaScript библиотека, предназначенная для рисования графиков. С ее помощью можно легко и быстро создавать красивые динамические графики, которые будут корректно работать в любом браузере независимо от того, какая ОС установлена у пользователя.

Примечание: все примеры, библиотека Flot, а также кое-какие дополнительные материалы к этой заметке собраны в этом архиве.

1. Простой график

Давайте нарисуем с помощью Flot какой-нибудь несложный график. Чтобы было чуточку интересней, пусть графиков будет сразу несколько. Для передачи данных библиотеке Flot, их нужно представить в следующем виде:

var all_data = [
  { label: "Данные 1", color: 0, data: [[1, 0], [2, 10], [3, 70]]},
  { label: "Данные 2", color: 1, data: [[1, 130], [2, 230], [3, 320]]}
  // ВАЖНО: IE не понимает запятых на конце :(
];

Числа 1, 2 и 3 — это координаты точек по оси абсцисс, числа рядом с ними — координаты по оси ординат. Указывать названия рядов и используемые цвета не обязательно. Будьте внимательны — если поставить запятую вслед за последним элементом массива или хэша, Internet Explorer скажет, что в коде ошибка, и откажется его выполнять. Все остальные браузеры обрабатывают эту ситуацию нормально, что в очередной раз доказывает, что создателям IE нужно оторвать руки.

Если мы хотим, чтобы по оси OX отображались даты и время, их значения должно быть представлено в UTC (имеются в виду числа типа 1149537600000). Мне кажется не очень удобным работать с UTC, тем более, что избежать этого можно с помощью незамысловатого приема:

var all_data = [
  { label: "Данные 1", color: 0,
    data: [["2010/10/01", 0], ["2010/11/01", 1], ["2010/12/01", 7]]},
  { label: "Данные 2", color: 1,
    data: [["2010/10/01", 13], ["2010/11/01", 23], ["2010/12/01", 32]]}
];
// преобразуем даты в UTC
for(var j = 0; j < all_data.length; ++j) {
  for(var i = 0; i < all_data[j].data.length; ++i)
    all_data[j].data[i][0] = Date.parse(all_data[j].data[i][0]);
}

Можно считать, что все уже написано — до готового графика осталось совсем чуть-чуть:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>Название страницы</title>
  <!-- подгружаем Flot -->
  <!--[if IE]><script language="javascript" type="text/javascript" src="flot/excanvas.min.js"></script><![endif]-->
  <script language="javascript" type="text/javascript" src="flot/jquery.js"></script>
  <script language="javascript" type="text/javascript" src="flot/jquery.flot.js"></script>
</head>
<body>
  <p><noscript><strong style="color: red;">
    Для отображения данных необходимо включить JavaScript!
  </strong></noscript></p>
  <!-- тут будет выводится график -->
  <div id="placeholder" style="width:600px;height:300px;"></div>

<script language="javascript" type="text/javascript">
// данные для графиков
var all_data = [
  { data: [["2010/10/01", 0], ["2010/10/5", 1],
           ["2010/10/10", 7], ["2010/10/15", 8]]},
  { data: [["2010/10/01", 13], ["2010/10/5", 23],
           ["2010/10/10", 32], ["2010/10/15", 33]]}
];
// преобразуем даты в UTC
for(var j = 0; j < all_data.length; ++j) {
 for(var i = 0; i < all_data[j].data.length; ++i)
   all_data[j].data[i][0] = Date.parse(all_data[j].data[i][0]);
}
// свойства графика
var plot_conf = {
 series: {
   lines: {
     show: true,
     lineWidth: 2
   }
 },
 xaxis: {
   mode: "time",
   timeformat: "%y/%m/%d",
 }
};
// выводим график
$.plot($("#placeholder"), all_data, plot_conf);
</script>
</body>
</html>

На мой взгляд, все предельно просто и в комментариях не нуждается. Результат выглядит следующим образом:

Простой график в Flot

2. Выводим легенду

Вывести легенду к графику очень просто — достаточно указать label в описании данных, как мы это делали в начале статьи. Как вы могли заметить, в последнем примере ассоциативный массив содержал только элементы data.

По умолчанию легенда отображается в правом верхнем углу графика, частично закрывая его. Чтобы легенда отобразилась в конкретном месте на странице, достаточно дописать в переменную plot_conf:

  legend: {
    container: $("#legend")
  } // помним про запятые и IE

… где legend — это id слоя, в котором будет выведена легенда. Полный код примера вы можете посмотреть в файле step2.html, который находится в прилагающемся к статье архиву.

3. Скрываем данные

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

// рисуем графики в первый раз
redraw();

function redraw() {
  var data = [];
  for(var j = 0; j < all_data.length; ++j)
    if(!hide[j]) // что скрываем, а что нет
      data.push(all_data[j]);

  $.plot($("#placeholder"), data, plot_conf);
 
  // легенду рисуем только один раз
  plot_conf.legend.show = false;
}

Массив hide содержит all_data.length элементов. Если i-ый элемент массива равен true, значит i-ый ряд данных нужно скрыть. После первого рисования графика следует присвоить plot_conf.legend.show значение false. Легенду достаточно нарисовать один раз, незачем тратить на ее повторное создание лишние такты процессора.

После того, как Flot нарисует легенду, мы можем добавить в нее чекбоксы:

// рисуем чекбоксы в легенде

// еще IE не умеет заменять innerHTML в table
var legend = document.getElementById('legend');
var legend_tbl = legend.getElementsByTagName('table')[0];
var legend_html = '<table style="font-size: smaller;' +
                  ' color: rgb(84, 84, 84);"><tbody>';
for(var i = 0; i < legend_tbl.rows.length; i++) {
  legend_html += '<tr>' +
    '<td><input type="checkbox" onclick="hide['+ i +']=!hide['+ i
    + '];redraw();" checked="1"></td>'
    + legend_tbl.rows[i].innerHTML
    + '</tr>';
}
legend_html += "</tbody></table>";
legend.innerHTML = legend_html;

Internet Explorer не умеет изменять innerHTML таблиц, в связи с чем приходится переписывать таблицу с нуля и присваивать полученный код innerHTML слою, эту таблицу содержащему. Интересное объяснение того, почему IE так себя ведет, вы найдете на ХабраХабре. Правда, на момент написания этих строк, статья была недоступна:

Доступ к публикации закрыт

Вы пытаетесь открыть публикацию, написанную пользователем GreLI.
Автор переместил топик в черновики.

На всякий случай я взял копию статьи из кэша Google и сохранил в архиве, прилагающемуся к статье.

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

Flot: график с легендой

Полный код примера вы найдете в файле step3.html.

4. Кроме того

Возможности Flot настолько велики, что для полного их описания потребовалась бы далеко не одна и не две таких статьи. За кадром осталась поддержка плагинов, подгрузка данных с помощью Ajax и многое другое. Чтобы составить более-менее полное впечатление о возможностях библиотеки, загляните в раздел с примерами на сайте проекта.

Напоследок я приведу еще один пример, работу которого я хотел бы оставить для самостоятельного изучения.

Сложный пример использования Flot

Нажимая по ссылке «Сменить вид», пользователь может выбирать, в каком виде будут отображаться данные — в виде гистограмм или графиков. Превью внизу страницы позволяет выбрать отображаемый диапазон данных. Полный код примера вы найдете в прилагающемся к статье архиву, в файле result.html.

5. Заключение

Flot — это прекрасная библиотека, которая должна быть в арсенале каждого веб-разработчика. Открытый код, полная кроссплатформенность, мощный функционал, отличная документация — о чем еще можно мечтать? В очередной раз я убеждаюсь в том, что этот ваш Flash никому не нужен!

Дополнение: Если у вас возникли проблемы с работой Flot в Internet Explorer 9, загляните сюда.

Метки: .


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