// Initialize the map const map = new maplibregl.Map({ container: 'map', style: 'https://tiles.openfreemap.org/styles/liberty', center: [2.3522, 48.8566], // Default center (Paris) zoom: 4 }); // Add navigation controls map.addControl(new maplibregl.NavigationControl()); // Add draw controls for polygon let drawnPolygon = null; let drawingMode = false; let points = []; let lineString = null; let polygonFill = null; // Add a button to toggle drawing mode const drawButton = document.createElement('button'); drawButton.textContent = 'Draw Polygon'; drawButton.style.position = 'absolute'; drawButton.style.top = '10px'; drawButton.style.right = '10px'; drawButton.style.zIndex = '1'; drawButton.style.padding = '5px 10px'; drawButton.style.backgroundColor = '#0078ff'; drawButton.style.color = 'white'; drawButton.style.border = 'none'; drawButton.style.borderRadius = '3px'; drawButton.style.cursor = 'pointer'; document.getElementById('map').appendChild(drawButton); drawButton.addEventListener('click', () => { drawingMode = !drawingMode; drawButton.textContent = drawingMode ? 'Cancel Drawing' : 'Draw Polygon'; if (!drawingMode) { // Clear the drawing points = []; if (lineString) { map.removeLayer('line-string'); map.removeSource('line-string'); lineString = null; } if (polygonFill) { map.removeLayer('polygon-fill'); map.removeSource('polygon-fill'); polygonFill = null; } } }); // Handle map click events for drawing map.on('click', (e) => { if (!drawingMode) return; const coords = [e.lngLat.lng, e.lngLat.lat]; points.push(coords); // If we have at least 3 points, create a polygon if (points.length >= 3) { const polygonCoords = [...points, points[0]]; // Close the polygon // Create or update the line string if (lineString) { map.removeLayer('line-string'); map.removeSource('line-string'); } lineString = { type: 'Feature', geometry: { type: 'LineString', coordinates: polygonCoords } }; map.addSource('line-string', { type: 'geojson', data: lineString }); map.addLayer({ id: 'line-string', type: 'line', source: 'line-string', paint: { 'line-color': '#0078ff', 'line-width': 2 } }); // Create or update the polygon fill if (polygonFill) { map.removeLayer('polygon-fill'); map.removeSource('polygon-fill'); } polygonFill = { type: 'Feature', geometry: { type: 'Polygon', coordinates: [polygonCoords] } }; map.addSource('polygon-fill', { type: 'geojson', data: polygonFill }); map.addLayer({ id: 'polygon-fill', type: 'fill', source: 'polygon-fill', paint: { 'fill-color': '#0078ff', 'fill-opacity': 0.2 } }); // Store the drawn polygon for search drawnPolygon = { type: 'Polygon', coordinates: [polygonCoords] }; } }); // Handle custom date range selection document.getElementById('when').addEventListener('change', function() { const customDateGroup = document.getElementById('customDateGroup'); const customDateEndGroup = document.getElementById('customDateEndGroup'); if (this.value === 'custom') { customDateGroup.style.display = 'block'; customDateEndGroup.style.display = 'block'; } else { customDateGroup.style.display = 'none'; customDateEndGroup.style.display = 'none'; } }); // Handle form submission document.getElementById('searchForm').addEventListener('submit', function(e) { e.preventDefault(); // Show loading message const resultElement = document.getElementById('result'); resultElement.textContent = 'Searching...'; resultElement.className = ''; resultElement.style.display = 'block'; // Get form values const formData = new FormData(this); const params = new URLSearchParams(); // Add form fields to params for (const [key, value] of formData.entries()) { if (value) { params.append(key, value); } } // Handle custom date range if (formData.get('when') === 'custom') { params.delete('when'); } else { params.delete('start'); params.delete('stop'); } // Prepare the request let url = '/event/search'; let method = 'POST'; let body = null; // If we have a drawn polygon, use it for the search if (drawnPolygon) { body = JSON.stringify({ geometry: drawnPolygon }); } else if (formData.get('near') || formData.get('bbox')) { // If we have near or bbox parameters, use GET request url = '/event?' + params.toString(); method = 'GET'; } else { // Default to a simple point search in Paris if no spatial filter is provided body = JSON.stringify({ geometry: { type: 'Point', coordinates: [2.3522, 48.8566] } }); } // Make the request fetch(url + (method === 'GET' ? '' : '?' + params.toString()), { method: method, headers: { 'Content-Type': 'application/json' }, body: method === 'POST' ? body : null }) .then(response => { if (response.ok) { return response.json(); } else { return response.text().then(text => { throw new Error(text || response.statusText); }); } }) .then(data => { // Show success message resultElement.textContent = `Found ${data.features ? data.features.length : 0} events`; resultElement.className = 'success'; // Display results displayResults(data); }) .catch(error => { // Show error message resultElement.textContent = `Error: ${error.message}`; resultElement.className = 'error'; // Hide results container document.getElementById('resultsContainer').style.display = 'none'; }); }); // Function to display search results function displayResults(data) { // Show results container document.getElementById('resultsContainer').style.display = 'block'; // Initialize results map const resultsMap = new maplibregl.Map({ container: 'resultsMap', style: 'https://tiles.openfreemap.org/styles/liberty', center: [2.3522, 48.8566], // Default center (Paris) zoom: 4 }); // Add navigation controls to results map resultsMap.addControl(new maplibregl.NavigationControl()); // Add events to the map resultsMap.on('load', function() { // Add events as a source resultsMap.addSource('events', { type: 'geojson', data: data }); // Add a circle layer for events resultsMap.addLayer({ id: 'events-circle', type: 'circle', source: 'events', paint: { 'circle-radius': 8, 'circle-color': '#FF5722', 'circle-stroke-width': 2, 'circle-stroke-color': '#FFFFFF' } }); // Add popups for events if (data.features) { data.features.forEach(feature => { const coordinates = feature.geometry.coordinates.slice(); const properties = feature.properties; // Create popup content let popupContent = '
Type: ${properties.what}
`; } if (properties.where) { popupContent += `Where: ${properties.where}
`; } if (properties.start) { popupContent += `Start: ${properties.start}
`; } if (properties.stop) { popupContent += `End: ${properties.stop}
`; } // Add link to view full event popupContent += ``; popupContent += '