var map = L.map('map'); var tilesosmorg = new L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© Openstreetmap Contributors', maxNativeZoom: 19, maxZoom: 22 }); var tilesosmde = new L.TileLayer('https://{s}.osm.rrze.fau.de/osmde/{z}/{x}/{y}.png', { attribution: '© Openstreetmap Contributors', maxNativeZoom: 19, maxZoom: 22 }); var tilestfod = new L.TileLayer('https://{s}.tile.thunderforest.com/outdoors/{z}/{x}/{y}.png', { attribution: 'Maps © Thunderforest, Data © OpenStreetMap contributors', maxNativeZoom: 22, maxZoom: 22 }); L.control.scale({imperial: false}).addTo(map); var overlay_config = { maxNativeZoom: 22, maxZoom: 22, attribution: "", maximumAge: 1000*3600*24*10 } var routers = new L.TileLayer(tileurls.routers + '/{z}/{x}/{y}.png', overlay_config); var routers_v2 = new L.TileLayer(tileurls.routers_v2 + '/{z}/{x}/{y}.png', overlay_config); var routers_local = new L.TileLayer(tileurls.routers_local + '/{z}/{x}/{y}.png', overlay_config); var hoods_v2 = new L.TileLayer(tileurls.hoods_v2 + '/{z}/{x}/{y}.png', overlay_config); var hoods_poly = new L.TileLayer(tileurls.hoods_poly + '/{z}/{x}/{y}.png', overlay_config); var popuplayer = new L.TileLayer(''); layersControl = new L.Control.Layers({ "openstreetmap.org": tilesosmorg, "openstreetmap.de": tilesosmde, "Thunderforest Outdoors": tilestfod }, { "Routers V1": routers, "Routers V2": routers_v2, "Local Routers": routers_local, "Hoods V2": hoods_v2, "Poly-Hoods": hoods_poly, "Position-Popup": popuplayer }); map.addControl(layersControl); var router_pointer_radius = 7.5; // actually 7 but let's add some rounding tolerance if (window.matchMedia("(min--moz-device-pixel-ratio: 1.5),(-o-min-device-pixel-ratio: 3/2),(-webkit-min-device-pixel-ratio: 1.5),(min-device-pixel-ratio: 1.5),(min-resolution: 1.5dppx)").matches) { // Retina 2k Display: Make it easier to hit the pointer router_pointer_radius *= 2; } var popup; var popupopen = false; function update_permalink() { if (typeof mapurl != 'undefined') { var pos = map.getCenter(); var zoom = map.getZoom(); window.history.replaceState({}, document.title, mapurl + '?mapcenter=' + pos.lat.toFixed(5) + ',' + pos.lng.toFixed(5) + ',' + zoom + '&source=' + (map.hasLayer(tilesosmorg) ? 1 : (map.hasLayer(tilesosmde) ? 2 : 3)) + '&layers=' + (map.hasLayer(routers)|0) + ',' + (map.hasLayer(routers_v2)|0) + ',' + (map.hasLayer(routers_local)|0) + ',' + '0,' + (map.hasLayer(hoods_v2)|0) + ',' + (map.hasLayer(hoods_poly)|0) + ',' + (map.hasLayer(popuplayer)|0) ); } } function initialMap() { map.addLayer(tilesosmorg); } function initialLayers() { routers.addTo(map); routers_v2.addTo(map); routers_local.addTo(map); } function setupMap(getargs) { var getsrc = getargs.replace("source=", ""); if(getsrc==2) { map.addLayer(tilesosmde); } else if(getsrc==3) { map.addLayer(tilestfod); } else { map.addLayer(tilesosmorg); } } function setupLayers(getargs) { var getlayers = getargs.replace("layers=", "").split(","); if(getlayers[0]==1) { routers.addTo(map); } if(getlayers[1]==1) { routers_v2.addTo(map); } if(getlayers[2]==1) { routers_local.addTo(map); } // getlayers[3] former hoods_v1 unused if(getlayers[4]==1) { hoods_v2.addTo(map); } if(getlayers[5]==1) { hoods_poly.addTo(map); } if(getlayers[6]==1) { popuplayer.addTo(map); } } map.on('moveend', update_permalink); map.on('zoomend', update_permalink); map.on('overlayadd', update_permalink); map.on('overlayremove', update_permalink); map.on('baselayerchange', update_permalink); map.on('click', function(pos) { // height = width of world in px var size_of_world_in_px = map.options.crs.scale(map.getZoom()); layeropt = "" if (map.hasLayer(routers)) { console.debug("Looking for router in V1 ..."); layeropt += "&v1=on" } if (map.hasLayer(routers_v2)) { console.debug("Looking for router in V2 ..."); layeropt += "&v2=on" } if (map.hasLayer(routers_local)) { console.debug("Looking for router in local hoods ..."); layeropt += "&local=on" } var px_per_deg_lng = size_of_world_in_px / 360; var px_per_deg_lat = size_of_world_in_px / 180; // normalize longitude (user can shift map west/east and leave the [-180..180] range var lng = mod(pos.latlng.lng, 360); var lat = pos.latlng.lat; if (lng > 180) { lng -= 360; } ajax_get_request(url_get_nearest_router + "?lng=" + lng + "&lat=" + lat + layeropt, function(router) { if (router) { // decide if router is close enough var lng_delta = Math.abs(lng - router.lng) var lat_delta = Math.abs(lat - router.lat) // convert degree distances into px distances on the map var x_delta_px = lng_delta * px_per_deg_lng; var y_delta_px = lat_delta * px_per_deg_lat; // use pythagoras to calculate distance var px_distance = Math.sqrt(x_delta_px*x_delta_px + y_delta_px*y_delta_px); console.debug("Distance to closest router ("+router.hostname+"): " + px_distance+"px"); } // check if mouse click was on the router icon if (router && px_distance <= router_pointer_radius) { popupopen = true; console.log("Click on '"+router.hostname+"' detected."); console.log(router); var popup_html = ""; var has_neighbours = 'neighbours' in router && router.neighbours.length > 0; // avoid empty tables if (has_neighbours) { has_neighbours = false; for (var i = 0; i < router.neighbours.length; i++) { neighbour = router.neighbours[i]; if ('id' in neighbour) { has_neighbours = true; } } } if (has_neighbours) { console.log("Has "+router.neighbours.length+" neighbours."); popup_html += "
"; } else { console.log("Has no neighbours."); popup_html += "
"; } popup_html += 'Router '+router.hostname+''; popup_html += "
" if (has_neighbours) { popup_html += ''; popup_html += ""; popup_html += ""; popup_html += ""; popup_html += ""; popup_html += ""; for (var i = 0; i < router.neighbours.length; i++) { neighbour = router.neighbours[i]; // skip unknown neighbours if ('id' in neighbour) { popup_html += ""; popup_html += ''; // MACTODO popup_html += ""; popup_html += ""; popup_html += ""; } } popup_html += "
LinkQualityInterface
'+escapeHTML(neighbour.hostname)+'"+neighbour.quality+""+escapeHTML(neighbour.netif)+"
"; } popup = L.popup({offset: new L.Point(1, 1), maxWidth: 500}) .setLatLng([router.lat, router.lng]) .setContent(popup_html) .openOn(map); } else if(popupopen) { popupopen = false; } else if(map.hasLayer(popuplayer)) { popupopen = true; console.log("Click on lat: "+lat+", lng: "+lng+" detected."); var popup_html = "
"; popup_html += 'Coordinates'; popup_html += ''; popup_html += ''; popup_html += "
" popup = L.popup({offset: new L.Point(1, 1), maxWidth: 500}) .setLatLng([lat, lng]) .setContent(popup_html) .openOn(map); } }); }); function ajax_get_request(url, callback_fkt) { var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { var response_data = JSON.parse(xmlhttp.responseText); callback_fkt(response_data); } } xmlhttp.open("GET", url, true); xmlhttp.send(); } function mod(n, m) { // use own modulo function (see http://stackoverflow.com/q/4467539) return ((n % m) + m) % m; } var entityMap = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' }; function escapeHTML(string) { return String(string).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; }); }