-var weapons = ["laser", "shotgun", "uzi", "grenadelauncher", "electro", "crylink",
- "nex", "hagar", "rocketlauncher", "minstanex", "rifle", "fireball",
- "minelayer", "seeker", "tuba", "hlac", "hook", "porto"];
-
-var drawDamageChart = function(data) {
- // the chart should fill the "damageChart" div
- var width = document.getElementById("damageChart").offsetWidth;
-
- // transform the dataset into something nvd3 can use
- var transformedData = d3.nest()
- .key(function(d) { return d.weapon_cd; }).entries(data.weapon_stats);
-
- // transform games list into a map such that games[game_id] = linear sequence
- var games = {};
- data.games.forEach(function(v,i){ games[v] = i; });
-
- // margin model
- var margin = {top: 20, right: 30, bottom: 30, left: 60},
- height = 300 - margin.top - margin.bottom;
-
- width -= margin.left - margin.right;
-
- // colors
- var colors = d3.scale.category20().domain(weapons);
- keyColor = function(d, i) {return colors(d.key)};
-
- var chart;
- nv.addGraph(function() {
- chart = nv.models.stackedAreaChart()
- .margin(margin)
- .width(width)
- .height(height)
- .x(function(d) { return games[d.game_id] })
- .y(function(d) { return d.actual })
- .tooltip(function(key, x, y, e, graph) {
- return '<h3>' + key + '</h3>' + '<p>' + y + ' damage in game #' + x + '</p>'
- })
- .color(keyColor);
-
- chart.xAxis
- .axisLabel("Game ID")
- .showMaxMin(false)
- .ticks(5)
- .tickFormat(function(d) { return data.games[d]; });
-
- chart.yAxis
- .tickFormat(d3.format(',02d'));
-
- d3.select('#damageChartSVG')
- .datum(transformedData)
- .transition().duration(500).call(chart);
-
- nv.utils.windowResize(chart.update);
-
- return chart;
- });
+// Colors assigned to the various weapons
+var weaponColors = {
+ "arc": "#b8e9ff",
+ "laser": "#ff5933",
+ "blaster": "#ff5933",
+ "shotgun": "#1f77b4",
+ "uzi": "#b9e659",
+ "machinegun": "#b9e659",
+ "grenadelauncher": "#ff2600",
+ "mortar": "#ff2600",
+ "minelayer": "#bfbf00",
+ "electro": "#597fff",
+ "crylink": "#d940ff",
+ "nex": "#00e6ff",
+ "vortex": "#00e6ff",
+ "hagar": "#d98059",
+ "rocketlauncher": "#ffbf33",
+ "devastator": "#ffbf33",
+ "porto": "#7fff7f",
+ "minstanex": "#d62728",
+ "vaporizer": "#d62728",
+ "hook": "#a5ffd8",
+ "hlac": "#ffa533",
+ "seeker": "#ff5959",
+ "rifle": "#9467bd",
+ "tuba": "#d87f3f",
+ "fireball": "#33ff33"
+};
+
+// Flatten the existing weaponstats JSON requests
+// to ease indexing
+var flatten = function(weaponData) {
+ flattened = {}
+
+ // each game is a key entry...
+ weaponData.games.forEach(function(e,i) { flattened[e] = {}; });
+
+ // ... with indexes by weapon_cd
+ weaponData.weapon_stats.forEach(function(e,i) { flattened[e.game_id][e.weapon_cd] = e; });
+
+ return flattened;
+}
+
+// Calculate the Y value for a given weapon stat
+function accuracyValue(gameWeaponStats, weapon) {
+ if (gameWeaponStats[weapon] == undefined) {
+ return null;
+ }
+ var ws = gameWeaponStats[weapon];
+ var pct = ws.fired > 0 ? Math.round((ws.hit / ws.fired) * 100) : 0;
+
+ return pct;
+}
+
+// Calculate the tooltip text for a given weapon stat
+function accuracyTooltip(weapon, pct, averages) {
+ if (pct == null) {
+ return null;
+ }
+
+ var tt = weapon + ": " + pct.toString() + "%";
+ if (averages[weapon] != undefined) {
+ return tt + " (" + averages[weapon].toString() + "% average)";
+ }
+
+ return tt;
+}
+
+// Draw the accuracy chart in the "accuracyChart" div id
+function drawAccuracyChart(weaponData) {
+
+ var data = new google.visualization.DataTable();
+ data.addColumn('string', 'X');
+ data.addColumn('number', 'Shotgun');
+ data.addColumn({type: 'string', role: 'tooltip'});
+ data.addColumn('number', 'MG');
+ data.addColumn({type: 'string', role: 'tooltip'});
+ data.addColumn('number', 'Vortex');
+ data.addColumn({type: 'string', role: 'tooltip'});
+ data.addColumn('number', 'Vaporizer');
+ data.addColumn({type: 'string', role: 'tooltip'});
+ data.addColumn('number', 'Rifle');
+ data.addColumn({type: 'string', role: 'tooltip'});
+ data.addColumn('number', 'Arc');
+ data.addColumn({type: 'string', role: 'tooltip'});
+
+ var flattened = flatten(weaponData);
+
+ for(i in weaponData.games) {
+ var game_id = weaponData.games[i];
+ var sg = accuracyValue(flattened[game_id], "shotgun");
+ var sgTT = accuracyTooltip("shotgun", sg, weaponData.averages);
+ var mg = accuracyValue(flattened[game_id], "machinegun");
+ var mgTT = accuracyTooltip("machinegun", mg, weaponData.averages);
+ var vortex = accuracyValue(flattened[game_id], "vortex");
+ var vortexTT = accuracyTooltip("vortex", vortex, weaponData.averages);
+ var mn = accuracyValue(flattened[game_id], "vaporizer");
+ var mnTT = accuracyTooltip("vaporizer", mn, weaponData.averages);
+ var rifle = accuracyValue(flattened[game_id], "rifle");
+ var rifleTT = accuracyTooltip("rifle", rifle, weaponData.averages);
+ var arc = accuracyValue(flattened[game_id], "arc");
+ var arcTT = accuracyTooltip("arc", arc, weaponData.averages);
+
+ data.addRow([game_id.toString(), sg, sgTT, mg, mgTT, vortex,
+ vortexTT, mn, mnTT, rifle, rifleTT, arc, arcTT]);
+ }
+
+ var options = {
+ backgroundColor: { fill: 'transparent' },
+ lineWidth: 2,
+ legend: {
+ textStyle: { color: "#666" }
+ },
+ hAxis: {
+ title: 'Games',
+ textPosition: 'none',
+ titleTextStyle: { color: '#666' }
+ },
+ vAxis: {
+ title: 'Percentage',
+ titleTextStyle: { color: '#666' },
+ minValue: 0,
+ maxValue: 100,
+ baselineColor: '#333',
+ gridlineColor: '#333',
+ ticks: [20, 40, 60, 80, 100]
+ },
+ series: {
+ 0: { color: weaponColors["shotgun"] },
+ 1: { color: weaponColors["machinegun"] },
+ 2: { color: weaponColors["vortex"] },
+ 3: { color: weaponColors["vaporizer"] },
+ 4: { color: weaponColors["rifle"] },
+ 5: { color: weaponColors["arc"] }
+ }
+ };
+
+ var chart = new google.visualization.LineChart(document.getElementById('accuracyChart'));
+
+ // a click on a point sends you to that games' page
+ var accuracySelectHandler = function(e) {
+ var selection = chart.getSelection()[0];
+ if (selection != null && selection.row != null) {
+ var game_id = data.getFormattedValue(selection.row, 0);
+ window.location.href = "http://stats.xonotic.org/game/" + game_id.toString();
+ }
+ };
+ google.visualization.events.addListener(chart, 'select', accuracySelectHandler);
+
+ chart.draw(data, options);
+}
+
+// Calculate the damage Y value for a given weapon stat
+function damageValue(gameWeaponStats, weapon) {
+ if (gameWeaponStats[weapon] == undefined) {
+ return null;
+ }
+ return gameWeaponStats[weapon].actual;
+}
+
+// Calculate the damage tooltip text for a given weapon stat
+function damageTooltip(weapon, dmg) {
+ if (dmg == null) {
+ return null;
+ }
+ return weapon + ": " + dmg.toString() + " HP damage";