Merge pull request #24 from Cryptkeeper/new-design

2.0.0
This commit is contained in:
Cryptkeeper 2016-02-01 05:46:54 -06:00
commit c2dd49bf15
7 changed files with 125 additions and 33 deletions

5
CHANGELOG.md Normal file
View File

@ -0,0 +1,5 @@
**2.0.0**
- Servers are now referenced by their name on the graph controls instead of their IP.
- Servers now display their name on hover instead of their IP.
- Graph controls are now saved and loaded automatically.
- Moved server configuration into servers.json from config.json.

View File

@ -16,6 +16,9 @@ You can see an up-to-date copy of the master branch running on http://minetrack.
Database logging is disabled by default. You can enable it in ```config.json``` by setting ```logToDatabase``` to true.
This requires sqlite3 drivers to be installed.
#### What's being changed?
For the changelog, check out the [CHANGELOG](CHANGELOG.md) file.
#### How do I get added?
At the moment, the main "minetrack.me" site is only accepting networks that average roughly 1,000 players at peak for **PC** servers, and 100 players at peak for **PE** servers. This is due to limited capacity and it's functionality. If you fit this description, you're welcome to open a Pull Request adding the network to ```config.json```.

7
app.js
View File

@ -104,15 +104,16 @@ function handlePing(network, res, err) {
// Don't have too much data!
util.trimOldPings(graphData);
if (!graphData[network.ip]) {
graphData[network.ip] = [];
if (!graphData[network.name]) {
graphData[network.name] = [];
}
graphData[network.ip].push([timeMs, res ? res.players.online : 0]);
graphData[network.name].push([timeMs, res ? res.players.online : 0]);
// Send the update.
server.io.sockets.emit('updateHistoryGraph', {
ip: network.ip,
name: network.name,
players: (res ? res.players.online : 0),
timestamp: timeMs
});

View File

@ -214,6 +214,13 @@ function setAllGraphVisibility(visible) {
historyPlot.setupGrid();
historyPlot.draw();
// Update our localStorage
if (visible) {
resetGraphControls();
} else {
saveGraphControls(Object.keys(displayedGraphData));
}
}
function toggleControlsDrawer() {
@ -270,11 +277,30 @@ $(document).ready(function() {
});
socket.on('historyGraph', function(rawData) {
displayedGraphData = rawData;
var shownServers = loadGraphControls();
if (shownServers) {
var keys = Object.keys(rawData);
hiddenGraphData = [];
displayedGraphData = [];
for (var i = 0; i < keys.length; i++) {
var name = keys[i];
if (shownServers.indexOf(name) !== -1) {
displayedGraphData[name] = rawData[name];
} else {
hiddenGraphData[name] = rawData[name];
}
}
} else {
displayedGraphData = rawData;
}
$('#big-graph').css('height', '400px');
historyPlot = $.plot('#big-graph', convertGraphData(rawData), bigChartOptions);
historyPlot = $.plot('#big-graph', convertGraphData(displayedGraphData), bigChartOptions);
$('#big-graph').bind('plothover', handlePlotHover);
@ -286,7 +312,13 @@ $(document).ready(function() {
keys.sort();
for (var i = 0; i < keys.length; i++) {
html += '<td><input type="checkbox" class="graph-control" id="graph-controls" data-target-network="' + keys[i] + '" checked=checked> ' + keys[i] + '</input></td>';
var checkedString = '';
if (displayedGraphData[keys[i]]) {
checkedString = 'checked=checked';
}
html += '<td><input type="checkbox" class="graph-control" id="graph-controls" data-target-network="' + keys[i] + '" ' + checkedString + '> ' + keys[i] + '</input></td>';
if (sinceBreak >= 7) {
sinceBreak = 0;
@ -303,19 +335,19 @@ $(document).ready(function() {
socket.on('updateHistoryGraph', function(rawData) {
// Prevent race conditions.
if (!graphDuration) {
if (!graphDuration || !displayedGraphData || !hiddenGraphData) {
return;
}
// If it's not in our display group, use the hidden group instead.
var targetGraphData = displayedGraphData[rawData.ip] ? displayedGraphData : hiddenGraphData;
var targetGraphData = displayedGraphData[rawData.name] ? displayedGraphData : hiddenGraphData;
trimOldPings(targetGraphData, graphDuration);
targetGraphData[rawData.ip].push([rawData.timestamp, rawData.players]);
targetGraphData[rawData.name].push([rawData.timestamp, rawData.players]);
// Redraw if we need to.
if (displayedGraphData[rawData.ip]) {
if (displayedGraphData[rawData.name]) {
historyPlot.setData(convertGraphData(displayedGraphData));
historyPlot.setupGrid();
@ -460,9 +492,17 @@ $(document).ready(function() {
delete hiddenGraphData[serverIp];
}
// Redraw the graph
historyPlot.setData(convertGraphData(displayedGraphData));
historyPlot.setupGrid();
historyPlot.draw();
// Update our localStorage
if (Object.keys(hiddenGraphData).length === 0) {
resetGraphControls();
} else {
saveGraphControls(Object.keys(displayedGraphData));
}
});
});

View File

@ -2,6 +2,30 @@ var MISSING_FAVICON_BASE64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAA
var tooltip = $('#tooltip');
function saveGraphControls(displayedServers) {
if (typeof(localStorage) !== undefined) {
var json = JSON.stringify(displayedServers);
localStorage.setItem('displayedServers', json);
}
}
function loadGraphControls() {
if (typeof(localStorage) !== undefined) {
var item = localStorage.getItem('displayedServers');
if (item) {
return JSON.parse(item);
}
}
}
function resetGraphControls() {
if (typeof(localStorage) !== undefined) {
localStorage.removeItem('displayedServers');
}
}
function getTimestamp(ms, timeOnly) {
var date = new Date(0);
@ -96,7 +120,7 @@ function convertGraphData(rawData) {
function stringToColor(base) {
var hash;
for (var i = 0, hash = 0; i < base.length; i++) {
for (var i = base.length - 1, hash = 0; i >= 0; i--) {
hash = base.charCodeAt(i) + ((hash << 5) - hash);
}

View File

@ -1,17 +1,39 @@
var logger = require('./logger');
var config = require('../config.json');
var servers = require('../servers.json');
// Checks if we have a server in config.json with the IP.
function serverWithIpExists(ip) {
var serverNameLookup = {};
// Finds a server in servers.json with a matching IP.
// If it finds one, it caches the result for faster future lookups.
function getServerNameByIp(ip) {
var lookupName = serverNameLookup[ip];
if (lookupName) {
return lookupName;
}
for (var i = 0; i < servers.length; i++) {
var entry = servers[i];
if (entry.ip === ip) {
return true;
serverNameLookup[entry.ip] = entry.name;
return entry.name;
}
}
}
return false;
// Returns a list of configured server IPs from servers.json
function getServerIps() {
var ips = [];
for (var i = 0; i < servers.length; i++) {
ips.push(servers[i].ip);
}
return ips;
}
// This method is a monstrosity.
@ -20,16 +42,7 @@ function serverWithIpExists(ip) {
function trimUselessPings(data) {
var keys = Object.keys(data);
var keysToRemove = [];
for (var i = 0; i < keys.length; i++) {
// Don't bother we servers we deleted from config.json
if (!serverWithIpExists(keys[i])) {
keysToRemove.push(keys[i]);
continue;
}
var listing = data[keys[i]];
var lastTimestamp = 0;
@ -55,11 +68,6 @@ function trimUselessPings(data) {
data[keys[i]] = filteredListing;
}
// Delete data for any networks we don't care about anymore.
for (var i = 0; i < keysToRemove.length; i++) {
delete data[keysToRemove[i]];
}
}
exports.trimOldPings = function(data) {
@ -98,16 +106,25 @@ exports.setIntervalNoDelay = function(func, delay) {
};
exports.convertPingsToGraph = function(sqlData) {
var serverIps = getServerIps();
var graphData = {};
var startTime = exports.getCurrentTimeMs();
for (var i = 0; i < sqlData.length; i++) {
var entry = sqlData[i];
if (!graphData[entry.ip]) {
graphData[entry.ip] = [];
if (serverIps.indexOf(entry.ip) === -1) {
continue;
}
graphData[entry.ip].push([entry.timestamp, entry.playerCount]);
var name = getServerNameByIp(entry.ip);
if (!graphData[name]) {
graphData[name] = [];
}
graphData[name].push([entry.timestamp, entry.playerCount]);
}
// Break it into minutes.
@ -116,5 +133,7 @@ exports.convertPingsToGraph = function(sqlData) {
// Drop old data.
exports.trimOldPings(graphData);
logger.info('Converted data structure in ' + (exports.getCurrentTimeMs() - startTime) + 'ms');
return graphData;
};

View File

@ -1,6 +1,6 @@
{
"name": "minetrack",
"version": "1.0.0",
"version": "2.0.0",
"description": "A Minecraft server tracker that lets you focus on the basics.",
"main": "app.js",
"dependencies": {