1
0
mirror of https://github.com/s00500/ESPUI.git synced 2024-11-23 16:00:54 +00:00

Graph Frontend work

- Adds graph js file
- Adds graph styles
This commit is contained in:
Lukas Bachschwell 2019-04-15 13:49:15 +02:00
parent 36cfe78205
commit bff259008f
9 changed files with 423 additions and 30 deletions

View File

@ -1014,3 +1014,47 @@ input::-moz-focus-inner,
input::-moz-focus-outer { input::-moz-focus-outer {
border: 0; border: 0;
} }
/* Styles for Graph widget */
svg {
display: block;
width: 100%;
height: 100%;
}
.y-axis path,
.x-axis path {
stroke: gray;
stroke-width: 1;
fill: none;
}
.series {
stroke: steelblue;
stroke-width: 3;
fill: none;
}
.data-points circle {
stroke: steelblue;
stroke-width: 2;
fill: white;
}
.data-points text {
display: none;
}
.data-points circle:hover {
fill: steelblue;
stroke-width: 6;
}
.data-points circle:hover + text {
display: inline-block;
}
text {
text-anchor: end;
}

File diff suppressed because one or more lines are too long

View File

@ -1,30 +1,35 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<head> <meta charset="utf-8" />
<meta charset="utf-8">
<title>Control</title> <title>Control</title>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC" <link
rel="shortcut icon"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC"
/> />
<link rel="stylesheet" href="/css/normalize.css"> <link rel="stylesheet" href="/css/normalize.css" />
<link rel="stylesheet" href="/css/style.css"> <link rel="stylesheet" href="/css/style.css" />
<script src="/js/zepto.min.js"></script> <script src="/js/zepto.min.js"></script>
<script src="/js/slider.js"></script> <script src="/js/slider.js"></script>
<script src="/js/graph.js"></script>
<script src="/js/controls.js"></script> <script src="/js/controls.js"></script>
<script src="/js/tabbedcontent.js"></script> <script src="/js/tabbedcontent.js"></script>
</head> </head>
<body onload="javascript:start();"> <body onload="javascript:start();">
<div> <div>
<h4><div id="mainHeader">Control</div> <span id="conStatus" class="label">Offline</span></h4></div> <h4>
<div id="mainHeader">Control</div>
<span id="conStatus" class="label">Offline</span>
</h4>
</div>
<hr /> <hr />
<div class="container"> <div class="container">
<div id="row" class="row u-full-width"></div> <div id="row" class="row u-full-width"></div>
<ul id="tabsnav" class="navigation navigation-tabs u-full-width"></ul> <ul id="tabsnav" class="navigation navigation-tabs u-full-width"></ul>
<div id="tabscontent" class="tabscontent u-full-width"></div> <div id="tabscontent" class="tabscontent u-full-width"></div>
</div> </div>
</body> </body>
</html> </html>

297
data/js/graph.js Normal file
View File

@ -0,0 +1,297 @@
function lineGraph(parent, xAccessor, yAccessor) {
// Constant size definitions TODO: this could well be improved and calculated...
const width = 620;
const height = 420;
const gutter = 40;
const pixelsPerTick = 30;
/**
* Creates an object that contatins transform functions that:
* transforms numeric data into coordinate space, linearly
* transforms coordinates into numeric data, linearly
*/
function numericTransformer(dataMin, dataMax, pxMin, pxMax) {
var dataDiff = dataMax - dataMin,
pxDiff = pxMax - pxMin,
dataRatio = pxDiff / dataDiff,
coordRatio = dataDiff / pxDiff;
return {
// transforms a data point to a coordinate point
toCoord: function(data) {
return (data - dataMin) * dataRatio + pxMin;
},
// transforms a coord point to a data point
toData: function(coord) {
return (coord - pxMin) * coordRatio + dataMin;
}
};
}
/**
* Renders an axis.
* orientation = 'x' or 'y'
* transform = a function for transforming px into data for labeling/creating tick marks
*/
function axisRenderer(orientation, transform) {
var axisGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
var axisPath = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
axisGroup.setAttribute("class", orientation + "-axis");
var xMin = gutter;
var xMax = width - gutter;
var yMin = height - gutter;
var yMax = gutter;
if (orientation === "x") {
axisPath.setAttribute(
"d",
"M " + xMin + " " + yMin + " L " + xMax + " " + yMin
);
// generate labels
for (var i = xMin; i <= xMax; i++) {
if ((i - xMin) % pixelsPerTick === 0 && i !== xMin) {
var text = document.createElementNS(
"http://www.w3.org/2000/svg",
"text"
);
// primitive formatting
text.innerHTML = Math.floor(transform(i));
text.setAttribute("x", i);
text.setAttribute("y", yMin);
// offset the text by 1 em
text.setAttribute("dy", "1em");
axisGroup.appendChild(text);
}
}
} else {
axisPath.setAttribute(
"d",
"M " + xMin + " " + yMin + " L " + xMin + " " + yMax
);
// generate labels
for (var i = yMax; i <= yMin; i++) {
if ((i - yMin) % pixelsPerTick === 0 && i !== yMin) {
var tickGroup = document.createElementNS(
"http://www.w3.org/2000/svg",
"g"
);
var gridLine = document.createElementNS(
"http://www.w3.org/2000/svg",
"path"
);
text = document.createElementNS("http://www.w3.org/2000/svg", "text");
// primitive formatting
text.innerHTML = Math.floor(transform(i));
text.setAttribute("x", xMin);
text.setAttribute("y", i);
// offset the text labels to align with grid line and keeping it to the left of the y-axis
text.setAttribute("dx", "-.5em");
text.setAttribute("dy", ".3em");
gridLine.setAttribute(
"d",
"M " + xMin + " " + i + " L " + xMax + " " + i
);
tickGroup.appendChild(gridLine);
tickGroup.appendChild(text);
axisGroup.appendChild(tickGroup);
}
}
}
axisGroup.appendChild(axisPath);
parent.appendChild(axisGroup);
}
/**
* Renders a line
*/
function lineRenderer(xAccessor, yAccessor, xTransform, yTransform) {
var line = document.createElementNS("http://www.w3.org/2000/svg", "path");
xAccessor.reset();
yAccessor.reset();
if (!xAccessor.hasNext() || !yAccessor.hasNext()) {
return;
}
var pathString =
"M " + xTransform(xAccessor.next()) + " " + yTransform(yAccessor.next());
while (xAccessor.hasNext() && yAccessor.hasNext()) {
pathString +=
" L " +
xTransform(xAccessor.next()) +
" " +
yTransform(yAccessor.next());
}
line.setAttribute("class", "series");
line.setAttribute("d", pathString);
parent.appendChild(line);
}
/**
* Renders data point circles + text labels
*/
function pointRenderer(xAccessor, yAccessor, xTransform, yTransform) {
var pointGroup = document.createElementNS(
"http://www.w3.org/2000/svg",
"g"
);
pointGroup.setAttribute("class", "data-points");
xAccessor.reset();
yAccessor.reset();
if (!xAccessor.hasNext() || !yAccessor.hasNext()) {
return;
}
while (xAccessor.hasNext() && yAccessor.hasNext()) {
var xDataValue = xAccessor.next();
var x = xTransform(xDataValue);
var yDataValue = yAccessor.next();
var y = yTransform(yDataValue);
var circle = document.createElementNS(
"http://www.w3.org/2000/svg",
"circle"
);
circle.setAttribute("cx", x);
circle.setAttribute("cy", y);
circle.setAttribute("r", "4");
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
// primitive formatting
text.innerHTML = Math.floor(xDataValue) + " / " + Math.floor(yDataValue);
text.setAttribute("x", x);
text.setAttribute("y", y);
text.setAttribute("dx", "1em");
text.setAttribute("dy", "-.7em");
pointGroup.appendChild(circle);
pointGroup.appendChild(text);
}
parent.appendChild(pointGroup);
}
// perform the rendering
xTransform = numericTransformer(
xAccessor.min(),
xAccessor.max(),
0 + gutter,
width - gutter
);
// NOTE: for y... have to reverse coordinate space
yTransform = numericTransformer(
yAccessor.min(),
yAccessor.max(),
height - gutter,
0 + gutter
);
axisRenderer("x", xTransform.toData);
axisRenderer("y", yTransform.toData);
lineRenderer(xAccessor, yAccessor, xTransform.toCoord, yTransform.toCoord);
pointRenderer(xAccessor, yAccessor, xTransform.toCoord, yTransform.toCoord);
}
// Final render function
function renderGraphSvg(dataArray, renderId) {
var figure = document.getElementById(renderId);
while (figure.hasChildNodes()) {
figure.removeChild(figure.lastChild);
}
console.log(dataArray);
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("viewBox", "0 0 640 440");
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
lineGraph(
svg,
// time accessor
(function(data, min, max) {
var i = 0;
return {
hasNext: function() {
return i < data.length;
},
next: function() {
return data[i++].x;
},
reset: function() {
i = 0;
},
min: function() {
return min;
},
max: function() {
return max;
}
};
})(
dataArray,
Math.min.apply(
Math,
dataArray.map(function(o) {
return o.x;
})
),
Math.max.apply(
Math,
dataArray.map(function(o) {
return o.x;
})
)
),
// value accessor
(function(data, min, max) {
var i = 0;
return {
hasNext: function() {
return i < data.length;
},
next: function() {
return data[i++].y;
},
reset: function() {
i = 0;
},
min: function() {
return min;
},
max: function() {
return max;
}
};
})(
dataArray,
Math.min.apply(
Math,
dataArray.map(function(o) {
return o.y;
})
),
Math.max.apply(
Math,
dataArray.map(function(o) {
return o.y;
})
)
)
);
figure.appendChild(svg);
}

15
data/js/graph.min.js vendored Normal file
View File

@ -0,0 +1,15 @@
function lineGraph(parent,xAccessor,yAccessor){const width=620;const height=420;const gutter=40;const pixelsPerTick=30;function numericTransformer(dataMin,dataMax,pxMin,pxMax){var dataDiff=dataMax-dataMin,pxDiff=pxMax-pxMin,dataRatio=pxDiff/dataDiff,coordRatio=dataDiff/pxDiff;return{toCoord:function(data){return(data-dataMin)*dataRatio+pxMin;},toData:function(coord){return(coord-pxMin)*coordRatio+dataMin;}};}
function axisRenderer(orientation,transform){var axisGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var axisPath=document.createElementNS("http://www.w3.org/2000/svg","path");axisGroup.setAttribute("class",orientation+"-axis");var xMin=gutter;var xMax=width-gutter;var yMin=height-gutter;var yMax=gutter;if(orientation==="x"){axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMax+" "+yMin);for(var i=xMin;i<=xMax;i++){if((i-xMin)%pixelsPerTick===0&&i!==xMin){var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",i);text.setAttribute("y",yMin);text.setAttribute("dy","1em");axisGroup.appendChild(text);}}}else{axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMin+" "+yMax);for(var i=yMax;i<=yMin;i++){if((i-yMin)%pixelsPerTick===0&&i!==yMin){var tickGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var gridLine=document.createElementNS("http://www.w3.org/2000/svg","path");text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",xMin);text.setAttribute("y",i);text.setAttribute("dx","-.5em");text.setAttribute("dy",".3em");gridLine.setAttribute("d","M "+xMin+" "+i+" L "+xMax+" "+i);tickGroup.appendChild(gridLine);tickGroup.appendChild(text);axisGroup.appendChild(tickGroup);}}}
axisGroup.appendChild(axisPath);parent.appendChild(axisGroup);}
function lineRenderer(xAccessor,yAccessor,xTransform,yTransform){var line=document.createElementNS("http://www.w3.org/2000/svg","path");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
var pathString="M "+xTransform(xAccessor.next())+" "+yTransform(yAccessor.next());while(xAccessor.hasNext()&&yAccessor.hasNext()){pathString+=" L "+
xTransform(xAccessor.next())+
" "+
yTransform(yAccessor.next());}
line.setAttribute("class","series");line.setAttribute("d",pathString);parent.appendChild(line);}
function pointRenderer(xAccessor,yAccessor,xTransform,yTransform){var pointGroup=document.createElementNS("http://www.w3.org/2000/svg","g");pointGroup.setAttribute("class","data-points");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
while(xAccessor.hasNext()&&yAccessor.hasNext()){var xDataValue=xAccessor.next();var x=xTransform(xDataValue);var yDataValue=yAccessor.next();var y=yTransform(yDataValue);var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");circle.setAttribute("cx",x);circle.setAttribute("cy",y);circle.setAttribute("r","4");var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(xDataValue)+" / "+Math.floor(yDataValue);text.setAttribute("x",x);text.setAttribute("y",y);text.setAttribute("dx","1em");text.setAttribute("dy","-.7em");pointGroup.appendChild(circle);pointGroup.appendChild(text);}
parent.appendChild(pointGroup);}
xTransform=numericTransformer(xAccessor.min(),xAccessor.max(),0+gutter,width-gutter);yTransform=numericTransformer(yAccessor.min(),yAccessor.max(),height-gutter,0+gutter);axisRenderer("x",xTransform.toData);axisRenderer("y",yTransform.toData);lineRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);pointRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);}
function renderGraphSvg(dataArray,renderId){var figure=document.getElementById(renderId);while(figure.hasChildNodes()){figure.removeChild(figure.lastChild);}
console.log(dataArray);var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 640 440");svg.setAttribute("preserveAspectRatio","xMidYMid meet");lineGraph(svg,(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].x;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.x;})),Math.max.apply(Math,dataArray.map(function(o){return o.x;}))),(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].y;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.y;})),Math.max.apply(Math,dataArray.map(function(o){return o.y;}))));figure.appendChild(svg);}

View File

@ -6,6 +6,7 @@
#include "dataStyleCSS.h" #include "dataStyleCSS.h"
#include "dataControlsJS.h" #include "dataControlsJS.h"
#include "dataGraphJS.h"
#include "dataSliderJS.h" #include "dataSliderJS.h"
#include "dataTabbedcontentJS.h" #include "dataTabbedcontentJS.h"
#include "dataZeptoJS.h" #include "dataZeptoJS.h"
@ -219,6 +220,7 @@ void ESPUIClass::prepareFileSystem() {
deleteFile("/js/zepto.min.js"); deleteFile("/js/zepto.min.js");
deleteFile("/js/controls.js"); deleteFile("/js/controls.js");
deleteFile("/js/slider.js"); deleteFile("/js/slider.js");
deleteFile("/js/graph.js");
deleteFile("/js/tabbedcontent.js"); deleteFile("/js/tabbedcontent.js");
if (this->verbosity) { if (this->verbosity) {
@ -234,7 +236,8 @@ void ESPUIClass::prepareFileSystem() {
writeFile("/js/zepto.min.js", JS_ZEPTO); writeFile("/js/zepto.min.js", JS_ZEPTO);
writeFile("/js/controls.js", JS_CONTROLS); writeFile("/js/controls.js", JS_CONTROLS);
writeFile("/js/slider.js", JS_SLIDER); writeFile("/js/slider.js", JS_SLIDER);
; writeFile("/js/graph.js", JS_GRAPH);
writeFile("/js/tabbedcontent.js", JS_TABBEDCONTENT); writeFile("/js/tabbedcontent.js", JS_TABBEDCONTENT);
if (this->verbosity) { if (this->verbosity) {
@ -749,6 +752,16 @@ void ESPUIClass::begin(const char *_title, const char *username, const char *pas
request->send(response); request->send(response);
}); });
server->on("/js/graph.js", HTTP_GET, [](AsyncWebServerRequest *request) {
if (ESPUI.basicAuth && !request->authenticate(ESPUI.basicAuthUsername, ESPUI.basicAuthPassword)) {
return request->requestAuthentication();
}
AsyncWebServerResponse *response = request->beginResponse_P(200, "application/javascript", JS_GRAPH_GZIP, sizeof(JS_GRAPH_GZIP));
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server->on("/js/tabbedcontent.js", HTTP_GET, [](AsyncWebServerRequest *request) { server->on("/js/tabbedcontent.js", HTTP_GET, [](AsyncWebServerRequest *request) {
if (ESPUI.basicAuth && !request->authenticate(ESPUI.basicAuthUsername, ESPUI.basicAuthPassword)) { if (ESPUI.basicAuth && !request->authenticate(ESPUI.basicAuthUsername, ESPUI.basicAuthPassword)) {
return request->requestAuthentication(); return request->requestAuthentication();

19
src/dataGraphJS.h Normal file
View File

@ -0,0 +1,19 @@
const char JS_GRAPH[] PROGMEM = R"=====(
function lineGraph(parent,xAccessor,yAccessor){const width=620;const height=420;const gutter=40;const pixelsPerTick=30;function numericTransformer(dataMin,dataMax,pxMin,pxMax){var dataDiff=dataMax-dataMin,pxDiff=pxMax-pxMin,dataRatio=pxDiff/dataDiff,coordRatio=dataDiff/pxDiff;return{toCoord:function(data){return(data-dataMin)*dataRatio+pxMin;},toData:function(coord){return(coord-pxMin)*coordRatio+dataMin;}};}
function axisRenderer(orientation,transform){var axisGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var axisPath=document.createElementNS("http://www.w3.org/2000/svg","path");axisGroup.setAttribute("class",orientation+"-axis");var xMin=gutter;var xMax=width-gutter;var yMin=height-gutter;var yMax=gutter;if(orientation==="x"){axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMax+" "+yMin);for(var i=xMin;i<=xMax;i++){if((i-xMin)%pixelsPerTick===0&&i!==xMin){var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",i);text.setAttribute("y",yMin);text.setAttribute("dy","1em");axisGroup.appendChild(text);}}}else{axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMin+" "+yMax);for(var i=yMax;i<=yMin;i++){if((i-yMin)%pixelsPerTick===0&&i!==yMin){var tickGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var gridLine=document.createElementNS("http://www.w3.org/2000/svg","path");text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",xMin);text.setAttribute("y",i);text.setAttribute("dx","-.5em");text.setAttribute("dy",".3em");gridLine.setAttribute("d","M "+xMin+" "+i+" L "+xMax+" "+i);tickGroup.appendChild(gridLine);tickGroup.appendChild(text);axisGroup.appendChild(tickGroup);}}}
axisGroup.appendChild(axisPath);parent.appendChild(axisGroup);}
function lineRenderer(xAccessor,yAccessor,xTransform,yTransform){var line=document.createElementNS("http://www.w3.org/2000/svg","path");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
var pathString="M "+xTransform(xAccessor.next())+" "+yTransform(yAccessor.next());while(xAccessor.hasNext()&&yAccessor.hasNext()){pathString+=" L "+
xTransform(xAccessor.next())+
" "+
yTransform(yAccessor.next());}
line.setAttribute("class","series");line.setAttribute("d",pathString);parent.appendChild(line);}
function pointRenderer(xAccessor,yAccessor,xTransform,yTransform){var pointGroup=document.createElementNS("http://www.w3.org/2000/svg","g");pointGroup.setAttribute("class","data-points");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
while(xAccessor.hasNext()&&yAccessor.hasNext()){var xDataValue=xAccessor.next();var x=xTransform(xDataValue);var yDataValue=yAccessor.next();var y=yTransform(yDataValue);var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");circle.setAttribute("cx",x);circle.setAttribute("cy",y);circle.setAttribute("r","4");var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(xDataValue)+" / "+Math.floor(yDataValue);text.setAttribute("x",x);text.setAttribute("y",y);text.setAttribute("dx","1em");text.setAttribute("dy","-.7em");pointGroup.appendChild(circle);pointGroup.appendChild(text);}
parent.appendChild(pointGroup);}
xTransform=numericTransformer(xAccessor.min(),xAccessor.max(),0+gutter,width-gutter);yTransform=numericTransformer(yAccessor.min(),yAccessor.max(),height-gutter,0+gutter);axisRenderer("x",xTransform.toData);axisRenderer("y",yTransform.toData);lineRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);pointRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);}
function renderGraphSvg(dataArray,renderId){var figure=document.getElementById(renderId);while(figure.hasChildNodes()){figure.removeChild(figure.lastChild);}
console.log(dataArray);var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 640 440");svg.setAttribute("preserveAspectRatio","xMidYMid meet");lineGraph(svg,(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].x;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.x;})),Math.max.apply(Math,dataArray.map(function(o){return o.x;}))),(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].y;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.y;})),Math.max.apply(Math,dataArray.map(function(o){return o.y;}))));figure.appendChild(svg);}
)=====";
const uint8_t JS_GRAPH_GZIP[1254] PROGMEM = { 31,139,8,0,212,110,180,92,2,255,205,87,221,111,219,54,16,127,247,95,225,8,88,32,213,178,172,54,94,7,84,225,67,218,14,93,129,36,40,154,96,192,48,236,129,147,104,153,152,44,9,20,109,139,112,253,191,239,142,212,151,109,41,67,157,22,221,67,28,241,190,121,252,221,29,185,88,167,161,228,89,58,78,120,202,62,8,154,47,237,156,10,150,74,183,188,9,67,86,20,153,112,85,253,229,236,194,44,45,228,120,203,35,185,36,175,95,249,129,89,47,25,143,151,146,204,27,66,188,150,146,9,50,175,215,57,47,89,82,124,98,226,145,135,255,144,43,63,88,212,110,211,245,138,9,30,62,10,154,22,139,76,192,194,142,168,164,119,60,117,245,127,90,186,121,137,43,248,165,165,179,219,80,49,70,198,123,190,88,144,74,98,90,107,228,165,38,107,209,169,81,67,214,103,10,174,136,97,206,106,101,55,204,50,17,25,86,77,155,25,153,64,48,185,22,233,78,102,239,80,230,77,29,172,142,204,217,25,174,94,212,158,157,23,141,159,137,246,27,236,93,153,189,7,90,171,172,253,53,218,122,101,98,116,94,180,161,76,42,131,193,126,31,236,71,77,150,104,201,139,207,44,141,152,128,252,100,130,195,249,160,116,234,202,58,111,38,51,40,247,65,100,235,156,68,89,8,153,77,165,23,10,70,37,251,53,97,184,186,127,176,173,165,148,249,155,217,108,187,221,122,219,43,47,19,241,236,149,239,251,179,98,19,91,174,21,91,78,80,27,250,68,225,144,207,180,147,131,46,152,106,226,241,10,38,111,164,20,252,239,181,100,182,21,38,180,40,44,183,179,147,137,53,69,225,202,61,166,133,24,16,85,107,90,18,141,186,105,135,170,80,202,96,239,144,12,194,213,154,47,186,233,34,132,88,165,229,236,234,221,29,69,21,65,224,119,99,107,130,222,39,22,124,40,243,113,171,105,180,108,104,78,0,41,183,209,23,39,250,180,249,53,65,129,128,79,38,206,14,124,218,124,170,79,246,167,67,224,19,226,95,94,242,11,162,149,204,137,73,86,202,115,147,140,186,144,48,252,231,241,52,101,226,183,199,187,91,114,135,27,91,36,0,41,187,65,135,205,157,74,238,112,199,165,229,242,94,134,178,92,179,209,30,94,4,76,235,37,91,29,156,47,205,115,192,231,187,37,79,34,27,117,28,64,240,30,182,206,206,75,118,67,131,154,239,36,91,233,36,95,19,165,147,222,38,91,61,149,108,213,38,27,232,223,164,60,98,193,163,91,104,152,207,44,143,31,126,248,229,208,25,171,33,96,68,160,101,77,189,159,245,241,15,129,195,187,210,236,58,75,255,117,242,252,184,198,208,117,125,84,7,200,170,45,14,241,13,242,6,80,89,107,104,104,142,250,133,106,176,58,129,153,130,39,204,218,66,219,155,113,112,54,189,185,103,104,186,101,51,220,92,245,120,216,175,147,231,99,168,241,232,9,6,121,182,157,64,157,80,160,72,46,90,185,37,45,238,33,79,182,243,229,203,133,58,165,214,35,10,246,136,33,162,155,7,56,187,52,38,230,212,154,45,180,155,245,82,163,105,106,182,21,80,199,2,193,22,18,201,236,158,88,46,47,123,67,105,189,79,136,1,201,232,201,0,70,24,193,232,201,16,246,163,228,20,147,213,64,178,10,184,140,48,156,66,73,47,110,219,112,122,1,146,104,104,118,176,145,103,60,149,231,130,67,43,63,187,93,181,86,6,182,172,239,49,90,170,248,206,112,250,218,195,215,147,31,47,81,191,211,100,205,200,241,105,155,155,1,233,226,161,17,54,76,213,42,171,62,101,69,186,72,57,82,14,185,8,147,179,171,211,104,67,66,205,199,113,238,177,247,14,241,112,246,14,240,4,88,158,87,51,232,187,14,143,78,38,161,168,103,80,84,29,102,55,83,3,115,101,240,82,49,60,84,94,62,57,82,166,222,47,154,223,129,115,183,242,76,182,6,217,213,141,100,212,83,179,173,6,10,180,96,34,61,47,147,22,129,43,158,218,142,219,89,211,18,214,254,196,92,59,221,238,85,21,42,232,73,163,234,200,168,58,50,122,112,193,109,92,152,41,215,180,22,157,244,198,170,103,222,30,199,50,152,255,83,153,175,152,95,94,245,34,58,52,163,73,85,234,191,133,161,78,255,20,218,156,126,150,62,108,98,253,228,186,17,130,42,215,48,62,70,166,73,44,120,188,22,157,82,141,153,172,42,225,173,250,24,217,141,112,53,126,140,56,118,26,13,129,251,44,98,5,246,155,138,46,216,42,219,48,131,142,138,4,173,82,106,2,70,135,79,218,12,74,51,201,58,17,153,154,132,234,58,183,36,241,215,9,224,247,8,253,27,206,182,111,51,44,16,127,236,143,95,207,253,241,124,238,247,74,230,216,159,197,134,221,20,57,11,165,126,78,130,22,220,178,162,63,224,111,188,98,76,86,131,205,188,243,193,130,107,31,188,109,93,64,160,187,170,159,217,156,248,245,75,184,106,202,237,99,182,238,234,99,126,141,138,94,194,210,88,46,225,213,155,246,139,161,208,159,112,97,255,203,43,65,72,15,146,174,20,186,218,163,247,30,213,149,126,77,67,84,125,60,120,14,224,75,217,233,64,67,55,42,80,194,42,79,148,141,75,183,225,66,77,229,237,158,179,198,80,134,113,57,78,165,76,203,115,148,157,31,144,77,245,63,205,166,122,78,54,181,50,220,212,170,226,235,118,107,192,44,148,224,191,224,198,10,203,181,18,0,0 };

View File

@ -2,4 +2,4 @@ const char HTML_INDEX[] PROGMEM = R"=====(
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4><div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span></h4></div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html> <!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4><div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span></h4></div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
)====="; )=====";
const uint8_t HTML_INDEX_GZIP[910] PROGMEM = { 31,139,8,0,78,66,142,92,2,255,133,84,109,147,162,56,16,254,43,156,159,238,106,119,6,81,199,153,217,21,171,130,130,51,42,34,32,40,126,11,144,145,96,120,25,18,68,253,245,151,200,204,237,94,237,213,30,85,36,79,186,159,126,186,105,160,71,127,76,173,201,38,88,235,82,194,50,50,30,221,86,105,148,32,24,143,71,25,98,80,138,18,88,81,196,212,154,189,221,61,141,71,12,51,130,198,147,34,103,85,65,70,114,123,108,153,57,204,144,122,194,168,41,139,138,73,17,167,160,156,169,157,6,199,44,81,99,116,194,17,186,187,29,190,74,56,199,12,67,114,71,35,72,144,170,116,198,35,130,243,163,84,33,162,118,104,194,195,163,154,73,152,75,116,164,164,66,111,106,12,25,252,134,51,120,64,114,153,31,190,135,144,162,225,224,43,246,53,203,105,186,139,217,161,0,252,90,185,94,162,123,7,142,52,113,4,246,4,152,98,47,150,246,243,70,0,109,22,107,27,79,7,96,57,91,79,228,115,162,217,220,56,209,82,215,152,175,184,119,56,231,177,135,87,110,92,11,189,9,24,242,53,22,145,86,41,84,135,25,95,140,254,36,170,137,254,36,244,214,134,102,250,186,119,227,42,254,214,233,41,239,118,143,96,167,111,188,139,219,237,251,181,211,247,57,110,119,171,167,100,110,79,169,221,155,143,223,28,207,123,179,133,205,227,56,159,115,12,145,87,147,251,179,250,81,232,235,185,227,110,136,9,180,2,244,143,107,173,185,62,225,135,197,21,23,231,195,96,229,71,94,191,214,231,47,183,39,221,206,151,78,215,6,24,120,177,123,51,144,198,53,200,85,244,68,105,0,152,198,145,102,99,28,162,155,47,238,186,158,98,104,95,116,67,79,34,221,252,242,82,6,141,104,132,22,184,158,163,249,90,186,73,2,121,62,165,224,48,209,93,54,32,229,78,62,61,167,75,123,63,31,190,27,207,172,127,76,192,37,85,206,59,111,17,218,3,205,47,154,105,243,110,5,7,253,124,60,110,7,56,24,146,53,52,186,67,231,221,124,10,94,153,85,59,161,9,175,195,115,26,210,154,78,193,86,142,171,146,104,135,193,99,186,30,62,15,163,157,254,20,174,129,130,188,41,90,244,68,117,243,157,99,108,95,156,99,176,115,136,149,173,46,251,173,209,221,219,224,98,78,245,254,114,3,148,229,70,31,248,211,215,171,149,130,174,149,122,231,197,21,92,56,110,206,250,195,51,106,196,171,240,187,142,159,116,247,51,30,183,41,89,216,115,202,125,126,4,102,10,206,171,75,183,89,185,221,179,101,216,23,243,90,52,171,105,161,152,46,109,204,180,104,204,165,183,57,71,145,40,97,31,235,126,16,27,171,211,62,119,250,193,110,78,192,75,220,143,47,15,101,152,177,107,208,51,154,189,251,112,138,50,20,62,166,13,188,181,84,39,198,230,232,214,118,54,153,252,244,37,83,118,33,136,38,8,177,246,35,150,35,74,229,188,168,50,72,240,21,221,243,211,255,145,111,198,150,72,163,10,151,76,162,85,164,202,41,149,175,168,100,197,125,134,243,251,148,59,229,214,251,11,139,18,28,163,234,183,148,168,253,147,233,111,73,12,134,33,138,63,254,232,127,51,229,219,168,144,70,97,17,95,164,34,39,5,140,213,20,158,96,235,255,70,25,172,216,159,127,125,231,140,24,159,196,100,25,140,5,146,112,172,102,16,231,47,60,26,85,63,230,73,75,162,37,204,5,131,103,116,25,100,53,149,34,2,41,85,9,12,17,25,91,111,111,188,109,136,215,192,105,162,2,46,249,17,152,84,109,162,15,190,168,152,39,65,159,86,46,89,21,205,135,179,35,96,125,247,86,19,210,142,165,206,63,50,53,17,84,254,212,52,135,159,90,29,14,241,1,50,92,228,210,15,120,39,72,191,168,212,228,71,66,65,248,232,220,167,210,207,166,255,46,224,115,19,93,21,123,59,150,255,6,7,151,15,103,173,5,0,0 }; const uint8_t HTML_INDEX_GZIP[910] PROGMEM = { 31,139,8,0,213,110,180,92,2,255,133,84,109,147,162,56,16,254,43,156,159,238,106,119,6,81,199,153,217,21,171,130,130,51,42,34,32,40,126,11,144,145,96,120,25,18,68,253,245,151,200,204,237,94,237,213,30,85,36,79,186,159,126,186,105,160,71,127,76,173,201,38,88,235,82,194,50,50,30,221,86,105,148,32,24,143,71,25,98,80,138,18,88,81,196,212,154,189,221,61,141,71,12,51,130,198,147,34,103,85,65,70,114,123,108,153,57,204,144,122,194,168,41,139,138,73,17,167,160,156,169,157,6,199,44,81,99,116,194,17,186,187,29,190,74,56,199,12,67,114,71,35,72,144,170,116,198,35,130,243,163,84,33,162,118,104,194,195,163,154,73,152,75,116,164,164,66,111,106,12,25,252,134,51,120,64,114,153,31,190,135,144,162,225,224,43,246,53,203,105,186,139,217,161,0,252,90,185,94,162,123,7,142,52,113,4,246,4,152,98,47,150,246,243,70,0,109,22,107,27,79,7,96,57,91,79,228,115,162,217,220,56,209,82,215,152,175,184,119,56,231,177,135,87,110,92,11,189,9,24,242,53,22,145,86,41,84,135,25,95,140,254,36,170,137,254,36,244,214,134,102,250,186,119,227,42,254,214,233,41,239,118,143,96,167,111,188,139,219,237,251,181,211,247,57,110,119,171,167,100,110,79,169,221,155,143,223,28,207,123,179,133,205,227,56,159,115,12,145,87,147,251,179,250,81,232,235,185,227,110,136,9,180,2,244,143,107,173,185,62,225,135,197,21,23,231,195,96,229,71,94,191,214,231,47,183,39,221,206,151,78,215,6,24,120,177,123,51,144,198,53,200,85,244,68,105,0,152,198,145,102,99,28,162,155,47,238,186,158,98,104,95,116,67,79,34,221,252,242,82,6,141,104,132,22,184,158,163,249,90,186,73,2,121,62,165,224,48,209,93,54,32,229,78,62,61,167,75,123,63,31,190,27,207,172,127,76,192,37,85,206,59,111,17,218,3,205,47,154,105,243,110,5,7,253,124,60,110,7,56,24,146,53,52,186,67,231,221,124,10,94,153,85,59,161,9,175,195,115,26,210,154,78,193,86,142,171,146,104,135,193,99,186,30,62,15,163,157,254,20,174,129,130,188,41,90,244,68,117,243,157,99,108,95,156,99,176,115,136,149,173,46,251,173,209,221,219,224,98,78,245,254,114,3,148,229,70,31,248,211,215,171,149,130,174,149,122,231,197,21,92,56,110,206,250,195,51,106,196,171,240,187,142,159,116,247,51,30,183,41,89,216,115,202,125,126,4,102,10,206,171,75,183,89,185,221,179,101,216,23,243,90,52,171,105,161,152,46,109,204,180,104,204,165,183,57,71,145,40,97,31,235,126,16,27,171,211,62,119,250,193,110,78,192,75,220,143,47,15,101,152,177,107,208,51,154,189,251,112,138,50,20,62,166,13,188,181,84,39,198,230,232,214,118,54,153,252,244,37,83,118,33,136,38,8,177,246,35,150,35,74,229,188,168,50,72,240,21,221,243,211,255,145,111,198,150,72,163,10,151,76,162,85,164,202,41,149,175,168,100,197,125,134,243,251,148,59,229,214,251,11,139,18,28,163,234,183,148,168,253,147,233,111,73,12,134,33,138,63,254,232,127,51,229,219,168,144,70,97,17,95,164,34,39,5,140,213,20,158,96,235,255,70,25,172,216,159,127,125,231,140,24,159,196,100,25,140,5,146,112,172,102,16,231,47,60,26,85,63,230,73,75,162,37,204,5,131,103,116,25,100,53,149,34,2,41,85,9,12,17,25,91,111,111,188,109,136,215,192,105,162,2,46,249,17,152,84,109,162,15,190,168,152,39,65,159,86,46,89,21,205,135,179,35,96,125,247,86,19,210,142,165,206,63,50,53,17,84,254,212,52,135,159,90,29,14,241,1,50,92,228,210,15,120,39,72,191,168,212,228,71,66,65,248,232,220,167,210,207,166,255,46,224,115,19,93,21,123,59,150,255,6,7,151,15,103,173,5,0,0 };

File diff suppressed because one or more lines are too long