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:
@ -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;
|
||||
}
|
||||
|
2
data/css/style.min.css
vendored
2
data/css/style.min.css
vendored
File diff suppressed because one or more lines are too long
@ -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
297
data/js/graph.js
Normal 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
15
data/js/graph.min.js
vendored
Normal 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);}
|
Reference in New Issue
Block a user