/** * Map initialization and GeoJSON visualization * This file handles the map creation and displaying GeoJSON data on it */ // Store the map object globally let map = null; let currentFeatureType = 'buildings'; // Initialize the map with default settings function initMap() { // If map already exists, remove it and create a new one if (map !== null) { map.remove(); } // Create a new map centered on a default location (Central US instead of NY) map = L.map('map').setView([33.0, -97.0], 8); // Define tile layers const osmLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OpenStreetMap contributors', maxZoom: 19 }); const satelliteLayer = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { attribution: 'Imagery © Esri', maxZoom: 19 }); // Add OpenStreetMap layer by default osmLayer.addTo(map); // Add layer control const baseLayers = { "OpenStreetMap": osmLayer, "Satellite": satelliteLayer }; L.control.layers(baseLayers, null, {position: 'topright'}).addTo(map); // Add a scale control L.control.scale().addTo(map); return map; } // Display GeoJSON data on the map function displayGeoJSON(geojsonData) { if (!map) { initMap(); } // Update feature type if available in the data if (geojsonData && geojsonData.feature_type) { currentFeatureType = geojsonData.feature_type; } // Clear any existing GeoJSON layers map.eachLayer(function(layer) { if (layer instanceof L.GeoJSON) { map.removeLayer(layer); } }); // Add the GeoJSON data to the map with styling based on feature type const geojsonLayer = L.geoJSON(geojsonData, { style: function(feature) { // Different styling based on feature type switch(currentFeatureType) { case 'buildings': return { fillColor: '#e63946', weight: 1.5, opacity: 1, color: '#999', fillOpacity: 0.7 }; case 'trees': return { fillColor: '#2a9d8f', weight: 1, opacity: 0.9, color: '#006d4f', fillOpacity: 0.7 }; case 'water': return { fillColor: '#0077b6', weight: 1, opacity: 0.8, color: '#023e8a', fillOpacity: 0.6 }; case 'roads': return { fillColor: '#a8dadc', weight: 3, opacity: 1, color: '#457b9d', fillOpacity: 0.8 }; default: return { fillColor: getRandomColor(), weight: 2, opacity: 1, color: '#666', fillOpacity: 0.7 }; } }, pointToLayer: function(feature, latlng) { // Style points based on feature type let pointStyle = { radius: 8, color: "#000", weight: 1, opacity: 1, fillOpacity: 0.8 }; // Set color based on feature type switch(currentFeatureType) { case 'buildings': pointStyle.fillColor = '#e63946'; break; case 'trees': pointStyle.fillColor = '#2a9d8f'; break; case 'water': pointStyle.fillColor = '#0077b6'; break; case 'roads': pointStyle.fillColor = '#a8dadc'; break; default: pointStyle.fillColor = getRandomColor(); } return L.circleMarker(latlng, pointStyle); }, onEachFeature: function(feature, layer) { // Add popups to show feature properties if (feature.properties) { let popupContent = '