{% load static %} {% if code == "js_includes" %} {% elif code == "html" %}
{% if not fullscreen %}
{% if timeskip == "1" %} {% endif %}
{% if download == "1" %}
{% endif %}
 
{% endif %}
 
{% if fullscreen %}
{% endif %} {% for tag in tags %} {% endfor %} {% for color in colors %} {% endfor %} {% for legendlabel in legendlabels %} {% endfor %}
{% elif code == "tag_update_func" %} let updateLegendTimeout = null; let latestPosition = null; let timeplots = []; let previousPoint = null; function showTooltip(x, y, contents) { $('
' + contents + '
').css({ position: 'absolute', display: 'none', top: y + 5, left: x + 5, border: '1px solid #fdd', padding: '2px', 'background-color': '#fee', opacity: 0.80 }).appendTo("body").fadeIn(200); } function calc_timeplot_resolution(id, period, month, year) { switch(period) { case "quarter": return 6; case "hour": return 6; case "day": return 24 case "month": return daysInMonth(month, year); case "year": return 12; } } function daysInMonth(iMonth, iYear) { return 32 - new Date(iYear, iMonth - 1, 32).getDate(); } function daysInYear(iYear) { return new Date(iYear, 1, 29).getDate() === 29 ? 366 : 365; } function zeropad(value) { return value < 10 ? "0" + value.toString() : value.toString(); } function UpdateTimeplot(id, spancnt) { $("#" + id + " .loading").show(); let prop = GetObjectProperties(id); {% if fullscreen %} let period = window.opener.jQuery("#{{ timeplot_id }} .period").val(); let spancount = window.opener.jQuery("#{{ timeplot_id }} .spancount").val(); let quarter = parseInt(window.opener.jQuery("#{{ timeplot_id }} .quarter").val()); let hour = parseInt(window.opener.jQuery("#{{ timeplot_id }} .hour").val()); let day = window.opener.jQuery("#{{ timeplot_id }} .day").val(); let month = parseInt(window.opener.jQuery("#{{ timeplot_id }} .month").val()); let year = parseInt(window.opener.jQuery("#{{ timeplot_id }} .year").val()); let cumulative = window.opener.jQuery("#{{ timeplot_id }} [name='cumulative']").val(); let resolution = window.opener.jQuery("#{{ timeplot_id }} [name='resolution']").val(); {% else %} let period = $("#" + id + " .period").val(); let spancount = isNaN(spancnt) ? parseInt($("#" + id + " .spancount").val()) : null; let quarter = parseInt($("#" + id + " .quarter").val()); let hour = parseInt($("#" + id + " .hour").val()); let day = parseInt($("#" + id + " .day").val()); let month = parseInt($("#" + id + " .month").val()); let year = parseInt($("#" + id + " .year").val()); let cumulative = prop["cumulative"]; let resolution = prop["resolution"]; {% endif %} if (resolution === undefined) { return; } if (resolution.length === 0) { resolution = calc_timeplot_resolution(id, period, month, year); } const start = year + ":" + month + ":" + day + ":" + hour + ":" + (quarter * 15); let req = []; const decimals = parseInt(prop["decimals"]); const tag_count = parseInt(prop["tag_count"]); for (let i = 0; i < tag_count; i++) { let params = []; params.push("i=" + i); params.push("t=" + prop["tag_" + i]); params.push("p=" + period); params.push("s=" + start); params.push("sc=" + spancount); params.push("cum=" + cumulative); params.push("res=" + resolution); const re = new RegExp(".*/(\\d+)/?$"); const match = re.exec(window.location.pathname); const plant_homepage = match[1]; params.push("page="+ plant_homepage); req.push(params.join(",")); } $.get( "/service/get_timeplot_data/" + req.join(";") + "/?rand=" + new Date().getTime(), function(data) { let series_data = []; let bar_width = 1; data = data.split("\n"); for (let i = 0; i < data.length; i++) { let d; let series_label = ""; if (data[i].length !== 0) { try { d = JSON.parse(data[i]); } catch (err) { d = []; } } else { d = []; } if (cumulative === "1") { let last_value = d.length > 0 ? (d[d.length - 1][1] / Math.pow(10, decimals)).toFixed(decimals) : "?"; series_label = ( prop["legendlabel_" + i] != null && prop["legendlabel_" + i].length > 0 ? prop["legendlabel_" + i] : prop["tag_" + i] ) + " = " + last_value; } else { let last_value = d.length > 0 ? (d[d.length - 1][1] / Math.pow(10, decimals)).toFixed(decimals) : "?"; series_label = ( prop["legendlabel_" + i] != null && prop["legendlabel_" + i].length > 0 ? prop["legendlabel_" + i] : prop["tag_" + i] ) + " = " + last_value; } const color = prop["color_" + i] != null && prop["color_" + i].length !== 0 ? prop["color_" + i] : null; if (decimals !== 0) { for (let n = 0; n < d.length; n++) { d[n][1] = d[n][1] / Math.pow(10, decimals); } } series_data.push({ color: color, data: d, label: series_label }); } let ticks = []; let markings = []; let show_points = false; let x_min = 0; let x_max = 0; let y_min = isNaN(parseInt(prop["min"])) ? null : prop["min"]; let y_max = isNaN(parseInt(prop["max"])) ? null : prop["max"]; {# generates labels for x axis aka ticks #} switch(period) { {# minutes in quarter #} case "quarter": for (let q = 0; q <= spancount; q++) { if (spancount <= 2) { for (let m = 0; m <= 15; m += 1) { const hh = parseInt(hour + q * .25 + quarter * .25) % 24; const mm = (m + q * 15 + quarter * 15) % 60; ticks.push([q * 15 + m, zeropad(hh) + ":" + zeropad(mm)]); } } else if (spancount == 4) { for (let m = 0; m <= 60; m += 1) { const hh = parseInt(hour + parseInt((m + q * 15 + quarter * 15) / 60) + q * 0.25) % 24; const mm = (m + q * 15 + quarter * 15) % 60; ticks.push([q * 15 + m, zeropad(hh) + ":" + zeropad(mm)]); } } else if (spancount < 96) { const hh = parseInt(hour + q * .25 + quarter * .25) % 24; const mm = (q * 15 + quarter * 15) % 60; ticks.push([q * 15, zeropad(hh) + ":" + zeropad(mm)]); } else { if (q % 4 === 0) { const hh = parseInt(hour + q * .25 + quarter * 0.25) % 24; const mm = (q * 15 + quarter * 15) % 60; ticks.push([q * 15, zeropad(hh) + ":" + zeropad(mm)]); } } } show_points = true; x_max = 15 * spancount; break; {# minutes in hour #} case "hour": for (let h = 0; h < spancount; h++) { if (spancount < 10) { let min_inc = spancount < 4 ? 10 : 30; for (let m = 0; m < 60; m += min_inc) { ticks.push([h * 60 + m, zeropad((hour + h) % 24) + ":" + zeropad(m)]); } if (h === spancount - 1) { ticks.push([(h + 1) * 60, zeropad((hour + h + 1) % 24) + ":00"]); } } else { ticks.push([h * 60, zeropad((hour + h) % 24) + ":00"]); if (h === spancount - 1) { ticks.push([(h + 1) * 60, zeropad((hour + h + 1) % 24) + ":00"]); } } } show_points = true; x_max = 60 * spancount; break; {# hours in day #} case "day": const h_inc = [1, 2, 2, 4, 4, 6, 6]; for (let h = 0; h <= spancount * 24; h += h_inc[spancount - 1]) { ticks.push([h, zeropad(h % 24)]); } x_max = 24 * spancount; break; {# days in month #} case "month": let days_ofs = 0; const m_inc = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10]; let x_ticks = []; for (let m = 0; m < spancount; m++) { const mm = (month + m) % 12; const yy = year + Math.floor((month + m) / 12); for (let i = 1; i <= daysInMonth(mm, yy); i++) { x_ticks.push([days_ofs + i, i.toString()]); // 3 PORT/KREM: BUGFIX 1.1.4a } days_ofs += daysInMonth(mm, yy); } for (let i = 0; i + m_inc[spancount - 1] <= x_ticks.length; i += m_inc[spancount - 1]) { ticks.push(x_ticks[i]); } ticks.push([days_ofs + 1, "1"]); // 3 PORT/KREM: BUGFIX 1.1.4a x_min = 1; x_max = days_ofs + 1; break; {# months in year #} case "year": const y_inc = [1, 1, 1, 1, 1, 1, 1]; let days_cnt = 0; for (let y = 0; y < spancount; y++) { let y_days_cnt = 0; for (let m = 0; m < 12; m += y_inc[spancount - 1]) { ticks.push([(days_cnt + y_days_cnt) / 10.0, (m + 1).toString()]); {# 3 PORT/KREM: BUGFIX 1.1.4a #} y_days_cnt += daysInMonth(m + 1, year + y); } days_cnt += daysInYear(year + y) ticks.push([days_cnt / 10.0, "1"]); // 3 PORT/KREM: BUGFIX 1.1.4a } x_min = 0; x_max = days_cnt / 10.0; break; } {# calculate bar width for cumulative graph #} if (cumulative === "1") { try { bar_width = x_max / spancount / resolution / tag_count * 0.8; } catch(err) { bar_width = 1; } if (series_data.length > 1) { for (var i = 1; i < series_data.length; i++) { for (var j = 0; j < series_data[i].data.length; j++) series_data[i].data[j][0] += bar_width; } } } let series_options = {}; switch (prop["graphstyle"]) { case "bars": series_options = { bars: { show: true, align: "left", barWidth: bar_width } }; break; default: series_options = { lines: { show: true }, points: { show: show_points } }; break; } timeplots[id] = $.plot( $("#" + id + " .graph"), series_data, { series: series_options, crosshair: { mode: "x", color: "#AA000060", lineWidth: 2 }, xaxis: { ticks: ticks, min: x_min, max: x_max, autoScale: "none" }, yaxis: { ticks: 10, min: y_min, max: y_max }, grid: { show: true, backgroundColor: { colors: ["#FFFFFF", "#E4E4E4"] }, markings: markings, clickable: false, hoverable: true, autoHighlight: false }, legend: { show: GetObjectProperties(id)["tag_0"].length !== 0 && GetObjectProperties(id)["showlegend"] === "true", labelFormatter: function(label, series) { let legendunit = prop["legendunit"]; if (legendunit != null && legendunit.length > 0) { return label + " " + legendunit; } return label; }, position: "ne", backgroundColor: '#FFFFFFD8', backgroundOpacity: 0 } } ); $("#" + id + " .legendLayer").css('background', '#FFFFFFD8'); $("#" + id + " .background").attr('fill-opacity', '0'); $("#" + id + " .graph").bind("plothover", function(event, pos, item) { if (!updateLegendTimeout) { updateLegendTimeout = setTimeout( function () { const plot = timeplots[id]; updateLegendTimeout = null; const 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; } let dataset = plot.getData(); for (let i = 0; i < dataset.length; ++i) { let series = dataset[i]; // find the nearest points, x-wise let j = 0; for (j = 0; j < series.data.length; ++j) { if (series.data[j][0] > pos.x) { break; } } // now interpolate let y; let p1 = series.data[j - 1]; let p2 = series.data[j]; if (p1 == null && p2 == null) { //return; continue; } if (p1 == null) { y = p2[1]; } else if (p2 == null) { y = p1[1]; } else { y = p1[1] + (p2[1] - p1[1]) * (pos.x - p1[0]) / (p2[0] - p1[0]); } $("#" + id + " .legendLayer > g > text > tspan").eq(i).text( series.label.replace(/=.*/, "= " + y.toFixed(decimals) + (prop["legendunit"] != null && prop["legendunit"].length > 0 ? " " + prop["legendunit"] : "")) ); } }, 50 ); } if (show_points && item) { if (previousPoint !== item.datapoint) { previousPoint = item.datapoint; $("#tooltip").remove(); let x = item.datapoint[0].toFixed(decimals); let y = item.datapoint[1].toFixed(decimals); showTooltip(item.pageX, item.pageY, item.series.label.replace(/=.*/, "= " + y)); } } else { $("#tooltip").remove(); previousPoint = null; } }); $("#" + id + " .loading").hide(); } ); } function UpdateTimeplotCmdVisibility(id) { let value = $("#" + id + " .period").val(); $("#" + id + " .quarter").hide(); $("#" + id + " .hour").hide(); $("#" + id + " .day").hide(); $("#" + id + " .month").hide(); switch(value) { case "quarter": $("#" + id + " .quarter").show(); $("#" + id + " .hour").show(); $("#" + id + " .day").show(); $("#" + id + " .month").show(); break; case "hour": $("#" + id + " .hour").show(); $("#" + id + " .day").show(); $("#" + id + " .month").show(); break; case "day": $("#" + id + " .day").show(); $("#" + id + " .month").show(); break; case "month": $("#" + id + " .month").show(); break; } } function UpdateSpanCountCombo(id) { const period = $("#" + id + " .period").val(); const min = 1; let max = 1; let html = ""; const prop = GetObjectProperties(id); let values = []; switch(period) { case "quarter": max = 7; values = [1, 2, 4, 8, 24, 48, 96]; break; case "hour": max = 6; values = [1, 2, 6, 12, 24, 48]; break; case "day": max = 7; break; case "month": max = 12; break; case "year": max = 40; break; } let sel_default = prop["initialized"] === 0 ? prop["spancount"] : 1; if (values.length === 0) { values = [...Array(max).keys()].map(i => i + min); } for (let i = 0; i <= max - min; i++) { let val = values[i]; let sel = val === sel_default ? ' selected="selected"' : ''; html += ''; } {# first erase to avoid unusual number jumping #} $("#" + id + " .spancount").html("").html(html); return sel_default; } function ChangeTimeplotDate(id, increment) { const period = $("#" + id + " .period").val(); const hour = parseInt($("#" + id + " .hour").val()); const quarter = parseInt($("#" + id + " .quarter").val()); let day = parseInt($("#" + id + " .day").val()); let month = parseInt($("#" + id + " .month").val()); let year = parseInt($("#" + id + " .year").val()); let date = new Date(year, month - 1, day, hour, 0, 0, 0); switch(period) { case "quarter": const i = (quarter + increment) * 15; date = new Date(year, month - 1, day, hour + parseInt(i / 60), i % 60, 0, 0); break; case "hour": date = new Date(year, month - 1, day, hour + increment, 0, 0, 0); break; case "day": date.setDate(date.getDate() + increment); break; case "month": date = new Date(year, month - 1 + increment, day, hour, 0, 0, 0); break; case "year": date = new Date(year + increment, month - 1, day, hour, 0, 0, 0); break; } day = date.getDate(); month = date.getMonth() + 1; year = date.getFullYear(); const year_exists = $(".period_selection .year option[value='" + year + "']").val() != null; if (year_exists) { const days_in_month = daysInMonth(month, year); if (days_in_month !== $("#" + id + " .day option").length) { let html = ""; for (let n = 1; n <= daysInMonth(month, year); n++) { html += ''; } $("#" + id + " .day").html(html); } $("#" + id + " .quarter").val(parseInt(date.getMinutes() / 15)); $("#" + id + " .hour").val(date.getHours()); $("#" + id + " .day").val(day); $("#" + id + " .month").val(month); $("#" + id + " .year").val(year); return true; } return false; } function ChangeNumberOfDaysInMonth(id) { ChangeTimeplotDate(id, 0); } function UpdateTimeplotTrigger(id) { if (ChangeTimeplotDate(id, 0)) { UpdateTimeplot(id); } } {% elif code == "page_load_init" %} UpdateTimeplotCmdVisibility("{{ id }}"); UpdateSpanCountCombo("{{ id }}"); UpdateTimeplot("{{ id }}"); $("#{{ id }} [name='initialized']").val("1"); {% elif code == "init_jq_binding" %} $(".cybro_{{ type }} .timeplot_trigger").change(function() { const id = $(this).parent().parent().parent().attr("id"); UpdateTimeplotTrigger(id); }); $(".cybro_{{ type }} .period").change(function() { const id = $(this).parent().parent().parent().attr("id"); UpdateSpanCountCombo(id); UpdateTimeplotCmdVisibility(id); UpdateTimeplotTrigger(id); }); $(".cybro_{{ type }} .month").change(function() { const id = $(this).parent().parent().parent().attr("id"); ChangeNumberOfDaysInMonth(id); UpdateTimeplotTrigger(id); }); $(".cybro_{{ type }} .next").click(function() { const id = $(this).parent().parent().parent().attr("id"); if (ChangeTimeplotDate(id, 1)) { UpdateTimeplot(id); } return false; }); $(".cybro_{{ type }} .prev").click(function() { const id = $(this).parent().parent().parent().attr("id"); if (ChangeTimeplotDate(id, -1)) { UpdateTimeplot(id); } return false; }); $(".cybro_{{ type }} .now").click(function() { const id = $(this).parent().parent().parent().attr("id"); const spancount = parseInt($("#" + id + " .spancount").val()); const now = new Date(); $("#" + id + " .hour").val(now.getHours()); $("#" + id + " .day").val(now.getDate()); $("#" + id + " .month").val(now.getMonth() + 1); $("#" + id + " .year").val(now.getFullYear()); if (ChangeTimeplotDate(id, -(spancount - 1))) { UpdateTimeplot(id); } return false; }); $(".cybro_{{ type }} .download_csv_data").click(function() { const id = $(this).parent().parent().parent().attr("id"); const prop = GetObjectProperties(id); const period = $("#" + id + " .period").val(); const hour = $("#" + id + " .hour").val(); const day = $("#" + id + " .day").val(); const month = $("#" + id + " .month").val(); const year = $("#" + id + " .year").val(); const start = year + ":" + month + ":" + day + ":" + hour; const cumulative = prop["cumulative"]; let resolution = prop["resolution"]; const spancount = $("#" + id + " .spancount").val(); if (resolution.length === 0) { resolution = calc_timeplot_resolution(id, period, month, year); } let params = []; let tags = []; for (let i = 0; i < parseInt(prop["tag_count"]); i++) { tags.push(prop["tag_" + i]); } params.push("t=" + tags.join("+")); params.push("p=" + period); params.push("s=" + start); params.push("sc=" + spancount); params.push("cum=" + cumulative); params.push("res=" + resolution); params.push("dec=" + prop["decimals"]); const re = new RegExp(".*/(\\d+)/?$"); const match = re.exec(window.location.pathname); const plant_homepage = match[1]; params.push("page="+ plant_homepage); window.location = "/service/download_timeplot_data/" + params.join(",") + "/?rand=" + new Date().getTime(); return false; }); $(".cybro_{{ type }} .timeplot_fullscreen").click(function() { const container = $(this).parents(".cybro_{{ type }}"); const id = $(container).attr("id"); const prop = GetObjectProperties(id); let args = []; let tags = []; let colors = []; let legend_labels = []; var myWin; for (let i = 0; i < parseInt(prop["tag_count"]); i++) { tags.push(prop["tag_" + i]); } for (let i = 0; i < parseInt(prop["tag_count"]); i++) { if (prop["color_" + i].length !== 0) { colors.push(prop["color_" + i]); } } for (let i = 0; i < parseInt(prop["tag_count"]); i++) { if (prop["legendlabel_" + i] != null && prop["legendlabel_" + i].length !== 0) { legend_labels.push(prop["legendlabel_" + i]); } } colors = colors.join(","); if (colors.length === 0) { colors = "-"; } legend_labels = legend_labels.join(","); if (legend_labels.length === 0) { legend_labels = "-"; } const re = new RegExp(".*/(\\d+)/?$"); const match = re.exec(window.location.pathname); const plant_homepage = match[1]; args.push(id); args.push(prop["graphstyle"]); args.push(tags.join(",")); args.push(prop["min"]); args.push(prop["max"]); args.push(escape(colors)); args.push(prop["decimals"]); args.push(encodeURIComponent(legend_labels)); args.push(prop["legendunit"] != null && prop["legendunit"].length > 0 ? prop["legendunit"] : "-"); args.push(prop["showlegend"]); args.push(plant_homepage); let w = 800; let h = 600; if (window.screen) { w = window.screen.availWidth; h = window.screen.availHeight; } window.open("/timeplot/" + args.join("/") + "/", "myWin", "resizable,width=" + w + ",height=" + h + ",top=0,left=0"); return false; }); {% endif %}