unboxIT
Рисуем графики 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 (который положим в корень), листинг которого чуть ниже:
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);
В качестве разнообразия я буду использовать ООП подход.
Чуть более дробно о том, что здесь происходит.
Мы подключаемся к серверу 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.
При обращении к этому файлу мы будем получать данные вида:
Значения в квадратных скобках это: метка времени Unix, напряжение, ток и мощность соответственно.
Важно понимать, что для корректного выполнения скрипта необходима поддержка PHP.
Теперь у нас есть подготовленные данные, и можно приступать к настройке самого Highstock.
3. Highstock
Прежде всего нам потребуется библиотека jquery, которую скачаем jquery.com/download, и также расположим файл в корне.
Разумеется нам потребуется и сам Highstock, который надо скачать www.highcharts.com/download.
На момент написания последняя версия 6.0.4.
После распаковки архива сразу переименуем файл index.htm например в index_old.html и создадим файл energy.html следующего содержания:
// 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: ‘Всё’
>]
>,
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
>],
Это обычный HTML файл с JavaScript.
Теперь пройдёмся по самым значимым строкам, чуть подробнее.
Подключаем библиотеки jquery и highstock.
Откуда будем получать данные, это рассмотренный ранее файл ‘jsonp.php’, который лежит в корне.
Я буду рендерить сразу 3 графика за раз, для чего подготавливаю соответствующие массивы.
Умножаем на 1000 поскольку в принятых JSON данных метка времени Unix передана в секундах, а нам нужны данные в микросекундах. В принципе можно было передавать JSON данные уже в микросекундах, но тогда у нас во времени всегда были 3 лишних нуля, увеличивая объём передаваемых данных, что не очень хорошо.
Теперь у нас есть все необходимые данные и можно заняться рендерингом.
‘container2’ это id блока div куда мы будем отрисовывать.
Название графика, которое будет показано сверху.
Шкала Y(ноль) Которая будет расположена справа, иметь подпись ‘Напряжение’, занимать она будет 50% от размера всего графика (поля рендеринга). Чуть далее идёт тоже самое только для ‘Тока’ и ‘Потребляемой мощности’.
Отличия для Шкалы Y(1) буду в следующем:
График тока будет отступать от верха 52% и при этом занимать 20%. Аналогично для шкалы Y(2).
Серия данных type: ‘spline’ — тип графика — огибающая (плавная) линия по нашим точкам. name: ‘Вольт’ – единица измерения которая будет показана при наведении на график, data: voltage – данные в виде массива подготовленные нами ранее и самый главный фокус yAxis: 0 – говорим что график будет отрисовываться для 0 (нулевой) оси. Тоже самое происходит с остальными значениями, только они отрисовываются относительно оси 1 – Ток, 2 – Мощность. Помним, что чуть ранее мы подготовили 3 оси Y (yAxis).
Теперь несколько слов о менее значимых параметрах.
Мы подключили тему, для отображения графиков с линейкой.
Подключили модуль для возможности экспорта графиков.
На самом деле список модулей довольно обширен, и вы можете подключить их самостоятельно, благо теперь понятно, как это делать.
Здесь я задаю языковые параметры, для русификации интерфейса.
Для переключения отображаемого диапазона данных, 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())
не могу сообразить, подскажите что не так? Спасибо
Скорее всего нет доступа к таблице t_power, либо она не создана, либо создана как-то не так.
Вот архив дампа с БД unboxit.ru/storage/files/t_power.sql.zip
Создайте пользователя и БД — power, после чего будучи в БД power импортируйте данные из архива (проще всего для этого использовать phpMyAdmin).
Скорее всего нет доступа к таблице t_power, либо она не создана, либо создана как-то не так.
Вот архив дампа с БД http://unboxit.ru/storage/files/t_power.sql.zip
Создайте пользователя и БД — power, после чего будучи в БД power импортируйте данные из архива (проще всего для этого использовать phpMyAdmin).
Все сделал и все работает))) странно почему с моей таблицей не работало(( в файле jsonp.php все указал верно((
В любом случае Спасибо большое)
Здравствуйте, я импортировал вашу таблицу к себе в бд, поменял соответственно хост, пользователя, пароль и название бд в 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.