mirror of https://github.com/lumapu/ahoy.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
377 lines
16 KiB
377 lines
16 KiB
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>{#NAV_HISTORY}</title>
|
|
{#HTML_HEADER}
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="format-detection" content="telephone=no">
|
|
|
|
</head>
|
|
|
|
<body>
|
|
{#HTML_NAV}
|
|
<div id="wrapper">
|
|
<div id="content">
|
|
<h3>{#TOTAL_POWER}</h3>
|
|
{#LAST} <span id="pwrNumValues"></span> {#VALUES}
|
|
<div class="chartDivContainer">
|
|
<div class="chartDiv" id="pwrChart"> </div>
|
|
<p>
|
|
{#LAST_VALUE}: <span id="pwrLast"></span> W.<br />
|
|
{#MAXIMUM}: <span id="pwrMax"></span> W.
|
|
{#UPDATED} <span id="pwrRefresh"></span> {#SECONDS}
|
|
</p>
|
|
</div>
|
|
<h3>{#TOTAL_POWER_DAY}</h3>
|
|
<div class="chartDivContainer">
|
|
<div class="chartDiv" id="pwrDayChart"> </div>
|
|
<p>
|
|
{#MAX_DAY}: <span id="pwrDayMaxDay"></span> W. <br />
|
|
{#UPDATED} <span id="pwrDayRefresh"></span> {#SECONDS}
|
|
</p>
|
|
</div>
|
|
|
|
<!--
|
|
<h3>{#TOTAL_YIELD_PER_DAY}</h3>
|
|
<div class="chartDivContainer">
|
|
<div class="chartDiv" id="ydChart"> </div>
|
|
<p>
|
|
{#MAXIMUM}: <span id="ydMax"></span> Wh<br />
|
|
</p>
|
|
</div>
|
|
|
|
<h4 style="margin-bottom:0px;">Insert data into Yield per day history</h4>
|
|
<fieldset style="padding: 1px;">
|
|
<legend class="des" style="margin-top: 0px;">Insert data (*.json) i.e. from a saved "/api/yieldDayHistory" call
|
|
</legend>
|
|
<form id="form" method="POST" action="/api/addYDHist" enctype="multipart/form-data"
|
|
accept-charset="utf-8">
|
|
<input type="button" class="btn my-4" style="padding: 3px;margin: 3px;" value="Insert" onclick="submit()">
|
|
<input type="file" name="insert" style="width: 80%;">
|
|
</form>
|
|
</fieldset>
|
|
-->
|
|
</div>
|
|
</div>
|
|
{#HTML_FOOTER}
|
|
|
|
<script type="text/javascript">
|
|
var powerHistObj = null;
|
|
var powerHistDayObj = null;
|
|
var ydHistObj = null;
|
|
|
|
|
|
|
|
Number.prototype.pad = function (size) {
|
|
var s = String(this);
|
|
while (s.length < (size || 2)) { s = "0" + s; }
|
|
return s;
|
|
}
|
|
|
|
class powChart {
|
|
static objcnt = 0; // to give each object elemets a unique name prefix
|
|
|
|
constructor(namePrefix) {
|
|
// configurable vars
|
|
this.mChartHight = 250;
|
|
this.datapoints = 256;
|
|
this.xGridDist = 50;
|
|
this.yGridDist = 100;
|
|
// info vars
|
|
this.maxValue = 0;
|
|
this.mLastValue = 0;
|
|
// intern vars
|
|
this.svg = null;
|
|
this.refreshIntervall = 30; // seconds
|
|
this.lastValueTs = 0; // Timestmp of last value
|
|
|
|
++this.objcnt;
|
|
if (namePrefix === undefined)
|
|
this.namePrefix = "powChart" + this.objcnt;
|
|
else
|
|
this.namePrefix = namePrefix;
|
|
}
|
|
|
|
init(numDatapoints) {
|
|
this.datapoints = numDatapoints;
|
|
// generate svg
|
|
const svgns = "http://www.w3.org/2000/svg";
|
|
this.svg = document.createElementNS(svgns, "svg");
|
|
this.svg.setAttribute("class", "container");
|
|
this.svg.setAttribute("id", this.namePrefix + "_svg");
|
|
this.svg.setAttribute("viewBox", "0 0 " + String(this.datapoints * 2 + 50) + " " + String(this.mChartHight + 20));
|
|
this.svg.setAttribute("width", "100%");
|
|
this.svg.setAttribute("height", "100%");
|
|
// Gradient Line
|
|
let defLgLine = document.createElementNS(svgns, "defs");
|
|
{
|
|
let lg = document.createElementNS(svgns, "linearGradient")
|
|
lg.setAttribute("id", "verlVertLine");
|
|
lg.setAttribute("x1", "0%");
|
|
lg.setAttribute("y1", "0%");
|
|
lg.setAttribute("x2", "0%");
|
|
lg.setAttribute("y2", "100%");
|
|
let s1 = document.createElementNS(svgns, "stop")
|
|
s1.setAttribute("offset", "0%");
|
|
s1.setAttribute("stop-color", "blue");
|
|
let s2 = document.createElementNS(svgns, "stop")
|
|
s2.setAttribute("offset", "80%");
|
|
s2.setAttribute("stop-color", "#5050FF");
|
|
let s3 = document.createElementNS(svgns, "stop")
|
|
s3.setAttribute("offset", "100%");
|
|
s3.setAttribute("stop-color", "gray");
|
|
lg.appendChild(s1);
|
|
lg.appendChild(s2);
|
|
lg.appendChild(s3);
|
|
defLgLine.appendChild(lg);
|
|
}
|
|
this.svg.appendChild(defLgLine);
|
|
// Gradient Fill
|
|
let defLg = document.createElementNS(svgns, "defs");
|
|
{
|
|
let lg = document.createElementNS(svgns, "linearGradient")
|
|
lg.setAttribute("id", "verlVertFill");
|
|
lg.setAttribute("x1", "0%");
|
|
lg.setAttribute("y1", "0%");
|
|
lg.setAttribute("x2", "0%");
|
|
lg.setAttribute("y2", "100%");
|
|
let s1 = document.createElementNS(svgns, "stop")
|
|
s1.setAttribute("offset", "0%");
|
|
s1.setAttribute("stop-color", "#A0A0FF");
|
|
let s2 = document.createElementNS(svgns, "stop")
|
|
s2.setAttribute("offset", "50%");
|
|
s2.setAttribute("stop-color", "#C0C0FF");
|
|
let s3 = document.createElementNS(svgns, "stop")
|
|
s3.setAttribute("offset", "100%");
|
|
s3.setAttribute("stop-color", "#E0E0F0");
|
|
lg.appendChild(s1);
|
|
lg.appendChild(s2);
|
|
lg.appendChild(s3);
|
|
defLgLine.appendChild(lg);
|
|
}
|
|
this.svg.appendChild(defLg);
|
|
|
|
let chartFrame = document.createElementNS(svgns, "rect");
|
|
chartFrame.setAttribute("id", this.namePrefix + "_chartFrame");
|
|
chartFrame.setAttribute("class", "chartFrame");
|
|
chartFrame.setAttribute("x", "0");
|
|
chartFrame.setAttribute("y", "0");
|
|
chartFrame.setAttribute("width", String(this.datapoints * 2));
|
|
chartFrame.setAttribute("height", String(this.mChartHight));
|
|
this.svg.appendChild(chartFrame);
|
|
|
|
// Group chart content
|
|
let chartContent = document.createElementNS(svgns, "g");
|
|
chartContent.setAttribute("id", this.namePrefix + "_svgChartContent");
|
|
chartFrame.setAttribute("transform", "translate(29, 5)");
|
|
chartContent.setAttribute("transform", "translate(30, 5)");
|
|
|
|
// Graph values in a polyline
|
|
let poly = document.createElementNS(svgns, "polyline");
|
|
poly.setAttribute("id", this.namePrefix + "Poly");
|
|
poly.setAttribute("stroke", "url(#verlVertLine)");
|
|
poly.setAttribute("fill", "none");
|
|
chartContent.appendChild(poly);
|
|
// hidden polyline for fill
|
|
let polyFill = document.createElementNS(svgns, "polyline");
|
|
polyFill.setAttribute("id", this.namePrefix + "PolyFill");
|
|
polyFill.setAttribute("stroke", "none");
|
|
polyFill.setAttribute("fill", "url(#verlVertFill)");
|
|
chartContent.appendChild(polyFill);
|
|
|
|
// X-grid lines
|
|
let numXGridLines = (this.mChartHight / this.xGridDist);
|
|
for (let i = 0; i < numXGridLines; i++) {
|
|
let line = document.createElementNS(svgns, "line");
|
|
line.setAttribute("id", this.namePrefix + "XGrid" + i);
|
|
line.setAttribute("x1", String(0));
|
|
line.setAttribute("x2", String(this.datapoints * 2));
|
|
line.setAttribute("y1", String(this.mChartHight - (i + 1) * this.xGridDist));
|
|
line.setAttribute("y2", String(this.mChartHight - (i + 1) * this.xGridDist));
|
|
line.setAttribute("stroke-width", "1");
|
|
line.setAttribute("stroke-dasharray", "1,1");
|
|
line.setAttribute("stroke", "#A0A0A0");
|
|
chartContent.appendChild(line);
|
|
let text = document.createElementNS(svgns, "text");
|
|
text.setAttribute("id", this.namePrefix + "XGridText" + i);
|
|
text.setAttribute("x", "0");
|
|
text.setAttribute("y", String(this.mChartHight + 10 - (i + 1) * this.xGridDist));
|
|
text.innerHTML = (i + 1) * this.xGridDist;
|
|
this.svg.appendChild(text);
|
|
}
|
|
// Y-grid lines
|
|
let numYGridLines = (this.datapoints / this.yGridDist) * 2;
|
|
for (let i = numYGridLines; i > 0; i--) {
|
|
let line = document.createElementNS(svgns, "line");
|
|
line.setAttribute("id", this.namePrefix + "YGrid" + i);
|
|
line.setAttribute("x1", String((i) * this.yGridDist) - 1);
|
|
line.setAttribute("x2", String((i) * this.yGridDist) - 1);
|
|
line.setAttribute("y1", String(0));
|
|
line.setAttribute("y2", String(this.mChartHight));
|
|
line.setAttribute("stroke-width", "1");
|
|
line.setAttribute("stroke-dasharray", "1,3");
|
|
line.setAttribute("stroke", "#A0A0A0");
|
|
chartContent.appendChild(line);
|
|
let text = document.createElementNS(svgns, "text");
|
|
text.setAttribute("id", this.namePrefix + "YGridText" + i);
|
|
text.setAttribute("x", String((i) * this.yGridDist + 15));
|
|
text.setAttribute("y", String(this.mChartHight + 17));
|
|
text.innerHTML = "";
|
|
this.svg.appendChild(text);
|
|
}
|
|
//
|
|
this.svg.appendChild(chartContent);
|
|
};
|
|
|
|
getContainer() { return this.svg; };
|
|
|
|
setXScale(refreshIntervall, lastValueTs) {
|
|
this.refreshIntervall = refreshIntervall;
|
|
this.lastValueTs = lastValueTs;
|
|
}
|
|
|
|
update(values, maxVal) {
|
|
if (maxVal === undefined) {
|
|
this.maxValue = 0;
|
|
for (let val in values)
|
|
if (val > this.maxValue) this.maxValue = val;
|
|
}
|
|
else
|
|
this.maxValue = maxVal;
|
|
|
|
// normalize data to chart
|
|
let divider = this.maxValue / this.mChartHight;
|
|
if (divider == 0)
|
|
divider = 1;
|
|
|
|
let firstValPos = -1; // position of first value >0 W
|
|
let lastValPos = -1; // position of last value >0 W
|
|
let points = "";
|
|
for (let i = 0; i < this.datapoints; i++) {
|
|
let val = values[i];
|
|
if (val > 0) {
|
|
this.mLastValue = val;
|
|
lastValPos = i;
|
|
if (firstValPos < 0)
|
|
firstValPos = i;
|
|
val = val / divider;
|
|
points += ' ' + String(i * 2) + ',' + String(this.mChartHight - val);
|
|
}
|
|
}
|
|
let poly = document.getElementById(this.namePrefix + "Poly");
|
|
poly.setAttribute("points", points);
|
|
// "close" polyFill-line down to the x-axis
|
|
points += ' ' + +String(lastValPos * 2) + ',' + String(this.mChartHight);
|
|
points += ' ' + +String(firstValPos * 2) + ',' + String(this.mChartHight);
|
|
let polyFill = document.getElementById(this.namePrefix + "PolyFill");
|
|
polyFill.setAttribute("points", points);
|
|
|
|
// X-Grid lines
|
|
let numXGridLines = (this.mChartHight / this.xGridDist);
|
|
let dist = (this.maxValue / numXGridLines);
|
|
for (let i = 0; i < numXGridLines; i++) {
|
|
let tex = document.getElementById(this.namePrefix + "XGridText" + i);
|
|
tex.innerHTML = ((i + 1) * dist).toFixed(0);
|
|
}
|
|
|
|
// Y-Grid lines
|
|
if (isNaN(this.lastValueTs) || this.lastValueTs == 0)
|
|
this.lastValueTs = Date.now();
|
|
let date = new Date(this.lastValueTs);
|
|
let numYGridLines = (this.datapoints / this.yGridDist) * 2;
|
|
for (let i = numYGridLines; i > 0; i--) {
|
|
let tex = document.getElementById(this.namePrefix + "YGridText" + i);
|
|
if (this.refreshIntervall > 8600) // Display date
|
|
tex.innerHTML = date.getDate() + "." + (date.getMonth() + 1).pad(2);
|
|
else // Display time
|
|
tex.innerHTML = date.getHours() + ":" + date.getMinutes().pad(2);
|
|
date = new Date(date.getTime() - (this.refreshIntervall * (this.yGridDist / 2) * 1000));
|
|
}
|
|
};
|
|
}// class powChart
|
|
|
|
|
|
|
|
function parsePowerHistory(obj){
|
|
if (null != obj) {
|
|
let refresh = obj.refresh
|
|
let maximum = obj.max;
|
|
let addNextChart=false;
|
|
if (powerHistObj == null) {
|
|
powerHistObj = new powChart("ph");
|
|
powerHistObj.init(obj.value.length);
|
|
document.getElementById("pwrChart").appendChild(powerHistObj.getContainer());
|
|
// Regular update:
|
|
window.setInterval("getAjax('/api/powerHistory', parsePowerHistory)", refresh * 1000);
|
|
// one after the other
|
|
addNextChart=true;
|
|
}
|
|
powerHistObj.setXScale(refresh, obj.lastValueTs * 1000);
|
|
powerHistObj.update(obj.value, maximum);
|
|
|
|
document.getElementById("pwrLast").innerHTML = powerHistObj.mLastValue;
|
|
//document.getElementById("pwrMaxDay").innerHTML = obj.maxDay;
|
|
document.getElementById("pwrMax").innerHTML = maximum;
|
|
document.getElementById("pwrRefresh").innerHTML = refresh;
|
|
document.getElementById("pwrNumValues").innerHTML = obj.value.length;
|
|
if (addNextChart)
|
|
setTimeout(() => { getAjax("/api/powerHistoryDay", parsePowerHistoryDay); }, 50);
|
|
}
|
|
}
|
|
|
|
function parsePowerHistoryDay(obj) {
|
|
if (null != obj) {
|
|
let refresh = obj.refresh
|
|
if (refresh<30)
|
|
refresh = 30;
|
|
let maximum = obj.max;
|
|
let addNextChart = false;
|
|
if (powerHistDayObj == null) {
|
|
powerHistDayObj = new powChart("phDay");
|
|
powerHistDayObj.init(obj.value.length);
|
|
document.getElementById("pwrDayChart").appendChild(powerHistDayObj.getContainer());
|
|
// Regular update:
|
|
window.setInterval("getAjax('/api/powerHistoryDay', parsePowerHistoryDay)", refresh * 1000);
|
|
// one after the other
|
|
addNextChart = false; // if true: add YieldDayHistory
|
|
}
|
|
powerHistDayObj.setXScale(refresh, obj.lastValueTs * 1000);
|
|
powerHistDayObj.update(obj.value, maximum);
|
|
|
|
//document.getElementById("pwrDayLast").innerHTML = powerHistDayObj.mLastValue;
|
|
document.getElementById("pwrDayMaxDay").innerHTML = obj.maxDay;
|
|
//document.getElementById("pwrDayMax").innerHTML = maximum;
|
|
document.getElementById("pwrDayRefresh").innerHTML = refresh;
|
|
if (addNextChart)
|
|
setTimeout(() => { getAjax("/api/yieldDayHistory", parseYieldDayHistory); }, 50);
|
|
else
|
|
parseNav(obj.generic);
|
|
}
|
|
}
|
|
|
|
|
|
function parseYieldDayHistory(obj) {
|
|
if (null != obj) {
|
|
parseNav(obj.generic);
|
|
let refresh = obj.refresh
|
|
let maximum = obj.max;
|
|
let addNextChart = false;
|
|
if (ydHistObj == null) {
|
|
ydHistObj = new powChart("yd");
|
|
ydHistObj.init(obj.value.length);
|
|
document.getElementById("ydChart").appendChild(ydHistObj.getContainer());
|
|
// Regular update:
|
|
window.setInterval("getAjax('/api/yieldDayHistory', parseYieldDayHistory)", refresh * 500);
|
|
addNextChart = true;
|
|
}
|
|
ydHistObj.setXScale(refresh, obj.lastValueTs * 1000);
|
|
ydHistObj.update(obj.value, maximum);
|
|
|
|
document.getElementById("ydMax").innerHTML = maximum;
|
|
}
|
|
}
|
|
|
|
getAjax("/api/powerHistory", parsePowerHistory);
|
|
</script>
|
|
</body>
|
|
</html>
|
|
|