204 lines
No EOL
8.8 KiB
Python
204 lines
No EOL
8.8 KiB
Python
"""
|
|
Demo resource for the OpenEventDatabase.
|
|
"""
|
|
|
|
import falcon
|
|
from oedb.utils.logging import logger
|
|
|
|
class DemoResource:
|
|
"""
|
|
Resource for the demo endpoint.
|
|
Handles the /demo endpoint.
|
|
"""
|
|
|
|
def on_get(self, req, resp):
|
|
"""
|
|
Handle GET requests to the /demo endpoint.
|
|
Returns an HTML page with a MapLibre map showing current events.
|
|
|
|
Args:
|
|
req: The request object.
|
|
resp: The response object.
|
|
"""
|
|
logger.info("Processing GET request to /demo")
|
|
|
|
try:
|
|
# Set content type to HTML
|
|
resp.content_type = 'text/html'
|
|
|
|
# Create HTML response with MapLibre map
|
|
html = """
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>OpenEventDatabase Demo</title>
|
|
<script src="https://unpkg.com/maplibre-gl@3.0.0/dist/maplibre-gl.js"></script>
|
|
<link href="https://unpkg.com/maplibre-gl@3.0.0/dist/maplibre-gl.css" rel="stylesheet" />
|
|
<style>
|
|
body { margin: 0; padding: 0; font-family: Arial, sans-serif; }
|
|
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
|
|
.map-overlay {
|
|
position: absolute;
|
|
top: 10px;
|
|
left: 10px;
|
|
background: rgba(255, 255, 255, 0.9);
|
|
padding: 10px;
|
|
border-radius: 5px;
|
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
max-width: 300px;
|
|
}
|
|
h2 { margin-top: 0; }
|
|
ul { padding-left: 20px; }
|
|
a { color: #0078ff; text-decoration: none; }
|
|
a:hover { text-decoration: underline; }
|
|
.event-popup { max-width: 300px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="map"></div>
|
|
<div class="map-overlay">
|
|
<h2>OpenEventDatabase Demo</h2>
|
|
<p>This map shows current events from the OpenEventDatabase.</p>
|
|
<h3>API Endpoints:</h3>
|
|
<ul>
|
|
<li><a href="/" target="_blank">/ - API Information</a></li>
|
|
<li><a href="/event" target="_blank">/event - Get Events</a></li>
|
|
<li><a href="/stats" target="_blank">/stats - Database Statistics</a></li>
|
|
</ul>
|
|
<p><a href="https://source.cipherbliss.com/tykayn/oedb-backend" target="_blank">Source Code on GitHub</a></p>
|
|
</div>
|
|
|
|
<script>
|
|
// Initialize the map
|
|
const map = new maplibregl.Map({
|
|
container: 'map',
|
|
style: 'https://demotiles.maplibre.org/style.json',
|
|
center: [2.3522, 48.8566], // Default center (Paris)
|
|
zoom: 4
|
|
});
|
|
|
|
// Add navigation controls
|
|
map.addControl(new maplibregl.NavigationControl());
|
|
|
|
// Fetch events when the map is loaded
|
|
map.on('load', function() {
|
|
fetchEvents();
|
|
});
|
|
|
|
// Function to fetch events from the API
|
|
function fetchEvents() {
|
|
// Get current date in YYYY-MM-DD format
|
|
const today = new Date().toISOString().split('T')[0];
|
|
|
|
// Fetch events from the API
|
|
fetch('/event?when=' + today)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.features && data.features.length > 0) {
|
|
// Add events to the map
|
|
addEventsToMap(data);
|
|
|
|
// Fit map to events bounds
|
|
fitMapToBounds(data);
|
|
} else {
|
|
console.log('No events found');
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching events:', error);
|
|
});
|
|
}
|
|
|
|
// Function to add events to the map
|
|
function addEventsToMap(geojson) {
|
|
// Add a GeoJSON source for events
|
|
map.addSource('events', {
|
|
type: 'geojson',
|
|
data: geojson
|
|
});
|
|
|
|
// Add a circle layer for events
|
|
map.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
|
|
geojson.features.forEach(feature => {
|
|
const coordinates = feature.geometry.coordinates.slice();
|
|
const properties = feature.properties;
|
|
|
|
// Create popup content
|
|
let popupContent = '<div class="event-popup">';
|
|
popupContent += `<h3>${properties.label || 'Event'}</h3>`;
|
|
popupContent += `<p><strong>Date:</strong> ${properties.when || 'Unknown'}</p>`;
|
|
|
|
if (properties.what) {
|
|
popupContent += `<p><strong>Type:</strong> ${properties.what}</p>`;
|
|
}
|
|
|
|
if (properties.source) {
|
|
popupContent += `<p><a href="${properties.source}" target="_blank">More Information</a></p>`;
|
|
}
|
|
|
|
popupContent += '</div>';
|
|
|
|
// Create popup
|
|
const popup = new maplibregl.Popup({
|
|
closeButton: true,
|
|
closeOnClick: true
|
|
}).setHTML(popupContent);
|
|
|
|
// Add marker with popup
|
|
new maplibregl.Marker({
|
|
color: '#FF5722'
|
|
})
|
|
.setLngLat(coordinates)
|
|
.setPopup(popup)
|
|
.addTo(map);
|
|
});
|
|
}
|
|
|
|
// Function to fit map to events bounds
|
|
function fitMapToBounds(geojson) {
|
|
if (geojson.features.length === 0) return;
|
|
|
|
// Create a bounds object
|
|
const bounds = new maplibregl.LngLatBounds();
|
|
|
|
// Extend bounds with each feature
|
|
geojson.features.forEach(feature => {
|
|
bounds.extend(feature.geometry.coordinates);
|
|
});
|
|
|
|
// Fit map to bounds with padding
|
|
map.fitBounds(bounds, {
|
|
padding: 50,
|
|
maxZoom: 12
|
|
});
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
# Set the response body and status
|
|
resp.text = html
|
|
resp.status = falcon.HTTP_200
|
|
logger.success("Successfully processed GET request to /demo")
|
|
except Exception as e:
|
|
logger.error(f"Error processing GET request to /demo: {e}")
|
|
resp.status = falcon.HTTP_500
|
|
resp.text = f"Error: {str(e)}"
|
|
|
|
# Create a global instance of DemoResource
|
|
demo = DemoResource() |