Ability to categorize networks
This commit is contained in:
130
assets/js/graph.js
Normal file
130
assets/js/graph.js
Normal file
@ -0,0 +1,130 @@
|
||||
// Used by the individual server entries
|
||||
var smallChartOptions = {
|
||||
series: {
|
||||
shadowSize: 0
|
||||
},
|
||||
xaxis: {
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
show: false
|
||||
},
|
||||
yaxis: {
|
||||
minTickSize: 75,
|
||||
tickDecimals: 0,
|
||||
show: true,
|
||||
tickLength: 10,
|
||||
tickFormatter: function(value) {
|
||||
return formatNumber(value);
|
||||
},
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
labelWidth: -10
|
||||
},
|
||||
grid: {
|
||||
hoverable: true,
|
||||
color: "#696969"
|
||||
},
|
||||
colors: [
|
||||
"#E9E581"
|
||||
]
|
||||
};
|
||||
|
||||
// Used by the one chart to rule them all
|
||||
var bigChartOptions = {
|
||||
series: {
|
||||
shadowSize: 0
|
||||
},
|
||||
xaxis: {
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
show: false
|
||||
},
|
||||
yaxis: {
|
||||
show: true,
|
||||
tickSize: 2000,
|
||||
tickLength: 10,
|
||||
tickFormatter: function(value) {
|
||||
return formatNumber(value);
|
||||
},
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
labelWidth: -5,
|
||||
min: 0
|
||||
},
|
||||
grid: {
|
||||
hoverable: true,
|
||||
color: "#696969"
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
};
|
||||
|
||||
function toggleControlsDrawer() {
|
||||
var div = $('#big-graph-controls-drawer');
|
||||
|
||||
div.css('display', div.css('display') !== 'none' ? 'none' : 'block');
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
// Called by flot.js when they hover over a data point.
|
||||
function handlePlotHover(event, pos, item) {
|
||||
if (item) {
|
||||
var text = getTimestamp(item.datapoint[0] / 1000) + '\
|
||||
<br />\
|
||||
' + formatNumber(item.datapoint[1]) + ' Players';
|
||||
|
||||
if (item.series && item.series.label) {
|
||||
text = item.series.label + '<br />' + text;
|
||||
}
|
||||
|
||||
renderTooltip(item.pageX + 5, item.pageY + 5, text);
|
||||
} else {
|
||||
hideTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
// Converts the backend data into the schema used by flot.js
|
||||
function convertGraphData(rawData) {
|
||||
var data = [];
|
||||
|
||||
var keys = Object.keys(rawData);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
data.push({
|
||||
data: rawData[keys[i]],
|
||||
yaxis: 1,
|
||||
label: keys[i],
|
||||
color: stringToColor(keys[i])
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
@ -1,69 +1,3 @@
|
||||
var smallChartOptions = {
|
||||
series: {
|
||||
shadowSize: 0
|
||||
},
|
||||
xaxis: {
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
show: false
|
||||
},
|
||||
yaxis: {
|
||||
minTickSize: 75,
|
||||
tickDecimals: 0,
|
||||
show: true,
|
||||
tickLength: 10,
|
||||
tickFormatter: function(value) {
|
||||
return formatNumber(value);
|
||||
},
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
labelWidth: -10
|
||||
},
|
||||
grid: {
|
||||
hoverable: true,
|
||||
color: "#696969"
|
||||
},
|
||||
colors: [
|
||||
"#E9E581"
|
||||
]
|
||||
};
|
||||
|
||||
var bigChartOptions = {
|
||||
series: {
|
||||
shadowSize: 0
|
||||
},
|
||||
xaxis: {
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
show: false
|
||||
},
|
||||
yaxis: {
|
||||
show: true,
|
||||
tickSize: 2000,
|
||||
tickLength: 10,
|
||||
tickFormatter: function(value) {
|
||||
return formatNumber(value);
|
||||
},
|
||||
font: {
|
||||
color: "#E3E3E3"
|
||||
},
|
||||
labelWidth: -5,
|
||||
min: 0
|
||||
},
|
||||
grid: {
|
||||
hoverable: true,
|
||||
color: "#696969"
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
}
|
||||
};
|
||||
|
||||
var lastMojangServiceUpdate;
|
||||
|
||||
var graphs = {};
|
||||
var lastPlayerEntries = {};
|
||||
|
||||
@ -71,57 +5,6 @@ var historyPlot;
|
||||
var displayedGraphData;
|
||||
var hiddenGraphData = [];
|
||||
|
||||
// Generate (and set) the HTML that displays Mojang status.
|
||||
function updateMojangServices() {
|
||||
if (!lastMojangServiceUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
var keys = Object.keys(lastMojangServiceUpdate);
|
||||
var newStatus = 'Mojang Services: ';
|
||||
var serviceCountByType = {
|
||||
Online: 0,
|
||||
Unstable: 0,
|
||||
Offline: 0
|
||||
};
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var entry = lastMojangServiceUpdate[keys[i]];
|
||||
|
||||
serviceCountByType[entry.title] += 1;
|
||||
}
|
||||
|
||||
if (serviceCountByType['Online'] === keys.length) {
|
||||
$('#tagline').attr('class', 'status-online');
|
||||
|
||||
newStatus += 'All systems operational.';
|
||||
} else {
|
||||
if (serviceCountByType['Unstable'] > serviceCountByType['Offline']) {
|
||||
$('#tagline').attr('class', 'status-unstable');
|
||||
} else {
|
||||
$('#tagline').attr('class', 'status-offline');
|
||||
}
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var entry = lastMojangServiceUpdate[keys[i]];
|
||||
|
||||
if (entry.startTime) {
|
||||
newStatus += entry.name + ' ' + entry.title.toLowerCase() + ' for ' + msToTime((new Date()).getTime() - entry.startTime + ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('#tagline-text').text(newStatus);
|
||||
}
|
||||
|
||||
function findErrorMessage(error) {
|
||||
if (error.description) {
|
||||
return error.description;
|
||||
} else if (error.errno) {
|
||||
return error.errno;
|
||||
}
|
||||
}
|
||||
|
||||
function updateServerStatus(lastEntry) {
|
||||
var info = lastEntry.info;
|
||||
var div = $('#status_' + safeName(info.name));
|
||||
@ -171,19 +54,30 @@ function updateServerStatus(lastEntry) {
|
||||
}
|
||||
|
||||
function sortServers() {
|
||||
var keys = Object.keys(lastPlayerEntries);
|
||||
var nameList = [];
|
||||
var byCategories = getServersByCategory();
|
||||
|
||||
keys.sort(function(a, b) {
|
||||
return lastPlayerEntries[b] - lastPlayerEntries[a];
|
||||
});
|
||||
var categories = Object.keys(byCategories);
|
||||
|
||||
keys.reverse();
|
||||
for (var i = 0; i < categories.length; i++) {
|
||||
var relevantPlayers = [];
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
$('#' + safeName(keys[i])).prependTo('#server-container');
|
||||
for (var x = 0; x < byCategories[categories[i]].length; x++) {
|
||||
var server = byCategories[categories[i]][x];
|
||||
|
||||
$('#ranking_' + safeName(keys[i])).text('#' + (keys.length - i));
|
||||
relevantPlayers[server.name] = lastPlayerEntries[server.name];
|
||||
}
|
||||
|
||||
var keys = Object.keys(relevantPlayers);
|
||||
|
||||
keys.sort(function(a, b) {
|
||||
return relevantPlayers[b] - relevantPlayers[a];
|
||||
});
|
||||
|
||||
for (var x = 0; x < keys.length; x++) {
|
||||
$('#' + safeName(keys[x])).appendTo('#server-container-' + categories[i]);
|
||||
|
||||
$('#ranking_' + safeName(keys[x])).text('#' + (x + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -223,12 +117,6 @@ function setAllGraphVisibility(visible) {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleControlsDrawer() {
|
||||
var div = $('#big-graph-controls-drawer');
|
||||
|
||||
div.css('display', div.css('display') !== 'none' ? 'none' : 'block');
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
var socket = io.connect({
|
||||
reconnect: true,
|
||||
@ -239,8 +127,6 @@ $(document).ready(function() {
|
||||
var mojangServicesUpdater;
|
||||
var sortServersTask;
|
||||
|
||||
var graphDuration;
|
||||
|
||||
socket.on('connect', function() {
|
||||
$('#tagline-text').text('Loading...');
|
||||
|
||||
@ -264,18 +150,15 @@ $(document).ready(function() {
|
||||
lastPlayerEntries = {};
|
||||
graphs = {};
|
||||
|
||||
$('#server-container').html('');
|
||||
$('#quick-jump-container').html('');
|
||||
$('#server-container-list').html('');
|
||||
|
||||
createdCategories = false;
|
||||
|
||||
$('#big-graph').html('');
|
||||
$('#big-graph-checkboxes').html('');
|
||||
$('#big-graph-controls').css('display', 'none');
|
||||
});
|
||||
|
||||
socket.on('setGraphDuration', function(value) {
|
||||
graphDuration = value;
|
||||
});
|
||||
|
||||
socket.on('historyGraph', function(rawData) {
|
||||
var shownServers = loadGraphControls();
|
||||
|
||||
@ -335,14 +218,14 @@ $(document).ready(function() {
|
||||
|
||||
socket.on('updateHistoryGraph', function(rawData) {
|
||||
// Prevent race conditions.
|
||||
if (!graphDuration || !displayedGraphData || !hiddenGraphData) {
|
||||
if (!displayedGraphData || !hiddenGraphData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's not in our display group, use the hidden group instead.
|
||||
var targetGraphData = displayedGraphData[rawData.name] ? displayedGraphData : hiddenGraphData;
|
||||
|
||||
trimOldPings(targetGraphData, graphDuration);
|
||||
trimOldPings(targetGraphData, publicConfig.graphDuration);
|
||||
|
||||
targetGraphData[rawData.name].push([rawData.timestamp, rawData.players]);
|
||||
|
||||
@ -356,6 +239,8 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
socket.on('add', function(servers) {
|
||||
createCategories();
|
||||
|
||||
for (var i = 0; i < servers.length; i++) {
|
||||
var history = servers[i];
|
||||
var listing = [];
|
||||
@ -396,7 +281,7 @@ $(document).ready(function() {
|
||||
<div class="column" style="float: right;">\
|
||||
<div class="chart" id="chart_' + safeName(info.name) + '"></div>\
|
||||
</div>'
|
||||
}).appendTo("#server-container");
|
||||
}).appendTo("#server-container-" + getServerByIp(info.ip).category);
|
||||
|
||||
var favicon = MISSING_FAVICON_BASE64;
|
||||
|
||||
@ -406,8 +291,6 @@ $(document).ready(function() {
|
||||
|
||||
$('#favicon_' + safeName(info.name)).attr('src', favicon);
|
||||
|
||||
$('#quick-jump-container').append('<img id="quick-jump-' + safeName(info.name) + '" data-target-network="' + safeName(info.name) + '" title="' + info.name + '" alt="' + info.name + '" class="quick-jump-icon" src="' + favicon + '">');
|
||||
|
||||
graphs[lastEntry.info.name] = {
|
||||
listing: listing,
|
||||
plot: $.plot('#chart_' + safeName(info.name), [listing], smallChartOptions)
|
||||
@ -430,7 +313,6 @@ $(document).ready(function() {
|
||||
// We have a new favicon, update the old one.
|
||||
if (update.result && update.result.favicon) {
|
||||
$('#favicon_' + safeName(update.info.name)).attr('src', update.result.favicon);
|
||||
$('#quick-jump-' + safeName(update.info.name)).attr('src', update.result.favicon);
|
||||
}
|
||||
|
||||
var graph = graphs[update.info.name];
|
||||
@ -451,31 +333,11 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('updateMojangServices', function(data) {
|
||||
// Store the update and force an update.
|
||||
lastMojangServiceUpdate = data;
|
||||
|
||||
updateMojangServices();
|
||||
});
|
||||
socket.on('updateMojangServices', updateMojangServices);
|
||||
|
||||
// Start any special updating tasks.
|
||||
mojangServicesUpdater = setInterval(function() {
|
||||
updateMojangServices();
|
||||
}, 1000);
|
||||
|
||||
sortServersTask = setInterval(function() {
|
||||
sortServers();
|
||||
}, 10 * 1000);
|
||||
|
||||
// Our super fancy scrolly thing!
|
||||
$(document).on('click', '.quick-jump-icon', function(e) {
|
||||
var serverName = $(this).attr('data-target-network');
|
||||
var target = $('#server-' + serverName);
|
||||
|
||||
$('html, body').animate({
|
||||
scrollTop: target.offset().top
|
||||
}, 100);
|
||||
});
|
||||
mojangServicesUpdater = setInterval(updateMojangServices, 1000);
|
||||
sortServersTask = setInterval(sortServers, 10000);
|
||||
|
||||
$(document).on('click', '.graph-control', function(e) {
|
||||
var serverIp = $(this).attr('data-target-network');
|
||||
|
@ -2,28 +2,111 @@ var MISSING_FAVICON_BASE64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAA
|
||||
|
||||
var tooltip = $('#tooltip');
|
||||
|
||||
function saveGraphControls(displayedServers) {
|
||||
if (typeof(localStorage) !== undefined) {
|
||||
var json = JSON.stringify(displayedServers);
|
||||
var lastMojangServiceUpdate;
|
||||
var publicConfig;
|
||||
|
||||
localStorage.setItem('displayedServers', json);
|
||||
}
|
||||
var createdCategories = false;
|
||||
|
||||
function setPublicConfig(json) {
|
||||
publicConfig = json;
|
||||
}
|
||||
|
||||
function loadGraphControls() {
|
||||
if (typeof(localStorage) !== undefined) {
|
||||
var item = localStorage.getItem('displayedServers');
|
||||
function createCategories() {
|
||||
if (!createdCategories) {
|
||||
createdCategories = true;
|
||||
|
||||
if (item) {
|
||||
return JSON.parse(item);
|
||||
var keys = Object.keys(publicConfig.categories);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var title = publicConfig.categories[keys[i]];
|
||||
|
||||
$('#server-container-list').append('<div id="server-container-' + keys[i] + '" class="container server-container"><h3 class="category-header">' + title + '</h3></div>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function resetGraphControls() {
|
||||
if (typeof(localStorage) !== undefined) {
|
||||
localStorage.removeItem('displayedServers');
|
||||
function getServersByCategory() {
|
||||
var byCategory = {};
|
||||
|
||||
for (var i = 0; i < publicConfig.servers.length; i++) {
|
||||
var entry = publicConfig.servers[i];
|
||||
|
||||
if (!byCategory[entry.category]) {
|
||||
byCategory[entry.category] = [];
|
||||
}
|
||||
|
||||
byCategory[entry.category].push(entry);
|
||||
}
|
||||
|
||||
return byCategory;
|
||||
}
|
||||
|
||||
function getServerByIp(ip) {
|
||||
for (var i = 0; i < publicConfig.servers.length; i++) {
|
||||
var entry = publicConfig.servers[i];
|
||||
|
||||
if (entry.ip === ip) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate (and set) the HTML that displays Mojang status.
|
||||
// If nothing is passed, re-render the last update.
|
||||
// If something is passed, update and then re-render.
|
||||
function updateMojangServices(currentUpdate) {
|
||||
if (currentUpdate) {
|
||||
lastMojangServiceUpdate = currentUpdate;
|
||||
}
|
||||
|
||||
if (!lastMojangServiceUpdate) {
|
||||
return;
|
||||
}
|
||||
|
||||
var keys = Object.keys(lastMojangServiceUpdate);
|
||||
var newStatus = 'Mojang Services: ';
|
||||
|
||||
var serviceCountByType = {
|
||||
Online: 0,
|
||||
Unstable: 0,
|
||||
Offline: 0
|
||||
};
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var entry = lastMojangServiceUpdate[keys[i]];
|
||||
|
||||
serviceCountByType[entry.title] += 1;
|
||||
}
|
||||
|
||||
if (serviceCountByType['Online'] === keys.length) {
|
||||
$('#tagline').attr('class', 'status-online');
|
||||
|
||||
newStatus += 'All systems operational.';
|
||||
} else {
|
||||
if (serviceCountByType['Unstable'] > serviceCountByType['Offline']) {
|
||||
$('#tagline').attr('class', 'status-unstable');
|
||||
} else {
|
||||
$('#tagline').attr('class', 'status-offline');
|
||||
}
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var entry = lastMojangServiceUpdate[keys[i]];
|
||||
|
||||
if (entry.startTime) {
|
||||
newStatus += entry.name + ' ' + entry.title.toLowerCase() + ' for ' + msToTime((new Date()).getTime() - entry.startTime + ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$('#tagline-text').text(newStatus);
|
||||
}
|
||||
|
||||
function findErrorMessage(error) {
|
||||
if (error.description) {
|
||||
return error.description;
|
||||
} else if (error.errno) {
|
||||
return error.errno;
|
||||
}
|
||||
}
|
||||
|
||||
function getTimestamp(ms, timeOnly) {
|
||||
@ -84,39 +167,6 @@ function trimOldPings(data, graphDuration) {
|
||||
}
|
||||
}
|
||||
|
||||
function handlePlotHover(event, pos, item) {
|
||||
if (item) {
|
||||
var text = getTimestamp(item.datapoint[0] / 1000) + '\
|
||||
<br />\
|
||||
' + formatNumber(item.datapoint[1]) + ' Players';
|
||||
|
||||
if (item.series && item.series.label) {
|
||||
text = item.series.label + '<br />' + text;
|
||||
}
|
||||
|
||||
renderTooltip(item.pageX + 5, item.pageY + 5, text);
|
||||
} else {
|
||||
hideTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
function convertGraphData(rawData) {
|
||||
var data = [];
|
||||
|
||||
var keys = Object.keys(rawData);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
data.push({
|
||||
data: rawData[keys[i]],
|
||||
yaxis: 1,
|
||||
label: keys[i],
|
||||
color: stringToColor(keys[i])
|
||||
});
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
function stringToColor(base) {
|
||||
var hash;
|
||||
|
||||
|
Reference in New Issue
Block a user