- Опубликовано 04.01.2018 23:02
- Просмотров: 20187
Рисуем графики Highcharts (Highstock) по данным из MySQL
В этой статье я расскажу о том, как рисовать графики при помощи библиотеки Highcharts, а точнее её подвида Highstock. Данные при этом мы будем получать из MySQL при помощи PHP и передавать их в JSON формате.
Написать статью меня побудило полное отсутствие документации на русском языке. Кроме того, на момент написания в рунете, детально расписанного примера использования Highstock мне найти так и не удалось.
Итак, существует несколько подвидов библиотеки Highcharts, далее позволю себе вольный перевод:
- Highcharts – простое создание интерактивных диаграмм для web проектов
- Highstock – создание временных графиков на чистом JavaScript
- Highmaps – развёрнутые интерактивные карты с поддержкой касания
Поскольку мне было необходимо рисовать временные графики, я использовал Highstock.
Теперь о том почему именно Highcharts и коротко о том, как это работает.
В классическом подходе, когда мы говорим слово график мы подразумеваем картинку (jpeg, png и т.д.). Эту самую картинку кто-то должен подготовить по имеющимся данным. Делать статичную картинку не вариант. А если делать динамически (автоматически обновляемую), то необходимо при каждом обращении создавать новое изображение, а это довольно ресурсоёмко. И вот тут можно применить более прогрессивный подход.
Если описать процесс очень коротко, то Highstock получает данные от источника в JSON формате и затем отрисовывает (рендерит) их в окне браузера используя JavaScript. Тем самым мы не нагружаем каждый раз сервер, а всю работу по отрисовки переносим на сторону клиента. Кроме того, Highcharts библиотеки бесплатны для не коммерческого использования, в общем то что, надо.
В качестве источника данных, для Highcharts, может выступать web сервер с MySQL, микроконтроллер или что-то ещё, суть не в этом. Главное, это получить данные от источника в формате JSON. Если вы не знаете, что это такое, то это просто ещё один формат представления данных, как например XML. Если надо подробнее – гугл в помощь.
Библиотека Highstock обрабатывает полученные данные используя JavaScript в браузере и рисует их в виде графика.
Таким образом мы не нагружаем источник, он просто отдаёт данные, а вся отрисовка происходит на стороне клиента, будь то телефон, планшет или обычный компьютер.
Теперь перейдём к практике, разбив её на этапы.
1. MySQL
Предположим у нас уже есть данные представленные в виде одной таблицы “t_power” в MySQL (на всякий случай вот архив с дампом БД: t_power.sql.zip).
В таблице записаны данные от вольтметра-амперметра Peacefair pzem-004t. Тут всё очевидно, единственное на чём следует заострить внимание это на столбец date, он имеет тип datetime и предназначен для хранения информации о времени измерения.
В моём случае поля current и active, с данными для тока и мощности, были MySQL заполнены случайными значениями. А вот ‘Напряжение’ это вполне реальные данные.
2. JSON
Теперь нам необходимо получить данные из БД, и представить их в JSON формате. Для этого я буду использовать незамысловатый PHP скрипт jsonp.php (который положим в корень), листинг которого чуть ниже:
<?php
date_default_timezone_set( 'UTC' );
//echo date('Y-m-d H:i:s');
$mysqli = new mysqli('localhost', 'power', 'power', 'power');
$query = "SELECT `datetime`, `voltage`, `current`,`active` FROM `t_power`;";
$result = $mysqli->query($query);
while ($record = $result->fetch_row()){
$all[] = array(strtotime($record[0]), (float)$record[1], (float)$record[2], (float)$record[3]);
}
echo json_encode($all);
$mysqli->close();
?>
В качестве разнообразия я буду использовать ООП подход.
Чуть более дробно о том, что здесь происходит.
Мы подключаемся к серверу localhost, используя имя пользователя и пароль power. Четвёртый параметр - имя БД, в моём примере также power.
Получать мы будем столбцы `datetime`, `voltage`, `current`, `active`, тут всё очевидно.
$all[] = array(strtotime($record[0]), (float)$record[1], (float)$record[2], (float)$record[3]);
Строка формирует массив, первый элемент которого это метка времени Unix (тут используется функция преобразования времени strtotime()). Остальные элементы соответственно это данные о напряжении, токе, и потребляемой мощности. (float) перед знаком производит преобразование типов данных к числу.
Выполнив всё это в цикле while мы сформировали двумерный массив $all.
После чего выводим его, предварительно преобразовав выходные данные в JSON.
echo json_encode($all);
При обращении к этому файлу мы будем получать данные вида:
[
[1515029601,206.4,3.82,2985],
[1515029606,205.8,8.42,518],
[1515029633,210.6,10.65,1634],
[1515029666,219.8,7.98,2617],
…
[1515095928,209.4,0,0],
[1515095961,198.5,0,0]
]
Значения в квадратных скобках это: метка времени Unix, напряжение, ток и мощность соответственно.
Важно понимать, что для корректного выполнения скрипта необходима поддержка PHP.
Теперь у нас есть подготовленные данные, и можно приступать к настройке самого Highstock.
3. Highstock
Прежде всего нам потребуется библиотека jquery, которую скачаем jquery.com/download, и также расположим файл в корне.
Разумеется нам потребуется и сам Highstock, который надо скачать www.highcharts.com/download.
На момент написания последняя версия 6.0.4.
После распаковки архива сразу переименуем файл index.htm например в index_old.html и создадим файл energy.html следующего содержания:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Highstock Example</title>
<style type="text/css">
</style>
</head>
<body>
<script src="/jquery-3.2.1.min.js"></script>
<script src="/code/highstock.js"></script>
<script src="/code/themes/grid-light.js"></script>
<script src="/code/modules/exporting.js"></script>
<a href="https://unboxit.ru" target="_blank">Это и многое другое на unboxIT.ru</a>
<div id="container2" style="height: 500px; min-width: 310px"></div>
<script>
Highcharts.setOptions({
lang: {
loading: 'Загрузка...',
months: ['Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'],
weekdays: ['Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота'],
shortMonths: ['Янв', 'Фев', 'Март', 'Апр', 'Май', 'Июнь', 'Июль', 'Авг', 'Сент', 'Окт', 'Нояб', 'Дек'],
exportButtonTitle: "Экспорт",
printButtonTitle: "Печать",
rangeSelectorFrom: "С",
rangeSelectorTo: "По",
rangeSelectorZoom: "Период",
downloadPNG: 'Скачать PNG',
downloadJPEG: 'Скачать JPEG',
downloadPDF: 'Скачать PDF',
downloadSVG: 'Скачать SVG',
printChart: 'Напечатать график'
}
});
</script>
<script type="text/javascript">
$.getJSON('jsonp.php', function (data) {
// split the data set into voltage and current
var voltage = [],
current = [],
active = [],
dataLength = data.length,
i = 0;
for (i; i < dataLength; i += 1) {
voltage.push([
data[i][0] * 1000, // the date
data[i][1], // voltage
]);
current.push([
data[i][0] * 1000, // the date
data[i][2] // the current
]);
active.push([
data[i][0] * 1000, // the date
data[i][3] // the active power
]);
}
// create the chart
Highcharts.stockChart('container2', {
rangeSelector: {
selected: 1,
buttons: [{
type: 'minute',
count: 10,
text: '10м'
}, {
type: 'hour',
count: 1,
text: '1час'
}, {
type: 'hour',
count: 6,
text: '6час'
}, {
type: 'day',
count: 1,
text: '1дн'
}, {
type: 'week',
count: 1,
text: 'неделя'
}, {
type: 'month',
count: 1,
text: 'мес'
}, {
type: 'year',
count: 1,
text: 'год'
}, {
type: 'all',
text: 'Всё'
}]
},
title: {
text: 'Электросеть'
},
yAxis: [{
labels: {
align: 'right',
x: -3
},
title: {
text: 'Напряжение'
},
height: '50%',
lineWidth: 1,
resize: {
enabled: true
}
}, {
labels: {
align: 'right',
x: -3
},
title: {
text: 'Ток'
},
top: '52%',
height: '20%',
offset: 0,
lineWidth: 1
}, {
labels: {
align: 'right',
x: -3
},
title: {
text: 'Мощьность'
},
top: '75%',
height: '20%',
offset: 0,
lineWidth: 1
}],
tooltip: {
split: true
},
series: [{
type: 'spline',
name: 'Вольт',
data: voltage,
yAxis: 0
}, {
type: 'spline',
name: 'Ампер',
data: current,
yAxis: 1
}, {
type: 'spline',
name: 'Ватт',
data: active,
yAxis: 2
}]
});
});
</script>
</body>
</html>
Это обычный HTML файл с JavaScript.
Теперь пройдёмся по самым значимым строкам, чуть подробнее.
<script src="/jquery-3.2.1.min.js"></script>
<script src="/code/highstock.js"></script>
Подключаем библиотеки jquery и highstock.
$.getJSON('jsonp.php', function (data)
Откуда будем получать данные, это рассмотренный ранее файл 'jsonp.php', который лежит в корне.
voltage = [],
current = [],
active = [],
Я буду рендерить сразу 3 графика за раз, для чего подготавливаю соответствующие массивы.
data[i][0] * 1000
Умножаем на 1000 поскольку в принятых JSON данных метка времени Unix передана в секундах, а нам нужны данные в микросекундах. В принципе можно было передавать JSON данные уже в микросекундах, но тогда у нас во времени всегда были 3 лишних нуля, увеличивая объём передаваемых данных, что не очень хорошо.
Теперь у нас есть все необходимые данные и можно заняться рендерингом.
Highcharts.stockChart('container2' …
'container2' это id блока div куда мы будем отрисовывать.
title: {
text: 'Электросеть'
},
Название графика, которое будет показано сверху.
Далее:
yAxis: [{
labels: {
align: 'right',
x: -3
},
title: {
text: 'Напряжение'
},
height: '50%',
lineWidth: 1,
resize: {
enabled: true
}
},
Шкала Y(ноль) Которая будет расположена справа, иметь подпись 'Напряжение', занимать она будет 50% от размера всего графика (поля рендеринга). Чуть далее идёт тоже самое только для 'Тока' и 'Потребляемой мощности'.
Отличия для Шкалы Y(1) буду в следующем:
top: '52%', -
height: '20%',
График тока будет отступать от верха 52% и при этом занимать 20%. Аналогично для шкалы Y(2).
Далее:
series: [{
type: 'spline',
name: 'Вольт',
data: voltage,
yAxis: 0
},
Серия данных type: 'spline' - тип графика - огибающая (плавная) линия по нашим точкам. name: 'Вольт' – единица измерения которая будет показана при наведении на график, data: voltage – данные в виде массива подготовленные нами ранее и самый главный фокус yAxis: 0 – говорим что график будет отрисовываться для 0 (нулевой) оси. Тоже самое происходит с остальными значениями, только они отрисовываются относительно оси 1 – Ток, 2 – Мощность. Помним, что чуть ранее мы подготовили 3 оси Y (yAxis).
Теперь несколько слов о менее значимых параметрах.
<script src="/code/themes/grid-light.js"></script>
Мы подключили тему, для отображения графиков с линейкой.
<script src="/code/modules/exporting.js"></script>
Подключили модуль для возможности экспорта графиков.
На самом деле список модулей довольно обширен, и вы можете подключить их самостоятельно, благо теперь понятно, как это делать.
Ну и напоследок “десерт”:
Highcharts.setOptions({ lang: {...
Здесь я задаю языковые параметры, для русификации интерфейса.
Далее кнопки:
rangeSelector: {
selected: 1,
buttons: [{
type: 'minute',
count: 10,
text: '10м'
},..
Для переключения отображаемого диапазона данных, selected: 1 – она выбрана по умолчанию, type: 'minute', - тип минуты, count: 10 – значение 10, text: '10м' - что будет написано на самой кнопке.
Таким образом при щелчке по кнопке '10м', график начнёт отображать временной интервал в 10 минут. Остальные кнопки настраиваются аналогично.
Ну и собственно при обращении к energy.html мы увидим следующий график:
Надеюсь моя статья помогла немного разобраться с Highcharts. Теперь нарисовать, например, 1 график вообще не составит труда.
Полностью готовый пример включая Highstock-6.0.4 и jquery:
highstock-6.0.4rel.zip
Комментарии
Backend fatal error: PHP Fatal error: Call to a member function fetch_row() on boolean in /var/www/**/jso np.php on line 14\n, referer:
14-я строка у меня: while ($record = $result->fetch_row()){
не могу сообразить, подскажите что не так? Спасибо
Вот архив дампа с БД http://unboxit.ru/storage/files/t_power.sql.zip
Создайте пользователя и БД - power, после чего будучи в БД power импортируйте данные из архива (проще всего для этого использовать phpMyAdmin).
Все сделал и все работает))) странно почему с моей таблицей не работало(( в файле jsonp.php все указал верно((
В любом случае Спасибо большое)
Для начала следует проверить соединение с БД.
После строки $mysqli = new mysqli(...
вставьте код вроде такого:
if ($mysqli->conne ct_error) {
die('Ошибка подключения (' . $mysqli->connec t_errno . ') '
. $mysqli->connect_error);
}
Если статически, то работа выглядит сл. образом:
Получить данные JSON->Построить график по готовым данным.
То динамически, будет примерно так:
Подготовить график.
Получить данные JSON->вставить их в график->перерисовать.
Регулярно обновлять данные->добавля ть их к существующим данным->перерисовывать.
Тут уже идёт асинхронная работа, как только появляются новые данные идёт обновление и перерисовка.
Частично я реализовал это сдесь: https://unboxit.ru/blog/68-sistema-monitoringa-dlya-doma-na-raspberry-pi-zero-w.html
Но вообще лучше почитать офф. API.
В общем и я разобрался. Что бы это все работало, нужен сервер, например опенсервер, на котором все это запускается. На компе пхп не выполняется просто так) извиняюсь за нубство, но если входишь в это с нуля, сложно представить все нужное для работы.
в файле jsonp.php строчку подключения к БД нужно было пояснить так:
$mysqli = new mysqli('localho st', 'ИМЯ ПОЛЬЗОВАТЕЛЯ', 'ПАРОЛЬ ', 'ИМЯ БАЗЫ ДАННЫХ');
Уже некоторое время борюсь с массивами: у меня не получается вызвать массив voltage, так как он является локальным массивом функции $.getJSON и поэтому не может быть вызван позже в series
Так как график не получает данных, он не отрисовывается на странице
Может я чего-то не понимаю?
Борюсь с построением графика три дня, всё равно не строит. Код изменил под себя, проверил jquery и скрипт, который даёт данные - как будто всё работает, в тестовом режиме jquery работает. Не вижу никаких ошибок, а график всё равно не строится. Что может быть с этим? Вы решили свой вопрос?
Заработало на коленке, просто изменив параметры в файле json!!!
Искал такое готовое решение около месяца, т.к. своих знаний не достаточно! Огромное Вам человеческое СПАСИБО!
RSS лента комментариев этой записи