diff --git a/USERGUIDE.md b/USERGUIDE.md index 99ee4779..d5d6ac59 100644 --- a/USERGUIDE.md +++ b/USERGUIDE.md @@ -102,7 +102,8 @@ Starting from the top, the sidebar shows this information: #### logged in user, global MU, search - Details about you, the logged in user. This is only updated if you reload the page. This is a limitation of Ingress, not IITC. - - it shows your current level followed by your nick + - it shows your current level followed by your nickname + - hovering over your nickname allows you to sign out (NIGHTLY ONLY) - to the right, it shows to percentages. The upper one, e.g. “XM: 37%” tells you how much your XM bar is filled. The lower one, e.g. “level: 37%“ tells you that you have gathered 37% of the AP required for the next level. It shows “max level” if you have reached max level. - the tooltip mainly shows you absolute numbers instead of percentages. It also shows how many invites you have. - The next bar is a visual representation of global MindUnits (MU) per faction. It is updated every now and then. The tooltip shows the absolute MU count per faction. diff --git a/code/boot.js b/code/boot.js index fcb76729..7e5882a2 100644 --- a/code/boot.js +++ b/code/boot.js @@ -186,13 +186,22 @@ window.setupPlayerStat = function() { $('#playerstat').html('' + '

'+level+' ' + + '
' + ''+PLAYER.nickname+'' - + '
' + + 'sign out' + + '
' + + '
' + 'XM: '+xmRatio+'%' + '' + (level < 8 ? 'level: '+lvlApProg+'%' : 'max level') + '' + '
' + '

' ); + + $('#name').mouseenter(function() { + $('#signout').show(); + }).mouseleave(function() { + $('#signout').hide(); + }); } window.setupSidebarToggle = function() { diff --git a/code/map_data.js b/code/map_data.js index 529f9c70..157ab1d6 100644 --- a/code/map_data.js +++ b/code/map_data.js @@ -49,21 +49,28 @@ window.requestData = function() { $.each(tiles, function(ind, tls) { data = { minLevelOfDetail: -1 }; data.boundsParamsList = tls; - window.requests.add(window.postAjax('getThinnedEntitiesV2', data, window.handleDataResponse)); + window.requests.add(window.postAjax('getThinnedEntitiesV2', data, window.handleDataResponse, window.handleFailedRequest)); }); } +// Handle failed map data request +window.handleFailedRequest = function() { + if(requests.isLastRequest('getThinnedEntitiesV2')) { + var leftOverPortals = portalRenderLimit.mergeLowLevelPortals(null); + handlePortalsRender(leftOverPortals); + } +} + // works on map data response and ensures entities are drawn/updated. window.handleDataResponse = function(data, textStatus, jqXHR) { // remove from active ajax queries list if(!data || !data.result) { window.failedRequestCount++; console.warn(data); + handleFailedRequest(); return; } - var portalUpdateAvailable = false; - var portalInUrlAvailable = false; var m = data.result.map; // defer rendering of portals because there is no z-index in SVG. // this means that what’s rendered last ends up on top. While the @@ -72,8 +79,6 @@ window.handleDataResponse = function(data, textStatus, jqXHR) { // https://github.com/Leaflet/Leaflet/issues/185 var ppp = []; var p2f = {}; - // Reset new portals count of Portal Render Limit handler - portalRenderLimit.resetCounting(); $.each(m, function(qk, val) { $.each(val.deletedGameEntityGuids, function(ind, guid) { if(getTypeByGuid(guid) === TYPE_FIELD && window.fields[guid] !== undefined) { @@ -92,8 +97,6 @@ window.handleDataResponse = function(data, textStatus, jqXHR) { // format for portals: { controllingTeam, turret } if(ent[2].turret !== undefined) { - if(selectedPortal === ent[0]) portalUpdateAvailable = true; - if(urlPortal && ent[0] == urlPortal) portalInUrlAvailable = true; var latlng = [ent[2].locationE6.latE6/1E6, ent[2].locationE6.lngE6/1E6]; if(!window.getPaddedBounds().contains(latlng) @@ -102,7 +105,7 @@ window.handleDataResponse = function(data, textStatus, jqXHR) { ) return; - portalRenderLimit.pushPortal(ent); + ppp.push(ent); // delay portal render } else if(ent[2].edge !== undefined) { renderLink(ent); @@ -118,7 +121,7 @@ window.handleDataResponse = function(data, textStatus, jqXHR) { } }); }); - + $.each(ppp, function(ind, portal) { if(portal[2].portalV2['linkedFields'] === undefined) { portal[2].portalV2['linkedFields'] = []; @@ -128,12 +131,29 @@ window.handleDataResponse = function(data, textStatus, jqXHR) { portal[2].portalV2['linkedFields'] = uniqueArray(p2f[portal[0]]); } }); + + // Process the portals with portal render limit handler first + // Low level portal will hold until last request + var newPpp = portalRenderLimit.splitOrMergeLowLevelPortals(ppp); + handlePortalsRender(newPpp); + + resolvePlayerNames(); + renderUpdateStatus(); +} + +window.handlePortalsRender = function(portals) { + var portalUpdateAvailable = false; + var portalInUrlAvailable = false; // Preserve and restore "selectedPortal" between portal re-render if(portalUpdateAvailable) var oldSelectedPortal = selectedPortal; - runHooks('portalDataLoaded', {portals : ppp}); - $.each(ppp, function(ind, portal) { renderPortal(portal); }); + runHooks('portalDataLoaded', {portals : portals}); + $.each(portals, function(ind, portal) { + if(selectedPortal === portal[0]) portalUpdateAvailable = true; + if(urlPortal && portal[0] == urlPortal) portalInUrlAvailable = true; + renderPortal(portal); + }); var selectedPortalLayer = portals[oldSelectedPortal]; if(portalUpdateAvailable && selectedPortalLayer) selectedPortal = oldSelectedPortal; @@ -150,8 +170,6 @@ window.handleDataResponse = function(data, textStatus, jqXHR) { } if(portalUpdateAvailable) renderPortalDetails(selectedPortal); - resolvePlayerNames(); - renderUpdateStatus(); } // removes entities that are still handled by Leaflet, although they @@ -492,9 +510,9 @@ window.renderLink = function(ent) { weight:2, clickable: false, guid: ent[0], + data: ent[2], smoothFactor: 0 // doesn’t work for two points anyway, so disable }); - // determine which links are very short and don’t render them at all. // in most cases this will go unnoticed, but improve rendering speed. poly._map = window.map; @@ -590,7 +608,8 @@ window.renderField = function(ent) { vertices: reg, lastUpdate: ent[1], creationZoom: map.getZoom(), - guid: ent[0] + guid: ent[0], + data: ent[2]}); }; // However, LayerGroups (and FeatureGroups) don’t fire add/remove diff --git a/code/portal_render_limit.js b/code/portal_render_limit.js index 58961023..ec4e93a2 100644 --- a/code/portal_render_limit.js +++ b/code/portal_render_limit.js @@ -3,9 +3,22 @@ // Functions to handle hiding low level portal when portal render // limit is reached. // -// After initialized and reset in window.requestData(), portals in -// response data will pass to function "pushPortal". Each new portal -// not on the map will add 1 to newPortalsPerLevel[portal level]. +// On initialization, previous minLevel will preserve to previousMinLevel +// with zoom level difference. +// +// After initialized and reset in window.requestData(), "processPortals" +// intercept all portals data in "handleDataResponse". Put the count of +// new portals to newPortalsPerLevel[portal level]. And split portals +// into two parts base on previousMinLevel. Portals with level >= +// previousMinLevel will return as result and continue to render. +// Others will save to portalsPreviousMinLevel. If there is no more +// active request of map data, portals will not split and +// portalsPreviousMinLevel will add back to result and render base on +// current minLevel. +// +// "handleFailRequest" is added to handle the case when the last request +// failed and "processPortals" didn't get called. It will get +// portalsPreviousMinLevel base on current minLevel and render them. // // "getMinLevel" will be called by "getMinPortalLevel" in utils_misc.js // to determine min portal level to draw on map. @@ -28,12 +41,28 @@ window.portalRenderLimit = function() {} window.portalRenderLimit.initialized = false; window.portalRenderLimit.minLevelSet = false; window.portalRenderLimit.minLevel = -1; +window.portalRenderLimit.previousMinLevel = -1; +window.portalRenderLimit.previousZoomLevel; window.portalRenderLimit.newPortalsPerLevel = new Array(MAX_PORTAL_LEVEL + 1); +window.portalRenderLimit.portalsPreviousMinLevel = new Array(MAX_PORTAL_LEVEL + 1); window.portalRenderLimit.init = function () { + var currentZoomLevel = map.getZoom(); + portalRenderLimit.previousZoomLevel = portalRenderLimit.previousZoomLevel || currentZoomLevel; + + // If there is a minLevel set in previous run, calculate previousMinLevel with it. + if(portalRenderLimit.minLevelSet) { + var zoomDiff = currentZoomLevel - portalRenderLimit.previousZoomLevel; + portalRenderLimit.previousMinLevel = Math.max(portalRenderLimit.minLevel - zoomDiff, -1); + portalRenderLimit.previousMinLevel = Math.min(portalRenderLimit.previousMinLevel, MAX_PORTAL_LEVEL); + } + + portalRenderLimit.previousZoomLevel = currentZoomLevel; + portalRenderLimit.initialized = true; portalRenderLimit.minLevel = -1; portalRenderLimit.resetCounting(); + portalRenderLimit.resetPortalsPreviousMinLevel(); } window.portalRenderLimit.resetCounting = function() { @@ -43,13 +72,59 @@ window.portalRenderLimit.resetCounting = function() { } } -window.portalRenderLimit.pushPortal = function(ent) { - var portalGuid = ent[0]; - var portalLevel = parseInt(getPortalLevel(ent[2])); - var layerGroup = portalsLayers[portalLevel]; - - if(findEntityInLeaflet(layerGroup, window.portals, ent[0])) return; - portalRenderLimit.newPortalsPerLevel[portalLevel]++; +window.portalRenderLimit.resetPortalsPreviousMinLevel = function() { + for(var i = 0; i <= MAX_PORTAL_LEVEL; i++) { + portalRenderLimit.portalsPreviousMinLevel[i] = new Array(); + } +} + +window.portalRenderLimit.splitOrMergeLowLevelPortals = function(originPortals) { + portalRenderLimit.resetCounting(); + portalRenderLimit.countingPortals(originPortals); + + var resultPortals = requests.isLastRequest('getThinnedEntitiesV2') + ? portalRenderLimit.mergeLowLevelPortals(originPortals) + : portalRenderLimit.splitLowLevelPortals(originPortals); + + return resultPortals; +} + +window.portalRenderLimit.countingPortals = function(portals) { + $.each(portals, function(ind, portal) { + var portalGuid = portal[0]; + var portalLevel = parseInt(getPortalLevel(portal[2])); + var layerGroup = portalsLayers[portalLevel]; + + if(findEntityInLeaflet(layerGroup, window.portals, portalGuid)) return true; + + portalRenderLimit.newPortalsPerLevel[portalLevel]++; + }); +} + +window.portalRenderLimit.splitLowLevelPortals = function(portals) { + var resultPortals = new Array(); + $.each(portals, function(ind, portal) { + var portalLevel = parseInt(getPortalLevel(portal[2])); + if(portalLevel < portalRenderLimit.previousMinLevel) { + portalRenderLimit.portalsPreviousMinLevel[portalLevel].push(portal); + }else{ + resultPortals.push(portal); + } + }); + return resultPortals; +} + +window.portalRenderLimit.mergeLowLevelPortals = function(appendTo) { + var resultPortals = appendTo ? appendTo : new Array(); + for(var i = portalRenderLimit.getMinLevel(); + i < portalRenderLimit.previousMinLevel; + i++) { + $.merge(resultPortals, portalRenderLimit.portalsPreviousMinLevel[i]); + } + + // Reset portalsPreviousMinLevel, ensure they return only once + portalRenderLimit.resetPortalsPreviousMinLevel(); + return resultPortals; } window.portalRenderLimit.getMinLevel = function() { diff --git a/code/request_handling.js b/code/request_handling.js index 6fe0acd3..6766fd5f 100644 --- a/code/request_handling.js +++ b/code/request_handling.js @@ -111,3 +111,14 @@ window.requests._callOnRefreshFunctions = function() { window.requests.addRefreshFunction = function(f) { window.requests._onRefreshFunctions.push(f); } + +window.requests.isLastRequest = function(action) { + var result = true; + $.each(window.activeRequests, function(ind, req) { + if(req.action === action) { + result = false; + return false; + } + }); + return result; +} \ No newline at end of file diff --git a/code/utils_misc.js b/code/utils_misc.js index 270ce855..8fb3dfd5 100644 --- a/code/utils_misc.js +++ b/code/utils_misc.js @@ -58,7 +58,7 @@ window.postAjax = function(action, data, success, error) { data = JSON.stringify($.extend({method: 'dashboard.'+action}, data)); var remove = function(data, textStatus, jqXHR) { window.requests.remove(jqXHR); }; var errCnt = function(jqXHR) { window.failedRequestCount++; window.requests.remove(jqXHR); }; - return $.ajax({ + var result = $.ajax({ // use full URL to avoid issues depending on how people set their // slash. See: // https://github.com/breunigs/ingress-intel-total-conversion/issues/56 @@ -73,6 +73,8 @@ window.postAjax = function(action, data, success, error) { req.setRequestHeader('X-CSRFToken', readCookie('csrftoken')); } }); + result.action = action; + return result; } // converts unix timestamps to HH:mm:ss format if it was today; diff --git a/plugins/guess-player-levels.user.js b/plugins/guess-player-levels.user.js index c220a76d..cd77945b 100644 --- a/plugins/guess-player-levels.user.js +++ b/plugins/guess-player-levels.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @id iitc-plugin-guess-player-levels@breunigs // @name iitc: guess player level -// @version 0.2.1 +// @version 0.3 // @namespace https://github.com/breunigs/ingress-intel-total-conversion // @updateURL https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/guess-player-levels.user.js // @downloadURL https://raw.github.com/breunigs/ingress-intel-total-conversion/gh-pages/plugins/guess-player-levels.user.js @@ -92,19 +92,30 @@ window.plugin.guessPlayerLevels.guess = function() { var namesR = plugin.guessPlayerLevels.sort(playersRes); var namesE = plugin.guessPlayerLevels.sort(playersEnl); + var totallvlR = 0; + var totallvlE = 0; var max = Math.max(namesR.length, namesE.length); for(var i = 0; i < max; i++) { var nickR = namesR[i]; var lvlR = playersRes[nickR]; var lineR = nickR ? nickR + ':\t' + lvlR : '\t'; - + if(!isNaN(parseInt(lvlR))) + totallvlR += parseInt(lvlR); + var nickE = namesE[i]; var lvlE = playersEnl[nickE]; var lineE = nickE ? nickE + ':\t' + lvlE : '\t'; - - s += lineR + '\t\t' + lineE + '\n'; + if(!isNaN(parseInt(lvlE))) + totallvlE += parseInt(lvlE); + + s += '\n'+lineR + '\t' + lineE + '\n'; } - + s += '\nTotal level :\t'+totallvlR+'\tTotal level :\t'+totallvlE; + s += '\nTotal player:\t'+namesR.length+'\tTotal player:\t'+namesE.length; + var averageR = 0, averageE = 0; + if (namesR.length > 0) averageR = (totallvlR/namesR.length); + if (namesE.length > 0) averageE = (totallvlE/namesE.length); + s += '\nAverage level:\t'+averageR.toFixed(2)+'\tAverage level:\t'+averageE.toFixed(2); s += '\n\nIf there are some unresolved names, simply try again.' console.log(s); alert(s); diff --git a/style.css b/style.css index 7763bb22..f25501f9 100644 --- a/style.css +++ b/style.css @@ -338,21 +338,34 @@ h2 { width: 100%; } -h2 span { +h2 #name { display: inline-block; overflow: hidden; text-overflow: "~"; vertical-align: top; white-space: nowrap; width: 205px; + position: relative; } -h2 div { +h2 #stats { float: right; height: 100%; overflow: hidden; } +h2 #signout { + font-size: 12px; + font-weight: normal; + line-height: 29px; + padding: 0 4px; + position: absolute; + top: 0; + right: 0; + background-color: rgba(8, 48, 78, 0.5); + display: none; /* starts hidden */ +} + h2 sup, h2 sub { display: block; font-size: 11px;