var map = L.map('map').setView([55.68, 12.57], 13); L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap' }).addTo(map); let known_store_chains; let icons = {}; var markers = L.featureGroup().addTo(map); var polygons = L.featureGroup().addTo(map); var heatmap = L.featureGroup().addTo(map); const CategoryField = document.getElementById('Category'); const CountryField = document.getElementById('Country'); const LoadingIndicator = document.getElementById('LoadingIndicator'); const SubmitButton = document.getElementById('SubmitButton'); const form = document.getElementById('QueryForm'); const heatmap_intensity_element = document.getElementById("HeatmapIntensity"); const heatmap_radius_element = document.getElementById("HeatmapRadius"); var shops; const DefaultSearchValue = "supermarket"; var Categories = [] var overlayMaps = { "POI markers": markers, "Nearest POI polygons": polygons, "POI heatmap": heatmap }; var layerControl = L.control.layers({},overlayMaps).addTo(map); form.addEventListener('submit', (event) => { event.preventDefault(); // Prevents the default form submission changeCategory(); }); heatmap_intensity_element.addEventListener('input', (event) => { changeHeatmap(); }); heatmap_radius_element.addEventListener('input', (event) => { changeHeatmap(); }); function changeHeatmap() { const url = new URL(location); url.searchParams.set("HeatmapIntensity", heatmap_intensity_element.value); history.pushState({}, "", url); url.searchParams.set("HeatmapRadius", heatmap_radius_element.value); history.pushState({}, "", url); drawHeatmap(); } function changeCategory() { if (!SubmitButton.disabled) { // Disallow double queries SubmitButton.disabled = true; LoadingIndicator.hidden = false; const url = new URL(location); url.searchParams.set("category", CategoryField.value); history.pushState({}, "", url); markers.clearLayers(); polygons.clearLayers(); fetchAll(CountryField.value, CategoryField.value); } } function alterHeatMapParameter(event) { event.srcElement.value; } async function fetchCategories() { let response; try { response = await fetch("categories.json"); if (!response.ok) { // If the response status is not OK, throw an error throw new Error(`HTTP error! Status: ${response.status}`); } } catch (error) { alert(`Failed to fetch categories\n${error.message}`) } categories = await response.json(); CategoryField.pattern = categories.join('|'); const CategoriesDataList = document.getElementById('CategoriesDataList'); categories.forEach(function(item){ var option = document.createElement('option'); option.value = item; option.innerHTML = item; CategoriesDataList.appendChild(option); }); } async function fetchChains() { try { const response = await fetch("chains.json"); known_store_chains = await response.json(); if (!response.ok) { // If the response status is not OK, throw an error throw new Error(`HTTP error! Status: ${response.status}`); } } catch (error) { alert(`Failed to fetch chains\n${error.message}`) } icons["Unknown"] = L.icon({ iconUrl: 'icons/Unknown.png', iconSize: [10, 16], iconAnchor: [5, 8], }); for (let known_store_chain in known_store_chains) { icons[known_store_chain] = L.icon({ iconUrl: `icons/${known_store_chain}.png`, iconAnchor: [8, 8], }); } const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const urlParam = urlParams.get('category') const fieldValue = CategoryField.value // Retains saved value from input field on reload if (urlParam) { fetchAll(CountryField.value, urlParam); CategoryField.value = urlParam; } else if (fieldValue !== "") { fetchAll(CountryField.value, fieldValue); } else { CategoryField.value = DefaultSearchValue; fetchAll(CountryField.value, DefaultSearchValue); } } function addPolygon(store) { let color; if (known_store_chains.hasOwnProperty(store.brand)) { color = known_store_chains[store.brand]; } else { color = 'grey'; } L.polygon(store.polygon, {color: color}).addTo(polygons); } function addShop(shop) { let icon; if (known_store_chains.hasOwnProperty(shop.brand)){ icon = icons[shop.brand]; } else { icon = icons["Unknown"]; } L.marker([shop.lat, shop.long], { title: shop.name, icon: icon, }).addTo(markers); addPolygon(shop); } function drawHeatmap() { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const HeatmapIntensityUrlParam = urlParams.get("HeatmapIntensity") if (HeatmapIntensityUrlParam){ heatmap_intensity_element.value = HeatmapIntensityUrlParam; } const HeatmapRadiusUrlParam = urlParams.get("HeatmapRadius") if (HeatmapRadiusUrlParam){ heatmap_radius_element.value = HeatmapRadiusUrlParam; } heatmap.clearLayers(); const shops_heatmap_format = shops.map(r => [r.lat, r.long, parseInt(heatmap_intensity_element.value)]); // Convert data to heatmap format var heat = L.heatLayer(shops_heatmap_format, {radius: parseInt(heatmap_radius_element.value)}).addTo(heatmap); } async function fetchAll(country, category) { let response; try { response = await fetch(`all.json?country=${country}&category=${category}`) if (!response.ok) { // If the response status is not OK, throw an error throw new Error(`HTTP error! Status: ${response.status}`); } } catch (error) { alert(`Failed to fetch data\n${error.message}`) } shops = await response.json(); shops.forEach((shop) => addShop(shop)); // Add icons and polygons drawHeatmap(); LoadingIndicator.hidden = true; SubmitButton.disabled = false; } fetchChains(); fetchCategories();