// all function related to the map import * as dt from './datetime.js' import * as utils from "./chart_utilities.js" import { showChart, loadAll } from './showcharts.js' let map = null let bounds let popuptext = '' let clickedSensor = 0 let clickedcoords = {} const colorscale = ['#d53e4f', '#fc8d59', '#fee08b', '#e6f598', '#99d594', '#3288bd', '#808080']; const dba = [100, 80, 60, 40, 20, 0, -999]; export async function showMap(params) { utils.removeTabs() if(map && map.remove) { map.off(); map.remove(); } map = L.map('map', {scrollWheelZoom: false}).setView(params.center, parseInt(params.zoom)) L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map) bounds = map.getBounds(); map.on('moveend', async function () { bounds = map.getBounds() await buildMarkers(bounds) }); let legend = L.control({position: 'bottomright'}) legend.onAdd = function (map) { let div = L.DomUtil.create('div', 'info legend') let div_color = L.DomUtil.create('div', 'info legend inner', div) div_color.innerHTML += 'dbA
'; // loop through our density intervals and generate a label with a colored square for each interval for (let i = 0; i < dba.length - 1; i++) { div_color.innerHTML += '' + '  ' + dba[i] + (i == 0 ? '+' : '') + '
' } div_color.innerHTML += '  offline' return div }; legend.addTo(map) let lastdate = await buildMarkers() showLastDate(lastdate); map.on('popupopen', function () { document.querySelector('.speciallink').addEventListener('click', async function (x) { console.log(`Event clicked: ${clickedSensor}`) document.querySelector('#navi').style.display = 'block' params.sid = clickedSensor let triggerEl = document.querySelector('#livetab') bootstrap.Tab.getInstance(triggerEl).show() // Select tab by name let ok = await showChart(params, 'live', 'dlive') if (ok) { await loadAll(params) } map.setView([clickedcoords.lat, clickedcoords.lng]); }) }) } function getColor(d) { let val = parseInt(d); for (let i = 0; i < dba.length; i++) { if (val >= dba[i]) { return (colorscale[i]); } } } function calcPolygon(bounds) { return L.polygon([[bounds.getNorth(), bounds.getWest()], [bounds.getNorth(), bounds.getEast()], [bounds.getSouth(), bounds.getEast()], [bounds.getSouth(), bounds.getWest()]], { color: 'black', fillOpacity: 0.5 }); ; } // With all Markers in cluster (markers) calculate the median // of the values. With this median fetch the color and return it. // If there are 'offline' sensors (value == -1) strip then before // calculating the median. If there are only offline sensor, return // color of value==-1 (dark gray). function getMedian(markers) { markers.sort(function (a, b) { // first sort, the lowest first let y1 = a.options.value; let y2 = b.options.value; if (y1 < y2) { return -1; } if (y2 < y1) { return 1; } return 0; }); // console.log(markers); let i = 0; // now find the 'offlines' (value == -1) for (i = 0; i < markers.length; i++) { if (markers[i].options.value > 0) { break; } } markers.splice(0, i); // remove these from array let lang = markers.length; if (lang > 1) { // if ((lang % 2) == 1) { // uneven -> return getColor(markers[(Math.floor(lang / 2))].options.value); // median is in the middle } else { // evaen -> lang = lang / 2; // median is mean of both middle values // console.log(lang); let wert = (markers[lang - 1].options.value + markers[lang].options.value) / 2; return getColor(wert); } } else if (lang == 1) { // only one marker -> return its color return getColor(markers[0].options.value); } return getColor(-1); // only offlines } function buildIcon(color, n, indoor) { let x = 100; if (n < 10) { x = 200; } else if (n < 100) { x = 150; } let txtColor = "black"; if (color == colorscale[5]) { txtColor = "white" } let circIcon = '' + ''; if (n !== 0) { circIcon += '' + n + ''; } if(indoor) { circIcon += '' } circIcon += ''; let circIconUrl = encodeURI("data:image/svg+xml," + circIcon).replace(new RegExp('#', 'g'), '%23'); return circIconUrl; } export async function buildMarkers() { // debug_log('buildMarkers(bounds)'); const box = { west: bounds.getWest(), south: bounds.getSouth(), east: bounds.getEast(), north: bounds.getNorth() } const url = `/api/getmapdata?type=noise&box=${bounds.toBBoxString()}` let ret = await fetch(url) .catch(e => { console.log(e) }); let sensors = await ret.json() if (!sensors.err) { let markers = L.markerClusterGroup({ spiderfyOnMaxZoom: true, showCoverageOnHover: false, zoomToBoundsOnClick: true, // disableClusteringAtZoom: 14, iconCreateFunction: function (cluster) { let mymarkers = cluster.getAllChildMarkers(); let color = getMedian(mymarkers); return new L.Icon({ iconUrl: buildIcon(color, cluster.getChildCount(), 0), iconSize: [35, 35] }); }, }); for (let x of sensors.values) { if (x.value <= -4) { continue } let marker = L.marker([x.location[1], x.location[0]], { icon: new L.Icon({ iconUrl: buildIcon(getColor(parseInt(x.value)), 0, x.indoor), iconSize: [35, 35], }), name: x.id, value: x.value, url: '/graph?sid=' + x.id, lastseen: dt.formatISODate(x.lastseen), indoor: x.indoor }) .on('click', e => onMarkerClick(e, true)) // define click- and .bindPopup(popuptext); // and bint the popup text markers.addLayer(marker); } map.addLayer(markers); return sensors.lastdate } else { utils.showError(sensors.err) } } async function onMarkerClick(e, click) { let item = e.target.options; clickedSensor = item.name; clickedcoords = e.latlng let offlinetext = ` offline Last seen:${item.lastseen}` let normaltext = ` LA_max:${item.value}` let popuptext = `

Sensor: ${item.name}

${item.value < 0 ? offlinetext : normaltext}
${item.indoor==1 ? "indoor" : ""}
` let popup = e.target.getPopup(); popup.setContent(popuptext); // set text into popup e.target.openPopup(); // show the popup if (click == true) { // if we clicked e.target.closePopup(); // show the popup } } async function getCoords(city) { let url = NOMINATIM_URL + city; const response = await axios.get(encodeURI(url)); const data = response.data; return data[0]; } // Map auf Stadt setzen async function setCenter(adr) { let data = await getCoords(adr); map.setView([parseFloat(data.lat), parseFloat(data.lon)]); console.log(data); } // Show the last date below tha map grafics async function showLastDate(ld) { const url = `/api/getmapdata?type=noise` let ret = await fetch(url) .catch(e => { console.log(e) }); let sensors = await ret.json() let actsensors = 0 for (let x of sensors.values) { if (x.value >= 0) { actsensors++ } } document.querySelector('#mapdate').innerText = 'Values from ' + dt.formatISODate(ld).slice(0,-3) document.querySelector('#actsensors').innerText = `Active sensors: ${actsensors} (registered: ${sensors.count})` // $('#actsensors').html(`${erg.count} aktive Sensoren (angemeldet ${allsens})`) }