WINNUM Community
График работы оборудования - Версия для печати

+- WINNUM Community (https://community.winnum.io)
+-- Сообщество Все сообщества (https://community.winnum.io/forumdisplay.php?fid=1)
+--- Сообщество Динамические приложения в WINNUM Platform (https://community.winnum.io/forumdisplay.php?fid=2)
+--- Темы: График работы оборудования (/showthread.php?tid=32)



График работы оборудования - Lamantur - 02-20-2025

Добрый день, уважаемые коллеги!
Сегодня мы будем делать график загрузки оборудования полностью своими руками:
   

К этому графику можно добавить временную шкалу и сделать его полноценным отчетом.

У данного метода есть как преимущества, так и недостатки.
Главное преимущество - это точность расположения элементов. Кроме того самостоятельное рисование  позволяет создать абсолютно любой график с любыми временными промежутками и отрезками, варьировать размеры и цвета, а так же дает понимание того как этот график строится.

Недостаток в том, что все погрешности измерений, если они предусмотрены - видны на таком графике, т.к. он привязывается ко временным отрезкам, а не относительным величинам, можно увидеть небольшие изменения тегов, в 1 пиксель, из-за чего будут сливаться цвета.
В этой функции мы используем  " getPriorityTagDuration " для получения всех временных отрезков тегов исходя из их приоритетности. 
В результате мы получаем временные коды в миллисекундах, что дает возможность пересчитать местоположение и ширину закрашенной области. Для подсказки при наведении используем <title> в svg. Кроме того график можно обрезать и растягивать, если нужно разбить его на несколько смен, или сделать подробный график - как в стандартном приложении, для этого не нужно вызывать функцию для каждого часа. она не даст более точный результат, промежутка может быть не видно на графике, только потому, что он меньше пикселя шириной.
Ниже код функции и пример ее вызова:
appid - id приложения, можно увидеть в адресной строке
id - id html элемента, куда вставлять график
from - время от - указывается в закодированном виде, можно использовать baseSdkUtils.encode("20.02.2025 00:00:00");
to - baseSdkUtils.encode("20.02.2025 23:00:00");
product - id продукта, т.е. станка - oid - в карточке станка в адресной строке - "WNProduct"

Код:
/********************************* Процесс рисования графика **************************************/
// createBarCart( 'winnum.org.app.WNApplicationInstance:10', 'E8857FA3-F16B-423A-B043-2A353BDFE480', '19.02.2025%2019%3A30%3A00', '20.02.2025%2007%3A30%3A00', 'winnum.org.product.WNProduct:80' );

function createBarCart(appid, id, from, to, product){
var fromYMDformat = from.split("%")[0].split(".")[2] + "-" + from.split("%")[0].split(".")[1] + "-" + from.split("%")[0].split(".")[0];
var toYDMformat = to.split("%")[0].split(".")[2] + "-" + to.split("%")[0].split(".")[1] + "-" + to.split("%")[0].split(".")[0];
let yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
var dd = yesterday.getDate();
var mm = yesterday.getMonth() + 1;
var yyyy = yesterday.getFullYear();
if(dd<10){ dd = "0" + dd;}
if(mm<10){ mm = "0" + mm;}
var thisday = dd+"."+mm+"."+yyyy;

var today = new Date();
var td=today.getDate();
var tm = today.getMonth() + 1;
var ty = today.getFullYear();
var todaydmy = ty+"-"+tm+"-"+td;
var realtoday = td+"."+tm+"."+ty;
var yesterdaydmy = thisday.split('.')[2] + "-" + thisday.split('.')[1] + "-" + thisday.split('.')[0];

var startOfDayY = new Date(baseSdkUtils.decode(from).split(".")[2].split(" ")[0], baseSdkUtils.decode(from).split(".")[1] - 1, baseSdkUtils.decode(from).split(".")[0], baseSdkUtils.decode(from).split(" ")[1].split(":")[0], baseSdkUtils.decode(from).split(" ")[1].split(":")[1], baseSdkUtils.decode(from).split(" ")[1].split(":")[2]);
var startOfDayMs = Number(startOfDayY.getTime());

var endtOfDayY = new Date(baseSdkUtils.decode(to));
var endOfDayMs = endtOfDayY.getTime();
var arrayForDraw = [];
var tagColorSet = {};

baseSdkUtils.service.WNApplicationHelper.getTag(appid,function(data){
    for (var i = 0; i < data.getElementsByTagName('item').length; i++){
       var item = data.getElementsByTagName('item')[i];
       var tagDescription = baseSdkUtils.decode(item.getAttribute('tagName'));
       var tagColor = baseSdkUtils.decode(item.getAttribute('tagColor'));
       tagColorSet[tagDescription] = tagColor;
    }

    baseSdkUtils.service.WNApplicationTagHelper.getPriorityTagDuration(appid, product, fromYMDformat, toYDMformat, function(data){
        if ( baseSdkUtils.isSuccess(data) ){
            var str = '<svg viewBox="0 0 100 2">';
            for (var i = 0; i < data.getElementsByTagName('item').length; i++){
                var item = data.getElementsByTagName('item')[i];
                var timems = item.getAttribute('timeData');
                var tagName = baseSdkUtils.decode(item.getAttribute('TAG'));
                var startTime = baseSdkUtils.decode(item.getAttribute('START'));
                var endTime = baseSdkUtils.decode(item.getAttribute('END'));
                var now = new Date();
                var nowMs = now.getTime();
                            var x1 = (Number(timems.split(',')[0]) - startOfDayMs)/864000;
                            if(x1 < 0) x1 = 0;
                           
                            var x2 = (Number(timems.split(',')[1]) - startOfDayMs)/864000;
                            if( Number( timems.split(',')[1] ) >=  nowMs){
                                x2 = (nowMs - startOfDayMs)/864000;
                               
                            }
                            var start = baseSdkUtils.decode(item.getAttribute('START'));
                            var end = baseSdkUtils.decode(item.getAttribute('END'));
                            var serial = baseSdkUtils.decode(item.getAttribute('SERIAL_NUMBER'));
                            var duration = baseSdkUtils.decode(item.getAttribute('DURATION'));
                           
                            var colorTag = '#FFFFFF';
                           
                            for(var key in tagColorSet){
                               
                                if(tagName == key){
                               
                                    colorTag = tagColorSet[key];
                                }
                               
                            }
                           
                           if(x2 >= 0){
                                        str = str + '<polyline points="'+ x1 +',100 '+ x2 +',100 '+ x2 +',0 '+ x1 +',0" fill="'+ colorTag +'"><title>' + tagName +" "+ startTime.split(" ")[1].split(".")[0] +" - "+ endTime.split(" ")[1].split(".")[0] + '</title></polyline>';
                                }
            }
           
            str = str + "</svg>"
           
            document.getElementById(id).innerHTML = str;

           
        }
    });
});

}


Структура <SVG> дает возможность построить векторное изображение, а это значит, что вы можете увеличивать его, приближать или растянуть, качество при этом не упадет.
Вы можете задать свои цвета вместо конструкции  ColorTag, назначив их явно, тогда не придется искать их среди возможных тегов этого приложения, но они будут статичны.
График можно обновлять и сделать его онлайн. Cool
Huh В самом начале функции определяется множество переменных, это связано с необходимостью получения сегодняшнего и вчерашнего дня, чтобы можно было создавать график за текущую и предшествующую смены. Если вам не нужны привязки к текущим моментам, вы можете пользоваться  getPriorityTagDuration сразу, при том время в ней - начала и конца указывать с точностью до суток. Да такой график можно построить за 3 суток сразу. Но помните, что это не длительные отчеты - чем больше данных - тем дольше ждать ответа, а значит между вызовами нужны паузы.