1
0
mirror of https://github.com/s00500/ESPUI.git synced 2025-06-12 04:10:39 +00:00

Graph Frontend work

- Adds graph js file
- Adds graph styles
This commit is contained in:
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 {
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>
<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" />
<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>
<script src="/js/zepto.min.js"></script>
<script src="/js/slider.js"></script>
<script src="/js/graph.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>

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);}