// all function related to the map import * as dt from './datetime.js' let map let bounds let popuptext = '' const colorscale = ['#d53e4f', '#fc8d59', '#fee08b', '#e6f598', '#99d594', '#3288bd', '#808080']; const dba = [100, 80, 60, 40, 20, 0, -999]; export const showMap = (params) => { 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) } 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 }); ; } async function plotMap(cid, poly) { // if sensor nbr is give, find coordinates, else use Stuttgart center debug_log('plotMap()'); let myLatLng; if (cid != -1) { myLatLng = await getSensorKoords(cid); } else { let stgt = await getCoords('Stuttgart'); myLatLng = {lat: parseFloat(stgt.lat), lng: parseFloat(stgt.lon)}; } // generate map centered on Stuttgart map = L.map('map').setView(myLatLng, firstZoom); L.tileLayer('https://{s}.tile.openstreetmap.de/{z}/{x}/{y}.png', { maxZoom: 17, attribution: '© OpenStreetMap contributors' }).addTo(map); bounds = map.getBounds(); map.scrollWheelZoom.disable(); 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 infobutton = L.control({position: 'topright'}); infobutton.onAdd = function (map) { let div = L.DomUtil.create('div'); div.innerHTML = ''; div.onclick = function () { dialogCenter.dialog('open'); console.log('Clicked on Zentrieren'); } return div; } infobutton.addTo(map); if (useStgtBorder) { fetchStuttgartBounds(); } if (myLatLng.error != undefined) { showError(3, "Kein Lärmsensor", cid); } else { await buildMarkers(bounds); map.on('popupopen', function () { $('.speciallink').click(function (x) { showGrafik(clickedSensor); }); }); } } // 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 != -1) { 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 !== 0) { 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 = `http://localhost:3004/getmapdata?type=noise&box=${bounds.toBBoxString()}` let ret = await fetch(url) .catch(e => { console.log(e) }); let sensors = await ret.json() 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) { 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.formatJSDate(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); showLastDate(sensors.lastDate); } async function onMarkerClick(e, click) { let item = e.target.options; let clickedSensor = item.name; 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); }