Updated Elements and caching

- flag nocache deactivates the use of cache
- the graph adapts to the screensize (after re-redering)
- the server automatically generates a json with the current cpu usage.
pull/18/head^2
Trivernis 6 years ago
parent 3dab31a7c2
commit be7e9574af

@ -44,8 +44,8 @@ function getDataByPath(array, path) {
* Shows/Hides the sidebar action-menu
*/
function toggleActionMenu() {
let state = $('.mainview').attr("state");
if (state === "retracted") {
let state = $('.mainview').attr("state"); // get the current state of the mainview element(s)
if (state === "retracted") { // set the sate to fullsize or retracted depending on the previous value
$('.mainview').attr("state", "fullsize");
} else {
$('.mainview').attr("state", "retracted");
@ -58,11 +58,11 @@ function toggleActionMenu() {
* @param title the title of the targtet that is displayed
*/
function navigate(view, title) {
if (view !== 'index.htm') window.location.hash = view;
else window.location.hash = "";
$('.content').load(view);
let sideTitle = title || view.replace(/\.htm/, '');
setTitle(sideTitle);
if (view !== 'index.htm') window.location.hash = view; // set the hash if the url is not the index.htm
else window.location.hash = ""; // reset the hash if the hash url is the index.htm
$('.content').load(view); // load the view into the content class elements
let sideTitle = title || view.replace(/\.htm/, ''); // get the side title as the given title or the filename without extension
setTitle(sideTitle); // set the sides title
}
/**
@ -81,57 +81,54 @@ function setTitle(title) {
* TODO: Seperated Background canvas and graph canvas. Div with span elements for x and y values.
*/
function drawGraph(element, data, options) {
element.innerHTML = "";
let cv1 = document.createElement('canvas');
let cv2 = document.createElement('canvas');
let spanDiv = document.createElement('div');
spanDiv.setAttribute('class', 'labels');
let ctx1 = cv1.getContext('2d');
let ctx2 = cv2.getContext('2d');
element.appendChild(cv1);
element.appendChild(cv2);
let canvWidth = cv1.width;
let canvHeight = cv2.height;
ctx1.clearRect(0, 0, canvWidth, canvHeight);
ctx2.clearRect(0, 0, canvWidth, canvHeight);
let xData = [];
let yData = [];
element.innerHTML = ""; // reset the element
let cv1 = document.createElement('canvas'); // create a canvas for the background
let cv2 = document.createElement('canvas'); // create a canvas for the graph
let spanDiv = document.createElement('div'); // create a div for labels
spanDiv.setAttribute('class', 'labels'); // set the class for the div
let ctx1 = cv1.getContext('2d'); // get the 2d-context for canvas 1
let ctx2 = cv2.getContext('2d'); // get the 2d-context for canvas 2
element.appendChild(cv1); // append canvas 1 to the element
element.appendChild(spanDiv); // append the labels div to the element
element.appendChild(cv2); // append canvas 2 to the element
let canvWidth = cv2.width = cv1.width = cv1.clientWidth; // set the width of the canvas elements to the clients width
let canvHeight = cv2.height = cv1.height = cv1.clientHeight; // set the height of the canvas elements to the clients height
let xData = []; // set xData to an empty array
let yData = []; // set yData to an empty array
if (!options) options = {};
ctx1.beginPath();
ctx1.strokeStyle = $(element).css('color');
ctx1.font = "80% Arial";
ctx1.strokeStyle = $(element).css('color'); // set the stroke style to the parent elements color
for (let dt of data) {
for (let dt of data) { // seperate x values and y values to two arrays
xData.push(dt[0]);
yData.push(dt[1]);
}
let xMax = options.xMax || Math.max.apply(Math, xData);
let xMin = options.xMin || Math.min.apply(Math, xData);
let yMax = options.yMax || Math.max.apply(Math, yData);
let yMin = options.yMin || Math.min.apply(Math, yData);
let xUnit = options.xUnit || "";
let yUnit = options.yUnit || "";
let xStep = canvWidth / (xMax - xMin);
let yStep = canvHeight / (yMax - yMin);
let gridCount = canvHeight/yStep;
while (gridCount > 10) {
gridCount /= 10;
let xMax = options.xMax || Math.max.apply(Math, xData); // set the max x value
let xMin = options.xMin || Math.min.apply(Math, xData); // set the min x value
let yMax = options.yMax || Math.max.apply(Math, yData); // set the max y value
let yMin = options.yMin || Math.min.apply(Math, yData); // set the min y value
let xUnit = options.xUnit || ""; // set the unit of the x values
let yUnit = options.yUnit || ""; // set the unit of the y values
let xStep = canvWidth / (xMax - xMin); // set the equivalent pixel step size for an x step
let yStep = canvHeight / (yMax - yMin); // set the equivalent pixel step size for an y step
let gridCount = canvHeight/yStep; // define the count of grids on the y axis
while (gridCount > 7) {
gridCount /= 1.5;
}
let gridH = (canvHeight/gridCount);
for (let i = gridH; i < (canvHeight - gridH/10); i+= gridH) {
let span = document.createElement('span');
span.style = `position: absolute; top: ${(i/canvHeight)*100}%; left: 0`;
span.innerText = Math.round((canvHeight - i)/yStep)+Number(yMin)+" "+yUnit;
spanDiv.appendChild(span);
let gridH = (canvHeight/gridCount); // define the height of the grid
for (let i = gridH; i < (canvHeight - gridH/10); i+= gridH) { // create a vertical grid
let span = document.createElement('span'); // create a span element
span.style = `position: absolute; top: calc(${((i)/canvHeight)*100}% - 1.2em); left: 0`; // set the style of the span element
span.innerText = Math.round((canvHeight - i)/yStep)+Number(yMin)+" "+yUnit; // set the text of the span element
spanDiv.appendChild(span); // append the span element to the div
ctx1.moveTo(0, i);
ctx1.lineTo(canvWidth, i);
ctx1.lineTo(canvWidth, i); // draw a grid line
ctx1.stroke();
}
gridCount = canvWidth/xStep;
while (gridCount > 10) {
while (gridCount > 10) { // do the same as above for the x-axis
gridCount /= 2;
}
let gridW = (canvWidth/gridCount);
@ -147,21 +144,63 @@ function drawGraph(element, data, options) {
let x = 0;
let y = canvHeight;
if (data.length > 0) {
x = data[0][0];
y = data[0][1];
if (data.length > 0) { // get the first coordinate as point a
x = data[0][0] * xStep;
y= canvHeight - ((data[0][1] - yMin) * yStep)
}
ctx2.beginPath();
ctx2.strokeStyle = $(element).css('outline-color');
ctx2.strokeStyle = $(element).css('outline-color'); // set the stroke style to the css value 'outline-color' of the parent
for (let dt of data) {
ctx2.moveTo(x, y);
x = dt[0] * xStep;
y = canvHeight - ((dt[1] - yMin) * yStep);
ctx2.lineTo(x, y);
ctx2.moveTo(x, y); // move to point a (point b of last turn)
x = dt[0] * xStep; // get the x value of point b
y = canvHeight - ((dt[1] - yMin) * yStep); // get the y value of point b
ctx2.lineTo(x, y); // draw a line from point a to point b
ctx2.stroke();
}
element.appendChild(spanDiv);
cv2.addEventListener('mousemove', evt => { // add a mousedown listener that displays a tooltip with the x and y values
let mousePos = getMousePos(cv2, evt);
showTooltip(`x: ${Math.round(mousePos.x/xStep*10)/10+' '+xUnit},y: ${Math.round((cv1.clientHeight-mousePos.y)/yStep*10)/10+' '+yUnit}`, {x: evt.clientX, y: evt.clientY}, true);
});
}
/**
* returns the position of the mouse over a canvas
* @param canvas
* @param evt
* @returns {{x: number, y: number}}
*/
function getMousePos(canvas, evt) {
let rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
/**
* shows a tooltip with the id #tooltip
* @param text
* @param position
* @param keep if false or not set the tooltip will be deleted after 2 seconds
*/
function showTooltip(text, position, keep) {
let el = document.querySelector('#tooltip') || document.createElement('span'); // set the span to the element with the id or create one if it doesn't exist
el.innerText = text; // set the text of the span to the text
el.setAttribute('id', 'tooltip'); // set the id to 'tooltip'
el.style = `position: absolute; top: ${position.y+10}; left: ${position.x+10}; background: white; color: black;`; // set the style that way that the
// absolute x and y of the mouse represent the spans coordinates
document.body.appendChild(el); // append the span to the documents body
if (!keep) setTimeout(() => el.remove(), 2000); // if keep is false or undefined set a timeout of 2 seconds for deletion of the span
}
/**
* deletes the tooltip with the id #tooltip
*/
function hideTooltip() {
let tooltip = document.querySelector('#tooltip'); // select the element with the id tooltip
if (tooltip) tooltip.remove(); // delete the element if it does exist
}
// -- Events --

@ -111,6 +111,8 @@
box-shadow: 0 5px 5px $cOnSurfaceShadow
cursor: pointer
text-align: justify
.panel.max-width
width: calc(100% - 75px)
.panel:hover
background: darken($cPrimary, 4%)
.panel:active
@ -145,24 +147,26 @@
left: 0
overflow: auto
.graph
color: $cPrimaryVariant
box-shadow: inset 0 1px 5px $cOnSurfaceShadow
border-radius: $sPadding
outline-color: $cOnPrimary
background: darken($cPrimary, 4%)
position: absolute
left: $sPadding
top: 20%
height: calc(80% - 12.5px)
width: calc(100% - 25px)
canvas, .labels
position: absolute
top: 0
left: 0
height: 100%
width: 100%
span
padding: 2px
font-weight: bold
color: $cOnPrimary
opacity: 0.75
.graph
color: $cPrimaryVariant
box-shadow: inset 0 1px 5px $cOnSurfaceShadow
border-radius: $sPadding
outline-color: $cOnPrimary
background: darken($cPrimary, 4%)
canvas, .labels
position: absolute
top: 0
left: 0
height: 100%
width: 100%
span
padding: 2px
font-weight: bold
color: $cOnPrimary
opacity: 0.75

@ -1,6 +1,7 @@
const fs = require("fs"),
path = require("path"),
cache_dir = "./.cache";
cache_dir = "./.cache",
args = require('args-parser')(process.argv);
let cache = {};
let logger = require("winston");
@ -72,7 +73,7 @@ exports.cache = function (filename, data) {
* @return {Boolean} Is it cached or not
*/
exports.isCached = function (filename) {
return false //TODO: change back
if (args.nocache) return false; // return false if the flag nocache is set
let cached_entry = cache[filename];
if (cached_entry) { // check if the cache entry exists
logger.debug("Found cache entry for %s", filename);

@ -1,8 +1,12 @@
/**
* A Series of utility functions
*/
const fs = require('fs'),
si = require('systeminformation');
function noOp() {}
let sysdataPath = './res/data/sys.json';
let sysData = {};
/**
* returns the extension of a file for the given filename.
@ -19,7 +23,23 @@ exports.getExtension = function (filename) {
console.error(error);
return null;
}
}
};
exports.genSystemData = function () {
si.currentLoad(data => {
if (!sysData["100perc"]) sysData["100perc"] = [];
sysData["100perc"].push([sysData["100perc"].length, data.currentload]);
if (sysData["100perc"].length > 100) {
sysData["100perc"].shift();
for (let i = 0; i < sysData["100perc"].length; i++) {
sysData["100perc"][i][0] -=1;
}
}
});
fs.writeFile(sysdataPath, JSON.stringify(sysData), err => {
if (err) console.error(err);
});
};
/**
* lets you define a cleanup for your program exit

@ -6,6 +6,7 @@
"jsdom": "^12.2.0",
"node-sass": "^4.9.3",
"perfy": "^1.1.5",
"systeminformation": "^3.45.9",
"winston": "^3.1.0",
"winston-daily-rotate-file": "^3.3.3"
}

@ -29,6 +29,7 @@
[12,31],
[13,34],
[14,33],
[15,32]
[15,32],
[16,34]
]
}

@ -0,0 +1 @@
{"100perc":[[0,7.592260658628322],[1,10.5375],[2,10.708504544888557],[3,6.638329791223903],[4,7.6230942264433885],[5,7.015130674002751],[6,8.763849122370223],[7,8.952807869505666],[8,13.56121814791796],[9,10.153423974055134],[10,10.926780591243606],[11,6.225826575171553],[12,11.89020586400499],[13,11.692038931869229],[14,8.594237245852563],[15,10.90455396132252],[16,27.02868350085805],[17,12.44228129289904],[18,13.291770573566083],[19,9.575],[20,11.679560768654854],[21,11.670195541163283],[22,19.142821441959263],[23,15.54559043348281],[24,12.289457267623206],[25,12.060613588374116]]}

@ -1,21 +1,29 @@
<div style="width: 100%; margin: auto">
<img src="RCN-Logo.png" style="margin: 0 calc(50% - 25px); max-width: 100px; height: auto"/>
</div>
<p>
The Raspberry pi Communication-Network is a network of Raspberry-Pi's.
It's currently still in development. <br> The purpose of this server is to
display the status of all raspberry-pi's in the network and the data
of several sensors that are connected to these raspberry pi's. The data
is stored in a database running on the main backend-server. The
frontend-server is running either on a differend device or also on the
backend-server-device. If this is the case, then the data is directly
fetched from several json files instead of using webservices. The json-
files are generated by a script running in the background that get's
data from the database and stores it in these json-files every few
seconds (depending on the type of data).
</p>
<div class="spacer">
</div>
<script type="text/javascript">
setTitle('About')
</script>
setTitle('About');
</script>
<div class="panelContainer">
<div class="panel">
<p>
The Raspberry pi Communication-Network is a network of Raspberry-Pi's.
It's currently still in development. <br> The purpose of this server is to
display the status of all raspberry-pi's in the network and the data
of several sensors that are connected to these raspberry pi's. The data
is stored in a database running on the main backend-server. The
frontend-server is running either on a differend device or also on the
backend-server-device. If this is the case, then the data is directly
fetched from several json files instead of using webservices. The json-
files are generated by a script running in the background that get's
data from the database and stores it in these json-files every few
seconds (depending on the type of data).
</p>
</div>
<div class="panel max-width">
<span class="title">
CPU Temperature
</span>
<div class="graph" onmouseout="hideTooltip()">
</div>
</div>
</div>
<script type="text/javascript" src="about.js"></script>

@ -3,7 +3,7 @@
<span class="title">
CPU Temperature
</span>
<div class="graph">
<div class="graph" onmouseout="hideTooltip()">
</div>
</div>
</div>

@ -0,0 +1,9 @@
function draw() {
$.getJSON('sys.json', data =>{
let c = document.querySelector('.graph');
drawGraph(c, data['100perc'], {yMax: 100, yMin: "0", xUnit: "s", yUnit: "%"});
});
}
draw();
let refreshInterval = setInterval(draw, 1000);

@ -83,6 +83,7 @@ var options = {};
function main() {
try {
prepro.setLogger(logger);
setInterval(utils.genSystemData, 1000);
protocoll.createServer(options, function (req, res) {
logger.verbose({'msg': 'Received request', 'method': req.method, 'url': req.url});

Loading…
Cancel
Save