diff --git a/README.md b/README.md index b5a6486d..afd73b95 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Contributors [mledoze](https://github.com/mledoze), [OshiHidra](https://github.com/OshiHidra), [Scrool](https://github.com/Scrool), +[sorgo](https://github.com/sorgo), [Xelio](https://github.com/Xelio), [ZauberNerd](https://github.com/ZauberNerd) diff --git a/code/boot.js b/code/boot.js index 5c735d9a..ec9be61c 100644 --- a/code/boot.js +++ b/code/boot.js @@ -93,7 +93,22 @@ window.setupMap = function() { map.attributionControl.setPrefix(''); // listen for changes and store them in cookies map.on('moveend', window.storeMapPosition); - map.on('zoomend', window.storeMapPosition); + map.on('zoomend', function() { + window.storeMapPosition; + + // remove all resonators if zoom out to < RESONATOR_DISPLAY_ZOOM_LEVEL + if(isResonatorsShow()) return; + for(var i = 1; i < portalsLayers.length; i++) { + portalsLayers[i].eachLayer(function(item) { + var itemGuid = item.options.guid; + // check if 'item' is a resonator + if(getTypeByGuid(itemGuid) != TYPE_RESONATOR) return true; + portalsLayers[i].removeLayer(item); + }); + } + + console.log('Remove all resonators'); + }); $("[name='leaflet-base-layers']").change(function () { writeCookie('ingress.intelmap.type', $(this).parent().index()); }); diff --git a/code/map_data.js b/code/map_data.js index cc747a76..98749a6a 100644 --- a/code/map_data.js +++ b/code/map_data.js @@ -142,13 +142,16 @@ window.cleanUp = function() { var minlvl = getMinPortalLevel(); for(var i = 0; i < portalsLayers.length; i++) { // i is also the portal level - portalsLayers[i].eachLayer(function(portal) { + portalsLayers[i].eachLayer(function(item) { + var itemGuid = item.options.guid; + // check if 'item' is a portal + if(getTypeByGuid(itemGuid) != TYPE_PORTAL) return true; // portal must be in bounds and have a high enough level. Also don’t // remove if it is selected. - if(portal.options.guid == window.selectedPortal || - (b.contains(portal.getLatLng()) && i >= minlvl)) return; + if(itemGuid == window.selectedPortal || + (b.contains(item.getLatLng()) && i >= minlvl)) return true; cnt[0]++; - portalsLayers[i].removeLayer(portal); + portalsLayers[i].removeLayer(item); }); } linksLayer.eachLayer(function(link) { @@ -182,6 +185,12 @@ window.removeByGuid = function(guid) { if(!window.fields[guid]) return; fieldsLayer.removeLayer(window.fields[guid]); break; + case TYPE_RESONATOR: + if(!window.resonators[guid]) return; + var r = window.resonators[guid]; + for(var i = 1; i < portalsLayers.length; i++) + portalsLayers[i].removeLayer(r); + break; default: console.warn('unknown GUID type: ' + guid); //window.debug.printStackTrace(); @@ -230,7 +239,17 @@ window.renderPortal = function(ent) { details: ent[2], guid: ent[0]}); - p.on('remove', function() { delete window.portals[this.options.guid]; }); + p.on('remove', function() { + var portalGuid = this.options.guid + + // remove attached resonators, skip if + // all resonators have already removed by zooming + if(isResonatorsShow()) { + for(var i = 0; i <= 7; i++) + removeByGuid(portalResonatorGuid(portalGuid,i)); + } + delete window.portals[portalGuid]; + }); p.on('add', function() { window.portals[this.options.guid] = this; // handles the case where a selected portal gets removed from the @@ -243,10 +262,69 @@ window.renderPortal = function(ent) { window.renderPortalDetails(ent[0]); window.map.setView(latlng, 17); }); + + window.renderResonators(ent); + // portalLevel contains a float, need to round down p.addTo(portalsLayers[parseInt(portalLevel)]); } +window.renderResonators = function(ent) { + + var portalLevel = getPortalLevel(ent[2]); + if(portalLevel < getMinPortalLevel() && ent[0] != selectedPortal) return; + + if(!isResonatorsShow()) return; + + for(var i=0; i < ent[2].resonatorArray.resonators.length; i++) { + var rdata = ent[2].resonatorArray.resonators[i]; + + if(rdata == null) continue; + + if(window.resonators[portalResonatorGuid(ent[0],i)]) continue; + + // offset in meters + var dn = rdata.distanceToPortal*SLOT_TO_LAT[rdata.slot]; + var de = rdata.distanceToPortal*SLOT_TO_LNG[rdata.slot]; + + // Coordinate offset in radians + var dLat = dn/EARTH_RADIUS; + var dLon = de/(EARTH_RADIUS*Math.cos(Math.PI/180*(ent[2].locationE6.latE6/1E6))); + + // OffsetPosition, decimal degrees + var lat0 = ent[2].locationE6.latE6/1E6 + dLat * 180/Math.PI; + var lon0 = ent[2].locationE6.lngE6/1E6 + dLon * 180/Math.PI; + var Rlatlng = [lat0, lon0]; + var r = L.circleMarker(Rlatlng, { + radius: 3, + // #AAAAAA outline seems easier to see the fill opacity + color: '#AAAAAA', + opacity: 1, + weight: 1, + fillColor: COLORS_LVL[rdata.level], + fillOpacity: rdata.energyTotal/RESO_NRG[rdata.level], + clickable: false, + level: rdata.level, + details: rdata, + pDetails: ent[2], + guid: portalResonatorGuid(ent[0],i) }); + + r.on('remove', function() { delete window.resonators[this.options.guid]; }); + r.on('add', function() { window.resonators[this.options.guid] = this; }); + + r.addTo(portalsLayers[parseInt(portalLevel)]); + } +} + +// append portal guid with -resonator-[slot] to get guid for resonators +window.portalResonatorGuid = function(portalGuid, slot) { + return portalGuid + '-resonator-' + slot; +} + +window.isResonatorsShow = function() { + return map.getZoom() >= RESONATOR_DISPLAY_ZOOM_LEVEL; +} + window.portalResetColor = function(portal) { portal.setStyle({color: portal.options.fillColor}); } diff --git a/code/utils_misc.js b/code/utils_misc.js index 4959c40a..aa8d44a5 100644 --- a/code/utils_misc.js +++ b/code/utils_misc.js @@ -154,6 +154,8 @@ window.getTypeByGuid = function(guid) { // .b == fields // .c == player/creator // .d == chat messages + // + // resonator guid is [portal guid]-resonator-[slot] switch(guid.slice(33)) { case '11': case '12': @@ -172,6 +174,7 @@ window.getTypeByGuid = function(guid) { return TYPE_CHAT; default: + if(guid.slice(-11,-2) == 'resonator') return TYPE_RESONATOR; return TYPE_UNKNOWN; } } diff --git a/main.js b/main.js index 22ff37b0..0def816c 100644 --- a/main.js +++ b/main.js @@ -139,11 +139,19 @@ var NOMINATIM = 'http://nominatim.openstreetmap.org/search?format=json&limit=1&q var DEG2RAD = Math.PI / 180; var TEAM_NONE = 0, TEAM_RES = 1, TEAM_ENL = 2; var TEAM_TO_CSS = ['none', 'res', 'enl']; -var TYPE_UNKNOWN = 0, TYPE_PORTAL = 1, TYPE_LINK = 2, TYPE_FIELD = 3, TYPE_PLAYER = 4, TYPE_CHAT = 5; +var TYPE_UNKNOWN = 0, TYPE_PORTAL = 1, TYPE_LINK = 2, TYPE_FIELD = 3, TYPE_PLAYER = 4, TYPE_CHAT = 5, TYPE_RESONATOR = 6; // make PLAYER variable available in site context var PLAYER = window.PLAYER; var CHAT_SHRINKED = 60; +// Minimum zoom level resonator will display +var RESONATOR_DISPLAY_ZOOM_LEVEL = 17; + +// Constants for resonator positioning +var SLOT_TO_LAT = [0, Math.sqrt(2)/2, 1, Math.sqrt(2)/2, 0, -Math.sqrt(2)/2, -1, -Math.sqrt(2)/2]; +var SLOT_TO_LNG = [1, Math.sqrt(2)/2, 0, -Math.sqrt(2)/2, -1, -Math.sqrt(2)/2, 0, Math.sqrt(2)/2]; +var EARTH_RADIUS=6378137; + // STORAGE /////////////////////////////////////////////////////////// // global variables used for storage. Most likely READ ONLY. Proper // way would be to encapsulate them in an anonymous function and write @@ -164,6 +172,7 @@ var portalsLayers, linksLayer, fieldsLayer; window.portals = {}; window.links = {}; window.fields = {}; +window.resonators = {}; // plugin framework. Plugins may load earlier than iitc, so don’t // overwrite data