X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=xonstat%2Fstatic%2Fjs%2FweaponCharts.js;h=3a0bf5c14fa02e721817de4801ae2780e17c1b38;hb=075c11600a553f75668633e1872608e2afa186cd;hp=8b3d64a6a538465310f164d1b4f0586c7a1e703e;hpb=1da06c9505c0449fa1a2321c3f8a3405d00ec64b;p=xonotic%2Fxonstat.git diff --git a/xonstat/static/js/weaponCharts.js b/xonstat/static/js/weaponCharts.js index 8b3d64a..3a0bf5c 100644 --- a/xonstat/static/js/weaponCharts.js +++ b/xonstat/static/js/weaponCharts.js @@ -27,257 +27,136 @@ var weaponColors = { "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"; -} - -// Draw the damage chart into the "damageChart" div id -function drawDamageChart(weaponData) { - - var data = new google.visualization.DataTable(); - data.addColumn('string', 'X'); - data.addColumn('number', 'Shotgun'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Machine Gun'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Vortex'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Rifle'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Mortar'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Electro'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Crylink'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Hagar'); - data.addColumn({type: 'string', role: 'tooltip'}); - data.addColumn('number', 'Devastator'); - 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 = damageValue(flattened[game_id], "shotgun"); - var sgTT = damageTooltip("shotgun", sg); - var mg = damageValue(flattened[game_id], "machinegun"); - var mgTT = damageTooltip("machinegun", mg); - var vortex = damageValue(flattened[game_id], "vortex"); - var vortexTT = damageTooltip("vortex", vortex); - var mn = damageValue(flattened[game_id], "vaporizer"); - var mnTT = damageTooltip("vaporizer", mn); - var rifle = damageValue(flattened[game_id], "rifle"); - var rifleTT = damageTooltip("rifle", rifle); - var mortar = damageValue(flattened[game_id], "mortar"); - var mortarTT = damageTooltip("mortar", mortar); - var electro = damageValue(flattened[game_id], "electro"); - var electroTT = damageTooltip("electro", electro); - var crylink = damageValue(flattened[game_id], "crylink"); - var crylinkTT = damageTooltip("crylink", crylink); - var hagar = damageValue(flattened[game_id], "hagar"); - var hagarTT = damageTooltip("hagar", hagar); - var rl = damageValue(flattened[game_id], "devastator"); - var rlTT = damageTooltip("devastator", rl); - var arc = damageValue(flattened[game_id], "arc"); - var arcTT = damageTooltip("arc", arc); - - data.addRow([ - game_id.toString(), - sg, sgTT, - mg, mgTT, - vortex, vortexTT, - rifle, rifleTT, - mortar, mortarTT, - electro, electroTT, - crylink, crylinkTT, - hagar, hagarTT, - rl, rlTT, - arc, arcTT - ]); - } - - var options = { - backgroundColor: { fill: 'transparent' }, - legend: { - position: 'top', - maxLines: 3, - textStyle: { color: "#666" } - }, - vAxis: { - title: 'HP Damage', - titleTextStyle: {color: '#666'}, - baselineColor: '#333', - gridlineColor: '#333', - }, - hAxis: { - title: 'Games', - textPosition: 'none', - titleTextStyle: { color: '#666' }, - }, - isStacked: true, - series: { - 0: { color: weaponColors["shotgun"] }, - 1: { color: weaponColors["machinegun"] }, - 2: { color: weaponColors["vortex"] }, - 3: { color: weaponColors["rifle"] }, - 4: { color: weaponColors["mortar"] }, - 5: { color: weaponColors["electro"] }, - 6: { color: weaponColors["crylink"] }, - 7: { color: weaponColors["hagar"] }, - 8: { color: weaponColors["devastator"] }, - 9: { color: weaponColors["arc"] } - } - }; - - var chart = new google.visualization.ColumnChart(document.getElementById('damageChart')); - - // a click on a point sends you to that game's page - var damageSelectHandler = 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', damageSelectHandler); +// 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 "
" + + key.point.weapon_cd + ": " + + Math.round(key.point.y*100) + "% (" + + Math.round(data.averages[key.point.weapon_cd]) + "% avg)" + + "
"; + }); + + 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; + }); +}; - chart.draw(data, options); -} +// 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 = "
" + + 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 += "
"; + + 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; + }); +};