Pull to refresh

Рисуем интерактивные графики с помощью Flot php и mysql

Reading time 5 min
Views 3.9K
image
Работая долгое время с разными системами мониторинга я очень полюбил строить всякого рода графики. Некоторое время меня выручал rrdtool, но всегда хотелось получить большую интерактивность, ради чего даже прикрутил к нему веб мордочку на php. Но однажды наткнувшись на графики от flot не смог пройти мимо. То о чем давно я давно мечтал — зум графиков без задержек на обновление страницы, всплывающие подсказки — все было тут.
Сразу предупрежу, что мой уровень в javascript ~ 0, и где-то 0,5 в php, так что target группа моего дальнейшего рассказа скорее админы, которые так же как и я блуждали в инете за поиском готового решения flot+mysql, потому как сам я такого в просторах сети не нашел.

Итак. Начнем с закачки самого флота с гугликода. Закидываем в директорию веб сервера (либо линкуем) и из index.html выбираем Tracking curves with crosshair (with crosshair plugin), можно выбрать абсолютно любую, но именно она будет использована в примере.
Ее уже переработанный код:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Flot Examples</title>
<link href="layout.css" rel="stylesheet" type="text/css"></link>
<!--[if IE]><script language="javascript" type="text/javascript" src="../excanvas.min.js"></script><![endif]-->
<script language="javascript" type="text/javascript" src="../jquery.js"></script>
<script language="javascript" type="text/javascript" src="../jquery.flot.js"></script>
<script language="javascript" type="text/javascript" src="../jquery.flot.crosshair.js"></script>
</head>
<body>
<h1>Flot crosshairs Example</h1>
<div id="placeholder" style="width:620px;height:225px"></div> //размер графика
<p>Love plots.</p>
<p id="hoverdata"></p>
<script id="source" language="javascript" type="text/javascript">
var plot;
$(function () {
get_data();
});
function get_data() {
$.ajax({ url: "getdata.php", //имя php скрипта в той же директории, которая берет начальные данные из mysql
dataType: "json",
success: function(sin)
{
for (var i = 0; i < sin.length; ++i)
sin[i][0] = sin[i][0]*1000 + 3 * 1000 * 60 * 60; //мой график использует временную шкалу, это поправка нужна для перевода mysql unix_timestamp(time) в формат который понимает flot + UTC+3
function weekendAreas(axes) {
var markings = [];
var d1 = new Date(axes.xaxis.min);
// go to the first Saturday
d1.setUTCDate(datasets.getUTCDate() - ((d1.getUTCDay() + 1) % 7))
d1.setUTCSeconds(0);
d1.setUTCMinutes(0);
d1.setUTCHours(0);
var i = d1.getTime();
do {
// when we don't set yaxis, the rectangle automatically
// extends to infinity upwards and downwards
markings.push({ xaxis: { from: i, to: i + 2 * 24 * 60 * 60 * 1000 } });
i += 7 * 24 * 60 * 60 * 1000;
} while (i < axes.xaxis.max);
return markings;
}
plot = $.plot($("#placeholder"),
[ { data: sin, label: "hz = 00000"} ], {
series: {
lines: { show: true }
},
crosshair: { mode: "x" },
grid: { hoverable: true, autoHighlight: false },
yaxis: { min: 0 },
xaxis: { mode: "time" }
});
var i = 0;
(function () {
i = i + 1;
$.ajax({ url: "getlastdata.php", //имя php скрипта в той же директории, которая берет последние данные из mysql каждую минуту
dataType: "json",
success: function(ans)
{
ans[0][0] = ans[0][0]*1000 + 3 * 1000 * 60 * 60; //так как я брал в последних данных только одно значение - достаточно изменения только одного значения времени
sin.push([ans[0][0],ans[0][1]]);
plot = $.plot($("#placeholder"),
[ { data: sin, label: "hz=0" } ], {
series: {
lines: { show: true }
},
crosshair: { mode: "x" },
grid: { hoverable: true, autoHighlight: false },
yaxis: { min: 0 },
xaxis: { mode: "time" }
});
var legends = $("#placeholder .legendLabel");
legends.each(function () {
$(this).css('width', $(this).width() + 30);
});
var updateLegendTimeout = null;
var latestPosition = null;
function updateLegend() {
updateLegendTimeout = null;
var pos = latestPosition;
var axes = plot.getAxes();
if (pos.x < axes.xaxis.min || pos.x > axes.xaxis.max ||
pos.y < axes.yaxis.min || pos.y > axes.yaxis.max)
return;
var i, j, dataset = plot.getData();
for (i = 0; i < dataset.length; ++i) {
var series = dataset[i];
// find the nearest points, x-wise
for (j = 0; j < series.data.length; ++j)
if (series.data[j][0] > pos.x)
break;
legends.eq(i).text(series.label.replace(/=.*/, "= " + series.data[j][1])); //в оригинальном примере здесь было значение шкалы х, мне же необходимо было выводить не время, а значение данных.
}
}
$("#placeholder").bind("plothover", function (event, pos, item) {
latestPosition = pos;
if (!updateLegendTimeout)
updateLegendTimeout = setTimeout(updateLegend, 50);
});
}
});
setTimeout(arguments.callee, 60000) //минутный таймаут для перезапуска функции получения последних данных и перерисовки графика
})();
}
});
}
</script>
</body>
</html>
/////////////////////////////////////////////////код getdata.php
<?
$hostname = "localhost";
$username = "user";
$password = "pass";
$dbName = "mon";
$time="2010-01-22 23:40:00";
/* Таблица MySQL, в которой хранятся данные */
$table = "hztest";
/* создать соединение */
mysql_connect($hostname,$username,$password) OR DIE("Не могу создать соединение ");
/* выбрать базу данных. Если произойдет ошибка - вывести ее */
mysql_select_db($dbName) or die(mysql_error());
$dataset1 = array();
/* составить запрос для вставки информации о клиенте в таблицу */
$query = "SELECT UNIX_TIMESTAMP(time),hztest FROM $table WHERE time > '$time'";
/* Выполнить запрос. Если произойдет ошибка - вывести ее. */
$res = mysql_query($query) or die(mysql_error());
while ($row=mysql_fetch_array($res)) {
$dataset1[] = array( $row['UNIX_TIMESTAMP(time)'], $row['hztest'] );
}
echo json_encode($dataset1);
/* Закрыть соединение */
mysql_close();
?>

Соответственно getlastdata.php отличается только
строчкой $query
$query = «SELECT UNIX_TIMESTAMP(time),hztest FROM $table ORDER BY time DESC LIMIT 0,1»;

Главное достоинство, несмотря на то, что скорее всего тут очень много всего можно оптимизировать — все это сооружение работает. Впрочем, я писал все это для тех, кому хочется попробовать возможности flot, не разбираясь в подробностях взаимодействия php & javascript. В двух словах происходит начальная загрузка данных из mysql за указанное время, а потом каждую минуту подгружается по одному значению и график перестраивается с его учетом без обновления всей страницы. Таймаут можно установить не жестко с помощью time записанного как SELECT NOW() — interval n hours, а чтобы иметь на графике всегда один и тот же промежуток времени используйте sin.shift() каждый цикл, он удаляет первое значение в массиве.

ЗЫ Для корректной передачи данных из php в javascript потребуется php json (я тестил в fedora, там пришлось установить дополнительный одноименный пакет для его работы)
ЗЫЫ спасибо DmitryGushin за инвайт
Tags:
Hubs:
+7
Comments 6
Comments Comments 6

Articles