Страница 4 из 12

Re: Строим графики Highstock

Добавлено: Пн авг 03, 2015 6:04 pm
Urbas81
xxc писал(а): У меня работает автоматическое обновление графиков - правда, пришлось менять код выдачи JSON.
Смысл в чем: в выдаче JSON добавлен последний ID для отобранных данных. А в скрипте на странице после получения данных мы этот ID запоминаем. После чего по таймеру периодически проверяем - не появились ли данные для графика с ID большим, чем мы уже получили. Если данные есть - добавляем их к графику.
На код бы взглянуть :? :mrgreen:

Re: Строим графики Highstock

Добавлено: Пн авг 03, 2015 9:07 pm
xxc
Urbas81 писал(а): На код бы взглянуть :? :mrgreen:
На "чистоту" кода не претендую - писался в торопях.
jsonp.phpПоказать

Код: Выделить всё

<?
  /*
  * Автор Казаков Сергей
  * на форуме под ником Bagir
  * благодарность denis на примеры
  * ver 1.3
  */

  include_once("./config.php");
  include_once("./lib/loader.php");
  $session = new session("prj");
  $db = new mysql(DB_HOST, '', DB_USER, DB_PASSWORD, DB_NAME); // connecting to database
  include_once("./load_settings.php");
  if (!headers_sent()) {
    header("HTTP/1.0: 200 OK\n");
    header('Content-Type: text/html; charset=utf-8');
  }


  // Получить имя и проверить
  if (isset($params['name'])) {
    $name = $params['name'];
  } else
    returm;


  $date_start = isset($params['start']) ? $params['start'] : null;
  $date_end = isset($params['end']) ? $params['end'] : null;
  $last_id = isset($params['lastid']) ? (int)$params['lastid'] : 0;



  // Разбить на объект и свойство (возможен вариант поиска в pvalues сразу по PROPERTY_NAME=$name не разбирая на объект и свойство)
  $name = explode('.', $name); 

  // Получить объект по имени
  $obj = getObject($name[0]);
  // Получить id свойства
  $prop_id = $obj->getPropertyByName($name[1], $obj->class_id, $obj->id);
  $pvalue = SQLSelectOne("SELECT * FROM pvalues WHERE PROPERTY_ID='" . $prop_id . "' AND OBJECT_ID='" . $obj->id . "'");
  $sql = "SELECT ID, UNIX_TIMESTAMP(ADDED) as ADDED, VALUE FROM phistory WHERE VALUE_ID='$pvalue[ID] '";
  if (!is_null($date_start)){
    $sql .= " and ADDED >= '$date_start'";
  }
  if (!is_null($date_end)){
    $sql .= " and cast(ADDED as DATE) <= '$date_end'";
  }
  if ($last_id>0){
    $sql .= " and id>$last_id";
  }


  $sql .= "  ORDER BY ADDED ";
  $arr_s = SQLSelect($sql);
  $data = [];
  $date_prev = null;

  header('Content-Type: application/json');

  $breaks = [];
  $DTPrev = new DateTime();
  $DTCurrent = new DateTime();
  $prev = null;
  foreach ($arr_s as $row){
    $added = $row['ADDED'];
    $t = (float)($row['VALUE']);
    if (!is_null($prev)){
      $diff = $added - $prev;
      if ($diff > 60*60) { // 1 hour
        $breaks[] = ["start"=>$prev, "end"=>$row['ADDED'], 'size'=>$diff];
      }
      $data[] = [$added*1000, $t];
    }
    $prev = $row['ADDED'];
    $last_id = $row['ID'];
  }



  echo(json_encode([
    'last_id'=>$last_id,
    'data'=>$data,
    'breaks'=>$breaks,
    'description'=>$obj->description
  ]));


  $session->save();
  $db->Disconnect(); // closing database connection
?>
Код страницы с графикомПоказать

Код: Выделить всё

<script type="text/javascript" src="/js/jquery.js"></script>
<script src="/highcharts/js/highstock.js"></script>
<script src="/highcharts/js/modules/broken-axis.js"></script>
<script type="text/javascript" language="javascript">

var url = '/jsonp.php/?name=Sensor1.temp';
var last_id = 0;

$(function () {
        $.getJSON(url, function (data) {

            var breaks = [];
            $.each(data.breaks, function (idx, e) {
                breaks.push({
                    from: e.start,
                    to: e.end,
                    breakSize: e.size
                });
            });
//            console.log(breaks);

            var chart = $("#chart-container").highcharts('StockChart', {
                chart: {
                    zoomtype: 'x',
                    events: {
                        selection: function (e) {
                        },
                        load: function (e) {
                        }
                    }
                },

                title: {text: data.description},
                xAxis: {
                    type: 'datetime',
                },
                yAxis: {title: {text: 'Температура, °C'}},
                rangeSelector: {
                    buttons: [
                        {type: 'all', count: 1, text: 'Все'},
                        {type: 'hour', count: 1, text: 'Час'},
                        {type: 'day', count: 1, text: 'День'},
                        {type: 'month', count: 1, text: 'Мес'},
                        {type: 'year', count: 1, text: 'Год'}],
                    selected: 0,
                    inputEnabled: false
                },
                series: [{
                    type: 'area',
                    name: 'Temperature',
                    tooltip: {
                        valueDecimals: 1
                    },
                    gapSize: 0,
                    data: data.data
                }
                ]
            });

            last_id = data.last_id;
            setInterval(function () {
                updateChart();
            }, 30000);

        });
    });

    function updateChart() {
        $.ajax({
            dataType: 'json',
            method: 'POST',
            url: url + '&lastid=' + last_id,
            success: function (data) {
                var ser = $("#chart-container").highcharts().series[0];
                last_id = data.last_id;
                $.each(data.data, function (idx, e) {
                    ser.addPoint(e);
                })
            }

        });
}
</script>

<div id="chart-container" style="height: 500px; min-width: 500px"></div>

Обновление работает. Но вот с разрывами в графике - например датчик завис или нет связи - пока не разобрался - не хватает времени.

Re: Строим графики Highstock

Добавлено: Пн авг 03, 2015 9:38 pm
olehs
Вижу, что у всех код работает, но не понимаю как.
У меня $.getJSON уходит в ошибку parseerror, что и логично, т.к. то, что возвращает сценарий, не совсем валидный JSON

Код: Выделить всё

jQuery182043176942504942417_1438627650102([[1437944711000,33.40],[1437979275000,30.79],[1437979879000,30.70],[1437980485000,30.79],[1437981089000,31],[1437981696000,31],[1437982300000,30.90],[1437982904000,30.79],[1437983511000,30.70],[1437984115000,30.60],[1437984719000,30.60],[1438013955000,32.90],[1438014560000,32.59],[1438015165000,32.09],[1438015770000,31.90],[1438016375000,31.70],[1438016981000,31.50],[1438017586000,31.29],[1438018191000,31.29],[1438018795000,31.20],[1438020611000,31.20],[1438021219000,31.10]....
Кто-то сталкивался с таким? Может есть модифицированный сценарий?

Re: Строим графики Highstock

Добавлено: Пн авг 03, 2015 9:50 pm
xxc
olehs писал(а): У меня $.getJSON уходит в ошибку parseerror, что и логично, т.к. то, что возвращает сценарий, не совсем валидный JSON
Выдавало такую ж ошибку, пока я не стал забирать JSON не через $.getJSON, а так:

Код: Выделить всё

$.ajax({
            dataType: 'json',
            method: 'POST',
            url: url,
            success: function (data) {
                ......
                })
            }
        });
Т.е. с явным указанием типа данных - dataType: 'json'

Re: Строим графики Highstock

Добавлено: Пн авг 03, 2015 9:58 pm
olehs
olehs писал(а):Вижу, что у всех код работает, но не понимаю как.
У меня $.getJSON уходит в ошибку parseerror, что и логично, т.к. то, что возвращает сценарий, не совсем валидный JSON

Код: Выделить всё

jQuery182043176942504942417_1438627650102([[1437944711000,33.40],[1437979275000,30.79],[1437979879000,30.70],[1437980485000,30.79],[1437981089000,31],[1437981696000,31],[1437982300000,30.90],[1437982904000,30.79],[1437983511000,30.70],[1437984115000,30.60],[1437984719000,30.60],[1438013955000,32.90],[1438014560000,32.59],[1438015165000,32.09],[1438015770000,31.90],[1438016375000,31.70],[1438016981000,31.50],[1438017586000,31.29],[1438018191000,31.29],[1438018795000,31.20],[1438020611000,31.20],[1438021219000,31.10].... 
Кто-то сталкивался с таким? Может есть модифицированный сценарий?
Простите, вопрос снимается. Все-таки это была ошибка в данных истории.

Re: Строим графики Highstock

Добавлено: Вт авг 04, 2015 9:19 am
Urbas81
xxc писал(а):
Urbas81 писал(а): На код бы взглянуть :? :mrgreen:
На "чистоту" кода не претендую - писался в торопях.
Обновление работает. Но вот с разрывами в графике - например датчик завис или нет связи - пока не разобрался - не хватает времени.
Спасибо. Сначала подумал что речь идет про автоматическое обновление там, где выведено несколько графиков на одном поле.

Re: Строим графики Highstock

Добавлено: Пт сен 25, 2015 9:11 am
Fav0rit
Только недавно натыкался на эту библиотеку с графиками и хотел их прикрутить к умному дому, а оказалось все уже давно прикручено,, работает и есть готовые примеры, это просто замечательно.
Огромнейшее спасибо за проделанную работу, все очень круто.

И, пожалуй, внесу свои 5 копеек.
Мне очень понравилась возможность в некоторых графиках отображать сразу две и более осей, это может быть полезно, когда мы хотим отобразить на одном графике, например, температуру и влажность в помещении. Приведу готовый пример своего графика, уверен, желающие разберутся.
В этом примере отображены четыре графика и две оси, причем графики температур на нечетных позициях, а графики влажности на четных в описании, это сделано для того, чтобы не мудрить в SeriesOptions с индивидуальным заданием оси yaxis, там просто вычисляется остаток от деления.
В классе осей y есть параметр "opposite: false/true" он как раз и показывает с какой стороны отображать ось. По умолчанию в библиотеке он false, он в MD true, поэтому сразу пример не заработал. opposite: true можно не писать, а false обязательно, но лучше писать и там и там, тогда при обновлениях точно ничего не слетит.
СпойлерПоказать
<script type="text/javascript" src="../../highcharts/js/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="../../highcharts/js/highstock.js"></script>
<script type="text/javascript">

$(function () {
var seriesOptions = [],
obsss = 0,
seriesCounter = 0,
timeback = 0,
names = ['температура в зале','влажность в зале','температура на улице','влажность на улице'],
sensornames = ['LivingRoom.Temperature',
'LivingRoom.Humidity',
'Weather.Temperature',
'Weather.Humidity'
];

Highcharts.setOptions({
lang: {
months: ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль',
'Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],

shortMonths: ['Янв','Фев','Мар','Апр','Май','Июн','Июл',
'Авг','Сен','Окт','Ноя','Дек'],

weekdays: ['Вск','Пнд','Втр','Срд','Чтв','Птн','Сбт'],

rangeSelectorZoom: 'Маcштаб',
rangeSelectorFrom: 'От',
rangeSelectorTo: 'До',
thousandsSep: ' '
},
global: {
useUTC: false
}
});


// create the chart when all data is loaded
createChart = function () {
$('#container').highcharts('StockChart', {
rangeSelector: {
buttons: [{ type: 'hour', count: 1, text: '1h' },
{ type: 'day', count: 1, text: '1d' },
{ type: 'day', count: 2, text: '2d' },
{ type: 'week', count: 1, text: '1w' },
{ type: 'month', count: 1, text: '1m' },
{ type: 'month', count: 6, text: '6m' },
{ type: 'year', count: 1, text: '1y' },
{ type: 'all', text: 'All' }],
selected: 1 // Какая кнопка выбрана по умолчанию
},

title: { text : 'График температуры и влажности'},
legend: { enabled : true,
layout : 'horizontal',
align : 'center',
verticalAlign : 'top',
borderWidth: 0,
x : 0,
y : 20 },

xAxis : {
minRange: 3600 * 1000, // one hour
crosshair: true
},

yAxis: [{ // Primary yAxis
labels: {
format: '{value}°C',
style: {
color: Highcharts.getOptions().colors[1]
}
},
title: {
text: 'Temperature',
style: {
color: Highcharts.getOptions().colors[1]
}
},
opposite: false
}, { // Secondary yAxis
title: {
text: 'Humidity',
style: {
color: Highcharts.getOptions().colors[0]
}
},
labels: {
format: '{value} %',
style: {
color: Highcharts.getOptions().colors[0]
}
},
opposite: true
}],

$.each(names, function (i, name) {
$.getJSON('/objects/?script=jconhs&name='+sensornames+'&callback=?', function (data) {

seriesOptions = {
name: name,
data: data,
yAxis: (i%2),
type: 'spline'
};

// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter += 1;

if (seriesCounter === names.length) {
createChart();
}
});
});

});



</script>

<div id="container" style="height: 600px; min-width: 500px"></div>

Re: Строим графики Highstock

Добавлено: Пн сен 28, 2015 12:18 am
Fav0rit
Вот проблемка есть, которую я все никак не могу победить изменением параметров отрисовки, видимо как-то связано именно с JSON, с которым я работать не умею. Данные с датчиков приходят с различными интервалами, использую MySensor, система часто опрашивает гейт, поэтому повторные сведения не пишет, поэтому на графиках видны только параметры в момент изменения значения, из-за чего график представляет из себя гармошку, а ось времени, как её ни настраивай, нифига не линейная, что жутко раздражает и убивает всю идею. Примеры графиков с сайта с конфигами для непериодических данных работать не хотят, в отрисовке ничего не меняется, как я ни пытаюсь...

Re: Строим графики Highstock

Добавлено: Вт сен 29, 2015 1:13 pm
Fav0rit
Более менее разобрался я с этими графиками, однако не уверен, что сказанное мною ниже на 100% верно, если кто-то исправит, я буду только рад.
В библиотеке есть несколько типов графиков, а именно Highcharts, Highstock, Highmaps. Последний тип нас не интересует, там только карты, а вот первые два очень даже ничего, как функционально, так и внешне.
Самый удобный и симпатичный из этих трех Highstock, однако с его использованием есть некоторые заморочки.
Первая и самая главная из них - кривое представление не периодичных данных. Например, данные с температурного графика в комнате пишутся в лог каждую минуту, а веб-переменная с температурой на улице обновляется раз в час. В итоге может получиться такая неприятность, что при частом изменении температуры в комнате час на графике будет сильно растянут, а в случае отсутствия изменений в параметрах длинный отрезок времени может отображаться как очень короткий. При отрисовке нескольких графиков на одном поле это особенно заметно. Какими-то параметрами и функциями самой библиотеки лично мне решить эту проблему не удалось.
Стоит заметить, что в модуле Highcrarts те же самые данные отображаются абсолютно правильно, шкала времени строго линейна, но в нем не так удобно реализовано масштабирование и выборка данных за отдельный период времени.
Для использования модуля Highstock предлагаю следующий костыль, как одно из возможных решений.
Чтобы не периодичные данные данные стали периодичными, можно создать отдельный класс, например, Graphics создать в нем объекты с названиями вида GraphsLivingroom, GraphsKitchen, GraphsPowermeter1 и, тому подобными. Для класса создать полный набор всевозможных логгируемых свойств. В списке сценариев создать сценарий заполнения соответствующих свойств объектов класса Graphs из свойств реальных объектов и ежеминутно запускать этот скрипт. В итоге, все свойства объектов нового класса будут заполняться одновременно с равными интервалами, без разрывов и.т.п. График Highstock будет строиться правильно. Минусом являются дополнительные телодвижения и увеличение базы данных, потому что в ней будут храниться ежеминутные (хотя можно обновлять значения и каждые 5, 10 минут и.т.д.) записи о данных, которые могут обновляться раз в час, плюс само по себе такое дублирование не самый красивый выход.
Если кто-то покажет нормально работающий Highstock с правильной отрисовкой данных различной периодичности, я буду просто счастлив.
Пока выход либо использование Highcharts, либо костыль в Highstock.

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

Re: Строим графики Highstock

Добавлено: Чт окт 08, 2015 12:36 pm
zelevova
Fav0rit писал(а):UPD: оказывается, костыль не работает. Ни в какую не хочет писать в историю одинаковые значения каждую минуту. Я в полной растерянности...
Это не баг а фитча. ;)
Свойство записывает первое и последнее значение уникального значения. Больше 2 подряд одинаковых значений быть не может. Это сделано для оптимизации хранения данных в БД.