diff --git a/master.js b/master.js
index 58e1547f..d5e0f079 100644
--- a/master.js
+++ b/master.js
@@ -307,6 +307,49 @@ app.post("/api/getStats", function(req,res) {
});
}
});
+
+// Modified version of getStats which feeds the web interface production graphs
+// at /nodes. It is like getStats but it does not report items which were not
+// produced at the moment of recording. (This is to save space, the 0-items were
+// making up about 92% of the response body weight.)
+app.post("/api/getTimelineStats", function(req,res) {
+ console.log(req.body);
+ if(typeof req.body == "object" && req.body.slaveID) {
+ // if not specified, get stats for last 24 hours
+ if(!req.body.fromTime) {
+ req.body.fromTime = Date.now() - 86400000 // 24 hours in MS
+ }
+ if(!req.body.toTime) {
+ req.body.toTime = Date.now();
+ }
+ console.log("Looking... " + JSON.stringify(req.body));
+ db.flows.find({
+ slaveID: req.body.slaveID,
+ }, function(err, docs) {
+ if(err) {
+ console.error(err);
+ return;
+ }
+
+ //Filter out all the entries outside the time range.
+ docs = docs.filter(function (el) {
+ return el.timestamp <= req.body.toTime && el.timestamp >= req.body.fromTime;
+ });
+
+ //Filter out all the elements that weren't produced.
+ docs.forEach(el => {
+ for(let key in el.data) {
+ if(el.data[key] === '0') {
+ delete el.data[key];
+ }
+ }
+ });
+
+ res.send(docs);
+ });
+ }
+});
+
app.get("/api/getFactorioLocale", function(req,res){
getFactorioLocale.asObject(config.factorioDirectory, "en", (err, factorioLocale) => res.send(factorioLocale));
});
diff --git a/static/index.html b/static/index.html
index 03a05b22..f5a5559e 100644
--- a/static/index.html
+++ b/static/index.html
@@ -1,7 +1,7 @@
<%- include("head.html") %>
-
+
@@ -11,6 +11,7 @@
Storage
+
diff --git a/static/main.js b/static/main.js
index 6806f13d..7cb7fdad 100644
--- a/static/main.js
+++ b/static/main.js
@@ -78,7 +78,7 @@ function getImageFromName(name){
return "https://wiki.factorio.com/images/" + capitalizeFirstLetter(replaceAll(factorioLocale["fluid-name"][name], ' ', '_').toLowerCase()) + ".png";
} else if(factorioLocale["equipment-name"] && factorioLocale["equipment-name"][name]){
return "https://wiki.factorio.com/images/" + capitalizeFirstLetter(replaceAll(factorioLocale["equipment-name"][name], ' ', '_').toLowerCase()) + ".png";
- } else return "";
+ } else return "/pictures/unknown-item.png";
}
window.factorioLocale = {};
$.getJSON("/api/getFactorioLocale", (locale) => {
diff --git a/static/pictures/unknown-item.png b/static/pictures/unknown-item.png
new file mode 100644
index 00000000..59a23725
Binary files /dev/null and b/static/pictures/unknown-item.png differ
diff --git a/static/slaveDisplay.js b/static/slaveDisplay.js
index 2add9d04..c1dc2292 100644
--- a/static/slaveDisplay.js
+++ b/static/slaveDisplay.js
@@ -44,32 +44,34 @@ let chartIgnoreList = [
// ID of slave, ID of canvasjs div without #
function makeGraph(slaveID, selector) {
- post("api/getStats", {slaveID: slaveID}, function(data){
+ post("api/getTimelineStats", {slaveID: slaveID}, function(pointsInTime) {
//console.log("Building chart " + slaveID + " with this data:")
- //console.log(data)
- if(data.length > 0) {
- // find keys
- let itemNames = [];
- for(let key in data[data.length - 1].data) {
- itemNames[itemNames.length] = key
+
+ //Find all keys at all points in time.
+ let itemNames = {};
+ pointsInTime.forEach(function(point) {
+ for(let key in point.data) {
+ itemNames[key] = true;
}
- let chartData = [];
- for(let o = 0; o < itemNames.length; o++) {
- if(!chartIgnoreList.includes(itemNames[o])){
- chartData[chartData.length] = generateLineChartArray(data, itemNames[o]);
- }
- }
- //console.log(chartData)
- drawChart(selector, chartData)
- }
- // callback(data);
+ });
+ itemNames = Object.keys(itemNames);
+
+ //Generate a chart list for each item.
+ const displayNames = itemNames.filter(function(name) {
+ return !chartIgnoreList.includes(name);
+ });
+ const chartData = displayNames.map(function(name) {
+ return generateLineChartArray(pointsInTime, name)
+ });
+
+ chartData.length && drawChart(selector, chartData)
})
}
// production info
// string, object, function(object)
function post(url, data, callback) {
- console.log("POST " + url + JSON.stringify(data))
+ console.log("POST " + url, data);
var xhr = new XMLHttpRequest();
xhr.open("POST", url, true);
xhr.setRequestHeader("Content-type", "application/json");
@@ -83,27 +85,26 @@ function post(url, data, callback) {
}
function generateLineChartArray(data, nameKey) {
+ const legendKeys = ["copper-cable", "iron-plate", "copper-plate", "electronic-circuit", "steel-plate", "advanced-circuit", "crude-oil", "petroleum-gas"];
let chartData = [];
for(let i = 0; i < data.length; i++) {
- // only show recent data
- if(data[i].timestamp > Date.now() - (24*60*60*1000)){
- let y = data[i].data[nameKey]
- if(!data[i].data[nameKey]) {
- y = 0;
- } else if(y < 0) {
- y = 0;
- }
- chartData[chartData.length] = {
- x: new Date(data[i].timestamp),
- y: Number(y)
- }
+ let y = data[i].data[nameKey]
+ if(!data[i].data[nameKey]) {
+ y = 0;
+ } else if(y < 0) {
+ y = 0;
+ }
+ chartData[chartData.length] = {
+ x: new Date(data[i].timestamp),
+ y: Number(y)
}
}
chartData = sortByKey(chartData, "x");
let xyz = {};
xyz.name = nameKey;
xyz.type = "line";
- if(nameKey == "copper-wire"||nameKey == "iron-plate"||nameKey == "copper-plate"||nameKey == "electronic-circuit"||nameKey == "steel-plate"||nameKey == "advanced-circuit"||nameKey == "crude-oil"||nameKey == "petroleum-gas"){
+
+ if(legendKeys.indexOf(nameKey) >= 0){
xyz.showInLegend = true;
}
xyz.dataPoints = chartData;
@@ -113,7 +114,7 @@ function generateLineChartArray(data, nameKey) {
var chartsByID = {};
function drawChart(selector, chartData) {
// selector is ID of element, ex "chartContainer" or "-123199123"
- console.log(chartData)
+ // console.log(chartData)
chartsByID[selector] = new CanvasJS.Chart(selector, {
title:{
text: "Production graph"
diff --git a/static/storage.js b/static/storage.js
index c68cd982..ee15e77d 100644
--- a/static/storage.js
+++ b/static/storage.js
@@ -1,16 +1,49 @@
// function to draw data we recieve from ajax requests
+_lastData = [];
function drawcontents(data) {
- data = sortByKey(data, "count");
- let result = "
";
- for(i = 0;i < data.length; i++) {
- var img = getImageFromName(data[i].name);
- var searchField = document.querySelector("#search");
- if(!searchField.value || data[i].name.includes(searchField.value)) {
- result = result + "
" + data[i].name + "
" + data[i].count + "
";
+ data = data || _lastData; //Cache data so we can drawcontents without waiting for the server, for the search box.
+ _lastData = data;
+
+ const search = new RegExp(document.querySelector("#search").value, 'i');
+ data = data.filter(function(item) {
+ return search.test(item.name);
+ })
+
+ sortByKey(data, "count");
+
+ const table = document.querySelector("#contents tbody"); //tables have tbody inserted automatically
+ const rows = table.children;
+
+ //update existing rows or create new ones
+ data.forEach(function(item, i) {
+ let row = rows[i];
+ if(!row) {
+ row = document.createElement('tr');
+ row.innerHTML = "
"
- document.getElementById("contents").innerHTML = result;
}
// get cluster inventory from master
@@ -33,8 +66,11 @@ if(JSON.parse(localStorage.settings)["Periodically update storage screen"]) {
// function to sort arrays of objects after a keys value
function sortByKey(array, key) {
- return array.sort(function(a, b) {
- var x = Number(a[key]); var y = Number(b[key]);
- return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ array.sort(function(a, b) {
+ return b[key] - a[key];
});
-}
\ No newline at end of file
+}
+
+document.querySelector("#search").addEventListener('input', function() {
+ drawcontents();
+})
\ No newline at end of file