-
- {{info.Hostname}}
-
+ {{serverinfo.Hostname}}
-
-
{{key}}: {{value}}
+
+
+ {{key}}:
+ {{value}}
+
-
-
diff --git a/index.html b/index.html
index 1286fbe..76ecddf 100644
--- a/index.html
+++ b/index.html
@@ -12,62 +12,7 @@
-
+
@@ -106,8 +51,8 @@
-
-
+
+
diff --git a/js/serverInfo.js b/js/serverInfo.js
index 56b31d5..8dacc45 100644
--- a/js/serverInfo.js
+++ b/js/serverInfo.js
@@ -1,19 +1,231 @@
+app.controller('ServerInfoController', ServerInfoController);
-app.controller( 'ServerInfoController', ServerInfoController );
+var DATA_LIMIT = 100;
+var recordedData = [];
-function ServerInfoController( $scope, rconService, $routeParams, $interval )
-{
- $scope.info = {};
+function ServerInfoController($scope, rconService, $routeParams, $interval) {
+ $scope.useCharts = false;
- $scope.refresh = function ()
- {
- rconService.Request( 'serverinfo', $scope, function ( msg ) {
- $scope.info = JSON.parse( msg.Message );
- } );
- }
+ // TODO: move serverinfo to service
+ $scope.serverinfo = {};
- rconService.InstallService( $scope, $scope.refresh );
+ $scope.playersChart = {
+ options: {
+ chart: {
+ type: 'pieChart',
+ height: 250,
+ margin: {
+ top: 0,
+ right: 75,
+ bottom: 0,
+ left: 75
+ },
+ donut: true,
+ x: function(d) {
+ return d.key;
+ },
+ y: function(d) {
+ return d.y;
+ },
+ yAxis: {
+ axisLabel: 'Slots',
+ tickFormat: function(d) {
+ return d3.format('.d')(d);
+ }
+ },
+ showLabels: true,
+ pie: {
+ startAngle: function(d) {
+ return d.startAngle / 2 - Math.PI / 2
+ },
+ endAngle: function(d) {
+ return d.endAngle / 2 - Math.PI / 2
+ }
+ },
+ duration: 500
+ }
+ },
+ data: []
+ };
+
+ $scope.performanceChart = {
+ options: {
+ chart: {
+ type: 'multiChart',
+ height: 200,
+ margin: {
+ top: 30,
+ right: 75,
+ bottom: 40,
+ left: 75
+ },
+ color: [
+ 'darkred', 'yellowgreen'
+ ],
+ duration: 0,
+ lines1: {
+ duration: 0
+ },
+ lines2: {
+ duration: 0
+ },
+ useInteractiveGuideline: true,
+ yAxis1: {
+ axisLabel: 'Framerate',
+ tickFormat: function(d) {
+ return d3.format(',d')(d);
+ }
+ },
+ yAxis2: {
+ axisLabel: 'Entities',
+ tickFormat: function(d) {
+ return d3.format(',d')(d);
+ },
+ // axisLabelDistance: 12
+ },
+ xAxis: {
+ axisLabel: "Time",
+ tickFormat: function(d) {
+ return d3.time.format('%H:%M:%S')(new Date(d))
+ }
+ }
+ }
+ },
+ data: [
+ {
+ key: 'Framerate',
+ type: "line",
+ duration: 0,
+ yAxis: 1,
+ values: []
+ }, {
+ key: 'Entities',
+ type: 'line',
+ duration: 0,
+ yAxis: 2,
+ values: []
+ }
+ ]
+ };
+
+ $scope.netChart = {
+ options: {
+ chart: {
+ type: 'stackedAreaChart',
+ height: 250,
+ margin: {
+ top: 0,
+ right: 75,
+ bottom: 40,
+ left: 75
+ },
+ useVoronoi: false,
+ duration: 0,
+ useInteractiveGuideline: true,
+ yAxis: {
+ axisLabel: 'Network',
+ tickFormat: function(bytes) {
+ var fmt = d3.format('.0f');
+ if (bytes < 1024) {
+ return fmt(bytes) + 'B';
+ } else if (bytes < 1024 * 1024) {
+ return fmt(bytes / 1024) + 'kB';
+ } else if (bytes < 1024 * 1024 * 1024) {
+ return fmt(bytes / 1024 / 1024) + 'MB';
+ } else {
+ return fmt(bytes / 1024 / 1024 / 1024) + 'GB';
+ }
+ }
+ },
+ xAxis: {
+ axisLabel: "Time",
+ tickFormat: function(d) {
+ return d3.time.format('%H:%M:%S')(new Date(d))
+ }
+ }
+ }
+ },
+ data: [
+ {
+ key: 'IN',
+ values: []
+ }, {
+ key: 'OUT',
+ values: []
+ }
+ ]
+ };
+
+ rconService.InstallService($scope, _refresh);
+
+ // TODO: move updateinterval to service
+ var timer = $interval(_refresh, 1000);
+ $scope.$on("$destroy", function() {
+ $interval.cancel(timer);
+ $scope.serverinfo = {};
+ });
+
+ function _refresh() {
+ rconService.Request('serverinfo', $scope, function(msg) {
+ _updateData(JSON.parse(msg.Message));
+ });
+ }
+
+ function _updateData(data) {
+ $scope.serverinfo = data;
+
+ if ($scope.useCharts) {
+ _collectChartData(data);
+ _generateChartData();
+ }
+ }
+
+ function _collectChartData(data) {
+ // player chart
+ $scope.playersChart.data = [
+ {
+ key: 'Queued',
+ y: data.Queued
+ }, {
+ key: 'Joining',
+ y: data.Joining
+ }, {
+ key: 'Players',
+ y: data.Players
+ }, {
+ key: 'Free',
+ y: (data.MaxPlayers - (data.Joining + data.Players))
+ }
+ ];
+
+ recordedData.push({ts: Date.now(), data: data});
+ if (recordedData.length > DATA_LIMIT) {
+ recordedData = recordedData.slice(Math.max(recordedData.length - DATA_LIMIT, 1));
+ }
+ }
+
+ function _generateChartData() {
+
+ var fpsChartValues = [];
+ var entChartValues = [];
+
+ var netInChartValues = [];
+ var netOutChartValues = [];
+
+ for (var i = 0; i < recordedData.length; i++) {
+ var record = recordedData[i];
+ fpsChartValues.push({x: record.ts, y: record.data.Framerate});
+ entChartValues.push({x: record.ts, y: record.data.EntityCount});
+
+ netInChartValues.push({x: record.ts, y: record.data.NetworkIn});
+ netOutChartValues.push({x: record.ts, y: record.data.NetworkOut});
+ }
+
+ $scope.performanceChart.data[0].values = fpsChartValues;
+ $scope.performanceChart.data[1].values = entChartValues;
+
+ $scope.netChart.data[0].values = netInChartValues;
+ $scope.netChart.data[1].values = netOutChartValues;
+ }
- var timer = $interval( $scope.refresh, 500 );
- $scope.$on( "$destroy", function () { $interval.cancel( timer ); } );
}
diff --git a/rcon.css b/rcon.css
index d62ac92..90b6a00 100644
--- a/rcon.css
+++ b/rcon.css
@@ -123,7 +123,7 @@ a:hover
color: #fff;
}
-.navbar-default .navbar-nav > li > .navbar-text,
+.navbar-default .navbar-text,
.navbar-default .navbar-nav > li > a, .navbar-default .navbar-nav > li > a:hover, .navbar-default .navbar-nav > li > a:focus
{
color: #fff;