diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..5b4213d --- /dev/null +++ b/CHANGELOG.md @@ -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. diff --git a/README.md b/README.md index 08d09b7..a2757be 100644 --- a/README.md +++ b/README.md @@ -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```. diff --git a/app.js b/app.js index 6501a98..7b235c1 100644 --- a/app.js +++ b/app.js @@ -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 }); diff --git a/assets/js/site.js b/assets/js/site.js index 11d9e8f..0175218 100644 --- a/assets/js/site.js +++ b/assets/js/site.js @@ -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 += ' ' + keys[i] + ''; + var checkedString = ''; + + if (displayedGraphData[keys[i]]) { + checkedString = 'checked=checked'; + } + + html += ' ' + keys[i] + ''; 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)); + } }); }); diff --git a/assets/js/util.js b/assets/js/util.js index b128990..449effc 100644 --- a/assets/js/util.js +++ b/assets/js/util.js @@ -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); } diff --git a/lib/util.js b/lib/util.js index 0e9914b..de946a1 100644 --- a/lib/util.js +++ b/lib/util.js @@ -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; }; \ No newline at end of file diff --git a/package.json b/package.json index b277459..f33df8b 100644 --- a/package.json +++ b/package.json @@ -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": {