mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-12 07:04:52 +09:00
Merge pull request #55 from DDR0/dev
ui improvements for the web interface storage tab
This commit is contained in:
commit
c52fd3f966
6 files changed
+128
-47
No files matched your search
@@ -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));
|
||||
});
|
||||
|
||||
+2
-1
@@ -1,7 +1,7 @@
|
||||
<!doctype HTML>
|
||||
<head>
|
||||
<%- include("head.html") %>
|
||||
<script src="storage.js"></script>
|
||||
<script defer src="storage.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
@@ -11,6 +11,7 @@
|
||||
<h2>Storage</h2>
|
||||
<input type="text" placeholder="search" id="search"></input>
|
||||
<div id="contents">
|
||||
<table><tbody><!-- populated by js --></tbody></table>
|
||||
</div>
|
||||
<canvas id="contentGraph" width="200" height="200"></canvas>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -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) => {
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 126 B |
+33
-32
@@ -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"
|
||||
|
||||
+49
-13
@@ -1,16 +1,49 @@
|
||||
// function to draw data we recieve from ajax requests
|
||||
_lastData = [];
|
||||
function drawcontents(data) {
|
||||
data = sortByKey(data, "count");
|
||||
let result = "<table>";
|
||||
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 + "<tr><td><image src='" + img + "' onerror='hideThis(this);'></td><td>" + data[i].name + "</td><td>" + data[i].count + "</td></tr>";
|
||||
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 = "<td><img width=32 height=32></td><td class=name></td><td class=count></td>";
|
||||
table.appendChild(row);
|
||||
}
|
||||
|
||||
const img = row.querySelector('img');
|
||||
const imgName = getImageFromName(item.name);
|
||||
if(img.getAttribute('src') !== imgName) {
|
||||
img.setAttribute('src',imgName);
|
||||
}
|
||||
|
||||
const name = row.querySelector('.name');
|
||||
if(name.textContent !== item.name) {
|
||||
name.textContent = item.name;
|
||||
}
|
||||
|
||||
const count = row.querySelector('.count');
|
||||
if(count.textContent !== ''+item.count) {
|
||||
count.textContent = item.count;
|
||||
}
|
||||
});
|
||||
|
||||
//remove excess rows, for example, after filtering
|
||||
while (data.length < rows.length) {
|
||||
table.removeChild(rows[data.length]);
|
||||
}
|
||||
result = result + "</table>"
|
||||
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];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelector("#search").addEventListener('input', function() {
|
||||
drawcontents();
|
||||
})
|
||||
Reference in new issue
Block a user