Last active
June 6, 2019 14:12
-
-
Save argrath/1416b0fecd8e6bda5b8279e03e776a61 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @id iitc-plugin-graph-difference | |
// @name IITC plugin: Graph Difference | |
// @category Tweaks | |
// @version 0.2019060 | |
// @namespace https://github.com/jonatkins/ingress-intel-total-conversion | |
// @description Graph difference | |
// @include https://*.ingress.com/intel* | |
// @include http://*.ingress.com/intel* | |
// @match https://*.ingress.com/intel* | |
// @match http://*.ingress.com/intel* | |
// @include https://*.ingress.com/mission/* | |
// @include http://*.ingress.com/mission/* | |
// @match https://*.ingress.com/mission/* | |
// @match http://*.ingress.com/mission/* | |
// @grant none | |
// ==/UserScript== | |
function wrapper(plugin_info) { | |
// ensure plugin framework is there, even if iitc is not yet loaded | |
if(typeof window.plugin !== 'function') window.plugin = function() {}; | |
// PLUGIN START //////////////////////////////////////////////////////// | |
window.plugin.graphDifference = function() {}; | |
window.plugin.graphDifference.setup = function() { | |
window.addHook('iitcLoaded', function() { | |
window.regionScoreboard = function () { | |
// TODO: rather than just load the region scores for the center of the map, display a list of regions in the current view | |
// and let the user select one (with automatic selection when just one region, and limited to close enough zooms so list size is reasonable) | |
var latLng = map.getCenter(); | |
var latE6 = Math.round(latLng.lat*1E6); | |
var lngE6 = Math.round(latLng.lng*1E6); | |
var dlg = dialog({title:'Region scores',html:'Loading regional scores...',width:450,minHeight:320}); | |
window.postAjax('getRegionScoreDetails', {latE6:latE6,lngE6:lngE6}, function(res){window.plugin.graphDifference.success(res,dlg);}, function(){regionScoreboardFailure(dlg);}); | |
} | |
} | |
) | |
} | |
window.plugin.graphDifference.chart = function (result, logscale) { | |
// svg area 400x130. graph area 350x100, offset to 40,10 | |
if(!Math.log10) | |
Math.log10 = function(x) { return Math.log(x) / Math.LN10; }; | |
var max = Math.max(result.gameScore[0],result.gameScore[1],10); //NOTE: ensure a min of 10 for the graph | |
var items = []; //we'll copy the items to an array indexed by checkpoint number - easier to access! | |
var cal = 0; | |
// for (var i=0; i<result.scoreHistory.length; i++) { | |
for (var i=result.scoreHistory.length-1; i>=0; i--) { | |
var s1 = result.scoreHistory[i][1]; | |
var s2 = result.scoreHistory[i][2]; | |
cal = cal + (s1 - s2); | |
max = Math.max(max, cal, -cal); //note: index 0 is the checkpoint number here | |
items[result.scoreHistory[i][0]] = [Math.max(cal, 0), Math.max(-cal, 0)]; | |
} | |
// items.reverse(); | |
// scale up maximum a little, so graph isn't squashed right against upper edge | |
max *= 1.09; | |
// 0 cannot be displayed on a log scale, so we set the minimum to 0.001 and divide by lg(0.001)=-3 | |
var scale = logscale | |
? function(y) { return 10 - Math.log10(Math.max(0.001,y/max)) / 3 * 100; } | |
: function(y) { return 110-y/max*100; }; | |
var teamPaths = [[],[]]; | |
var otherSvg = []; | |
for (var i=0; i<items.length; i++) { | |
var x=i*10+40; | |
if (items[i] !== undefined) { | |
// paths | |
if (i>0 && items[i-1] !== undefined) { | |
for (var t=0; t<2; t++) { | |
teamPaths[t].push('M'+(x-10)+','+scale(items[i-1][t])+' L'+x+','+scale(items[i][t])); | |
} | |
} | |
// markers | |
otherSvg.push('<g title="test" class="checkpoint" data-cp="'+i+'" data-enl="'+items[i][0]+'" data-res="'+items[i][1]+'">'); | |
otherSvg.push('<rect x="'+(i*10+35)+'" y="10" width="10" height="100" fill="black" fill-opacity="0" />'); | |
for (var t=0; t<2; t++) { | |
var col = t==0 ? COLORS[TEAM_ENL] : COLORS[TEAM_RES]; | |
otherSvg.push('<circle cx="'+x+'" cy="'+scale(items[i][t])+'" r="3" stroke-width="1" stroke="'+col+'" fill="'+col+'" fill-opacity="0.5" />'); | |
} | |
otherSvg.push('</g>'); | |
} | |
} | |
var paths = '<path d="M40,110 L40,10 M40,110 L390,110" stroke="#fff" />'; | |
// graph tickmarks - horizontal | |
var ticks = []; | |
for (var i=5; i<=35; i+=5) { | |
var x=i*10+40; | |
ticks.push('M'+x+',10 L'+x+',110'); | |
otherSvg.push('<text x="'+x+'" y="125" font-size="12" font-family="Roboto, Helvetica, sans-serif" text-anchor="middle" fill="#fff">'+i+'</text>'); | |
} | |
// vertical | |
// first we calculate the power of 10 that is smaller than the max limit | |
var vtickStep = Math.pow(10,Math.floor(Math.log10(max))); | |
var vticks = []; | |
if(logscale) { | |
for(var i=0;i<4;i++) { | |
vticks.push(vtickStep); | |
vtickStep /= 10; | |
} | |
} else { | |
// this could be between 1 and 10 grid lines - so we adjust to give nicer spacings | |
if (vtickStep < (max/5)) { | |
vtickStep *= 2; | |
} else if (vtickStep > (max/2)) { | |
vtickStep /= 2; | |
} | |
for (var i=vtickStep; i<=max; i+=vtickStep) { | |
vticks.push(i); | |
} | |
} | |
vticks.forEach(function(i) { | |
var y = scale(i); | |
ticks.push('M40,'+y+' L390,'+y); | |
var istr = i>=1000000000 ? i/1000000000+'B' : i>=1000000 ? i/1000000+'M' : i>=1000 ? i/1000+'k' : i; | |
otherSvg.push('<text x="35" y="'+y+'" font-size="12" font-family="Roboto, Helvetica, sans-serif" text-anchor="end" fill="#fff">'+istr+'</text>'); | |
}); | |
paths += '<path d="'+ticks.join(' ')+'" stroke="#fff" opacity="0.3" />;' | |
for (var t=0; t<2; t++) { | |
var col = t==0 ? COLORS[TEAM_ENL] : COLORS[TEAM_RES]; | |
if (teamPaths[t].length > 0) { | |
paths += '<path d="'+teamPaths[t].join(' ')+'" stroke="'+col+'" />'; | |
} | |
var y = scale(result.gameScore[t]); | |
paths += '<path d="M40,'+y+' L390,'+y+'" stroke="'+col+'" stroke-dasharray="3,2" opacity="0.8" />'; | |
} | |
var svg = '<div><svg width="400" height="130">' | |
+'<rect x="0" y="0" width="400" height="130" stroke="#FFCE00" fill="#08304E" />' | |
+paths | |
+otherSvg.join('') | |
+'<foreignObject height="18" width="45" y="111" x="0" class="node"><label title="Logarithmic scale">' | |
+'<input type="checkbox" class="logscale" style="height:auto;padding:0;vertical-align:middle"'+(logscale?' checked':'')+'/>' | |
+'log</label></foreignObject>' | |
+'</svg></div>'; | |
return svg; | |
} | |
window.plugin.graphDifference.table = function (result) { | |
var history = result.scoreHistory; | |
var table = '<table class="checkpoint_table"><thead><tr><th>Checkpoint</th><th>Enlightened</th><th>Resistance</th></tr></thead>'; | |
for(var i=0; i<history.length; i++) { | |
table += '<tr><td>' + history[i][0] + '</td><td>' + digits(history[i][1]) + '</td><td>' + digits(history[i][2]) + '</td></tr>'; | |
} | |
table += '</table>'; | |
return table; | |
} | |
window.plugin.graphDifference.success = function (data,dlg,logscale) { | |
if (data.result === undefined) { | |
return regionScoreboardFailure(dlg); | |
} | |
var agentTable = '<table><tr><th>#</th><th>Agent</th></tr>'; | |
for (var i=0; i<data.result.topAgents.length; i++) { | |
var agent = data.result.topAgents[i]; | |
agentTable += '<tr><td>'+(i+1)+'</td><td class="nickname '+(agent.team=='RESISTANCE'?'res':'enl')+'">'+agent.nick+'</td></tr>'; | |
} | |
if (data.result.topAgents.length==0) { | |
agentTable += '<tr><td colspan="2"><i>no top agents</i></td></tr>'; | |
} | |
agentTable += '</table>'; | |
var maxAverage = Math.max(data.result.gameScore[0], data.result.gameScore[1], 1); | |
var teamRow = []; | |
for (var t=0; t<2; t++) { | |
var team = t==0 ? 'Enlightened' : 'Resistance'; | |
var teamClass = t==0 ? 'enl' : 'res'; | |
var teamCol = t==0 ? COLORS[TEAM_ENL] : COLORS[TEAM_RES]; | |
var barSize = Math.round(data.result.gameScore[t]/maxAverage*200); | |
teamRow[t] = '<tr><th class="'+teamClass+'">'+team+'</th><td class="'+teamClass+'">'+digits(data.result.gameScore[t])+'</td><td><div style="background:'+teamCol+'; width: '+barSize+'px; height: 1.3ex; border: 2px outset '+teamCol+'"> </td></tr>'; | |
} | |
var first = PLAYER.team == 'RESISTANCE' ? 1 : 0; | |
// we need some divs to make the accordion work properly | |
dlg.html('<div class="cellscore">' | |
+'<b>Region scores for '+data.result.regionName+'</b>' | |
+'<div><table>'+teamRow[first]+teamRow[1-first]+'</table>' | |
+window.plugin.graphDifference.chart(data.result, logscale)+'</div>' | |
+'<b>Checkpoint overview</b>' | |
+'<div>'+window.plugin.graphDifference.table(data.result)+'</div>' | |
+'<b>Top agents</b>' | |
+'<div>'+agentTable+'</div>' | |
+'</div>'); | |
$('g.checkpoint', dlg).each(function(i, elem) { | |
elem = $(elem); | |
var tooltip = 'CP:\t'+elem.attr('data-cp') | |
+ '\nEnl:\t' + digits(elem.attr('data-enl')) | |
+ '\nRes:\t' + digits(elem.attr('data-res')); | |
elem.tooltip({ | |
content: convertTextToTableMagic(tooltip), | |
position: {my: "center bottom", at: "center top-10"} | |
}); | |
}); | |
$('.cellscore', dlg).accordion({ | |
header: 'b', | |
heightStyle: "fill", | |
}); | |
$('input.logscale', dlg).change(function(){ | |
var input = $(this); | |
window.plugin.graphDifference.success(data, dlg, input.prop('checked')); | |
}); | |
} | |
var setup = window.plugin.graphDifference.setup; | |
// PLUGIN END ////////////////////////////////////////////////////////// | |
setup.info = plugin_info; //add the script info data to the function as a property | |
if(!window.bootPlugins) window.bootPlugins = []; | |
window.bootPlugins.push(setup); | |
// if IITC has already booted, immediately run the 'setup' function | |
if(window.iitcLoaded && typeof setup === 'function') setup(); | |
} // wrapper end | |
// inject code into site context | |
var script = document.createElement('script'); | |
var info = {}; | |
if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description }; | |
script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');')); | |
(document.body || document.head || document.documentElement).appendChild(script); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment