]> git.xonotic.org Git - xonotic/xonstat.git/blobdiff - xonstat/static/js/weaponCharts.js
Change margin of the weaponCharts.
[xonotic/xonstat.git] / xonstat / static / js / weaponCharts.js
index dcd743e2bf7ccb128f2f560976a74d702989d521..3a0bf5c14fa02e721817de4801ae2780e17c1b38 100644 (file)
-var weapons = ["laser", "shotgun", "uzi", "grenadelauncher", "minelayer", "electro",
-    "crylink", "nex", "hagar", "rocketlauncher", "porto", "minstanex", "hook", "hlac",
-    "seeker", "rifle", "tuba", "fireball"];
-
-var weaponColors = ["#ff5933", "#b2b2b2", "#66e559", "#ff2600", "#bfbf00", "#597fff",
-    "#d83fff", "#00e5ff", "#d87f59", "#ffbf33", "#7fff7f", "#a5a5ff", "#a5ffd8",
-    "#ffa533", "#ff5959", "#d87f3f", "#d87f3f", "#33ff33"];
-
-var colorScale = d3.scale.ordinal().domain(weapons).range(weaponColors);
-
-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
-  keyColor = function(d, i) {return colorScale(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;
-  });
-}
-
-var drawAccuracyChart = function(data) {
-  // the chart should fill the "accuracyChart" div
-  var width = document.getElementById("accuracyChart").offsetWidth;
-
-  // get rid of empty values
-  data.weapon_stats = data.weapon_stats.filter(function(e){ return e.fired > 0; });
-
-  // transform the dataset into something nvd3 can use
-  var transformedData = d3.nest()
-    .key(function(d) { return d.weapon_cd; }).entries(data.weapon_stats);
-
-  var findNumGames = function(weapon) {
-    var numGames = transformedData.filter(function(e){return e.key == weapon})[0].values.length;
-    if(numGames !== undefined) {
-        return numGames;
-    } else {
-        return 0;
-    }
-  };
-
-  // 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: 40},
-      height = 300 - margin.top - margin.bottom;
-
-  width -= margin.left - margin.right;
-
-  // colors
-  keyColor = function(d, i) {return colorScale(d.key)};
-
-  var chart;
-  nv.addGraph(function() {
-    chart = nv.models.lineChart()
-      .margin(margin)
-      .width(width)
-      .height(height)
-      .forceY([0,1])
-      .x(function(d) { return games[d.game_id] })
-      .y(function(d) {
-        if(d.fired > 0) {
-          return d.hit/d.fired;
-        } else {
-          return 0;
-        }
-      })
-      .tooltip(function(key, x, y, e, graph) {
-        return '<h3>' + key + '</h3>' + '<p>' +  y + ' accuracy in game #' + x + ' <br /> ' + data.averages[key]  + '% average over ' + findNumGames(key) + ' games</p>';
-      })
-      .color(keyColor);
-
-    chart.xAxis
-      .axisLabel("Game ID")
-      .showMaxMin(false)
-      .ticks(5)
-      .tickFormat(function(d) { return data.games[d]; });
-
-    var yScale = d3.scale.linear().domain([0,1]).range([0,height]);
-    chart.yAxis
-      .axisLabel('% Accuracy')
-      .tickFormat(d3.format('2%'));
-
-    d3.select('#accuracyChartSVG')
-      .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"
+};
+
+// these weapons are used in the damage chart
+var damageWeapons = new Set(["vortex", "machinegun", "shotgun",
+        "arc", "uzi", "nex", "minstanex", "rifle", "grenadelauncher", "minelayer",
+        "rocketlauncher", "hlac", "seeker", "fireball",  
+        "mortar", "electro", "crylink", "hagar", "devastator"]);
+
+// these weapons are used in the accuracy chart
+var accuracyWeapons = new Set(["vortex", "machinegun", "shotgun", "vaporizer",
+        "arc", "uzi", "nex", "minstanex", "rifle"]);
+
+// draw an accuracy chart into the given element id
+function drawAccuracyChart(id, data) {
+
+    // transform games list into a map such that games[game_id] = linear sequence
+    var games = {};
+    data.games.forEach(function(v,i){ games[v] = i; });
+
+    // for use in filtering out weapons that were not fired
+    function wasFired(e) { return e.fired != 0; }
+
+    // for use in filtering out splash-damage weapons
+    function isAccuracyWeapon(e) { return accuracyWeapons.has(e.weapon_cd); }
+
+    // transform it into something NVD3 can use
+    var accuracyData = d3.nest().key(function(d) { return d.weapon_cd; })
+        .entries(data.weapon_stats.filter(isAccuracyWeapon).filter(wasFired));
+
+    nv.addGraph(function() {
+      var chart = nv.models.lineChart()
+        .useInteractiveGuideline(false)
+        .forceY([0,1])
+        .showLegend(true)
+        .showYAxis(true)
+        .showXAxis(true)
+        .color(function(d){ return weaponColors[d.key]; })
+        .x(function(d) { return games[d.game_id] })
+        .y(function(d) { return d.fired > 0 ? d.hit/d.fired : 0; })
+      ;
+
+      chart.tooltip.contentGenerator(function(key, y, e, graph) {
+          return "<table><tr><td>" +
+              key.point.weapon_cd + ": " +
+              Math.round(key.point.y*100) + "% (" +
+              Math.round(data.averages[key.point.weapon_cd]) + "% avg)" + 
+              "</td></tr></table>";
+      });
+
+      chart.lines.dispatch.on("elementClick", function(e) { 
+          window.location.href = "http://stats.xonotic.org/game/" + e.point.game_id.toString();
+      });
+
+      chart.yAxis
+          .axisLabel('Accuracy')
+          .tickFormat(d3.format('2%'));
+
+      chart.xAxis
+          .axisLabel('Games')
+          .tickFormat(function(e) { return ''; });
+
+      d3.select("#accuracyChartSVG")
+          .datum(accuracyData)
+          .call(chart);
+
+      nv.utils.windowResize(function() { chart.update() });
+      return chart;
+    });
+};
+
+// draw an damage chart into the given element id
+function drawDamageChart(id, data) {
+    
+    // transform games list into a map such that games[game_id] = linear sequence
+    var games = {};
+    data.games.forEach(function(v,i){ games[v] = i; });
+
+    // for use in filtering out splash-damage weapons
+    function isDamageWeapon(e) { return damageWeapons.has(e.weapon_cd); }
+
+    // transform it into something NVD3 can use
+    var damageData = d3.nest().key(function(d) { return d.weapon_cd; })
+        .entries(data.weapon_stats.filter(isDamageWeapon));
+
+    nv.addGraph(function() {
+        var chart = nv.models.multiBarChart()
+          .reduceXTicks(true)   //If 'false', every single x-axis tick label will be rendered.
+          .rotateLabels(0)      //Angle to rotate x-axis labels.
+          .showControls(true)   //Allow user to switch between 'Grouped' and 'Stacked' mode.
+          .groupSpacing(0.1)    //Distance between each group of bars.
+          .showXAxis(true)
+          .stacked(true)
+          .color(function(d){ return weaponColors[d.key]; })
+          .x(function(d) { return games[d.game_id] })
+          .y(function(d) { return d.actual; })
+        ;
+
+        chart.tooltip.contentGenerator(function(key, y, e, graph) {
+
+            var txt = "<table><tr><td>" +
+                key.data.weapon_cd  + ": " + key.data.actual + " HP damage";
+
+            if (key.data.frags > 0) {
+                if(key.data.frags > 1) {
+                    txt += " (" + key.data.frags + " frags)";
+                } else {
+                    txt += " (" + key.data.frags + " frag)";
+                }
+            }
+            txt += "</td></tr></table>";
+
+            return txt;
+        });
+
+        chart.multibar.dispatch.on("elementClick", function(e) { 
+            window.location.href = "http://stats.xonotic.org/game/" + e.data.game_id.toString();
+        });
+
+        chart.xAxis
+            .axisLabel('Games')
+            .tickFormat(function(e){ return '';});
+
+        chart.yAxis
+            .axisLabel('Damage (HP)')
+            .tickFormat(d3.format(',d'));
+
+        d3.select('#damageChartSVG')
+            .datum(damageData)
+            .call(chart);
+
+        nv.utils.windowResize(chart.update);
+
+        return chart;
+    });
+};